Source code for the Curilights Controller. See http://www.saccade.com/writing/projects/CuriController/ for details.
Dependencies: FatFileSystem mbed
This is the source code for the Curilights controller. This lets you interactively control a string of Curilights. It provides a simple click-wheel user interface for changing colors, brightness and behavior. It responds to movement and lighting.
Finished Controller
System Block Diagram
UIMenu.cpp@0:6da5625a6946, 2011-12-29 (annotated)
- Committer:
- isonno
- Date:
- Thu Dec 29 01:59:53 2011 +0000
- Revision:
- 0:6da5625a6946
- Child:
- 1:d1da77023e6a
Contest submission version
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
isonno |
0:6da5625a6946 | 1 | // |
isonno |
0:6da5625a6946 | 2 | // UIMenu - Click-knob menu implementation |
isonno |
0:6da5625a6946 | 3 | // |
isonno |
0:6da5625a6946 | 4 | |
isonno |
0:6da5625a6946 | 5 | #include "NokiaLCD.h" |
isonno |
0:6da5625a6946 | 6 | #include "UIMenu.h" |
isonno |
0:6da5625a6946 | 7 | #include "HoldInterrupts.h" |
isonno |
0:6da5625a6946 | 8 | |
isonno |
0:6da5625a6946 | 9 | static Timeout gScreenTimer; |
isonno |
0:6da5625a6946 | 10 | |
isonno |
0:6da5625a6946 | 11 | void PushKnobUI::ConnectDevices( RotaryEncoder * knob, PushButton * button ) |
isonno |
0:6da5625a6946 | 12 | { |
isonno |
0:6da5625a6946 | 13 | HoldInterrupts holdint(); |
isonno |
0:6da5625a6946 | 14 | |
isonno |
0:6da5625a6946 | 15 | if (! knob && fKnob) // Disconnect |
isonno |
0:6da5625a6946 | 16 | { |
isonno |
0:6da5625a6946 | 17 | fKnob->detach(); |
isonno |
0:6da5625a6946 | 18 | fKnob = NULL; |
isonno |
0:6da5625a6946 | 19 | } |
isonno |
0:6da5625a6946 | 20 | if (! button && fKnobButton) |
isonno |
0:6da5625a6946 | 21 | { |
isonno |
0:6da5625a6946 | 22 | fKnobButton->detach(); |
isonno |
0:6da5625a6946 | 23 | fKnobButton = NULL; |
isonno |
0:6da5625a6946 | 24 | } |
isonno |
0:6da5625a6946 | 25 | |
isonno |
0:6da5625a6946 | 26 | if (knob && !fKnob) |
isonno |
0:6da5625a6946 | 27 | { |
isonno |
0:6da5625a6946 | 28 | fKnob = knob; |
isonno |
0:6da5625a6946 | 29 | //fKnob->attach( this, &UIMenu::KnobMoved ); |
isonno |
0:6da5625a6946 | 30 | AttachKnob( fKnob ); |
isonno |
0:6da5625a6946 | 31 | } |
isonno |
0:6da5625a6946 | 32 | if (button && !fKnobButton) |
isonno |
0:6da5625a6946 | 33 | { |
isonno |
0:6da5625a6946 | 34 | fKnobButton = button; |
isonno |
0:6da5625a6946 | 35 | //fKnobButton->attach( this, &UIMenu::KnobPushed ); |
isonno |
0:6da5625a6946 | 36 | AttachButton( fKnobButton ); |
isonno |
0:6da5625a6946 | 37 | } |
isonno |
0:6da5625a6946 | 38 | } |
isonno |
0:6da5625a6946 | 39 | |
isonno |
0:6da5625a6946 | 40 | void PushKnobUI::SwitchTo( PushKnobUI * other ) |
isonno |
0:6da5625a6946 | 41 | { |
isonno |
0:6da5625a6946 | 42 | other->ConnectDevices( fKnob, fKnobButton ); |
isonno |
0:6da5625a6946 | 43 | fKnob = NULL; |
isonno |
0:6da5625a6946 | 44 | fKnobButton = NULL; |
isonno |
0:6da5625a6946 | 45 | } |
isonno |
0:6da5625a6946 | 46 | |
isonno |
0:6da5625a6946 | 47 | int32_t PushKnobUI::KnobMoved( int32_t step ) |
isonno |
0:6da5625a6946 | 48 | { |
isonno |
0:6da5625a6946 | 49 | printf("Knob moved %d\r\n", step ); |
isonno |
0:6da5625a6946 | 50 | Wake(); |
isonno |
0:6da5625a6946 | 51 | return step; |
isonno |
0:6da5625a6946 | 52 | } |
isonno |
0:6da5625a6946 | 53 | |
isonno |
0:6da5625a6946 | 54 | void PushKnobUI::KnobPushed() |
isonno |
0:6da5625a6946 | 55 | { |
isonno |
0:6da5625a6946 | 56 | Wake(); |
isonno |
0:6da5625a6946 | 57 | printf("Button pushed\r\n"); |
isonno |
0:6da5625a6946 | 58 | } |
isonno |
0:6da5625a6946 | 59 | |
isonno |
0:6da5625a6946 | 60 | void PushKnobUI::Wake() |
isonno |
0:6da5625a6946 | 61 | { |
isonno |
0:6da5625a6946 | 62 | fLCD->fade_backlight( true ); |
isonno |
0:6da5625a6946 | 63 | gScreenTimer.detach(); |
isonno |
0:6da5625a6946 | 64 | gScreenTimer.attach( this, &PushKnobUI::Sleep, 10 ); |
isonno |
0:6da5625a6946 | 65 | } |
isonno |
0:6da5625a6946 | 66 | |
isonno |
0:6da5625a6946 | 67 | void PushKnobUI::Sleep() |
isonno |
0:6da5625a6946 | 68 | { |
isonno |
0:6da5625a6946 | 69 | fLCD->fade_backlight( false ); |
isonno |
0:6da5625a6946 | 70 | gScreenTimer.detach(); |
isonno |
0:6da5625a6946 | 71 | } |
isonno |
0:6da5625a6946 | 72 | |
isonno |
0:6da5625a6946 | 73 | |
isonno |
0:6da5625a6946 | 74 | //---------------------------------------------------- |
isonno |
0:6da5625a6946 | 75 | |
isonno |
0:6da5625a6946 | 76 | UIMenu::UIMenu( CheapLCD * lcd, const char * header, bool upMenuItem ) : PushKnobUI( lcd ), |
isonno |
0:6da5625a6946 | 77 | fHeader( header ), |
isonno |
0:6da5625a6946 | 78 | fDisplayOn( false ), |
isonno |
0:6da5625a6946 | 79 | fUpMenuItem( upMenuItem ), |
isonno |
0:6da5625a6946 | 80 | fSelectedItem( kNoSelection ), |
isonno |
0:6da5625a6946 | 81 | fLCD( lcd ) |
isonno |
0:6da5625a6946 | 82 | {} |
isonno |
0:6da5625a6946 | 83 | |
isonno |
0:6da5625a6946 | 84 | void UIMenu::AddItem( const char * label ) |
isonno |
0:6da5625a6946 | 85 | { |
isonno |
0:6da5625a6946 | 86 | fLabels.push_back( string( label )); |
isonno |
0:6da5625a6946 | 87 | if (fDisplayOn) |
isonno |
0:6da5625a6946 | 88 | Display( true ); // Refresh |
isonno |
0:6da5625a6946 | 89 | } |
isonno |
0:6da5625a6946 | 90 | |
isonno |
0:6da5625a6946 | 91 | void UIMenu::ChangeItem( int item, const char * label ) |
isonno |
0:6da5625a6946 | 92 | { |
isonno |
0:6da5625a6946 | 93 | if ((item > 0) && (item < fLabels.size())) |
isonno |
0:6da5625a6946 | 94 | { |
isonno |
0:6da5625a6946 | 95 | fLabels[item] = string( label ); |
isonno |
0:6da5625a6946 | 96 | DrawItem( item ); |
isonno |
0:6da5625a6946 | 97 | } |
isonno |
0:6da5625a6946 | 98 | } |
isonno |
0:6da5625a6946 | 99 | |
isonno |
0:6da5625a6946 | 100 | int32_t UIMenu::KnobMoved( int32_t step ) |
isonno |
0:6da5625a6946 | 101 | { |
isonno |
0:6da5625a6946 | 102 | Wake(); |
isonno |
0:6da5625a6946 | 103 | |
isonno |
0:6da5625a6946 | 104 | if (fSelectedItem == kNoSelection) |
isonno |
0:6da5625a6946 | 105 | { |
isonno |
0:6da5625a6946 | 106 | fSelectedItem = (step > 0) ? 0 : fLabels.size() - 1; |
isonno |
0:6da5625a6946 | 107 | DrawItem( fSelectedItem ); |
isonno |
0:6da5625a6946 | 108 | } |
isonno |
0:6da5625a6946 | 109 | else |
isonno |
0:6da5625a6946 | 110 | { |
isonno |
0:6da5625a6946 | 111 | int lastItem = fSelectedItem; |
isonno |
0:6da5625a6946 | 112 | fSelectedItem += step; |
isonno |
0:6da5625a6946 | 113 | // Handle wrap-around |
isonno |
0:6da5625a6946 | 114 | if (fSelectedItem < 0) |
isonno |
0:6da5625a6946 | 115 | fSelectedItem = fLabels.size() - 1; |
isonno |
0:6da5625a6946 | 116 | if (fSelectedItem == fLabels.size()) |
isonno |
0:6da5625a6946 | 117 | fSelectedItem = 0; |
isonno |
0:6da5625a6946 | 118 | |
isonno |
0:6da5625a6946 | 119 | DrawItem( lastItem ); |
isonno |
0:6da5625a6946 | 120 | DrawItem( fSelectedItem ); |
isonno |
0:6da5625a6946 | 121 | } |
isonno |
0:6da5625a6946 | 122 | |
isonno |
0:6da5625a6946 | 123 | return 0; |
isonno |
0:6da5625a6946 | 124 | } |
isonno |
0:6da5625a6946 | 125 | |
isonno |
0:6da5625a6946 | 126 | void UIMenu::KnobPushed() |
isonno |
0:6da5625a6946 | 127 | { |
isonno |
0:6da5625a6946 | 128 | Wake(); |
isonno |
0:6da5625a6946 | 129 | printf("Selected %s\n\r", fLabels[fSelectedItem].c_str() ); |
isonno |
0:6da5625a6946 | 130 | } |
isonno |
0:6da5625a6946 | 131 | |
isonno |
0:6da5625a6946 | 132 | // Parameters controlling the display layout |
isonno |
0:6da5625a6946 | 133 | const int kLineSpace = 20; |
isonno |
0:6da5625a6946 | 134 | const int kTopGap = 4; |
isonno |
0:6da5625a6946 | 135 | const int kIndent = 12; |
isonno |
0:6da5625a6946 | 136 | #define MEDGREEN 0x0A0 // "medium" green |
isonno |
0:6da5625a6946 | 137 | |
isonno |
0:6da5625a6946 | 138 | void UIMenu::DrawItem( int i ) |
isonno |
0:6da5625a6946 | 139 | { |
isonno |
0:6da5625a6946 | 140 | if (! fDisplayOn) |
isonno |
0:6da5625a6946 | 141 | return; |
isonno |
0:6da5625a6946 | 142 | |
isonno |
0:6da5625a6946 | 143 | uint32_t foreColor = WHITE; |
isonno |
0:6da5625a6946 | 144 | uint32_t backColor = (i == fSelectedItem) ? MEDGREEN : BLACK; |
isonno |
0:6da5625a6946 | 145 | |
isonno |
0:6da5625a6946 | 146 | fLCD->clear( backColor, |
isonno |
0:6da5625a6946 | 147 | 0, i * kLineSpace + kLineSpace + kTopGap, |
isonno |
0:6da5625a6946 | 148 | 131, (i+1) * kLineSpace + kLineSpace + kTopGap ); |
isonno |
0:6da5625a6946 | 149 | fLCD->draw_glyph_text( foreColor, backColor, |
isonno |
0:6da5625a6946 | 150 | kIndent, (i+2) * kLineSpace, |
isonno |
0:6da5625a6946 | 151 | fLabels[i].c_str() ); |
isonno |
0:6da5625a6946 | 152 | } |
isonno |
0:6da5625a6946 | 153 | |
isonno |
0:6da5625a6946 | 154 | void UIMenu::Display( bool on ) |
isonno |
0:6da5625a6946 | 155 | { |
isonno |
0:6da5625a6946 | 156 | |
isonno |
0:6da5625a6946 | 157 | if (on) |
isonno |
0:6da5625a6946 | 158 | { |
isonno |
0:6da5625a6946 | 159 | fDisplayOn = true; |
isonno |
0:6da5625a6946 | 160 | fLCD->clear( GRAY, 0, kLineSpace + kTopGap-1, 131, kLineSpace + kTopGap ); |
isonno |
0:6da5625a6946 | 161 | if (! fHeader.empty()) |
isonno |
0:6da5625a6946 | 162 | fLCD->draw_glyph_text( WHITE, BLACK, 2, kLineSpace-2, fHeader.c_str() ); |
isonno |
0:6da5625a6946 | 163 | |
isonno |
0:6da5625a6946 | 164 | int maxLines = std::min( (int)((131 - (kLineSpace + kTopGap)) / kLineSpace), (int)fLabels.size() ); |
isonno |
0:6da5625a6946 | 165 | |
isonno |
0:6da5625a6946 | 166 | for (int i = 0; i < maxLines; ++i) |
isonno |
0:6da5625a6946 | 167 | DrawItem( i ); |
isonno |
0:6da5625a6946 | 168 | } |
isonno |
0:6da5625a6946 | 169 | else |
isonno |
0:6da5625a6946 | 170 | fDisplayOn = false; |
isonno |
0:6da5625a6946 | 171 | } |
isonno |
0:6da5625a6946 | 172 |