]> Shamusworld >> Repos - apple2/blob - src/gui/textedit.cpp
Set eol-style to native to keep things sane.
[apple2] / src / gui / textedit.cpp
1 //
2 // TEXTEDIT.CPP
3 //
4 // Graphical User Interface button class
5 // by James L. Hammons
6 //
7 // JLH = James L. Hammons <jlhamm@acm.org>
8 //
9 // WHO  WHEN        WHAT
10 // ---  ----------  ------------------------------------------------------------
11 // JLH  02/17/2006  Created this file
12 // JLH  03/01/2006  Added basic editing functionality
13 //
14
15 #include "textedit.h"
16 #include "guimisc.h"                                                            // Various support functions
17
18 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
19 #define MASK_R 0xFF000000
20 #define MASK_G 0x00FF0000
21 #define MASK_B 0x0000FF00
22 #define MASK_A 0x000000FF
23 #else
24 #define MASK_R 0x000000FF
25 #define MASK_G 0x0000FF00
26 #define MASK_B 0x00FF0000
27 #define MASK_A 0xFF000000
28 #endif
29
30 using namespace std;                                                            // For STL stuff
31
32 //
33 // Text edit class implementation
34 //
35
36 TextEdit::TextEdit(uint32 x/*= 0*/, uint32 y/*= 0*/, uint32 w/*= 0*/, uint32 h/*= 0*/,
37         string s/*= ""*/, Element * parent/*= NULL*/):
38         Element(x, y, w, h, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x40, 0x40, 0xFF, parent),
39         activated(false), clicked(false), inside(false),
40         img(NULL), text(s), caretPos(0), scrollPos(0),
41         activatedSave(false), clickedSave(false), insideSave(false),
42         caretPosSave(0), scrollPosSave(0)
43 {
44         if (extents.h == 0)
45                 extents.h = GetFontHeight();
46
47         // Setup hardwired colors...
48
49         uint8 * c = (uint8 *)&hiliteColor;
50         c[0] = 0xFF, c[1] = 0x80, c[2] = 0x00, c[3] = 0xFF;
51         c = (uint8 *)&cursorColor;
52         c[0] = 0x40, c[1] = 0xFF, c[2] = 0x60, c[3] = 0xFF;
53
54         // Create the text edit surface here...
55
56         img = SDL_CreateRGBSurface(SDL_SWSURFACE, extents.w, extents.h, 32,
57                 MASK_R, MASK_G, MASK_B, MASK_A);
58
59         Draw(); // Can we do this in the constructor??? Mebbe.
60 }
61
62 TextEdit::~TextEdit()
63 {
64         if (img)
65                 SDL_FreeSurface(img);
66 }
67
68 //Set different filters depending on type passed in on construction, e.g., filename, amount, etc...?
69 void TextEdit::HandleKey(SDLKey key)
70 {
71         if (!activated)
72                 return;
73
74         SaveStateVariables();
75         SDLMod keyMod = SDL_GetModState();
76
77         if ((key >= SDLK_a && key <= SDLK_z) || (key >= SDLK_0 && key <= SDLK_9)
78                 || key == SDLK_PERIOD || key == SDLK_SLASH || key == SDLK_SPACE)
79         {
80                 uint8 chr = (uint8)key;
81
82                 // Handle shift key as well...
83                 if (keyMod & KMOD_SHIFT)
84                 {
85                         if (key >= SDLK_a && key <= SDLK_z)
86                                 chr &= 0xDF;                                    // Set to upper case
87                 }
88
89                 text.insert(scrollPos + caretPos, 1, chr);
90
91                 // If we hit the edge, then scroll; else advance the caret
92                 if ((GetFontWidth() * caretPos) > (extents.w - GetFontWidth()))
93                         scrollPos++;
94                 else
95                         caretPos++;
96         }
97         else if (key == SDLK_BACKSPACE)
98         {
99                 // If there's something to delete, go ahead and delete it
100                 if ((scrollPos + caretPos) > 0)
101                 {
102                         text.erase(scrollPos + caretPos - 1, 1);
103
104                         // Scroll the cursor to the left if possible, otherwise move the scroll position
105                         if (caretPos > 0)
106                                 caretPos--;
107                         else
108                                 scrollPos--;
109                 }
110         }
111         else if (key == SDLK_DELETE)
112         {
113                 if ((scrollPos + caretPos) < text.length())
114                         text.erase(scrollPos + caretPos, 1);
115         }
116         else if (key == SDLK_LEFT)
117         {
118                 if (caretPos > 0)
119                         caretPos--;
120                 else if (scrollPos > 0)
121                         scrollPos--;
122         }
123         else if (key == SDLK_RIGHT)
124         {
125                 if ((scrollPos + caretPos) < text.length())
126                 {
127                         if ((GetFontWidth() * caretPos) > (extents.w - GetFontWidth()))
128                                 scrollPos++;
129                         else
130                                 caretPos++;
131                 }
132         }
133         else if (key == SDLK_RETURN)
134         {
135                 clicked = activated = false;
136         }
137
138         CheckStateAndRedrawIfNeeded();
139 }
140
141 void TextEdit::HandleMouseMove(uint32 x, uint32 y)
142 {
143         SaveStateVariables();
144         inside = Inside(x, y);
145         CheckStateAndRedrawIfNeeded();
146 }
147
148 void TextEdit::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
149 {
150         SaveStateVariables();
151
152 //Not sure that this is right way to handle this...
153 //Should set the cursor position based on where in the text box it was clicked...
154         if (inside)
155         {
156                 if (mouseDown)
157                         clicked = true;
158
159                 if (clicked && !mouseDown)
160                 {
161                         clicked = false, activated = true;
162
163                         // Send a message to our parent widget (if any) that we're activated
164                         if (parent)
165                                 parent->Notify(this);
166                 }
167         }
168         else
169                 clicked = activated = false;
170
171         CheckStateAndRedrawIfNeeded();
172 }
173
174 void TextEdit::Draw(void)
175 {
176         if (img == NULL)
177                 return;                                                                 // Bail out if no surface was created...
178
179         SDL_Rect rect = GetScreenCoords();
180
181         // Now, draw the appropriate text state!
182
183         if (!activated)
184         {
185                 if (inside)
186                 {
187                         SDL_Rect rect2;
188                         rect2.x = 1;
189                         rect2.y = 1;
190                         rect2.w = extents.w - 2;
191                         rect2.h = extents.h - 2;
192
193                         SDL_FillRect(img, NULL, hiliteColor);
194                         SDL_FillRect(img, &rect2, bgColor);
195                 }
196                 else
197                         SDL_FillRect(img, NULL, bgColor);
198         }
199         else
200                 SDL_FillRect(img, NULL, bgColor);//Make a different color here, so we're clear we're editing...
201
202 //Should also draw different text color depending on whether or not we're activated...
203         if (activated)
204                 DrawStringTrans(img, 0, 0, fgColor, text.c_str() + scrollPos);
205         else
206                 DrawStringTrans(img, 0, 0, fgColor, text.c_str());
207
208         // Draw the cursor, if any
209
210         if (activated)
211         {
212                 SDL_Rect rectCursor;
213                 rectCursor.x = caretPos * GetFontWidth();
214                 rectCursor.y = 0;
215                 rectCursor.w = 2;
216                 rectCursor.h = GetFontHeight();
217
218                 SDL_FillRect(img, &rectCursor, cursorColor);
219         }
220
221         SDL_BlitSurface(img, NULL, screen, &rect);      // This handles alpha blending too! :-D
222
223         needToRefreshScreen = true;
224 }
225
226 void TextEdit::Notify(Element *)
227 {
228 }
229
230 string TextEdit::GetText(void)
231 {
232         return text;
233 }
234
235 void TextEdit::SaveStateVariables(void)
236 {
237         activatedSave = activated;
238         clickedSave = clicked;
239         insideSave = inside;
240         caretPosSave = caretPos;
241         scrollPosSave = scrollPos;
242         lengthSave = text.length();
243 }
244
245 void TextEdit::CheckStateAndRedrawIfNeeded(void)
246 {
247         // Check to see if any of our state variables changed since we last saved them...
248         if (activated != activatedSave || clicked != clickedSave || inside != insideSave
249                 || caretPos != caretPosSave || scrollPos != scrollPosSave
250                 || text.length() != lengthSave)
251                 Draw();
252 }