diff options
Diffstat (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CGUIEditBox.cpp')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CGUIEditBox.cpp | 3110 |
1 files changed, 1555 insertions, 1555 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CGUIEditBox.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CGUIEditBox.cpp index a937cc2..7b6842d 100644 --- a/libraries/irrlicht-1.8/source/Irrlicht/CGUIEditBox.cpp +++ b/libraries/irrlicht-1.8/source/Irrlicht/CGUIEditBox.cpp | |||
@@ -1,1555 +1,1555 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt | 1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt |
2 | // This file is part of the "Irrlicht Engine". | 2 | // This file is part of the "Irrlicht Engine". |
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | 3 | // For conditions of distribution and use, see copyright notice in irrlicht.h |
4 | 4 | ||
5 | #include "CGUIEditBox.h" | 5 | #include "CGUIEditBox.h" |
6 | #ifdef _IRR_COMPILE_WITH_GUI_ | 6 | #ifdef _IRR_COMPILE_WITH_GUI_ |
7 | 7 | ||
8 | #include "IGUISkin.h" | 8 | #include "IGUISkin.h" |
9 | #include "IGUIEnvironment.h" | 9 | #include "IGUIEnvironment.h" |
10 | #include "IGUIFont.h" | 10 | #include "IGUIFont.h" |
11 | #include "IVideoDriver.h" | 11 | #include "IVideoDriver.h" |
12 | #include "rect.h" | 12 | #include "rect.h" |
13 | #include "os.h" | 13 | #include "os.h" |
14 | #include "Keycodes.h" | 14 | #include "Keycodes.h" |
15 | 15 | ||
16 | /* | 16 | /* |
17 | todo: | 17 | todo: |
18 | optional scrollbars | 18 | optional scrollbars |
19 | ctrl+left/right to select word | 19 | ctrl+left/right to select word |
20 | double click/ctrl click: word select + drag to select whole words, triple click to select line | 20 | double click/ctrl click: word select + drag to select whole words, triple click to select line |
21 | optional? dragging selected text | 21 | optional? dragging selected text |
22 | numerical | 22 | numerical |
23 | */ | 23 | */ |
24 | 24 | ||
25 | namespace irr | 25 | namespace irr |
26 | { | 26 | { |
27 | namespace gui | 27 | namespace gui |
28 | { | 28 | { |
29 | 29 | ||
30 | //! constructor | 30 | //! constructor |
31 | CGUIEditBox::CGUIEditBox(const wchar_t* text, bool border, | 31 | CGUIEditBox::CGUIEditBox(const wchar_t* text, bool border, |
32 | IGUIEnvironment* environment, IGUIElement* parent, s32 id, | 32 | IGUIEnvironment* environment, IGUIElement* parent, s32 id, |
33 | const core::rect<s32>& rectangle) | 33 | const core::rect<s32>& rectangle) |
34 | : IGUIEditBox(environment, parent, id, rectangle), MouseMarking(false), | 34 | : IGUIEditBox(environment, parent, id, rectangle), MouseMarking(false), |
35 | Border(border), Background(true), OverrideColorEnabled(false), MarkBegin(0), MarkEnd(0), | 35 | Border(border), Background(true), OverrideColorEnabled(false), MarkBegin(0), MarkEnd(0), |
36 | OverrideColor(video::SColor(101,255,255,255)), OverrideFont(0), LastBreakFont(0), | 36 | OverrideColor(video::SColor(101,255,255,255)), OverrideFont(0), LastBreakFont(0), |
37 | Operator(0), BlinkStartTime(0), CursorPos(0), HScrollPos(0), VScrollPos(0), Max(0), | 37 | Operator(0), BlinkStartTime(0), CursorPos(0), HScrollPos(0), VScrollPos(0), Max(0), |
38 | WordWrap(false), MultiLine(false), AutoScroll(true), PasswordBox(false), | 38 | WordWrap(false), MultiLine(false), AutoScroll(true), PasswordBox(false), |
39 | PasswordChar(L'*'), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER), | 39 | PasswordChar(L'*'), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER), |
40 | CurrentTextRect(0,0,1,1), FrameRect(rectangle) | 40 | CurrentTextRect(0,0,1,1), FrameRect(rectangle) |
41 | { | 41 | { |
42 | #ifdef _DEBUG | 42 | #ifdef _DEBUG |
43 | setDebugName("CGUIEditBox"); | 43 | setDebugName("CGUIEditBox"); |
44 | #endif | 44 | #endif |
45 | 45 | ||
46 | Text = text; | 46 | Text = text; |
47 | 47 | ||
48 | if (Environment) | 48 | if (Environment) |
49 | Operator = Environment->getOSOperator(); | 49 | Operator = Environment->getOSOperator(); |
50 | 50 | ||
51 | if (Operator) | 51 | if (Operator) |
52 | Operator->grab(); | 52 | Operator->grab(); |
53 | 53 | ||
54 | // this element can be tabbed to | 54 | // this element can be tabbed to |
55 | setTabStop(true); | 55 | setTabStop(true); |
56 | setTabOrder(-1); | 56 | setTabOrder(-1); |
57 | 57 | ||
58 | calculateFrameRect(); | 58 | calculateFrameRect(); |
59 | breakText(); | 59 | breakText(); |
60 | 60 | ||
61 | calculateScrollPos(); | 61 | calculateScrollPos(); |
62 | } | 62 | } |
63 | 63 | ||
64 | 64 | ||
65 | //! destructor | 65 | //! destructor |
66 | CGUIEditBox::~CGUIEditBox() | 66 | CGUIEditBox::~CGUIEditBox() |
67 | { | 67 | { |
68 | if (OverrideFont) | 68 | if (OverrideFont) |
69 | OverrideFont->drop(); | 69 | OverrideFont->drop(); |
70 | 70 | ||
71 | if (Operator) | 71 | if (Operator) |
72 | Operator->drop(); | 72 | Operator->drop(); |
73 | } | 73 | } |
74 | 74 | ||
75 | 75 | ||
76 | //! Sets another skin independent font. | 76 | //! Sets another skin independent font. |
77 | void CGUIEditBox::setOverrideFont(IGUIFont* font) | 77 | void CGUIEditBox::setOverrideFont(IGUIFont* font) |
78 | { | 78 | { |
79 | if (OverrideFont == font) | 79 | if (OverrideFont == font) |
80 | return; | 80 | return; |
81 | 81 | ||
82 | if (OverrideFont) | 82 | if (OverrideFont) |
83 | OverrideFont->drop(); | 83 | OverrideFont->drop(); |
84 | 84 | ||
85 | OverrideFont = font; | 85 | OverrideFont = font; |
86 | 86 | ||
87 | if (OverrideFont) | 87 | if (OverrideFont) |
88 | OverrideFont->grab(); | 88 | OverrideFont->grab(); |
89 | 89 | ||
90 | breakText(); | 90 | breakText(); |
91 | } | 91 | } |
92 | 92 | ||
93 | //! Gets the override font (if any) | 93 | //! Gets the override font (if any) |
94 | IGUIFont * CGUIEditBox::getOverrideFont() const | 94 | IGUIFont * CGUIEditBox::getOverrideFont() const |
95 | { | 95 | { |
96 | return OverrideFont; | 96 | return OverrideFont; |
97 | } | 97 | } |
98 | 98 | ||
99 | //! Get the font which is used right now for drawing | 99 | //! Get the font which is used right now for drawing |
100 | IGUIFont* CGUIEditBox::getActiveFont() const | 100 | IGUIFont* CGUIEditBox::getActiveFont() const |
101 | { | 101 | { |
102 | if ( OverrideFont ) | 102 | if ( OverrideFont ) |
103 | return OverrideFont; | 103 | return OverrideFont; |
104 | IGUISkin* skin = Environment->getSkin(); | 104 | IGUISkin* skin = Environment->getSkin(); |
105 | if (skin) | 105 | if (skin) |
106 | return skin->getFont(); | 106 | return skin->getFont(); |
107 | return 0; | 107 | return 0; |
108 | } | 108 | } |
109 | 109 | ||
110 | //! Sets another color for the text. | 110 | //! Sets another color for the text. |
111 | void CGUIEditBox::setOverrideColor(video::SColor color) | 111 | void CGUIEditBox::setOverrideColor(video::SColor color) |
112 | { | 112 | { |
113 | OverrideColor = color; | 113 | OverrideColor = color; |
114 | OverrideColorEnabled = true; | 114 | OverrideColorEnabled = true; |
115 | } | 115 | } |
116 | 116 | ||
117 | 117 | ||
118 | video::SColor CGUIEditBox::getOverrideColor() const | 118 | video::SColor CGUIEditBox::getOverrideColor() const |
119 | { | 119 | { |
120 | return OverrideColor; | 120 | return OverrideColor; |
121 | } | 121 | } |
122 | 122 | ||
123 | 123 | ||
124 | //! Turns the border on or off | 124 | //! Turns the border on or off |
125 | void CGUIEditBox::setDrawBorder(bool border) | 125 | void CGUIEditBox::setDrawBorder(bool border) |
126 | { | 126 | { |
127 | Border = border; | 127 | Border = border; |
128 | } | 128 | } |
129 | 129 | ||
130 | //! Sets whether to draw the background | 130 | //! Sets whether to draw the background |
131 | void CGUIEditBox::setDrawBackground(bool draw) | 131 | void CGUIEditBox::setDrawBackground(bool draw) |
132 | { | 132 | { |
133 | Background = draw; | 133 | Background = draw; |
134 | } | 134 | } |
135 | 135 | ||
136 | //! Sets if the text should use the overide color or the color in the gui skin. | 136 | //! Sets if the text should use the overide color or the color in the gui skin. |
137 | void CGUIEditBox::enableOverrideColor(bool enable) | 137 | void CGUIEditBox::enableOverrideColor(bool enable) |
138 | { | 138 | { |
139 | OverrideColorEnabled = enable; | 139 | OverrideColorEnabled = enable; |
140 | } | 140 | } |
141 | 141 | ||
142 | bool CGUIEditBox::isOverrideColorEnabled() const | 142 | bool CGUIEditBox::isOverrideColorEnabled() const |
143 | { | 143 | { |
144 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | 144 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; |
145 | return OverrideColorEnabled; | 145 | return OverrideColorEnabled; |
146 | } | 146 | } |
147 | 147 | ||
148 | //! Enables or disables word wrap | 148 | //! Enables or disables word wrap |
149 | void CGUIEditBox::setWordWrap(bool enable) | 149 | void CGUIEditBox::setWordWrap(bool enable) |
150 | { | 150 | { |
151 | WordWrap = enable; | 151 | WordWrap = enable; |
152 | breakText(); | 152 | breakText(); |
153 | } | 153 | } |
154 | 154 | ||
155 | 155 | ||
156 | void CGUIEditBox::updateAbsolutePosition() | 156 | void CGUIEditBox::updateAbsolutePosition() |
157 | { | 157 | { |
158 | core::rect<s32> oldAbsoluteRect(AbsoluteRect); | 158 | core::rect<s32> oldAbsoluteRect(AbsoluteRect); |
159 | IGUIElement::updateAbsolutePosition(); | 159 | IGUIElement::updateAbsolutePosition(); |
160 | if ( oldAbsoluteRect != AbsoluteRect ) | 160 | if ( oldAbsoluteRect != AbsoluteRect ) |
161 | { | 161 | { |
162 | calculateFrameRect(); | 162 | calculateFrameRect(); |
163 | breakText(); | 163 | breakText(); |
164 | calculateScrollPos(); | 164 | calculateScrollPos(); |
165 | } | 165 | } |
166 | } | 166 | } |
167 | 167 | ||
168 | 168 | ||
169 | //! Checks if word wrap is enabled | 169 | //! Checks if word wrap is enabled |
170 | bool CGUIEditBox::isWordWrapEnabled() const | 170 | bool CGUIEditBox::isWordWrapEnabled() const |
171 | { | 171 | { |
172 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | 172 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; |
173 | return WordWrap; | 173 | return WordWrap; |
174 | } | 174 | } |
175 | 175 | ||
176 | 176 | ||
177 | //! Enables or disables newlines. | 177 | //! Enables or disables newlines. |
178 | void CGUIEditBox::setMultiLine(bool enable) | 178 | void CGUIEditBox::setMultiLine(bool enable) |
179 | { | 179 | { |
180 | MultiLine = enable; | 180 | MultiLine = enable; |
181 | } | 181 | } |
182 | 182 | ||
183 | 183 | ||
184 | //! Checks if multi line editing is enabled | 184 | //! Checks if multi line editing is enabled |
185 | bool CGUIEditBox::isMultiLineEnabled() const | 185 | bool CGUIEditBox::isMultiLineEnabled() const |
186 | { | 186 | { |
187 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | 187 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; |
188 | return MultiLine; | 188 | return MultiLine; |
189 | } | 189 | } |
190 | 190 | ||
191 | 191 | ||
192 | void CGUIEditBox::setPasswordBox(bool passwordBox, wchar_t passwordChar) | 192 | void CGUIEditBox::setPasswordBox(bool passwordBox, wchar_t passwordChar) |
193 | { | 193 | { |
194 | PasswordBox = passwordBox; | 194 | PasswordBox = passwordBox; |
195 | if (PasswordBox) | 195 | if (PasswordBox) |
196 | { | 196 | { |
197 | PasswordChar = passwordChar; | 197 | PasswordChar = passwordChar; |
198 | setMultiLine(false); | 198 | setMultiLine(false); |
199 | setWordWrap(false); | 199 | setWordWrap(false); |
200 | BrokenText.clear(); | 200 | BrokenText.clear(); |
201 | } | 201 | } |
202 | } | 202 | } |
203 | 203 | ||
204 | 204 | ||
205 | bool CGUIEditBox::isPasswordBox() const | 205 | bool CGUIEditBox::isPasswordBox() const |
206 | { | 206 | { |
207 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | 207 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; |
208 | return PasswordBox; | 208 | return PasswordBox; |
209 | } | 209 | } |
210 | 210 | ||
211 | 211 | ||
212 | //! Sets text justification | 212 | //! Sets text justification |
213 | void CGUIEditBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) | 213 | void CGUIEditBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) |
214 | { | 214 | { |
215 | HAlign = horizontal; | 215 | HAlign = horizontal; |
216 | VAlign = vertical; | 216 | VAlign = vertical; |
217 | } | 217 | } |
218 | 218 | ||
219 | 219 | ||
220 | //! called if an event happened. | 220 | //! called if an event happened. |
221 | bool CGUIEditBox::OnEvent(const SEvent& event) | 221 | bool CGUIEditBox::OnEvent(const SEvent& event) |
222 | { | 222 | { |
223 | if (isEnabled()) | 223 | if (isEnabled()) |
224 | { | 224 | { |
225 | 225 | ||
226 | switch(event.EventType) | 226 | switch(event.EventType) |
227 | { | 227 | { |
228 | case EET_GUI_EVENT: | 228 | case EET_GUI_EVENT: |
229 | if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) | 229 | if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) |
230 | { | 230 | { |
231 | if (event.GUIEvent.Caller == this) | 231 | if (event.GUIEvent.Caller == this) |
232 | { | 232 | { |
233 | MouseMarking = false; | 233 | MouseMarking = false; |
234 | setTextMarkers(0,0); | 234 | setTextMarkers(0,0); |
235 | } | 235 | } |
236 | } | 236 | } |
237 | break; | 237 | break; |
238 | case EET_KEY_INPUT_EVENT: | 238 | case EET_KEY_INPUT_EVENT: |
239 | if (processKey(event)) | 239 | if (processKey(event)) |
240 | return true; | 240 | return true; |
241 | break; | 241 | break; |
242 | case EET_MOUSE_INPUT_EVENT: | 242 | case EET_MOUSE_INPUT_EVENT: |
243 | if (processMouse(event)) | 243 | if (processMouse(event)) |
244 | return true; | 244 | return true; |
245 | break; | 245 | break; |
246 | default: | 246 | default: |
247 | break; | 247 | break; |
248 | } | 248 | } |
249 | } | 249 | } |
250 | 250 | ||
251 | return IGUIElement::OnEvent(event); | 251 | return IGUIElement::OnEvent(event); |
252 | } | 252 | } |
253 | 253 | ||
254 | 254 | ||
255 | bool CGUIEditBox::processKey(const SEvent& event) | 255 | bool CGUIEditBox::processKey(const SEvent& event) |
256 | { | 256 | { |
257 | if (!event.KeyInput.PressedDown) | 257 | if (!event.KeyInput.PressedDown) |
258 | return false; | 258 | return false; |
259 | 259 | ||
260 | bool textChanged = false; | 260 | bool textChanged = false; |
261 | s32 newMarkBegin = MarkBegin; | 261 | s32 newMarkBegin = MarkBegin; |
262 | s32 newMarkEnd = MarkEnd; | 262 | s32 newMarkEnd = MarkEnd; |
263 | 263 | ||
264 | // control shortcut handling | 264 | // control shortcut handling |
265 | 265 | ||
266 | if (event.KeyInput.Control) | 266 | if (event.KeyInput.Control) |
267 | { | 267 | { |
268 | // german backlash '\' entered with control + '?' | 268 | // german backlash '\' entered with control + '?' |
269 | if ( event.KeyInput.Char == '\\' ) | 269 | if ( event.KeyInput.Char == '\\' ) |
270 | { | 270 | { |
271 | inputChar(event.KeyInput.Char); | 271 | inputChar(event.KeyInput.Char); |
272 | return true; | 272 | return true; |
273 | } | 273 | } |
274 | 274 | ||
275 | switch(event.KeyInput.Key) | 275 | switch(event.KeyInput.Key) |
276 | { | 276 | { |
277 | case KEY_KEY_A: | 277 | case KEY_KEY_A: |
278 | // select all | 278 | // select all |
279 | newMarkBegin = 0; | 279 | newMarkBegin = 0; |
280 | newMarkEnd = Text.size(); | 280 | newMarkEnd = Text.size(); |
281 | break; | 281 | break; |
282 | case KEY_KEY_C: | 282 | case KEY_KEY_C: |
283 | // copy to clipboard | 283 | // copy to clipboard |
284 | if (!PasswordBox && Operator && MarkBegin != MarkEnd) | 284 | if (!PasswordBox && Operator && MarkBegin != MarkEnd) |
285 | { | 285 | { |
286 | const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; | 286 | const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; |
287 | const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; | 287 | const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; |
288 | 288 | ||
289 | core::stringc s; | 289 | core::stringc s; |
290 | s = Text.subString(realmbgn, realmend - realmbgn).c_str(); | 290 | s = Text.subString(realmbgn, realmend - realmbgn).c_str(); |
291 | Operator->copyToClipboard(s.c_str()); | 291 | Operator->copyToClipboard(s.c_str()); |
292 | } | 292 | } |
293 | break; | 293 | break; |
294 | case KEY_KEY_X: | 294 | case KEY_KEY_X: |
295 | // cut to the clipboard | 295 | // cut to the clipboard |
296 | if (!PasswordBox && Operator && MarkBegin != MarkEnd) | 296 | if (!PasswordBox && Operator && MarkBegin != MarkEnd) |
297 | { | 297 | { |
298 | const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; | 298 | const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; |
299 | const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; | 299 | const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; |
300 | 300 | ||
301 | // copy | 301 | // copy |
302 | core::stringc sc; | 302 | core::stringc sc; |
303 | sc = Text.subString(realmbgn, realmend - realmbgn).c_str(); | 303 | sc = Text.subString(realmbgn, realmend - realmbgn).c_str(); |
304 | Operator->copyToClipboard(sc.c_str()); | 304 | Operator->copyToClipboard(sc.c_str()); |
305 | 305 | ||
306 | if (isEnabled()) | 306 | if (isEnabled()) |
307 | { | 307 | { |
308 | // delete | 308 | // delete |
309 | core::stringw s; | 309 | core::stringw s; |
310 | s = Text.subString(0, realmbgn); | 310 | s = Text.subString(0, realmbgn); |
311 | s.append( Text.subString(realmend, Text.size()-realmend) ); | 311 | s.append( Text.subString(realmend, Text.size()-realmend) ); |
312 | Text = s; | 312 | Text = s; |
313 | 313 | ||
314 | CursorPos = realmbgn; | 314 | CursorPos = realmbgn; |
315 | newMarkBegin = 0; | 315 | newMarkBegin = 0; |
316 | newMarkEnd = 0; | 316 | newMarkEnd = 0; |
317 | textChanged = true; | 317 | textChanged = true; |
318 | } | 318 | } |
319 | } | 319 | } |
320 | break; | 320 | break; |
321 | case KEY_KEY_V: | 321 | case KEY_KEY_V: |
322 | if ( !isEnabled() ) | 322 | if ( !isEnabled() ) |
323 | break; | 323 | break; |
324 | 324 | ||
325 | // paste from the clipboard | 325 | // paste from the clipboard |
326 | if (Operator) | 326 | if (Operator) |
327 | { | 327 | { |
328 | const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; | 328 | const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; |
329 | const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; | 329 | const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; |
330 | 330 | ||
331 | // add new character | 331 | // add new character |
332 | const c8* p = Operator->getTextFromClipboard(); | 332 | const c8* p = Operator->getTextFromClipboard(); |
333 | if (p) | 333 | if (p) |
334 | { | 334 | { |
335 | if (MarkBegin == MarkEnd) | 335 | if (MarkBegin == MarkEnd) |
336 | { | 336 | { |
337 | // insert text | 337 | // insert text |
338 | core::stringw s = Text.subString(0, CursorPos); | 338 | core::stringw s = Text.subString(0, CursorPos); |
339 | s.append(p); | 339 | s.append(p); |
340 | s.append( Text.subString(CursorPos, Text.size()-CursorPos) ); | 340 | s.append( Text.subString(CursorPos, Text.size()-CursorPos) ); |
341 | 341 | ||
342 | if (!Max || s.size()<=Max) // thx to Fish FH for fix | 342 | if (!Max || s.size()<=Max) // thx to Fish FH for fix |
343 | { | 343 | { |
344 | Text = s; | 344 | Text = s; |
345 | s = p; | 345 | s = p; |
346 | CursorPos += s.size(); | 346 | CursorPos += s.size(); |
347 | } | 347 | } |
348 | } | 348 | } |
349 | else | 349 | else |
350 | { | 350 | { |
351 | // replace text | 351 | // replace text |
352 | 352 | ||
353 | core::stringw s = Text.subString(0, realmbgn); | 353 | core::stringw s = Text.subString(0, realmbgn); |
354 | s.append(p); | 354 | s.append(p); |
355 | s.append( Text.subString(realmend, Text.size()-realmend) ); | 355 | s.append( Text.subString(realmend, Text.size()-realmend) ); |
356 | 356 | ||
357 | if (!Max || s.size()<=Max) // thx to Fish FH for fix | 357 | if (!Max || s.size()<=Max) // thx to Fish FH for fix |
358 | { | 358 | { |
359 | Text = s; | 359 | Text = s; |
360 | s = p; | 360 | s = p; |
361 | CursorPos = realmbgn + s.size(); | 361 | CursorPos = realmbgn + s.size(); |
362 | } | 362 | } |
363 | } | 363 | } |
364 | } | 364 | } |
365 | 365 | ||
366 | newMarkBegin = 0; | 366 | newMarkBegin = 0; |
367 | newMarkEnd = 0; | 367 | newMarkEnd = 0; |
368 | textChanged = true; | 368 | textChanged = true; |
369 | } | 369 | } |
370 | break; | 370 | break; |
371 | case KEY_HOME: | 371 | case KEY_HOME: |
372 | // move/highlight to start of text | 372 | // move/highlight to start of text |
373 | if (event.KeyInput.Shift) | 373 | if (event.KeyInput.Shift) |
374 | { | 374 | { |
375 | newMarkEnd = CursorPos; | 375 | newMarkEnd = CursorPos; |
376 | newMarkBegin = 0; | 376 | newMarkBegin = 0; |
377 | CursorPos = 0; | 377 | CursorPos = 0; |
378 | } | 378 | } |
379 | else | 379 | else |
380 | { | 380 | { |
381 | CursorPos = 0; | 381 | CursorPos = 0; |
382 | newMarkBegin = 0; | 382 | newMarkBegin = 0; |
383 | newMarkEnd = 0; | 383 | newMarkEnd = 0; |
384 | } | 384 | } |
385 | break; | 385 | break; |
386 | case KEY_END: | 386 | case KEY_END: |
387 | // move/highlight to end of text | 387 | // move/highlight to end of text |
388 | if (event.KeyInput.Shift) | 388 | if (event.KeyInput.Shift) |
389 | { | 389 | { |
390 | newMarkBegin = CursorPos; | 390 | newMarkBegin = CursorPos; |
391 | newMarkEnd = Text.size(); | 391 | newMarkEnd = Text.size(); |
392 | CursorPos = 0; | 392 | CursorPos = 0; |
393 | } | 393 | } |
394 | else | 394 | else |
395 | { | 395 | { |
396 | CursorPos = Text.size(); | 396 | CursorPos = Text.size(); |
397 | newMarkBegin = 0; | 397 | newMarkBegin = 0; |
398 | newMarkEnd = 0; | 398 | newMarkEnd = 0; |
399 | } | 399 | } |
400 | break; | 400 | break; |
401 | default: | 401 | default: |
402 | return false; | 402 | return false; |
403 | } | 403 | } |
404 | } | 404 | } |
405 | // default keyboard handling | 405 | // default keyboard handling |
406 | else | 406 | else |
407 | switch(event.KeyInput.Key) | 407 | switch(event.KeyInput.Key) |
408 | { | 408 | { |
409 | case KEY_END: | 409 | case KEY_END: |
410 | { | 410 | { |
411 | s32 p = Text.size(); | 411 | s32 p = Text.size(); |
412 | if (WordWrap || MultiLine) | 412 | if (WordWrap || MultiLine) |
413 | { | 413 | { |
414 | p = getLineFromPos(CursorPos); | 414 | p = getLineFromPos(CursorPos); |
415 | p = BrokenTextPositions[p] + (s32)BrokenText[p].size(); | 415 | p = BrokenTextPositions[p] + (s32)BrokenText[p].size(); |
416 | if (p > 0 && (Text[p-1] == L'\r' || Text[p-1] == L'\n' )) | 416 | if (p > 0 && (Text[p-1] == L'\r' || Text[p-1] == L'\n' )) |
417 | p-=1; | 417 | p-=1; |
418 | } | 418 | } |
419 | 419 | ||
420 | if (event.KeyInput.Shift) | 420 | if (event.KeyInput.Shift) |
421 | { | 421 | { |
422 | if (MarkBegin == MarkEnd) | 422 | if (MarkBegin == MarkEnd) |
423 | newMarkBegin = CursorPos; | 423 | newMarkBegin = CursorPos; |
424 | 424 | ||
425 | newMarkEnd = p; | 425 | newMarkEnd = p; |
426 | } | 426 | } |
427 | else | 427 | else |
428 | { | 428 | { |
429 | newMarkBegin = 0; | 429 | newMarkBegin = 0; |
430 | newMarkEnd = 0; | 430 | newMarkEnd = 0; |
431 | } | 431 | } |
432 | CursorPos = p; | 432 | CursorPos = p; |
433 | BlinkStartTime = os::Timer::getTime(); | 433 | BlinkStartTime = os::Timer::getTime(); |
434 | } | 434 | } |
435 | break; | 435 | break; |
436 | case KEY_HOME: | 436 | case KEY_HOME: |
437 | { | 437 | { |
438 | 438 | ||
439 | s32 p = 0; | 439 | s32 p = 0; |
440 | if (WordWrap || MultiLine) | 440 | if (WordWrap || MultiLine) |
441 | { | 441 | { |
442 | p = getLineFromPos(CursorPos); | 442 | p = getLineFromPos(CursorPos); |
443 | p = BrokenTextPositions[p]; | 443 | p = BrokenTextPositions[p]; |
444 | } | 444 | } |
445 | 445 | ||
446 | if (event.KeyInput.Shift) | 446 | if (event.KeyInput.Shift) |
447 | { | 447 | { |
448 | if (MarkBegin == MarkEnd) | 448 | if (MarkBegin == MarkEnd) |
449 | newMarkBegin = CursorPos; | 449 | newMarkBegin = CursorPos; |
450 | newMarkEnd = p; | 450 | newMarkEnd = p; |
451 | } | 451 | } |
452 | else | 452 | else |
453 | { | 453 | { |
454 | newMarkBegin = 0; | 454 | newMarkBegin = 0; |
455 | newMarkEnd = 0; | 455 | newMarkEnd = 0; |
456 | } | 456 | } |
457 | CursorPos = p; | 457 | CursorPos = p; |
458 | BlinkStartTime = os::Timer::getTime(); | 458 | BlinkStartTime = os::Timer::getTime(); |
459 | } | 459 | } |
460 | break; | 460 | break; |
461 | case KEY_RETURN: | 461 | case KEY_RETURN: |
462 | if (MultiLine) | 462 | if (MultiLine) |
463 | { | 463 | { |
464 | inputChar(L'\n'); | 464 | inputChar(L'\n'); |
465 | } | 465 | } |
466 | else | 466 | else |
467 | { | 467 | { |
468 | calculateScrollPos(); | 468 | calculateScrollPos(); |
469 | sendGuiEvent( EGET_EDITBOX_ENTER ); | 469 | sendGuiEvent( EGET_EDITBOX_ENTER ); |
470 | } | 470 | } |
471 | return true; | 471 | return true; |
472 | case KEY_LEFT: | 472 | case KEY_LEFT: |
473 | 473 | ||
474 | if (event.KeyInput.Shift) | 474 | if (event.KeyInput.Shift) |
475 | { | 475 | { |
476 | if (CursorPos > 0) | 476 | if (CursorPos > 0) |
477 | { | 477 | { |
478 | if (MarkBegin == MarkEnd) | 478 | if (MarkBegin == MarkEnd) |
479 | newMarkBegin = CursorPos; | 479 | newMarkBegin = CursorPos; |
480 | 480 | ||
481 | newMarkEnd = CursorPos-1; | 481 | newMarkEnd = CursorPos-1; |
482 | } | 482 | } |
483 | } | 483 | } |
484 | else | 484 | else |
485 | { | 485 | { |
486 | newMarkBegin = 0; | 486 | newMarkBegin = 0; |
487 | newMarkEnd = 0; | 487 | newMarkEnd = 0; |
488 | } | 488 | } |
489 | 489 | ||
490 | if (CursorPos > 0) CursorPos--; | 490 | if (CursorPos > 0) CursorPos--; |
491 | BlinkStartTime = os::Timer::getTime(); | 491 | BlinkStartTime = os::Timer::getTime(); |
492 | break; | 492 | break; |
493 | 493 | ||
494 | case KEY_RIGHT: | 494 | case KEY_RIGHT: |
495 | if (event.KeyInput.Shift) | 495 | if (event.KeyInput.Shift) |
496 | { | 496 | { |
497 | if (Text.size() > (u32)CursorPos) | 497 | if (Text.size() > (u32)CursorPos) |
498 | { | 498 | { |
499 | if (MarkBegin == MarkEnd) | 499 | if (MarkBegin == MarkEnd) |
500 | newMarkBegin = CursorPos; | 500 | newMarkBegin = CursorPos; |
501 | 501 | ||
502 | newMarkEnd = CursorPos+1; | 502 | newMarkEnd = CursorPos+1; |
503 | } | 503 | } |
504 | } | 504 | } |
505 | else | 505 | else |
506 | { | 506 | { |
507 | newMarkBegin = 0; | 507 | newMarkBegin = 0; |
508 | newMarkEnd = 0; | 508 | newMarkEnd = 0; |
509 | } | 509 | } |
510 | 510 | ||
511 | if (Text.size() > (u32)CursorPos) CursorPos++; | 511 | if (Text.size() > (u32)CursorPos) CursorPos++; |
512 | BlinkStartTime = os::Timer::getTime(); | 512 | BlinkStartTime = os::Timer::getTime(); |
513 | break; | 513 | break; |
514 | case KEY_UP: | 514 | case KEY_UP: |
515 | if (MultiLine || (WordWrap && BrokenText.size() > 1) ) | 515 | if (MultiLine || (WordWrap && BrokenText.size() > 1) ) |
516 | { | 516 | { |
517 | s32 lineNo = getLineFromPos(CursorPos); | 517 | s32 lineNo = getLineFromPos(CursorPos); |
518 | s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin > MarkEnd ? MarkBegin : MarkEnd); | 518 | s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin > MarkEnd ? MarkBegin : MarkEnd); |
519 | if (lineNo > 0) | 519 | if (lineNo > 0) |
520 | { | 520 | { |
521 | s32 cp = CursorPos - BrokenTextPositions[lineNo]; | 521 | s32 cp = CursorPos - BrokenTextPositions[lineNo]; |
522 | if ((s32)BrokenText[lineNo-1].size() < cp) | 522 | if ((s32)BrokenText[lineNo-1].size() < cp) |
523 | CursorPos = BrokenTextPositions[lineNo-1] + core::max_((u32)1, BrokenText[lineNo-1].size())-1; | 523 | CursorPos = BrokenTextPositions[lineNo-1] + core::max_((u32)1, BrokenText[lineNo-1].size())-1; |
524 | else | 524 | else |
525 | CursorPos = BrokenTextPositions[lineNo-1] + cp; | 525 | CursorPos = BrokenTextPositions[lineNo-1] + cp; |
526 | } | 526 | } |
527 | 527 | ||
528 | if (event.KeyInput.Shift) | 528 | if (event.KeyInput.Shift) |
529 | { | 529 | { |
530 | newMarkBegin = mb; | 530 | newMarkBegin = mb; |
531 | newMarkEnd = CursorPos; | 531 | newMarkEnd = CursorPos; |
532 | } | 532 | } |
533 | else | 533 | else |
534 | { | 534 | { |
535 | newMarkBegin = 0; | 535 | newMarkBegin = 0; |
536 | newMarkEnd = 0; | 536 | newMarkEnd = 0; |
537 | } | 537 | } |
538 | 538 | ||
539 | } | 539 | } |
540 | else | 540 | else |
541 | { | 541 | { |
542 | return false; | 542 | return false; |
543 | } | 543 | } |
544 | break; | 544 | break; |
545 | case KEY_DOWN: | 545 | case KEY_DOWN: |
546 | if (MultiLine || (WordWrap && BrokenText.size() > 1) ) | 546 | if (MultiLine || (WordWrap && BrokenText.size() > 1) ) |
547 | { | 547 | { |
548 | s32 lineNo = getLineFromPos(CursorPos); | 548 | s32 lineNo = getLineFromPos(CursorPos); |
549 | s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin < MarkEnd ? MarkBegin : MarkEnd); | 549 | s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin < MarkEnd ? MarkBegin : MarkEnd); |
550 | if (lineNo < (s32)BrokenText.size()-1) | 550 | if (lineNo < (s32)BrokenText.size()-1) |
551 | { | 551 | { |
552 | s32 cp = CursorPos - BrokenTextPositions[lineNo]; | 552 | s32 cp = CursorPos - BrokenTextPositions[lineNo]; |
553 | if ((s32)BrokenText[lineNo+1].size() < cp) | 553 | if ((s32)BrokenText[lineNo+1].size() < cp) |
554 | CursorPos = BrokenTextPositions[lineNo+1] + core::max_((u32)1, BrokenText[lineNo+1].size())-1; | 554 | CursorPos = BrokenTextPositions[lineNo+1] + core::max_((u32)1, BrokenText[lineNo+1].size())-1; |
555 | else | 555 | else |
556 | CursorPos = BrokenTextPositions[lineNo+1] + cp; | 556 | CursorPos = BrokenTextPositions[lineNo+1] + cp; |
557 | } | 557 | } |
558 | 558 | ||
559 | if (event.KeyInput.Shift) | 559 | if (event.KeyInput.Shift) |
560 | { | 560 | { |
561 | newMarkBegin = mb; | 561 | newMarkBegin = mb; |
562 | newMarkEnd = CursorPos; | 562 | newMarkEnd = CursorPos; |
563 | } | 563 | } |
564 | else | 564 | else |
565 | { | 565 | { |
566 | newMarkBegin = 0; | 566 | newMarkBegin = 0; |
567 | newMarkEnd = 0; | 567 | newMarkEnd = 0; |
568 | } | 568 | } |
569 | 569 | ||
570 | } | 570 | } |
571 | else | 571 | else |
572 | { | 572 | { |
573 | return false; | 573 | return false; |
574 | } | 574 | } |
575 | break; | 575 | break; |
576 | 576 | ||
577 | case KEY_BACK: | 577 | case KEY_BACK: |
578 | if ( !isEnabled() ) | 578 | if ( !isEnabled() ) |
579 | break; | 579 | break; |
580 | 580 | ||
581 | if (Text.size()) | 581 | if (Text.size()) |
582 | { | 582 | { |
583 | core::stringw s; | 583 | core::stringw s; |
584 | 584 | ||
585 | if (MarkBegin != MarkEnd) | 585 | if (MarkBegin != MarkEnd) |
586 | { | 586 | { |
587 | // delete marked text | 587 | // delete marked text |
588 | const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; | 588 | const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; |
589 | const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; | 589 | const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; |
590 | 590 | ||
591 | s = Text.subString(0, realmbgn); | 591 | s = Text.subString(0, realmbgn); |
592 | s.append( Text.subString(realmend, Text.size()-realmend) ); | 592 | s.append( Text.subString(realmend, Text.size()-realmend) ); |
593 | Text = s; | 593 | Text = s; |
594 | 594 | ||
595 | CursorPos = realmbgn; | 595 | CursorPos = realmbgn; |
596 | } | 596 | } |
597 | else | 597 | else |
598 | { | 598 | { |
599 | // delete text behind cursor | 599 | // delete text behind cursor |
600 | if (CursorPos>0) | 600 | if (CursorPos>0) |
601 | s = Text.subString(0, CursorPos-1); | 601 | s = Text.subString(0, CursorPos-1); |
602 | else | 602 | else |
603 | s = L""; | 603 | s = L""; |
604 | s.append( Text.subString(CursorPos, Text.size()-CursorPos) ); | 604 | s.append( Text.subString(CursorPos, Text.size()-CursorPos) ); |
605 | Text = s; | 605 | Text = s; |
606 | --CursorPos; | 606 | --CursorPos; |
607 | } | 607 | } |
608 | 608 | ||
609 | if (CursorPos < 0) | 609 | if (CursorPos < 0) |
610 | CursorPos = 0; | 610 | CursorPos = 0; |
611 | BlinkStartTime = os::Timer::getTime(); | 611 | BlinkStartTime = os::Timer::getTime(); |
612 | newMarkBegin = 0; | 612 | newMarkBegin = 0; |
613 | newMarkEnd = 0; | 613 | newMarkEnd = 0; |
614 | textChanged = true; | 614 | textChanged = true; |
615 | } | 615 | } |
616 | break; | 616 | break; |
617 | case KEY_DELETE: | 617 | case KEY_DELETE: |
618 | if ( !isEnabled() ) | 618 | if ( !isEnabled() ) |
619 | break; | 619 | break; |
620 | 620 | ||
621 | if (Text.size() != 0) | 621 | if (Text.size() != 0) |
622 | { | 622 | { |
623 | core::stringw s; | 623 | core::stringw s; |
624 | 624 | ||
625 | if (MarkBegin != MarkEnd) | 625 | if (MarkBegin != MarkEnd) |
626 | { | 626 | { |
627 | // delete marked text | 627 | // delete marked text |
628 | const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; | 628 | const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; |
629 | const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; | 629 | const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; |
630 | 630 | ||
631 | s = Text.subString(0, realmbgn); | 631 | s = Text.subString(0, realmbgn); |
632 | s.append( Text.subString(realmend, Text.size()-realmend) ); | 632 | s.append( Text.subString(realmend, Text.size()-realmend) ); |
633 | Text = s; | 633 | Text = s; |
634 | 634 | ||
635 | CursorPos = realmbgn; | 635 | CursorPos = realmbgn; |
636 | } | 636 | } |
637 | else | 637 | else |
638 | { | 638 | { |
639 | // delete text before cursor | 639 | // delete text before cursor |
640 | s = Text.subString(0, CursorPos); | 640 | s = Text.subString(0, CursorPos); |
641 | s.append( Text.subString(CursorPos+1, Text.size()-CursorPos-1) ); | 641 | s.append( Text.subString(CursorPos+1, Text.size()-CursorPos-1) ); |
642 | Text = s; | 642 | Text = s; |
643 | } | 643 | } |
644 | 644 | ||
645 | if (CursorPos > (s32)Text.size()) | 645 | if (CursorPos > (s32)Text.size()) |
646 | CursorPos = (s32)Text.size(); | 646 | CursorPos = (s32)Text.size(); |
647 | 647 | ||
648 | BlinkStartTime = os::Timer::getTime(); | 648 | BlinkStartTime = os::Timer::getTime(); |
649 | newMarkBegin = 0; | 649 | newMarkBegin = 0; |
650 | newMarkEnd = 0; | 650 | newMarkEnd = 0; |
651 | textChanged = true; | 651 | textChanged = true; |
652 | } | 652 | } |
653 | break; | 653 | break; |
654 | 654 | ||
655 | case KEY_ESCAPE: | 655 | case KEY_ESCAPE: |
656 | case KEY_TAB: | 656 | case KEY_TAB: |
657 | case KEY_SHIFT: | 657 | case KEY_SHIFT: |
658 | case KEY_F1: | 658 | case KEY_F1: |
659 | case KEY_F2: | 659 | case KEY_F2: |
660 | case KEY_F3: | 660 | case KEY_F3: |
661 | case KEY_F4: | 661 | case KEY_F4: |
662 | case KEY_F5: | 662 | case KEY_F5: |
663 | case KEY_F6: | 663 | case KEY_F6: |
664 | case KEY_F7: | 664 | case KEY_F7: |
665 | case KEY_F8: | 665 | case KEY_F8: |
666 | case KEY_F9: | 666 | case KEY_F9: |
667 | case KEY_F10: | 667 | case KEY_F10: |
668 | case KEY_F11: | 668 | case KEY_F11: |
669 | case KEY_F12: | 669 | case KEY_F12: |
670 | case KEY_F13: | 670 | case KEY_F13: |
671 | case KEY_F14: | 671 | case KEY_F14: |
672 | case KEY_F15: | 672 | case KEY_F15: |
673 | case KEY_F16: | 673 | case KEY_F16: |
674 | case KEY_F17: | 674 | case KEY_F17: |
675 | case KEY_F18: | 675 | case KEY_F18: |
676 | case KEY_F19: | 676 | case KEY_F19: |
677 | case KEY_F20: | 677 | case KEY_F20: |
678 | case KEY_F21: | 678 | case KEY_F21: |
679 | case KEY_F22: | 679 | case KEY_F22: |
680 | case KEY_F23: | 680 | case KEY_F23: |
681 | case KEY_F24: | 681 | case KEY_F24: |
682 | // ignore these keys | 682 | // ignore these keys |
683 | return false; | 683 | return false; |
684 | 684 | ||
685 | default: | 685 | default: |
686 | inputChar(event.KeyInput.Char); | 686 | inputChar(event.KeyInput.Char); |
687 | return true; | 687 | return true; |
688 | } | 688 | } |
689 | 689 | ||
690 | // Set new text markers | 690 | // Set new text markers |
691 | setTextMarkers( newMarkBegin, newMarkEnd ); | 691 | setTextMarkers( newMarkBegin, newMarkEnd ); |
692 | 692 | ||
693 | // break the text if it has changed | 693 | // break the text if it has changed |
694 | if (textChanged) | 694 | if (textChanged) |
695 | { | 695 | { |
696 | breakText(); | 696 | breakText(); |
697 | calculateScrollPos(); | 697 | calculateScrollPos(); |
698 | sendGuiEvent(EGET_EDITBOX_CHANGED); | 698 | sendGuiEvent(EGET_EDITBOX_CHANGED); |
699 | } | 699 | } |
700 | else | 700 | else |
701 | { | 701 | { |
702 | calculateScrollPos(); | 702 | calculateScrollPos(); |
703 | } | 703 | } |
704 | 704 | ||
705 | return true; | 705 | return true; |
706 | } | 706 | } |
707 | 707 | ||
708 | 708 | ||
709 | //! draws the element and its children | 709 | //! draws the element and its children |
710 | void CGUIEditBox::draw() | 710 | void CGUIEditBox::draw() |
711 | { | 711 | { |
712 | if (!IsVisible) | 712 | if (!IsVisible) |
713 | return; | 713 | return; |
714 | 714 | ||
715 | const bool focus = Environment->hasFocus(this); | 715 | const bool focus = Environment->hasFocus(this); |
716 | 716 | ||
717 | IGUISkin* skin = Environment->getSkin(); | 717 | IGUISkin* skin = Environment->getSkin(); |
718 | if (!skin) | 718 | if (!skin) |
719 | return; | 719 | return; |
720 | 720 | ||
721 | EGUI_DEFAULT_COLOR bgCol = EGDC_GRAY_EDITABLE; | 721 | EGUI_DEFAULT_COLOR bgCol = EGDC_GRAY_EDITABLE; |
722 | if ( isEnabled() ) | 722 | if ( isEnabled() ) |
723 | bgCol = focus ? EGDC_FOCUSED_EDITABLE : EGDC_EDITABLE; | 723 | bgCol = focus ? EGDC_FOCUSED_EDITABLE : EGDC_EDITABLE; |
724 | 724 | ||
725 | if (!Border && Background) | 725 | if (!Border && Background) |
726 | { | 726 | { |
727 | skin->draw2DRectangle(this, skin->getColor(bgCol), AbsoluteRect, &AbsoluteClippingRect); | 727 | skin->draw2DRectangle(this, skin->getColor(bgCol), AbsoluteRect, &AbsoluteClippingRect); |
728 | } | 728 | } |
729 | 729 | ||
730 | if (Border) | 730 | if (Border) |
731 | { | 731 | { |
732 | // draw the border | 732 | // draw the border |
733 | skin->draw3DSunkenPane(this, skin->getColor(bgCol), false, Background, AbsoluteRect, &AbsoluteClippingRect); | 733 | skin->draw3DSunkenPane(this, skin->getColor(bgCol), false, Background, AbsoluteRect, &AbsoluteClippingRect); |
734 | 734 | ||
735 | calculateFrameRect(); | 735 | calculateFrameRect(); |
736 | } | 736 | } |
737 | 737 | ||
738 | core::rect<s32> localClipRect = FrameRect; | 738 | core::rect<s32> localClipRect = FrameRect; |
739 | localClipRect.clipAgainst(AbsoluteClippingRect); | 739 | localClipRect.clipAgainst(AbsoluteClippingRect); |
740 | 740 | ||
741 | // draw the text | 741 | // draw the text |
742 | 742 | ||
743 | IGUIFont* font = getActiveFont(); | 743 | IGUIFont* font = getActiveFont(); |
744 | 744 | ||
745 | s32 cursorLine = 0; | 745 | s32 cursorLine = 0; |
746 | s32 charcursorpos = 0; | 746 | s32 charcursorpos = 0; |
747 | 747 | ||
748 | if (font) | 748 | if (font) |
749 | { | 749 | { |
750 | if (LastBreakFont != font) | 750 | if (LastBreakFont != font) |
751 | { | 751 | { |
752 | breakText(); | 752 | breakText(); |
753 | } | 753 | } |
754 | 754 | ||
755 | // calculate cursor pos | 755 | // calculate cursor pos |
756 | 756 | ||
757 | core::stringw *txtLine = &Text; | 757 | core::stringw *txtLine = &Text; |
758 | s32 startPos = 0; | 758 | s32 startPos = 0; |
759 | 759 | ||
760 | core::stringw s, s2; | 760 | core::stringw s, s2; |
761 | 761 | ||
762 | // get mark position | 762 | // get mark position |
763 | const bool ml = (!PasswordBox && (WordWrap || MultiLine)); | 763 | const bool ml = (!PasswordBox && (WordWrap || MultiLine)); |
764 | const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; | 764 | const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; |
765 | const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; | 765 | const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; |
766 | const s32 hlineStart = ml ? getLineFromPos(realmbgn) : 0; | 766 | const s32 hlineStart = ml ? getLineFromPos(realmbgn) : 0; |
767 | const s32 hlineCount = ml ? getLineFromPos(realmend) - hlineStart + 1 : 1; | 767 | const s32 hlineCount = ml ? getLineFromPos(realmend) - hlineStart + 1 : 1; |
768 | const s32 lineCount = ml ? BrokenText.size() : 1; | 768 | const s32 lineCount = ml ? BrokenText.size() : 1; |
769 | 769 | ||
770 | // Save the override color information. | 770 | // Save the override color information. |
771 | // Then, alter it if the edit box is disabled. | 771 | // Then, alter it if the edit box is disabled. |
772 | const bool prevOver = OverrideColorEnabled; | 772 | const bool prevOver = OverrideColorEnabled; |
773 | const video::SColor prevColor = OverrideColor; | 773 | const video::SColor prevColor = OverrideColor; |
774 | 774 | ||
775 | if (Text.size()) | 775 | if (Text.size()) |
776 | { | 776 | { |
777 | if (!isEnabled() && !OverrideColorEnabled) | 777 | if (!isEnabled() && !OverrideColorEnabled) |
778 | { | 778 | { |
779 | OverrideColorEnabled = true; | 779 | OverrideColorEnabled = true; |
780 | OverrideColor = skin->getColor(EGDC_GRAY_TEXT); | 780 | OverrideColor = skin->getColor(EGDC_GRAY_TEXT); |
781 | } | 781 | } |
782 | 782 | ||
783 | for (s32 i=0; i < lineCount; ++i) | 783 | for (s32 i=0; i < lineCount; ++i) |
784 | { | 784 | { |
785 | setTextRect(i); | 785 | setTextRect(i); |
786 | 786 | ||
787 | // clipping test - don't draw anything outside the visible area | 787 | // clipping test - don't draw anything outside the visible area |
788 | core::rect<s32> c = localClipRect; | 788 | core::rect<s32> c = localClipRect; |
789 | c.clipAgainst(CurrentTextRect); | 789 | c.clipAgainst(CurrentTextRect); |
790 | if (!c.isValid()) | 790 | if (!c.isValid()) |
791 | continue; | 791 | continue; |
792 | 792 | ||
793 | // get current line | 793 | // get current line |
794 | if (PasswordBox) | 794 | if (PasswordBox) |
795 | { | 795 | { |
796 | if (BrokenText.size() != 1) | 796 | if (BrokenText.size() != 1) |
797 | { | 797 | { |
798 | BrokenText.clear(); | 798 | BrokenText.clear(); |
799 | BrokenText.push_back(core::stringw()); | 799 | BrokenText.push_back(core::stringw()); |
800 | } | 800 | } |
801 | if (BrokenText[0].size() != Text.size()) | 801 | if (BrokenText[0].size() != Text.size()) |
802 | { | 802 | { |
803 | BrokenText[0] = Text; | 803 | BrokenText[0] = Text; |
804 | for (u32 q = 0; q < Text.size(); ++q) | 804 | for (u32 q = 0; q < Text.size(); ++q) |
805 | { | 805 | { |
806 | BrokenText[0] [q] = PasswordChar; | 806 | BrokenText[0] [q] = PasswordChar; |
807 | } | 807 | } |
808 | } | 808 | } |
809 | txtLine = &BrokenText[0]; | 809 | txtLine = &BrokenText[0]; |
810 | startPos = 0; | 810 | startPos = 0; |
811 | } | 811 | } |
812 | else | 812 | else |
813 | { | 813 | { |
814 | txtLine = ml ? &BrokenText[i] : &Text; | 814 | txtLine = ml ? &BrokenText[i] : &Text; |
815 | startPos = ml ? BrokenTextPositions[i] : 0; | 815 | startPos = ml ? BrokenTextPositions[i] : 0; |
816 | } | 816 | } |
817 | 817 | ||
818 | 818 | ||
819 | // draw normal text | 819 | // draw normal text |
820 | font->draw(txtLine->c_str(), CurrentTextRect, | 820 | font->draw(txtLine->c_str(), CurrentTextRect, |
821 | OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT), | 821 | OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT), |
822 | false, true, &localClipRect); | 822 | false, true, &localClipRect); |
823 | 823 | ||
824 | // draw mark and marked text | 824 | // draw mark and marked text |
825 | if (focus && MarkBegin != MarkEnd && i >= hlineStart && i < hlineStart + hlineCount) | 825 | if (focus && MarkBegin != MarkEnd && i >= hlineStart && i < hlineStart + hlineCount) |
826 | { | 826 | { |
827 | 827 | ||
828 | s32 mbegin = 0, mend = 0; | 828 | s32 mbegin = 0, mend = 0; |
829 | s32 lineStartPos = 0, lineEndPos = txtLine->size(); | 829 | s32 lineStartPos = 0, lineEndPos = txtLine->size(); |
830 | 830 | ||
831 | if (i == hlineStart) | 831 | if (i == hlineStart) |
832 | { | 832 | { |
833 | // highlight start is on this line | 833 | // highlight start is on this line |
834 | s = txtLine->subString(0, realmbgn - startPos); | 834 | s = txtLine->subString(0, realmbgn - startPos); |
835 | mbegin = font->getDimension(s.c_str()).Width; | 835 | mbegin = font->getDimension(s.c_str()).Width; |
836 | 836 | ||
837 | // deal with kerning | 837 | // deal with kerning |
838 | mbegin += font->getKerningWidth( | 838 | mbegin += font->getKerningWidth( |
839 | &((*txtLine)[realmbgn - startPos]), | 839 | &((*txtLine)[realmbgn - startPos]), |
840 | realmbgn - startPos > 0 ? &((*txtLine)[realmbgn - startPos - 1]) : 0); | 840 | realmbgn - startPos > 0 ? &((*txtLine)[realmbgn - startPos - 1]) : 0); |
841 | 841 | ||
842 | lineStartPos = realmbgn - startPos; | 842 | lineStartPos = realmbgn - startPos; |
843 | } | 843 | } |
844 | if (i == hlineStart + hlineCount - 1) | 844 | if (i == hlineStart + hlineCount - 1) |
845 | { | 845 | { |
846 | // highlight end is on this line | 846 | // highlight end is on this line |
847 | s2 = txtLine->subString(0, realmend - startPos); | 847 | s2 = txtLine->subString(0, realmend - startPos); |
848 | mend = font->getDimension(s2.c_str()).Width; | 848 | mend = font->getDimension(s2.c_str()).Width; |
849 | lineEndPos = (s32)s2.size(); | 849 | lineEndPos = (s32)s2.size(); |
850 | } | 850 | } |
851 | else | 851 | else |
852 | mend = font->getDimension(txtLine->c_str()).Width; | 852 | mend = font->getDimension(txtLine->c_str()).Width; |
853 | 853 | ||
854 | CurrentTextRect.UpperLeftCorner.X += mbegin; | 854 | CurrentTextRect.UpperLeftCorner.X += mbegin; |
855 | CurrentTextRect.LowerRightCorner.X = CurrentTextRect.UpperLeftCorner.X + mend - mbegin; | 855 | CurrentTextRect.LowerRightCorner.X = CurrentTextRect.UpperLeftCorner.X + mend - mbegin; |
856 | 856 | ||
857 | // draw mark | 857 | // draw mark |
858 | skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), CurrentTextRect, &localClipRect); | 858 | skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), CurrentTextRect, &localClipRect); |
859 | 859 | ||
860 | // draw marked text | 860 | // draw marked text |
861 | s = txtLine->subString(lineStartPos, lineEndPos - lineStartPos); | 861 | s = txtLine->subString(lineStartPos, lineEndPos - lineStartPos); |
862 | 862 | ||
863 | if (s.size()) | 863 | if (s.size()) |
864 | font->draw(s.c_str(), CurrentTextRect, | 864 | font->draw(s.c_str(), CurrentTextRect, |
865 | OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_HIGH_LIGHT_TEXT), | 865 | OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_HIGH_LIGHT_TEXT), |
866 | false, true, &localClipRect); | 866 | false, true, &localClipRect); |
867 | 867 | ||
868 | } | 868 | } |
869 | } | 869 | } |
870 | 870 | ||
871 | // Return the override color information to its previous settings. | 871 | // Return the override color information to its previous settings. |
872 | OverrideColorEnabled = prevOver; | 872 | OverrideColorEnabled = prevOver; |
873 | OverrideColor = prevColor; | 873 | OverrideColor = prevColor; |
874 | } | 874 | } |
875 | 875 | ||
876 | // draw cursor | 876 | // draw cursor |
877 | if ( IsEnabled ) | 877 | if ( IsEnabled ) |
878 | { | 878 | { |
879 | if (WordWrap || MultiLine) | 879 | if (WordWrap || MultiLine) |
880 | { | 880 | { |
881 | cursorLine = getLineFromPos(CursorPos); | 881 | cursorLine = getLineFromPos(CursorPos); |
882 | txtLine = &BrokenText[cursorLine]; | 882 | txtLine = &BrokenText[cursorLine]; |
883 | startPos = BrokenTextPositions[cursorLine]; | 883 | startPos = BrokenTextPositions[cursorLine]; |
884 | } | 884 | } |
885 | s = txtLine->subString(0,CursorPos-startPos); | 885 | s = txtLine->subString(0,CursorPos-startPos); |
886 | charcursorpos = font->getDimension(s.c_str()).Width + | 886 | charcursorpos = font->getDimension(s.c_str()).Width + |
887 | font->getKerningWidth(L"_", CursorPos-startPos > 0 ? &((*txtLine)[CursorPos-startPos-1]) : 0); | 887 | font->getKerningWidth(L"_", CursorPos-startPos > 0 ? &((*txtLine)[CursorPos-startPos-1]) : 0); |
888 | 888 | ||
889 | if (focus && (os::Timer::getTime() - BlinkStartTime) % 700 < 350) | 889 | if (focus && (os::Timer::getTime() - BlinkStartTime) % 700 < 350) |
890 | { | 890 | { |
891 | setTextRect(cursorLine); | 891 | setTextRect(cursorLine); |
892 | CurrentTextRect.UpperLeftCorner.X += charcursorpos; | 892 | CurrentTextRect.UpperLeftCorner.X += charcursorpos; |
893 | 893 | ||
894 | font->draw(L"_", CurrentTextRect, | 894 | font->draw(L"_", CurrentTextRect, |
895 | OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT), | 895 | OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT), |
896 | false, true, &localClipRect); | 896 | false, true, &localClipRect); |
897 | } | 897 | } |
898 | } | 898 | } |
899 | } | 899 | } |
900 | 900 | ||
901 | // draw children | 901 | // draw children |
902 | IGUIElement::draw(); | 902 | IGUIElement::draw(); |
903 | } | 903 | } |
904 | 904 | ||
905 | 905 | ||
906 | //! Sets the new caption of this element. | 906 | //! Sets the new caption of this element. |
907 | void CGUIEditBox::setText(const wchar_t* text) | 907 | void CGUIEditBox::setText(const wchar_t* text) |
908 | { | 908 | { |
909 | Text = text; | 909 | Text = text; |
910 | if (u32(CursorPos) > Text.size()) | 910 | if (u32(CursorPos) > Text.size()) |
911 | CursorPos = Text.size(); | 911 | CursorPos = Text.size(); |
912 | HScrollPos = 0; | 912 | HScrollPos = 0; |
913 | breakText(); | 913 | breakText(); |
914 | } | 914 | } |
915 | 915 | ||
916 | 916 | ||
917 | //! Enables or disables automatic scrolling with cursor position | 917 | //! Enables or disables automatic scrolling with cursor position |
918 | //! \param enable: If set to true, the text will move around with the cursor position | 918 | //! \param enable: If set to true, the text will move around with the cursor position |
919 | void CGUIEditBox::setAutoScroll(bool enable) | 919 | void CGUIEditBox::setAutoScroll(bool enable) |
920 | { | 920 | { |
921 | AutoScroll = enable; | 921 | AutoScroll = enable; |
922 | } | 922 | } |
923 | 923 | ||
924 | 924 | ||
925 | //! Checks to see if automatic scrolling is enabled | 925 | //! Checks to see if automatic scrolling is enabled |
926 | //! \return true if automatic scrolling is enabled, false if not | 926 | //! \return true if automatic scrolling is enabled, false if not |
927 | bool CGUIEditBox::isAutoScrollEnabled() const | 927 | bool CGUIEditBox::isAutoScrollEnabled() const |
928 | { | 928 | { |
929 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | 929 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; |
930 | return AutoScroll; | 930 | return AutoScroll; |
931 | } | 931 | } |
932 | 932 | ||
933 | 933 | ||
934 | //! Gets the area of the text in the edit box | 934 | //! Gets the area of the text in the edit box |
935 | //! \return Returns the size in pixels of the text | 935 | //! \return Returns the size in pixels of the text |
936 | core::dimension2du CGUIEditBox::getTextDimension() | 936 | core::dimension2du CGUIEditBox::getTextDimension() |
937 | { | 937 | { |
938 | core::rect<s32> ret; | 938 | core::rect<s32> ret; |
939 | 939 | ||
940 | setTextRect(0); | 940 | setTextRect(0); |
941 | ret = CurrentTextRect; | 941 | ret = CurrentTextRect; |
942 | 942 | ||
943 | for (u32 i=1; i < BrokenText.size(); ++i) | 943 | for (u32 i=1; i < BrokenText.size(); ++i) |
944 | { | 944 | { |
945 | setTextRect(i); | 945 | setTextRect(i); |
946 | ret.addInternalPoint(CurrentTextRect.UpperLeftCorner); | 946 | ret.addInternalPoint(CurrentTextRect.UpperLeftCorner); |
947 | ret.addInternalPoint(CurrentTextRect.LowerRightCorner); | 947 | ret.addInternalPoint(CurrentTextRect.LowerRightCorner); |
948 | } | 948 | } |
949 | 949 | ||
950 | return core::dimension2du(ret.getSize()); | 950 | return core::dimension2du(ret.getSize()); |
951 | } | 951 | } |
952 | 952 | ||
953 | 953 | ||
954 | //! Sets the maximum amount of characters which may be entered in the box. | 954 | //! Sets the maximum amount of characters which may be entered in the box. |
955 | //! \param max: Maximum amount of characters. If 0, the character amount is | 955 | //! \param max: Maximum amount of characters. If 0, the character amount is |
956 | //! infinity. | 956 | //! infinity. |
957 | void CGUIEditBox::setMax(u32 max) | 957 | void CGUIEditBox::setMax(u32 max) |
958 | { | 958 | { |
959 | Max = max; | 959 | Max = max; |
960 | 960 | ||
961 | if (Text.size() > Max && Max != 0) | 961 | if (Text.size() > Max && Max != 0) |
962 | Text = Text.subString(0, Max); | 962 | Text = Text.subString(0, Max); |
963 | } | 963 | } |
964 | 964 | ||
965 | 965 | ||
966 | //! Returns maximum amount of characters, previously set by setMax(); | 966 | //! Returns maximum amount of characters, previously set by setMax(); |
967 | u32 CGUIEditBox::getMax() const | 967 | u32 CGUIEditBox::getMax() const |
968 | { | 968 | { |
969 | return Max; | 969 | return Max; |
970 | } | 970 | } |
971 | 971 | ||
972 | 972 | ||
973 | bool CGUIEditBox::processMouse(const SEvent& event) | 973 | bool CGUIEditBox::processMouse(const SEvent& event) |
974 | { | 974 | { |
975 | switch(event.MouseInput.Event) | 975 | switch(event.MouseInput.Event) |
976 | { | 976 | { |
977 | case irr::EMIE_LMOUSE_LEFT_UP: | 977 | case irr::EMIE_LMOUSE_LEFT_UP: |
978 | if (Environment->hasFocus(this)) | 978 | if (Environment->hasFocus(this)) |
979 | { | 979 | { |
980 | CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y); | 980 | CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y); |
981 | if (MouseMarking) | 981 | if (MouseMarking) |
982 | { | 982 | { |
983 | setTextMarkers( MarkBegin, CursorPos ); | 983 | setTextMarkers( MarkBegin, CursorPos ); |
984 | } | 984 | } |
985 | MouseMarking = false; | 985 | MouseMarking = false; |
986 | calculateScrollPos(); | 986 | calculateScrollPos(); |
987 | return true; | 987 | return true; |
988 | } | 988 | } |
989 | break; | 989 | break; |
990 | case irr::EMIE_MOUSE_MOVED: | 990 | case irr::EMIE_MOUSE_MOVED: |
991 | { | 991 | { |
992 | if (MouseMarking) | 992 | if (MouseMarking) |
993 | { | 993 | { |
994 | CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y); | 994 | CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y); |
995 | setTextMarkers( MarkBegin, CursorPos ); | 995 | setTextMarkers( MarkBegin, CursorPos ); |
996 | calculateScrollPos(); | 996 | calculateScrollPos(); |
997 | return true; | 997 | return true; |
998 | } | 998 | } |
999 | } | 999 | } |
1000 | break; | 1000 | break; |
1001 | case EMIE_LMOUSE_PRESSED_DOWN: | 1001 | case EMIE_LMOUSE_PRESSED_DOWN: |
1002 | if (!Environment->hasFocus(this)) | 1002 | if (!Environment->hasFocus(this)) |
1003 | { | 1003 | { |
1004 | BlinkStartTime = os::Timer::getTime(); | 1004 | BlinkStartTime = os::Timer::getTime(); |
1005 | MouseMarking = true; | 1005 | MouseMarking = true; |
1006 | CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y); | 1006 | CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y); |
1007 | setTextMarkers(CursorPos, CursorPos ); | 1007 | setTextMarkers(CursorPos, CursorPos ); |
1008 | calculateScrollPos(); | 1008 | calculateScrollPos(); |
1009 | return true; | 1009 | return true; |
1010 | } | 1010 | } |
1011 | else | 1011 | else |
1012 | { | 1012 | { |
1013 | if (!AbsoluteClippingRect.isPointInside( | 1013 | if (!AbsoluteClippingRect.isPointInside( |
1014 | core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y))) | 1014 | core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y))) |
1015 | { | 1015 | { |
1016 | return false; | 1016 | return false; |
1017 | } | 1017 | } |
1018 | else | 1018 | else |
1019 | { | 1019 | { |
1020 | // move cursor | 1020 | // move cursor |
1021 | CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y); | 1021 | CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y); |
1022 | 1022 | ||
1023 | s32 newMarkBegin = MarkBegin; | 1023 | s32 newMarkBegin = MarkBegin; |
1024 | if (!MouseMarking) | 1024 | if (!MouseMarking) |
1025 | newMarkBegin = CursorPos; | 1025 | newMarkBegin = CursorPos; |
1026 | 1026 | ||
1027 | MouseMarking = true; | 1027 | MouseMarking = true; |
1028 | setTextMarkers( newMarkBegin, CursorPos); | 1028 | setTextMarkers( newMarkBegin, CursorPos); |
1029 | calculateScrollPos(); | 1029 | calculateScrollPos(); |
1030 | return true; | 1030 | return true; |
1031 | } | 1031 | } |
1032 | } | 1032 | } |
1033 | default: | 1033 | default: |
1034 | break; | 1034 | break; |
1035 | } | 1035 | } |
1036 | 1036 | ||
1037 | return false; | 1037 | return false; |
1038 | } | 1038 | } |
1039 | 1039 | ||
1040 | 1040 | ||
1041 | s32 CGUIEditBox::getCursorPos(s32 x, s32 y) | 1041 | s32 CGUIEditBox::getCursorPos(s32 x, s32 y) |
1042 | { | 1042 | { |
1043 | IGUIFont* font = getActiveFont(); | 1043 | IGUIFont* font = getActiveFont(); |
1044 | 1044 | ||
1045 | const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1; | 1045 | const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1; |
1046 | 1046 | ||
1047 | core::stringw *txtLine=0; | 1047 | core::stringw *txtLine=0; |
1048 | s32 startPos=0; | 1048 | s32 startPos=0; |
1049 | x+=3; | 1049 | x+=3; |
1050 | 1050 | ||
1051 | for (u32 i=0; i < lineCount; ++i) | 1051 | for (u32 i=0; i < lineCount; ++i) |
1052 | { | 1052 | { |
1053 | setTextRect(i); | 1053 | setTextRect(i); |
1054 | if (i == 0 && y < CurrentTextRect.UpperLeftCorner.Y) | 1054 | if (i == 0 && y < CurrentTextRect.UpperLeftCorner.Y) |
1055 | y = CurrentTextRect.UpperLeftCorner.Y; | 1055 | y = CurrentTextRect.UpperLeftCorner.Y; |
1056 | if (i == lineCount - 1 && y > CurrentTextRect.LowerRightCorner.Y ) | 1056 | if (i == lineCount - 1 && y > CurrentTextRect.LowerRightCorner.Y ) |
1057 | y = CurrentTextRect.LowerRightCorner.Y; | 1057 | y = CurrentTextRect.LowerRightCorner.Y; |
1058 | 1058 | ||
1059 | // is it inside this region? | 1059 | // is it inside this region? |
1060 | if (y >= CurrentTextRect.UpperLeftCorner.Y && y <= CurrentTextRect.LowerRightCorner.Y) | 1060 | if (y >= CurrentTextRect.UpperLeftCorner.Y && y <= CurrentTextRect.LowerRightCorner.Y) |
1061 | { | 1061 | { |
1062 | // we've found the clicked line | 1062 | // we've found the clicked line |
1063 | txtLine = (WordWrap || MultiLine) ? &BrokenText[i] : &Text; | 1063 | txtLine = (WordWrap || MultiLine) ? &BrokenText[i] : &Text; |
1064 | startPos = (WordWrap || MultiLine) ? BrokenTextPositions[i] : 0; | 1064 | startPos = (WordWrap || MultiLine) ? BrokenTextPositions[i] : 0; |
1065 | break; | 1065 | break; |
1066 | } | 1066 | } |
1067 | } | 1067 | } |
1068 | 1068 | ||
1069 | if (x < CurrentTextRect.UpperLeftCorner.X) | 1069 | if (x < CurrentTextRect.UpperLeftCorner.X) |
1070 | x = CurrentTextRect.UpperLeftCorner.X; | 1070 | x = CurrentTextRect.UpperLeftCorner.X; |
1071 | 1071 | ||
1072 | if ( !txtLine ) | 1072 | if ( !txtLine ) |
1073 | return 0; | 1073 | return 0; |
1074 | 1074 | ||
1075 | s32 idx = font->getCharacterFromPos(txtLine->c_str(), x - CurrentTextRect.UpperLeftCorner.X); | 1075 | s32 idx = font->getCharacterFromPos(txtLine->c_str(), x - CurrentTextRect.UpperLeftCorner.X); |
1076 | 1076 | ||
1077 | // click was on or left of the line | 1077 | // click was on or left of the line |
1078 | if (idx != -1) | 1078 | if (idx != -1) |
1079 | return idx + startPos; | 1079 | return idx + startPos; |
1080 | 1080 | ||
1081 | // click was off the right edge of the line, go to end. | 1081 | // click was off the right edge of the line, go to end. |
1082 | return txtLine->size() + startPos; | 1082 | return txtLine->size() + startPos; |
1083 | } | 1083 | } |
1084 | 1084 | ||
1085 | 1085 | ||
1086 | //! Breaks the single text line. | 1086 | //! Breaks the single text line. |
1087 | void CGUIEditBox::breakText() | 1087 | void CGUIEditBox::breakText() |
1088 | { | 1088 | { |
1089 | if ((!WordWrap && !MultiLine)) | 1089 | if ((!WordWrap && !MultiLine)) |
1090 | return; | 1090 | return; |
1091 | 1091 | ||
1092 | BrokenText.clear(); // need to reallocate :/ | 1092 | BrokenText.clear(); // need to reallocate :/ |
1093 | BrokenTextPositions.set_used(0); | 1093 | BrokenTextPositions.set_used(0); |
1094 | 1094 | ||
1095 | IGUIFont* font = getActiveFont(); | 1095 | IGUIFont* font = getActiveFont(); |
1096 | if (!font) | 1096 | if (!font) |
1097 | return; | 1097 | return; |
1098 | 1098 | ||
1099 | LastBreakFont = font; | 1099 | LastBreakFont = font; |
1100 | 1100 | ||
1101 | core::stringw line; | 1101 | core::stringw line; |
1102 | core::stringw word; | 1102 | core::stringw word; |
1103 | core::stringw whitespace; | 1103 | core::stringw whitespace; |
1104 | s32 lastLineStart = 0; | 1104 | s32 lastLineStart = 0; |
1105 | s32 size = Text.size(); | 1105 | s32 size = Text.size(); |
1106 | s32 length = 0; | 1106 | s32 length = 0; |
1107 | s32 elWidth = RelativeRect.getWidth() - 6; | 1107 | s32 elWidth = RelativeRect.getWidth() - 6; |
1108 | wchar_t c; | 1108 | wchar_t c; |
1109 | 1109 | ||
1110 | for (s32 i=0; i<size; ++i) | 1110 | for (s32 i=0; i<size; ++i) |
1111 | { | 1111 | { |
1112 | c = Text[i]; | 1112 | c = Text[i]; |
1113 | bool lineBreak = false; | 1113 | bool lineBreak = false; |
1114 | 1114 | ||
1115 | if (c == L'\r') // Mac or Windows breaks | 1115 | if (c == L'\r') // Mac or Windows breaks |
1116 | { | 1116 | { |
1117 | lineBreak = true; | 1117 | lineBreak = true; |
1118 | c = 0; | 1118 | c = 0; |
1119 | if (Text[i+1] == L'\n') // Windows breaks | 1119 | if (Text[i+1] == L'\n') // Windows breaks |
1120 | { | 1120 | { |
1121 | // TODO: I (Michael) think that we shouldn't change the text given by the user for whatever reason. | 1121 | // TODO: I (Michael) think that we shouldn't change the text given by the user for whatever reason. |
1122 | // Instead rework the cursor positioning to be able to handle this (but not in stable release | 1122 | // Instead rework the cursor positioning to be able to handle this (but not in stable release |
1123 | // branch as users might already expect this behavior). | 1123 | // branch as users might already expect this behavior). |
1124 | Text.erase(i+1); | 1124 | Text.erase(i+1); |
1125 | --size; | 1125 | --size; |
1126 | if ( CursorPos > i ) | 1126 | if ( CursorPos > i ) |
1127 | --CursorPos; | 1127 | --CursorPos; |
1128 | } | 1128 | } |
1129 | } | 1129 | } |
1130 | else if (c == L'\n') // Unix breaks | 1130 | else if (c == L'\n') // Unix breaks |
1131 | { | 1131 | { |
1132 | lineBreak = true; | 1132 | lineBreak = true; |
1133 | c = 0; | 1133 | c = 0; |
1134 | } | 1134 | } |
1135 | 1135 | ||
1136 | // don't break if we're not a multi-line edit box | 1136 | // don't break if we're not a multi-line edit box |
1137 | if (!MultiLine) | 1137 | if (!MultiLine) |
1138 | lineBreak = false; | 1138 | lineBreak = false; |
1139 | 1139 | ||
1140 | if (c == L' ' || c == 0 || i == (size-1)) | 1140 | if (c == L' ' || c == 0 || i == (size-1)) |
1141 | { | 1141 | { |
1142 | // here comes the next whitespace, look if | 1142 | // here comes the next whitespace, look if |
1143 | // we can break the last word to the next line | 1143 | // we can break the last word to the next line |
1144 | // We also break whitespace, otherwise cursor would vanish beside the right border. | 1144 | // We also break whitespace, otherwise cursor would vanish beside the right border. |
1145 | s32 whitelgth = font->getDimension(whitespace.c_str()).Width; | 1145 | s32 whitelgth = font->getDimension(whitespace.c_str()).Width; |
1146 | s32 worldlgth = font->getDimension(word.c_str()).Width; | 1146 | s32 worldlgth = font->getDimension(word.c_str()).Width; |
1147 | 1147 | ||
1148 | if (WordWrap && length + worldlgth + whitelgth > elWidth && line.size() > 0) | 1148 | if (WordWrap && length + worldlgth + whitelgth > elWidth && line.size() > 0) |
1149 | { | 1149 | { |
1150 | // break to next line | 1150 | // break to next line |
1151 | length = worldlgth; | 1151 | length = worldlgth; |
1152 | BrokenText.push_back(line); | 1152 | BrokenText.push_back(line); |
1153 | BrokenTextPositions.push_back(lastLineStart); | 1153 | BrokenTextPositions.push_back(lastLineStart); |
1154 | lastLineStart = i - (s32)word.size(); | 1154 | lastLineStart = i - (s32)word.size(); |
1155 | line = word; | 1155 | line = word; |
1156 | } | 1156 | } |
1157 | else | 1157 | else |
1158 | { | 1158 | { |
1159 | // add word to line | 1159 | // add word to line |
1160 | line += whitespace; | 1160 | line += whitespace; |
1161 | line += word; | 1161 | line += word; |
1162 | length += whitelgth + worldlgth; | 1162 | length += whitelgth + worldlgth; |
1163 | } | 1163 | } |
1164 | 1164 | ||
1165 | word = L""; | 1165 | word = L""; |
1166 | whitespace = L""; | 1166 | whitespace = L""; |
1167 | 1167 | ||
1168 | 1168 | ||
1169 | if ( c ) | 1169 | if ( c ) |
1170 | whitespace += c; | 1170 | whitespace += c; |
1171 | 1171 | ||
1172 | // compute line break | 1172 | // compute line break |
1173 | if (lineBreak) | 1173 | if (lineBreak) |
1174 | { | 1174 | { |
1175 | line += whitespace; | 1175 | line += whitespace; |
1176 | line += word; | 1176 | line += word; |
1177 | BrokenText.push_back(line); | 1177 | BrokenText.push_back(line); |
1178 | BrokenTextPositions.push_back(lastLineStart); | 1178 | BrokenTextPositions.push_back(lastLineStart); |
1179 | lastLineStart = i+1; | 1179 | lastLineStart = i+1; |
1180 | line = L""; | 1180 | line = L""; |
1181 | word = L""; | 1181 | word = L""; |
1182 | whitespace = L""; | 1182 | whitespace = L""; |
1183 | length = 0; | 1183 | length = 0; |
1184 | } | 1184 | } |
1185 | } | 1185 | } |
1186 | else | 1186 | else |
1187 | { | 1187 | { |
1188 | // yippee this is a word.. | 1188 | // yippee this is a word.. |
1189 | word += c; | 1189 | word += c; |
1190 | } | 1190 | } |
1191 | } | 1191 | } |
1192 | 1192 | ||
1193 | line += whitespace; | 1193 | line += whitespace; |
1194 | line += word; | 1194 | line += word; |
1195 | BrokenText.push_back(line); | 1195 | BrokenText.push_back(line); |
1196 | BrokenTextPositions.push_back(lastLineStart); | 1196 | BrokenTextPositions.push_back(lastLineStart); |
1197 | } | 1197 | } |
1198 | 1198 | ||
1199 | // TODO: that function does interpret VAlign according to line-index (indexed line is placed on top-center-bottom) | 1199 | // TODO: that function does interpret VAlign according to line-index (indexed line is placed on top-center-bottom) |
1200 | // but HAlign according to line-width (pixels) and not by row. | 1200 | // but HAlign according to line-width (pixels) and not by row. |
1201 | // Intuitively I suppose HAlign handling is better as VScrollPos should handle the line-scrolling. | 1201 | // Intuitively I suppose HAlign handling is better as VScrollPos should handle the line-scrolling. |
1202 | // But please no one change this without also rewriting (and this time fucking testing!!!) autoscrolling (I noticed this when fixing the old autoscrolling). | 1202 | // But please no one change this without also rewriting (and this time fucking testing!!!) autoscrolling (I noticed this when fixing the old autoscrolling). |
1203 | void CGUIEditBox::setTextRect(s32 line) | 1203 | void CGUIEditBox::setTextRect(s32 line) |
1204 | { | 1204 | { |
1205 | if ( line < 0 ) | 1205 | if ( line < 0 ) |
1206 | return; | 1206 | return; |
1207 | 1207 | ||
1208 | IGUIFont* font = getActiveFont(); | 1208 | IGUIFont* font = getActiveFont(); |
1209 | if (!font) | 1209 | if (!font) |
1210 | return; | 1210 | return; |
1211 | 1211 | ||
1212 | core::dimension2du d; | 1212 | core::dimension2du d; |
1213 | 1213 | ||
1214 | // get text dimension | 1214 | // get text dimension |
1215 | const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1; | 1215 | const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1; |
1216 | if (WordWrap || MultiLine) | 1216 | if (WordWrap || MultiLine) |
1217 | { | 1217 | { |
1218 | d = font->getDimension(BrokenText[line].c_str()); | 1218 | d = font->getDimension(BrokenText[line].c_str()); |
1219 | } | 1219 | } |
1220 | else | 1220 | else |
1221 | { | 1221 | { |
1222 | d = font->getDimension(Text.c_str()); | 1222 | d = font->getDimension(Text.c_str()); |
1223 | d.Height = AbsoluteRect.getHeight(); | 1223 | d.Height = AbsoluteRect.getHeight(); |
1224 | } | 1224 | } |
1225 | d.Height += font->getKerningHeight(); | 1225 | d.Height += font->getKerningHeight(); |
1226 | 1226 | ||
1227 | // justification | 1227 | // justification |
1228 | switch (HAlign) | 1228 | switch (HAlign) |
1229 | { | 1229 | { |
1230 | case EGUIA_CENTER: | 1230 | case EGUIA_CENTER: |
1231 | // align to h centre | 1231 | // align to h centre |
1232 | CurrentTextRect.UpperLeftCorner.X = (FrameRect.getWidth()/2) - (d.Width/2); | 1232 | CurrentTextRect.UpperLeftCorner.X = (FrameRect.getWidth()/2) - (d.Width/2); |
1233 | CurrentTextRect.LowerRightCorner.X = (FrameRect.getWidth()/2) + (d.Width/2); | 1233 | CurrentTextRect.LowerRightCorner.X = (FrameRect.getWidth()/2) + (d.Width/2); |
1234 | break; | 1234 | break; |
1235 | case EGUIA_LOWERRIGHT: | 1235 | case EGUIA_LOWERRIGHT: |
1236 | // align to right edge | 1236 | // align to right edge |
1237 | CurrentTextRect.UpperLeftCorner.X = FrameRect.getWidth() - d.Width; | 1237 | CurrentTextRect.UpperLeftCorner.X = FrameRect.getWidth() - d.Width; |
1238 | CurrentTextRect.LowerRightCorner.X = FrameRect.getWidth(); | 1238 | CurrentTextRect.LowerRightCorner.X = FrameRect.getWidth(); |
1239 | break; | 1239 | break; |
1240 | default: | 1240 | default: |
1241 | // align to left edge | 1241 | // align to left edge |
1242 | CurrentTextRect.UpperLeftCorner.X = 0; | 1242 | CurrentTextRect.UpperLeftCorner.X = 0; |
1243 | CurrentTextRect.LowerRightCorner.X = d.Width; | 1243 | CurrentTextRect.LowerRightCorner.X = d.Width; |
1244 | 1244 | ||
1245 | } | 1245 | } |
1246 | 1246 | ||
1247 | switch (VAlign) | 1247 | switch (VAlign) |
1248 | { | 1248 | { |
1249 | case EGUIA_CENTER: | 1249 | case EGUIA_CENTER: |
1250 | // align to v centre | 1250 | // align to v centre |
1251 | CurrentTextRect.UpperLeftCorner.Y = | 1251 | CurrentTextRect.UpperLeftCorner.Y = |
1252 | (FrameRect.getHeight()/2) - (lineCount*d.Height)/2 + d.Height*line; | 1252 | (FrameRect.getHeight()/2) - (lineCount*d.Height)/2 + d.Height*line; |
1253 | break; | 1253 | break; |
1254 | case EGUIA_LOWERRIGHT: | 1254 | case EGUIA_LOWERRIGHT: |
1255 | // align to bottom edge | 1255 | // align to bottom edge |
1256 | CurrentTextRect.UpperLeftCorner.Y = | 1256 | CurrentTextRect.UpperLeftCorner.Y = |
1257 | FrameRect.getHeight() - lineCount*d.Height + d.Height*line; | 1257 | FrameRect.getHeight() - lineCount*d.Height + d.Height*line; |
1258 | break; | 1258 | break; |
1259 | default: | 1259 | default: |
1260 | // align to top edge | 1260 | // align to top edge |
1261 | CurrentTextRect.UpperLeftCorner.Y = d.Height*line; | 1261 | CurrentTextRect.UpperLeftCorner.Y = d.Height*line; |
1262 | break; | 1262 | break; |
1263 | } | 1263 | } |
1264 | 1264 | ||
1265 | CurrentTextRect.UpperLeftCorner.X -= HScrollPos; | 1265 | CurrentTextRect.UpperLeftCorner.X -= HScrollPos; |
1266 | CurrentTextRect.LowerRightCorner.X -= HScrollPos; | 1266 | CurrentTextRect.LowerRightCorner.X -= HScrollPos; |
1267 | CurrentTextRect.UpperLeftCorner.Y -= VScrollPos; | 1267 | CurrentTextRect.UpperLeftCorner.Y -= VScrollPos; |
1268 | CurrentTextRect.LowerRightCorner.Y = CurrentTextRect.UpperLeftCorner.Y + d.Height; | 1268 | CurrentTextRect.LowerRightCorner.Y = CurrentTextRect.UpperLeftCorner.Y + d.Height; |
1269 | 1269 | ||
1270 | CurrentTextRect += FrameRect.UpperLeftCorner; | 1270 | CurrentTextRect += FrameRect.UpperLeftCorner; |
1271 | 1271 | ||
1272 | } | 1272 | } |
1273 | 1273 | ||
1274 | 1274 | ||
1275 | s32 CGUIEditBox::getLineFromPos(s32 pos) | 1275 | s32 CGUIEditBox::getLineFromPos(s32 pos) |
1276 | { | 1276 | { |
1277 | if (!WordWrap && !MultiLine) | 1277 | if (!WordWrap && !MultiLine) |
1278 | return 0; | 1278 | return 0; |
1279 | 1279 | ||
1280 | s32 i=0; | 1280 | s32 i=0; |
1281 | while (i < (s32)BrokenTextPositions.size()) | 1281 | while (i < (s32)BrokenTextPositions.size()) |
1282 | { | 1282 | { |
1283 | if (BrokenTextPositions[i] > pos) | 1283 | if (BrokenTextPositions[i] > pos) |
1284 | return i-1; | 1284 | return i-1; |
1285 | ++i; | 1285 | ++i; |
1286 | } | 1286 | } |
1287 | return (s32)BrokenTextPositions.size() - 1; | 1287 | return (s32)BrokenTextPositions.size() - 1; |
1288 | } | 1288 | } |
1289 | 1289 | ||
1290 | 1290 | ||
1291 | void CGUIEditBox::inputChar(wchar_t c) | 1291 | void CGUIEditBox::inputChar(wchar_t c) |
1292 | { | 1292 | { |
1293 | if (!isEnabled()) | 1293 | if (!isEnabled()) |
1294 | return; | 1294 | return; |
1295 | 1295 | ||
1296 | if (c != 0) | 1296 | if (c != 0) |
1297 | { | 1297 | { |
1298 | if (Text.size() < Max || Max == 0) | 1298 | if (Text.size() < Max || Max == 0) |
1299 | { | 1299 | { |
1300 | core::stringw s; | 1300 | core::stringw s; |
1301 | 1301 | ||
1302 | if (MarkBegin != MarkEnd) | 1302 | if (MarkBegin != MarkEnd) |
1303 | { | 1303 | { |
1304 | // replace marked text | 1304 | // replace marked text |
1305 | const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; | 1305 | const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; |
1306 | const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; | 1306 | const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; |
1307 | 1307 | ||
1308 | s = Text.subString(0, realmbgn); | 1308 | s = Text.subString(0, realmbgn); |
1309 | s.append(c); | 1309 | s.append(c); |
1310 | s.append( Text.subString(realmend, Text.size()-realmend) ); | 1310 | s.append( Text.subString(realmend, Text.size()-realmend) ); |
1311 | Text = s; | 1311 | Text = s; |
1312 | CursorPos = realmbgn+1; | 1312 | CursorPos = realmbgn+1; |
1313 | } | 1313 | } |
1314 | else | 1314 | else |
1315 | { | 1315 | { |
1316 | // add new character | 1316 | // add new character |
1317 | s = Text.subString(0, CursorPos); | 1317 | s = Text.subString(0, CursorPos); |
1318 | s.append(c); | 1318 | s.append(c); |
1319 | s.append( Text.subString(CursorPos, Text.size()-CursorPos) ); | 1319 | s.append( Text.subString(CursorPos, Text.size()-CursorPos) ); |
1320 | Text = s; | 1320 | Text = s; |
1321 | ++CursorPos; | 1321 | ++CursorPos; |
1322 | } | 1322 | } |
1323 | 1323 | ||
1324 | BlinkStartTime = os::Timer::getTime(); | 1324 | BlinkStartTime = os::Timer::getTime(); |
1325 | setTextMarkers(0, 0); | 1325 | setTextMarkers(0, 0); |
1326 | } | 1326 | } |
1327 | } | 1327 | } |
1328 | breakText(); | 1328 | breakText(); |
1329 | calculateScrollPos(); | 1329 | calculateScrollPos(); |
1330 | sendGuiEvent(EGET_EDITBOX_CHANGED); | 1330 | sendGuiEvent(EGET_EDITBOX_CHANGED); |
1331 | } | 1331 | } |
1332 | 1332 | ||
1333 | // calculate autoscroll | 1333 | // calculate autoscroll |
1334 | void CGUIEditBox::calculateScrollPos() | 1334 | void CGUIEditBox::calculateScrollPos() |
1335 | { | 1335 | { |
1336 | if (!AutoScroll) | 1336 | if (!AutoScroll) |
1337 | return; | 1337 | return; |
1338 | 1338 | ||
1339 | IGUISkin* skin = Environment->getSkin(); | 1339 | IGUISkin* skin = Environment->getSkin(); |
1340 | if (!skin) | 1340 | if (!skin) |
1341 | return; | 1341 | return; |
1342 | IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont(); | 1342 | IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont(); |
1343 | if (!font) | 1343 | if (!font) |
1344 | return; | 1344 | return; |
1345 | 1345 | ||
1346 | s32 cursLine = getLineFromPos(CursorPos); | 1346 | s32 cursLine = getLineFromPos(CursorPos); |
1347 | if ( cursLine < 0 ) | 1347 | if ( cursLine < 0 ) |
1348 | return; | 1348 | return; |
1349 | setTextRect(cursLine); | 1349 | setTextRect(cursLine); |
1350 | const bool hasBrokenText = MultiLine || WordWrap; | 1350 | const bool hasBrokenText = MultiLine || WordWrap; |
1351 | 1351 | ||
1352 | // Check horizonal scrolling | 1352 | // Check horizonal scrolling |
1353 | // NOTE: Calculations different to vertical scrolling because setTextRect interprets VAlign relative to line but HAlign not relative to row | 1353 | // NOTE: Calculations different to vertical scrolling because setTextRect interprets VAlign relative to line but HAlign not relative to row |
1354 | { | 1354 | { |
1355 | // get cursor position | 1355 | // get cursor position |
1356 | IGUIFont* font = getActiveFont(); | 1356 | IGUIFont* font = getActiveFont(); |
1357 | if (!font) | 1357 | if (!font) |
1358 | return; | 1358 | return; |
1359 | 1359 | ||
1360 | // get cursor area | 1360 | // get cursor area |
1361 | irr::u32 cursorWidth = font->getDimension(L"_").Width; | 1361 | irr::u32 cursorWidth = font->getDimension(L"_").Width; |
1362 | core::stringw *txtLine = hasBrokenText ? &BrokenText[cursLine] : &Text; | 1362 | core::stringw *txtLine = hasBrokenText ? &BrokenText[cursLine] : &Text; |
1363 | s32 cPos = hasBrokenText ? CursorPos - BrokenTextPositions[cursLine] : CursorPos; // column | 1363 | s32 cPos = hasBrokenText ? CursorPos - BrokenTextPositions[cursLine] : CursorPos; // column |
1364 | s32 cStart = font->getDimension(txtLine->subString(0, cPos).c_str()).Width; // pixels from text-start | 1364 | s32 cStart = font->getDimension(txtLine->subString(0, cPos).c_str()).Width; // pixels from text-start |
1365 | s32 cEnd = cStart + cursorWidth; | 1365 | s32 cEnd = cStart + cursorWidth; |
1366 | s32 txtWidth = font->getDimension(txtLine->c_str()).Width; | 1366 | s32 txtWidth = font->getDimension(txtLine->c_str()).Width; |
1367 | 1367 | ||
1368 | if ( txtWidth < FrameRect.getWidth() ) | 1368 | if ( txtWidth < FrameRect.getWidth() ) |
1369 | { | 1369 | { |
1370 | // TODO: Needs a clean left and right gap removal depending on HAlign, similar to vertical scrolling tests for top/bottom. | 1370 | // TODO: Needs a clean left and right gap removal depending on HAlign, similar to vertical scrolling tests for top/bottom. |
1371 | // This check just fixes the case where it was most noticable (text smaller than clipping area). | 1371 | // This check just fixes the case where it was most noticable (text smaller than clipping area). |
1372 | 1372 | ||
1373 | HScrollPos = 0; | 1373 | HScrollPos = 0; |
1374 | setTextRect(cursLine); | 1374 | setTextRect(cursLine); |
1375 | } | 1375 | } |
1376 | 1376 | ||
1377 | if ( CurrentTextRect.UpperLeftCorner.X+cStart < FrameRect.UpperLeftCorner.X ) | 1377 | if ( CurrentTextRect.UpperLeftCorner.X+cStart < FrameRect.UpperLeftCorner.X ) |
1378 | { | 1378 | { |
1379 | // cursor to the left of the clipping area | 1379 | // cursor to the left of the clipping area |
1380 | HScrollPos -= FrameRect.UpperLeftCorner.X-(CurrentTextRect.UpperLeftCorner.X+cStart); | 1380 | HScrollPos -= FrameRect.UpperLeftCorner.X-(CurrentTextRect.UpperLeftCorner.X+cStart); |
1381 | setTextRect(cursLine); | 1381 | setTextRect(cursLine); |
1382 | 1382 | ||
1383 | // TODO: should show more characters to the left when we're scrolling left | 1383 | // TODO: should show more characters to the left when we're scrolling left |
1384 | // and the cursor reaches the border. | 1384 | // and the cursor reaches the border. |
1385 | } | 1385 | } |
1386 | else if ( CurrentTextRect.UpperLeftCorner.X+cEnd > FrameRect.LowerRightCorner.X) | 1386 | else if ( CurrentTextRect.UpperLeftCorner.X+cEnd > FrameRect.LowerRightCorner.X) |
1387 | { | 1387 | { |
1388 | // cursor to the right of the clipping area | 1388 | // cursor to the right of the clipping area |
1389 | HScrollPos += (CurrentTextRect.UpperLeftCorner.X+cEnd)-FrameRect.LowerRightCorner.X; | 1389 | HScrollPos += (CurrentTextRect.UpperLeftCorner.X+cEnd)-FrameRect.LowerRightCorner.X; |
1390 | setTextRect(cursLine); | 1390 | setTextRect(cursLine); |
1391 | } | 1391 | } |
1392 | } | 1392 | } |
1393 | 1393 | ||
1394 | // calculate vertical scrolling | 1394 | // calculate vertical scrolling |
1395 | if (hasBrokenText) | 1395 | if (hasBrokenText) |
1396 | { | 1396 | { |
1397 | irr::u32 lineHeight = font->getDimension(L"A").Height + font->getKerningHeight(); | 1397 | irr::u32 lineHeight = font->getDimension(L"A").Height + font->getKerningHeight(); |
1398 | // only up to 1 line fits? | 1398 | // only up to 1 line fits? |
1399 | if ( lineHeight >= (irr::u32)FrameRect.getHeight() ) | 1399 | if ( lineHeight >= (irr::u32)FrameRect.getHeight() ) |
1400 | { | 1400 | { |
1401 | VScrollPos = 0; | 1401 | VScrollPos = 0; |
1402 | setTextRect(cursLine); | 1402 | setTextRect(cursLine); |
1403 | s32 unscrolledPos = CurrentTextRect.UpperLeftCorner.Y; | 1403 | s32 unscrolledPos = CurrentTextRect.UpperLeftCorner.Y; |
1404 | s32 pivot = FrameRect.UpperLeftCorner.Y; | 1404 | s32 pivot = FrameRect.UpperLeftCorner.Y; |
1405 | switch (VAlign) | 1405 | switch (VAlign) |
1406 | { | 1406 | { |
1407 | case EGUIA_CENTER: | 1407 | case EGUIA_CENTER: |
1408 | pivot += FrameRect.getHeight()/2; | 1408 | pivot += FrameRect.getHeight()/2; |
1409 | unscrolledPos += lineHeight/2; | 1409 | unscrolledPos += lineHeight/2; |
1410 | break; | 1410 | break; |
1411 | case EGUIA_LOWERRIGHT: | 1411 | case EGUIA_LOWERRIGHT: |
1412 | pivot += FrameRect.getHeight(); | 1412 | pivot += FrameRect.getHeight(); |
1413 | unscrolledPos += lineHeight; | 1413 | unscrolledPos += lineHeight; |
1414 | break; | 1414 | break; |
1415 | default: | 1415 | default: |
1416 | break; | 1416 | break; |
1417 | } | 1417 | } |
1418 | VScrollPos = unscrolledPos-pivot; | 1418 | VScrollPos = unscrolledPos-pivot; |
1419 | setTextRect(cursLine); | 1419 | setTextRect(cursLine); |
1420 | } | 1420 | } |
1421 | else | 1421 | else |
1422 | { | 1422 | { |
1423 | // First 2 checks are necessary when people delete lines | 1423 | // First 2 checks are necessary when people delete lines |
1424 | setTextRect(0); | 1424 | setTextRect(0); |
1425 | if ( CurrentTextRect.UpperLeftCorner.Y > FrameRect.UpperLeftCorner.Y && VAlign != EGUIA_LOWERRIGHT) | 1425 | if ( CurrentTextRect.UpperLeftCorner.Y > FrameRect.UpperLeftCorner.Y && VAlign != EGUIA_LOWERRIGHT) |
1426 | { | 1426 | { |
1427 | // first line is leaving a gap on top | 1427 | // first line is leaving a gap on top |
1428 | VScrollPos = 0; | 1428 | VScrollPos = 0; |
1429 | } | 1429 | } |
1430 | else if (VAlign != EGUIA_UPPERLEFT) | 1430 | else if (VAlign != EGUIA_UPPERLEFT) |
1431 | { | 1431 | { |
1432 | u32 lastLine = BrokenTextPositions.empty() ? 0 : BrokenTextPositions.size()-1; | 1432 | u32 lastLine = BrokenTextPositions.empty() ? 0 : BrokenTextPositions.size()-1; |
1433 | setTextRect(lastLine); | 1433 | setTextRect(lastLine); |
1434 | if ( CurrentTextRect.LowerRightCorner.Y < FrameRect.LowerRightCorner.Y) | 1434 | if ( CurrentTextRect.LowerRightCorner.Y < FrameRect.LowerRightCorner.Y) |
1435 | { | 1435 | { |
1436 | // last line is leaving a gap on bottom | 1436 | // last line is leaving a gap on bottom |
1437 | VScrollPos -= FrameRect.LowerRightCorner.Y-CurrentTextRect.LowerRightCorner.Y; | 1437 | VScrollPos -= FrameRect.LowerRightCorner.Y-CurrentTextRect.LowerRightCorner.Y; |
1438 | } | 1438 | } |
1439 | } | 1439 | } |
1440 | 1440 | ||
1441 | setTextRect(cursLine); | 1441 | setTextRect(cursLine); |
1442 | if ( CurrentTextRect.UpperLeftCorner.Y < FrameRect.UpperLeftCorner.Y ) | 1442 | if ( CurrentTextRect.UpperLeftCorner.Y < FrameRect.UpperLeftCorner.Y ) |
1443 | { | 1443 | { |
1444 | // text above valid area | 1444 | // text above valid area |
1445 | VScrollPos -= FrameRect.UpperLeftCorner.Y-CurrentTextRect.UpperLeftCorner.Y; | 1445 | VScrollPos -= FrameRect.UpperLeftCorner.Y-CurrentTextRect.UpperLeftCorner.Y; |
1446 | setTextRect(cursLine); | 1446 | setTextRect(cursLine); |
1447 | } | 1447 | } |
1448 | else if ( CurrentTextRect.LowerRightCorner.Y > FrameRect.LowerRightCorner.Y) | 1448 | else if ( CurrentTextRect.LowerRightCorner.Y > FrameRect.LowerRightCorner.Y) |
1449 | { | 1449 | { |
1450 | // text below valid area | 1450 | // text below valid area |
1451 | VScrollPos += CurrentTextRect.LowerRightCorner.Y-FrameRect.LowerRightCorner.Y; | 1451 | VScrollPos += CurrentTextRect.LowerRightCorner.Y-FrameRect.LowerRightCorner.Y; |
1452 | setTextRect(cursLine); | 1452 | setTextRect(cursLine); |
1453 | } | 1453 | } |
1454 | } | 1454 | } |
1455 | } | 1455 | } |
1456 | } | 1456 | } |
1457 | 1457 | ||
1458 | void CGUIEditBox::calculateFrameRect() | 1458 | void CGUIEditBox::calculateFrameRect() |
1459 | { | 1459 | { |
1460 | FrameRect = AbsoluteRect; | 1460 | FrameRect = AbsoluteRect; |
1461 | IGUISkin *skin = 0; | 1461 | IGUISkin *skin = 0; |
1462 | if (Environment) | 1462 | if (Environment) |
1463 | skin = Environment->getSkin(); | 1463 | skin = Environment->getSkin(); |
1464 | if (Border && skin) | 1464 | if (Border && skin) |
1465 | { | 1465 | { |
1466 | FrameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1; | 1466 | FrameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1; |
1467 | FrameRect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y)+1; | 1467 | FrameRect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y)+1; |
1468 | FrameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X)+1; | 1468 | FrameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X)+1; |
1469 | FrameRect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y)+1; | 1469 | FrameRect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y)+1; |
1470 | } | 1470 | } |
1471 | } | 1471 | } |
1472 | 1472 | ||
1473 | //! set text markers | 1473 | //! set text markers |
1474 | void CGUIEditBox::setTextMarkers(s32 begin, s32 end) | 1474 | void CGUIEditBox::setTextMarkers(s32 begin, s32 end) |
1475 | { | 1475 | { |
1476 | if ( begin != MarkBegin || end != MarkEnd ) | 1476 | if ( begin != MarkBegin || end != MarkEnd ) |
1477 | { | 1477 | { |
1478 | MarkBegin = begin; | 1478 | MarkBegin = begin; |
1479 | MarkEnd = end; | 1479 | MarkEnd = end; |
1480 | sendGuiEvent(EGET_EDITBOX_MARKING_CHANGED); | 1480 | sendGuiEvent(EGET_EDITBOX_MARKING_CHANGED); |
1481 | } | 1481 | } |
1482 | } | 1482 | } |
1483 | 1483 | ||
1484 | //! send some gui event to parent | 1484 | //! send some gui event to parent |
1485 | void CGUIEditBox::sendGuiEvent(EGUI_EVENT_TYPE type) | 1485 | void CGUIEditBox::sendGuiEvent(EGUI_EVENT_TYPE type) |
1486 | { | 1486 | { |
1487 | if ( Parent ) | 1487 | if ( Parent ) |
1488 | { | 1488 | { |
1489 | SEvent e; | 1489 | SEvent e; |
1490 | e.EventType = EET_GUI_EVENT; | 1490 | e.EventType = EET_GUI_EVENT; |
1491 | e.GUIEvent.Caller = this; | 1491 | e.GUIEvent.Caller = this; |
1492 | e.GUIEvent.Element = 0; | 1492 | e.GUIEvent.Element = 0; |
1493 | e.GUIEvent.EventType = type; | 1493 | e.GUIEvent.EventType = type; |
1494 | 1494 | ||
1495 | Parent->OnEvent(e); | 1495 | Parent->OnEvent(e); |
1496 | } | 1496 | } |
1497 | } | 1497 | } |
1498 | 1498 | ||
1499 | //! Writes attributes of the element. | 1499 | //! Writes attributes of the element. |
1500 | void CGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const | 1500 | void CGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const |
1501 | { | 1501 | { |
1502 | // IGUIEditBox::serializeAttributes(out,options); | 1502 | // IGUIEditBox::serializeAttributes(out,options); |
1503 | 1503 | ||
1504 | out->addBool ("Border", Border); | 1504 | out->addBool ("Border", Border); |
1505 | out->addBool ("Background", Background); | 1505 | out->addBool ("Background", Background); |
1506 | out->addBool ("OverrideColorEnabled", OverrideColorEnabled ); | 1506 | out->addBool ("OverrideColorEnabled", OverrideColorEnabled ); |
1507 | out->addColor ("OverrideColor", OverrideColor); | 1507 | out->addColor ("OverrideColor", OverrideColor); |
1508 | // out->addFont("OverrideFont", OverrideFont); | 1508 | // out->addFont("OverrideFont", OverrideFont); |
1509 | out->addInt ("MaxChars", Max); | 1509 | out->addInt ("MaxChars", Max); |
1510 | out->addBool ("WordWrap", WordWrap); | 1510 | out->addBool ("WordWrap", WordWrap); |
1511 | out->addBool ("MultiLine", MultiLine); | 1511 | out->addBool ("MultiLine", MultiLine); |
1512 | out->addBool ("AutoScroll", AutoScroll); | 1512 | out->addBool ("AutoScroll", AutoScroll); |
1513 | out->addBool ("PasswordBox", PasswordBox); | 1513 | out->addBool ("PasswordBox", PasswordBox); |
1514 | core::stringw ch = L" "; | 1514 | core::stringw ch = L" "; |
1515 | ch[0] = PasswordChar; | 1515 | ch[0] = PasswordChar; |
1516 | out->addString("PasswordChar", ch.c_str()); | 1516 | out->addString("PasswordChar", ch.c_str()); |
1517 | out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames); | 1517 | out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames); |
1518 | out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames); | 1518 | out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames); |
1519 | 1519 | ||
1520 | IGUIEditBox::serializeAttributes(out,options); | 1520 | IGUIEditBox::serializeAttributes(out,options); |
1521 | } | 1521 | } |
1522 | 1522 | ||
1523 | 1523 | ||
1524 | //! Reads attributes of the element | 1524 | //! Reads attributes of the element |
1525 | void CGUIEditBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) | 1525 | void CGUIEditBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) |
1526 | { | 1526 | { |
1527 | IGUIEditBox::deserializeAttributes(in,options); | 1527 | IGUIEditBox::deserializeAttributes(in,options); |
1528 | 1528 | ||
1529 | setDrawBorder( in->getAttributeAsBool("Border") ); | 1529 | setDrawBorder( in->getAttributeAsBool("Border") ); |
1530 | setDrawBackground( in->getAttributeAsBool("Background") ); | 1530 | setDrawBackground( in->getAttributeAsBool("Background") ); |
1531 | setOverrideColor(in->getAttributeAsColor("OverrideColor")); | 1531 | setOverrideColor(in->getAttributeAsColor("OverrideColor")); |
1532 | enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled")); | 1532 | enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled")); |
1533 | setMax(in->getAttributeAsInt("MaxChars")); | 1533 | setMax(in->getAttributeAsInt("MaxChars")); |
1534 | setWordWrap(in->getAttributeAsBool("WordWrap")); | 1534 | setWordWrap(in->getAttributeAsBool("WordWrap")); |
1535 | setMultiLine(in->getAttributeAsBool("MultiLine")); | 1535 | setMultiLine(in->getAttributeAsBool("MultiLine")); |
1536 | setAutoScroll(in->getAttributeAsBool("AutoScroll")); | 1536 | setAutoScroll(in->getAttributeAsBool("AutoScroll")); |
1537 | core::stringw ch = in->getAttributeAsStringW("PasswordChar"); | 1537 | core::stringw ch = in->getAttributeAsStringW("PasswordChar"); |
1538 | 1538 | ||
1539 | if (!ch.size()) | 1539 | if (!ch.size()) |
1540 | setPasswordBox(in->getAttributeAsBool("PasswordBox")); | 1540 | setPasswordBox(in->getAttributeAsBool("PasswordBox")); |
1541 | else | 1541 | else |
1542 | setPasswordBox(in->getAttributeAsBool("PasswordBox"), ch[0]); | 1542 | setPasswordBox(in->getAttributeAsBool("PasswordBox"), ch[0]); |
1543 | 1543 | ||
1544 | setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames), | 1544 | setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames), |
1545 | (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames)); | 1545 | (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames)); |
1546 | 1546 | ||
1547 | // setOverrideFont(in->getAttributeAsFont("OverrideFont")); | 1547 | // setOverrideFont(in->getAttributeAsFont("OverrideFont")); |
1548 | } | 1548 | } |
1549 | 1549 | ||
1550 | 1550 | ||
1551 | } // end namespace gui | 1551 | } // end namespace gui |
1552 | } // end namespace irr | 1552 | } // end namespace irr |
1553 | 1553 | ||
1554 | #endif // _IRR_COMPILE_WITH_GUI_ | 1554 | #endif // _IRR_COMPILE_WITH_GUI_ |
1555 | 1555 | ||