comparison ext/guichan-0.8.1/src/widgets/textfield.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/textfield.hpp"
49
50 #include "guichan/font.hpp"
51 #include "guichan/graphics.hpp"
52 #include "guichan/key.hpp"
53 #include "guichan/mouseinput.hpp"
54
55 namespace gcn
56 {
57 TextField::TextField()
58 {
59 mCaretPosition = 0;
60 mXScroll = 0;
61
62 setFocusable(true);
63
64 addMouseListener(this);
65 addKeyListener(this);
66 }
67
68 TextField::TextField(const std::string& text)
69 {
70 mCaretPosition = 0;
71 mXScroll = 0;
72
73 mText = text;
74 adjustSize();
75
76 setFocusable(true);
77
78 addMouseListener(this);
79 addKeyListener(this);
80 }
81
82 void TextField::setText(const std::string& text)
83 {
84 if(text.size() < mCaretPosition )
85 {
86 mCaretPosition = text.size();
87 }
88
89 mText = text;
90 }
91
92 void TextField::draw(Graphics* graphics)
93 {
94 Color faceColor = getBaseColor();
95 Color highlightColor, shadowColor;
96 int alpha = getBaseColor().a;
97 highlightColor = faceColor + 0x303030;
98 highlightColor.a = alpha;
99 shadowColor = faceColor - 0x303030;
100 shadowColor.a = alpha;
101
102 // Draw a border.
103 graphics->setColor(shadowColor);
104 graphics->drawLine(0, 0, getWidth() - 1, 0);
105 graphics->drawLine(0, 1, 0, getHeight() - 2);
106 graphics->setColor(highlightColor);
107 graphics->drawLine(getWidth() - 1, 1, getWidth() - 1, getHeight() - 1);
108 graphics->drawLine(0, getHeight() - 1, getWidth() - 1, getHeight() - 1);
109
110 // Push a clip area so the other drawings don't need to worry
111 // about the border.
112 graphics->pushClipArea(Rectangle(1, 1, getWidth() - 2, getHeight() - 2));
113
114 graphics->setColor(getBackgroundColor());
115 graphics->fillRectangle(Rectangle(0, 0, getWidth(), getHeight()));
116
117 if (isFocused())
118 {
119 drawCaret(graphics, getFont()->getWidth(mText.substr(0, mCaretPosition)) - mXScroll);
120 }
121
122 graphics->setColor(getForegroundColor());
123 graphics->setFont(getFont());
124 graphics->drawText(mText, 1 - mXScroll, 1);
125
126 graphics->popClipArea();
127 }
128
129 void TextField::drawCaret(Graphics* graphics, int x)
130 {
131 // Check the current clip area as a clip area with a different
132 // size than the widget might have been pushed (which is the
133 // case in the draw method when we push a clip area after we have
134 // drawn a border).
135 const Rectangle clipArea = graphics->getCurrentClipArea();
136
137 graphics->setColor(getForegroundColor());
138 graphics->drawLine(x, clipArea.height - 2, x, 1);
139 }
140
141 void TextField::mousePressed(MouseEvent& mouseEvent)
142 {
143 if (mouseEvent.getButton() == MouseEvent::LEFT)
144 {
145 mCaretPosition = getFont()->getStringIndexAt(mText, mouseEvent.getX() + mXScroll);
146 fixScroll();
147 }
148 }
149
150 void TextField::mouseDragged(MouseEvent& mouseEvent)
151 {
152 mouseEvent.consume();
153 }
154
155 void TextField::keyPressed(KeyEvent& keyEvent)
156 {
157 Key key = keyEvent.getKey();
158
159 if (key.getValue() == Key::LEFT && mCaretPosition > 0)
160 {
161 --mCaretPosition;
162 }
163
164 else if (key.getValue() == Key::RIGHT && mCaretPosition < mText.size())
165 {
166 ++mCaretPosition;
167 }
168
169 else if (key.getValue() == Key::DELETE && mCaretPosition < mText.size())
170 {
171 mText.erase(mCaretPosition, 1);
172 }
173
174 else if (key.getValue() == Key::BACKSPACE && mCaretPosition > 0)
175 {
176 mText.erase(mCaretPosition - 1, 1);
177 --mCaretPosition;
178 }
179
180 else if (key.getValue() == Key::ENTER)
181 {
182 distributeActionEvent();
183 }
184
185 else if (key.getValue() == Key::HOME)
186 {
187 mCaretPosition = 0;
188 }
189
190 else if (key.getValue() == Key::END)
191 {
192 mCaretPosition = mText.size();
193 }
194
195 else if (key.isCharacter()
196 && key.getValue() != Key::TAB)
197 {
198 mText.insert(mCaretPosition, std::string(1,(char)key.getValue()));
199 ++mCaretPosition;
200 }
201
202 if (key.getValue() != Key::TAB)
203 {
204 keyEvent.consume();
205 }
206
207 fixScroll();
208 }
209
210 void TextField::adjustSize()
211 {
212 setWidth(getFont()->getWidth(mText) + 6);
213 adjustHeight();
214
215 fixScroll();
216 }
217
218 void TextField::adjustHeight()
219 {
220 setHeight(getFont()->getHeight() + 4);
221 }
222
223 void TextField::fixScroll()
224 {
225 if (isFocused())
226 {
227 int caretX = getFont()->getWidth(mText.substr(0, mCaretPosition));
228
229 if (caretX - mXScroll >= getWidth() - 4)
230 {
231 mXScroll = caretX - getWidth() + 4;
232 }
233 else if (caretX - mXScroll <= 0)
234 {
235 mXScroll = caretX - getWidth() / 2;
236
237 if (mXScroll < 0)
238 {
239 mXScroll = 0;
240 }
241 }
242 }
243 }
244
245 void TextField::setCaretPosition(unsigned int position)
246 {
247 if (position > mText.size())
248 {
249 mCaretPosition = mText.size();
250 }
251 else
252 {
253 mCaretPosition = position;
254 }
255
256 fixScroll();
257 }
258
259 unsigned int TextField::getCaretPosition() const
260 {
261 return mCaretPosition;
262 }
263
264 const std::string& TextField::getText() const
265 {
266 return mText;
267 }
268
269 void TextField::fontChanged()
270 {
271 fixScroll();
272 }
273 }