comparison ext/guichan-0.8.1/src/widgets/textbox.cpp @ 0:4a0efb7baf70

* Datasets becomes the new trunk and retires after that :-)
author mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222
date Sun, 29 Jun 2008 18:44:17 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4a0efb7baf70
1 /* _______ __ __ __ ______ __ __ _______ __ __
2 * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\
3 * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
4 * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / /
5 * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / /
6 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
7 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
8 *
9 * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
10 *
11 *
12 * Per Larsson a.k.a finalman
13 * Olof Naessén a.k.a jansem/yakslem
14 *
15 * Visit: http://guichan.sourceforge.net
16 *
17 * License: (BSD)
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in
25 * the documentation and/or other materials provided with the
26 * distribution.
27 * 3. Neither the name of Guichan nor the names of its contributors may
28 * be used to endorse or promote products derived from this software
29 * without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
37 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
38 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
39 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 */
43
44 /*
45 * For comments regarding functions please see the header file.
46 */
47
48 #include "guichan/widgets/textbox.hpp"
49
50 #include "guichan/basiccontainer.hpp"
51 #include "guichan/font.hpp"
52 #include "guichan/graphics.hpp"
53 #include "guichan/key.hpp"
54 #include "guichan/mouseinput.hpp"
55
56 namespace gcn
57 {
58 TextBox::TextBox()
59 {
60 mCaretColumn = 0;
61 mCaretRow = 0;
62 mEditable = true;
63 mOpaque = true;
64
65 setFocusable(true);
66
67 addMouseListener(this);
68 addKeyListener(this);
69 adjustSize();
70 setText("");
71 }
72
73 TextBox::TextBox(const std::string& text)
74 {
75 mCaretColumn = 0;
76 mCaretRow = 0;
77 mEditable = true;
78 mOpaque = true;
79
80 setText(text);
81
82 setFocusable(true);
83
84 addMouseListener(this);
85 addKeyListener(this);
86 adjustSize();
87 }
88
89 void TextBox::setText(const std::string& text)
90 {
91 mCaretColumn = 0;
92 mCaretRow = 0;
93
94 mTextRows.clear();
95
96 std::string::size_type pos, lastPos = 0;
97 int length;
98 do
99 {
100 pos = text.find("\n", lastPos);
101
102 if (pos != std::string::npos)
103 {
104 length = pos - lastPos;
105 }
106 else
107 {
108 length = text.size() - lastPos;
109 }
110 std::string sub = text.substr(lastPos, length);
111 mTextRows.push_back(sub);
112 lastPos = pos + 1;
113
114 } while (pos != std::string::npos);
115
116 adjustSize();
117 }
118
119 void TextBox::draw(Graphics* graphics)
120 {
121 /*
122 int width = getWidth() + getBorderSize() * 2 - 1;
123 int height = getHeight() + getBorderSize() * 2 - 1;
124
125 graphics->setColor(getBackgroundColor());
126
127 unsigned int i;
128 for (i = 0; i < getBorderSize(); ++i)
129 {
130 graphics->drawLine(i,i, width - i, i);
131 graphics->drawLine(i,i + 1, i, height - i - 1);
132 graphics->drawLine(width - i,i + 1, width - i, height - i);
133 graphics->drawLine(i,height - i, width - i - 1, height - i);
134 }
135 */
136
137 unsigned int i;
138
139 if (mOpaque)
140 {
141 graphics->setColor(getBackgroundColor());
142 graphics->fillRectangle(Rectangle(0, 0, getWidth(), getHeight()));
143 }
144
145 if (isFocused() && isEditable())
146 {
147 drawCaret(graphics, getFont()->getWidth(mTextRows[mCaretRow].substr(0, mCaretColumn)), mCaretRow * getFont()->getHeight());
148 }
149
150 graphics->setColor(getForegroundColor());
151 graphics->setFont(getFont());
152
153 for (i = 0; i < mTextRows.size(); i++)
154 {
155 // Move the text one pixel so we can have a caret before a letter.
156 graphics->drawText(mTextRows[i], 1, i * getFont()->getHeight());
157 }
158 }
159
160 void TextBox::drawCaret(Graphics* graphics, int x, int y)
161 {
162 graphics->setColor(getForegroundColor());
163 graphics->drawLine(x, getFont()->getHeight() + y, x, y);
164 }
165
166 void TextBox::mousePressed(MouseEvent& mouseEvent)
167 {
168 if (mouseEvent.getButton() == MouseEvent::LEFT)
169 {
170 mCaretRow = mouseEvent.getY() / getFont()->getHeight();
171
172 if (mCaretRow >= (int)mTextRows.size())
173 {
174 mCaretRow = mTextRows.size() - 1;
175 }
176
177 mCaretColumn = getFont()->getStringIndexAt(mTextRows[mCaretRow], mouseEvent.getX());
178 }
179 }
180
181 void TextBox::mouseDragged(MouseEvent& mouseEvent)
182 {
183 mouseEvent.consume();
184 }
185
186 void TextBox::keyPressed(KeyEvent& keyEvent)
187 {
188 Key key = keyEvent.getKey();
189
190 if (key.getValue() == Key::LEFT)
191 {
192 --mCaretColumn;
193 if (mCaretColumn < 0)
194 {
195 --mCaretRow;
196
197 if (mCaretRow < 0)
198 {
199 mCaretRow = 0;
200 mCaretColumn = 0;
201 }
202 else
203 {
204 mCaretColumn = mTextRows[mCaretRow].size();
205 }
206 }
207 }
208
209 else if (key.getValue() == Key::RIGHT)
210 {
211 ++mCaretColumn;
212 if (mCaretColumn > (int)mTextRows[mCaretRow].size())
213 {
214 ++mCaretRow;
215
216 if (mCaretRow >= (int)mTextRows.size())
217 {
218 mCaretRow = mTextRows.size() - 1;
219 if (mCaretRow < 0)
220 {
221 mCaretRow = 0;
222 }
223
224 mCaretColumn = mTextRows[mCaretRow].size();
225 }
226 else
227 {
228 mCaretColumn = 0;
229 }
230 }
231 }
232
233 else if (key.getValue() == Key::DOWN)
234 {
235 setCaretRow(mCaretRow + 1);
236 }
237
238 else if (key.getValue() == Key::UP)
239 {
240 setCaretRow(mCaretRow - 1);
241 }
242
243 else if (key.getValue() == Key::HOME)
244 {
245 mCaretColumn = 0;
246 }
247
248 else if (key.getValue() == Key::END)
249 {
250 mCaretColumn = mTextRows[mCaretRow].size();
251 }
252
253 else if (key.getValue() == Key::ENTER && mEditable)
254 {
255 mTextRows.insert(mTextRows.begin() + mCaretRow + 1,
256 mTextRows[mCaretRow].substr(mCaretColumn, mTextRows[mCaretRow].size() - mCaretColumn));
257 mTextRows[mCaretRow].resize(mCaretColumn);
258 ++mCaretRow;
259 mCaretColumn = 0;
260 }
261
262 else if (key.getValue() == Key::BACKSPACE
263 && mCaretColumn != 0
264 && mEditable)
265 {
266 mTextRows[mCaretRow].erase(mCaretColumn - 1, 1);
267 --mCaretColumn;
268 }
269
270 else if (key.getValue() == Key::BACKSPACE
271 && mCaretColumn == 0
272 && mCaretRow != 0
273 && mEditable)
274 {
275 mCaretColumn = mTextRows[mCaretRow - 1].size();
276 mTextRows[mCaretRow - 1] += mTextRows[mCaretRow];
277 mTextRows.erase(mTextRows.begin() + mCaretRow);
278 --mCaretRow;
279 }
280
281 else if (key.getValue() == Key::DELETE
282 && mCaretColumn < (int)mTextRows[mCaretRow].size()
283 && mEditable)
284 {
285 mTextRows[mCaretRow].erase(mCaretColumn, 1);
286 }
287
288 else if (key.getValue() == Key::DELETE
289 && mCaretColumn == (int)mTextRows[mCaretRow].size()
290 && mCaretRow < ((int)mTextRows.size() - 1)
291 && mEditable)
292 {
293 mTextRows[mCaretRow] += mTextRows[mCaretRow + 1];
294 mTextRows.erase(mTextRows.begin() + mCaretRow + 1);
295 }
296
297 else if(key.getValue() == Key::PAGE_UP)
298 {
299 Widget* par = getParent();
300
301 if (par != NULL)
302 {
303 int rowsPerPage = par->getChildrenArea().height / getFont()->getHeight();
304 mCaretRow -= rowsPerPage;
305
306 if (mCaretRow < 0)
307 {
308 mCaretRow = 0;
309 }
310 }
311 }
312
313 else if(key.getValue() == Key::PAGE_DOWN)
314 {
315 Widget* par = getParent();
316
317 if (par != NULL)
318 {
319 int rowsPerPage = par->getChildrenArea().height / getFont()->getHeight();
320 mCaretRow += rowsPerPage;
321
322 if (mCaretRow >= (int)mTextRows.size())
323 {
324 mCaretRow = mTextRows.size() - 1;
325 }
326 }
327 }
328
329 else if(key.getValue() == Key::TAB
330 && mEditable)
331 {
332 mTextRows[mCaretRow].insert(mCaretColumn,std::string(" "));
333 mCaretColumn += 4;
334 }
335
336 else if (key.isCharacter()
337 && mEditable)
338 {
339 mTextRows[mCaretRow].insert(mCaretColumn,std::string(1,(char)key.getValue()));
340 ++mCaretColumn;
341 }
342
343 adjustSize();
344 scrollToCaret();
345
346 keyEvent.consume();
347 }
348
349 void TextBox::adjustSize()
350 {
351 unsigned int i;
352 int width = 0;
353 for (i = 0; i < mTextRows.size(); ++i)
354 {
355 int w = getFont()->getWidth(mTextRows[i]);
356 if (width < w)
357 {
358 width = w;
359 }
360 }
361
362 setWidth(width + 1);
363 setHeight(getFont()->getHeight() * mTextRows.size());
364 }
365
366 void TextBox::setCaretPosition(unsigned int position)
367 {
368 int row;
369
370 for (row = 0; row < (int)mTextRows.size(); row++)
371 {
372 if (position <= mTextRows[row].size())
373 {
374 mCaretRow = row;
375 mCaretColumn = position;
376 return; // we are done
377 }
378 else
379 {
380 position--;
381 }
382 }
383
384 // position beyond end of text
385 mCaretRow = mTextRows.size() - 1;
386 mCaretColumn = mTextRows[mCaretRow].size();
387 }
388
389 unsigned int TextBox::getCaretPosition() const
390 {
391 int pos = 0, row;
392
393 for (row = 0; row < mCaretRow; row++)
394 {
395 pos += mTextRows[row].size();
396 }
397
398 return pos + mCaretColumn;
399 }
400
401 void TextBox::setCaretRowColumn(int row, int column)
402 {
403 setCaretRow(row);
404 setCaretColumn(column);
405 }
406
407 void TextBox::setCaretRow(int row)
408 {
409 mCaretRow = row;
410
411 if (mCaretRow >= (int)mTextRows.size())
412 {
413 mCaretRow = mTextRows.size() - 1;
414 }
415
416 if (mCaretRow < 0)
417 {
418 mCaretRow = 0;
419 }
420
421 setCaretColumn(mCaretColumn);
422 }
423
424 unsigned int TextBox::getCaretRow() const
425 {
426 return mCaretRow;
427 }
428
429 void TextBox::setCaretColumn(int column)
430 {
431 mCaretColumn = column;
432
433 if (mCaretColumn > (int)mTextRows[mCaretRow].size())
434 {
435 mCaretColumn = mTextRows[mCaretRow].size();
436 }
437
438 if (mCaretColumn < 0)
439 {
440 mCaretColumn = 0;
441 }
442 }
443
444 unsigned int TextBox::getCaretColumn() const
445 {
446 return mCaretColumn;
447 }
448
449 const std::string& TextBox::getTextRow(int row) const
450 {
451 return mTextRows[row];
452 }
453
454 void TextBox::setTextRow(int row, const std::string& text)
455 {
456 mTextRows[row] = text;
457
458 if (mCaretRow == row)
459 {
460 setCaretColumn(mCaretColumn);
461 }
462
463 adjustSize();
464 }
465
466 unsigned int TextBox::getNumberOfRows() const
467 {
468 return mTextRows.size();
469 }
470
471 std::string TextBox::getText() const
472 {
473 if (mTextRows.size() == 0)
474 {
475 return std::string("");
476 }
477
478 int i;
479 std::string text;
480
481 for (i = 0; i < (int)mTextRows.size() - 1; ++i)
482 {
483 text = text + mTextRows[i] + "\n";
484 }
485
486 text = text + mTextRows[i];
487
488 return text;
489 }
490
491 void TextBox::fontChanged()
492 {
493 adjustSize();
494 }
495
496 void TextBox::scrollToCaret()
497 {
498 Rectangle scroll;
499 scroll.x = getFont()->getWidth(mTextRows[mCaretRow].substr(0, mCaretColumn));
500 scroll.y = getFont()->getHeight() * mCaretRow;
501 scroll.width = getFont()->getWidth(" ");
502 scroll.height = getFont()->getHeight() + 2; // add 2 for some extra space
503
504 showPart(scroll);
505 }
506
507 void TextBox::setEditable(bool editable)
508 {
509 mEditable = editable;
510 }
511
512 bool TextBox::isEditable() const
513 {
514 return mEditable;
515 }
516
517 void TextBox::addRow(const std::string row)
518 {
519 mTextRows.push_back(row);
520 adjustSize();
521 }
522
523 bool TextBox::isOpaque()
524 {
525 return mOpaque;
526 }
527
528 void TextBox::setOpaque(bool opaque)
529 {
530 mOpaque = opaque;
531 }
532 }