0x9c
[scummvm-innocent.git] / gui / editable.cpp
blob232873ffe3d66b8741b8fd168d16220d3920a342
1 /* ScummVM - Graphic Adventure Engine
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * $URL$
22 * $Id$
25 #include "common/events.h"
26 #include "gui/editable.h"
27 #include "gui/GuiManager.h"
29 namespace GUI {
31 EditableWidget::EditableWidget(GuiObject *boss, int x, int y, int w, int h, uint32 cmd)
32 : Widget(boss, x, y, w, h), CommandSender(boss), _cmd(cmd) {
33 init();
36 EditableWidget::EditableWidget(GuiObject *boss, const String &name, uint32 cmd)
37 : Widget(boss, name), CommandSender(boss), _cmd(cmd) {
38 init();
41 void EditableWidget::init() {
42 _caretVisible = false;
43 _caretTime = 0;
44 _caretPos = 0;
46 _caretInverse = false;
48 _editScrollOffset = 0;
50 _font = ThemeEngine::kFontStyleBold;
53 EditableWidget::~EditableWidget() {
56 void EditableWidget::reflowLayout() {
57 Widget::reflowLayout();
59 _editScrollOffset = g_gui.getStringWidth(_editString, _font) - getEditRect().width();
60 if (_editScrollOffset < 0)
61 _editScrollOffset = 0;
64 void EditableWidget::setEditString(const String &str) {
65 // TODO: We probably should filter the input string here,
66 // e.g. using tryInsertChar.
67 _editString = str;
68 _caretPos = _editString.size();
71 bool EditableWidget::tryInsertChar(byte c, int pos) {
72 if ((c >= 32 && c <= 127) || c >= 160) {
73 _editString.insertChar(c, pos);
74 return true;
76 return false;
79 void EditableWidget::handleTickle() {
80 uint32 time = getMillis();
81 if (_caretTime < time) {
82 _caretTime = time + kCaretBlinkTime;
83 drawCaret(_caretVisible);
87 bool EditableWidget::handleKeyDown(Common::KeyState state) {
88 bool handled = true;
89 bool dirty = false;
90 bool forcecaret = false;
92 // First remove caret
93 if (_caretVisible)
94 drawCaret(true);
96 switch (state.keycode) {
97 case Common::KEYCODE_RETURN:
98 case Common::KEYCODE_KP_ENTER:
99 // confirm edit and exit editmode
100 endEditMode();
101 dirty = true;
102 break;
103 case Common::KEYCODE_ESCAPE:
104 abortEditMode();
105 dirty = true;
106 break;
107 case Common::KEYCODE_BACKSPACE:
108 if (_caretPos > 0) {
109 _caretPos--;
110 _editString.deleteChar(_caretPos);
111 dirty = true;
113 sendCommand(_cmd, 0);
115 forcecaret = true;
116 break;
117 case Common::KEYCODE_DELETE:
118 if (_caretPos < (int)_editString.size()) {
119 _editString.deleteChar(_caretPos);
120 dirty = true;
122 sendCommand(_cmd, 0);
124 forcecaret = true;
125 break;
126 case Common::KEYCODE_LEFT:
127 if (_caretPos > 0) {
128 dirty = setCaretPos(_caretPos - 1);
130 forcecaret = true;
131 dirty = true;
132 break;
133 case Common::KEYCODE_RIGHT:
134 if (_caretPos < (int)_editString.size()) {
135 dirty = setCaretPos(_caretPos + 1);
137 forcecaret = true;
138 dirty = true;
139 break;
140 case Common::KEYCODE_HOME:
141 dirty = setCaretPos(0);
142 forcecaret = true;
143 break;
144 case Common::KEYCODE_END:
145 dirty = setCaretPos(_editString.size());
146 forcecaret = true;
147 break;
148 default:
149 if (tryInsertChar((byte)state.ascii, _caretPos)) {
150 _caretPos++;
151 dirty = true;
152 forcecaret = true;
154 sendCommand(_cmd, 0);
155 } else {
156 handled = false;
160 if (dirty)
161 draw();
163 if (forcecaret)
164 makeCaretVisible();
166 return handled;
169 int EditableWidget::getCaretOffset() const {
170 int caretpos = 0;
171 for (int i = 0; i < _caretPos; i++)
172 caretpos += g_gui.getCharWidth(_editString[i], _font);
174 caretpos -= _editScrollOffset;
176 return caretpos;
179 void EditableWidget::drawCaret(bool erase) {
180 // Only draw if item is visible
181 if (!isVisible() || !_boss->isVisible())
182 return;
184 Common::Rect editRect = getEditRect();
186 int x = editRect.left;
187 int y = editRect.top + 1;
189 x += getCaretOffset();
191 if (y < 0 || y + editRect.height() - 2 >= _h)
192 return;
194 x += getAbsX();
195 y += getAbsY();
197 g_gui.theme()->drawCaret(Common::Rect(x, y, x + 1, y + editRect.height() - 2), erase);
199 _caretVisible = !erase;
202 bool EditableWidget::setCaretPos(int newPos) {
203 assert(newPos >= 0 && newPos <= (int)_editString.size());
204 _caretPos = newPos;
205 return adjustOffset();
208 bool EditableWidget::adjustOffset() {
209 // check if the caret is still within the textbox; if it isn't,
210 // adjust _editScrollOffset
212 int caretpos = getCaretOffset();
213 const int editWidth = getEditRect().width();
215 if (caretpos < 0) {
216 // scroll left
217 _editScrollOffset += caretpos;
218 return true;
219 } else if (caretpos >= editWidth) {
220 // scroll right
221 _editScrollOffset -= (editWidth - caretpos);
222 return true;
223 } else if (_editScrollOffset > 0) {
224 const int strWidth = g_gui.getStringWidth(_editString, _font);
225 if (strWidth - _editScrollOffset < editWidth) {
226 // scroll right
227 _editScrollOffset = (strWidth - editWidth);
228 if (_editScrollOffset < 0)
229 _editScrollOffset = 0;
233 return false;
236 void EditableWidget::makeCaretVisible() {
237 _caretTime = getMillis() + kCaretBlinkTime;
238 _caretVisible = true;
239 drawCaret(false);
242 } // End of namespace GUI