Mana
Loading...
Searching...
No Matches
textfield.cpp
Go to the documentation of this file.
1/*
2 * The Mana Client
3 * Copyright (C) 2004-2009 The Mana World Development Team
4 * Copyright (C) 2009-2012 The Mana Developers
5 *
6 * This file is part of The Mana Client.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
23
24#include "graphics.h"
25
26#include "gui/gui.h"
27#include "gui/sdlinput.h"
28
29#include "resources/theme.h"
30
31#include "utils/copynpaste.h"
32#include "utils/stringutils.h"
33
34#include <guichan/font.hpp>
35
36#include <SDL.h>
37
38TextField::TextField(const std::string &text, bool loseFocusOnTab)
39 : gcn::TextField(text)
40 , mLoseFocusOnTab(loseFocusOnTab)
41{
42 auto &skin = gui->getTheme()->getSkin(SkinType::TextField);
43 setFrameSize(skin.frameSize);
44 mPadding = skin.padding;
45
46 setWidth(getFont()->getWidth(mText) + 2 * mPadding);
47 setHeight(getFont()->getHeight() + 2 * mPadding);
48 fixScroll();
49}
50
51void TextField::draw(gcn::Graphics *graphics)
52{
53 if (getFrameSize() == 0)
55
56 auto g = static_cast<Graphics *>(graphics);
57 g->pushClipRect(gcn::Rectangle(0, 0, getWidth(), getHeight()));
58
59 if (isFocused())
60 {
62 getFont()->getWidth(mText.substr(0, mCaretPosition)) - mXScroll);
63 }
64
66 graphics->setFont(getFont());
67 graphics->drawText(mText, mPadding - mXScroll, mPadding);
68
69 g->popClipRect();
70}
71
72void TextField::drawFrame(gcn::Graphics *graphics)
73{
74 const int bs = getFrameSize();
75
76 WidgetState state(this);
77 state.width += bs * 2;
78 state.height += bs * 2;
79
80 gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::TextField, state);
81}
82
83void TextField::setNumeric(bool numeric)
84{
85 mNumeric = numeric;
86 if (!numeric)
87 return;
88
89 const char *text = mText.c_str();
90 for (const char *textPtr = text; *textPtr; ++textPtr)
91 {
92 if (*textPtr < '0' || *textPtr > '9')
93 {
94 setText(mText.substr(0, textPtr - text));
95 return;
96 }
97 }
98}
99
101{
102 if (!mNumeric)
103 return 0;
104
105 int value = atoi(mText.c_str());
106 if (value < mMinimum)
107 return mMinimum;
108
109 if (value > mMaximum)
110 return mMaximum;
111
112 return value;
113}
114
115void TextField::drawCaret(gcn::Graphics *graphics, int x)
116{
118 graphics->drawLine(mPadding + x, mPadding, mPadding + x, getHeight() - mPadding);
119}
120
121void TextField::keyPressed(gcn::KeyEvent &keyEvent)
122{
123 switch (keyEvent.getKey().getValue())
124 {
125 case Key::LEFT:
126 {
127 while (mCaretPosition > 0)
128 {
129 --mCaretPosition;
130 if ((mText[mCaretPosition] & 192) != 128)
131 break;
132 }
133 } break;
134
135 case Key::RIGHT:
136 {
137 unsigned sz = mText.size();
138 while (mCaretPosition < sz)
139 {
140 ++mCaretPosition;
141 if (mCaretPosition == sz ||
142 (mText[mCaretPosition] & 192) != 128)
143 break;
144 }
145 } break;
146
147 case Key::UP:
148 {
149 if (mHistory && !mHistory->atBegining() && !mHistory->empty())
150 {
151 // Move backward through the history
152 mHistory->current--;
153 setText(*mHistory->current);
154 setCaretPosition(getText().length());
155 }
156 } break;
157
158 case Key::DOWN:
159 {
160 if (mHistory && !mHistory->atEnd())
161 {
162 // Move forward through the history
163 auto prevHist = mHistory->current++;
164
165 if (!mHistory->atEnd())
166 {
167 setText(*mHistory->current);
168 setCaretPosition(getText().length());
169 }
170 else
171 {
172 setText(std::string());
173 mHistory->current = prevHist;
174 }
175 }
176 else if (!getText().empty())
177 {
178 // Always clear (easy access to useful function)
179 setText(std::string());
180 }
181 } break;
182
183 case Key::DELETE_KEY:
184 {
185 unsigned sz = mText.size();
186 while (mCaretPosition < sz)
187 {
188 --sz;
189 mText.erase(mCaretPosition, 1);
190 if (mCaretPosition == sz ||
191 (mText[mCaretPosition] & 192) != 128)
192 break;
193 }
194 } break;
195
196 case Key::BACKSPACE:
197 {
198 while (mCaretPosition > 0)
199 {
200 --mCaretPosition;
201 int v = mText[mCaretPosition];
202 mText.erase(mCaretPosition, 1);
203 if ((v & 192) != 128) break;
204 }
205 } break;
206
207 case Key::ENTER:
208 if (mHistory)
209 {
210 // If the input is different from previous, put it in the history
211 if (!getText().empty() && (mHistory->empty() ||
212 !mHistory->matchesLastEntry(getText())))
213 {
214 mHistory->addEntry(getText());
215 }
216
217 mHistory->toEnd();
218 }
219
220 distributeActionEvent();
221 break;
222
223 case Key::HOME:
224 mCaretPosition = 0;
225 break;
226
227 case Key::END:
228 mCaretPosition = mText.size();
229 break;
230
231 case Key::TAB:
232 autoComplete();
233 if (mLoseFocusOnTab)
234 return;
235 break;
236
237 case SDLK_v:
238 if (keyEvent.isControlPressed())
239 handlePaste();
240 break;
241 }
242
243 keyEvent.consume();
244 fixScroll();
245}
246
247void TextField::textInput(const TextInput &textInput)
248{
249 mText.insert(mCaretPosition, textInput.getText());
250 mCaretPosition += textInput.getText().length();
251}
252
254{
255 if (mAutoComplete && !mText.empty())
256 {
257 const int caretPos = getCaretPosition();
258 int startName = 0;
259 const std::string inputText = getText();
260 std::string name = inputText.substr(0, caretPos);
261 std::string newName;
262
263 for (int f = caretPos - 1; f > -1; f--)
264 {
265 if (isWordSeparator(inputText[f]))
266 {
267 startName = f + 1;
268 name = inputText.substr(f + 1, caretPos - startName);
269 break;
270 }
271 }
272
273 if (caretPos == startName)
274 return;
275
276
277 std::vector<std::string> nameList;
279 newName = autocomplete(nameList, name);
280
281 if (newName.empty() && mHistory)
282 {
283
284 auto i = mHistory->history.begin();
285 std::vector<std::string> nameList;
286
287 while (i != mHistory->history.end())
288 {
289 std::string line = *i;
290 unsigned int f = 0;
291 while (f < line.length() && !isWordSeparator(line.at(f)))
292 {
293 f++;
294 }
295 line = line.substr(0, f);
296 if (!line.empty())
297 {
298 nameList.push_back(line);
299 }
300 ++i;
301 }
302
303 newName = autocomplete(nameList, name);
304 }
305
306 if (!newName.empty())
307 {
308 if(inputText[0] == '@' || inputText[0] == '/')
309 newName = "\"" + newName + "\"";
310
311 setText(inputText.substr(0, startName) + newName
312 + inputText.substr(caretPos, inputText.length()
313 - caretPos));
314
315 setCaretPosition(caretPos - name.length() + newName.length());
316 }
317 }
318}
319
321{
322 std::string text = getText();
323 std::string::size_type caretPos = getCaretPosition();
324
325 if (insertFromClipboard(text, caretPos)) {
326 setText(text);
327 setCaretPosition(caretPos);
328 }
329}
virtual void getAutoCompleteList(std::vector< std::string > &) const
Definition textfield.h:63
A central point of control for graphics.
Definition graphics.h:78
void drawText(const std::string &text, int x, int y, gcn::Graphics::Alignment alignment, const gcn::Color &color, gcn::Font *font, bool outline=false, bool shadow=false, const std::optional< gcn::Color > &outlineColor={}, const std::optional< gcn::Color > &shadowColor={})
Definition graphics.cpp:176
void setColor(const gcn::Color &color) override
Definition graphics.h:255
void pushClipRect(const gcn::Rectangle &rect)
Definition graphics.cpp:252
Theme * getTheme() const
The global GUI theme.
Definition gui.h:138
A text field.
Definition textfield.h:72
int mMinimum
Definition textfield.h:162
void textInput(const TextInput &textInput)
Handle text input (should possibly be new event in Guichan).
int mPadding
Definition textfield.h:165
void keyPressed(gcn::KeyEvent &keyEvent) override
Processes one keypress.
bool mNumeric
Definition textfield.h:161
TextHistory * mHistory
Text history.
Definition textfield.h:169
void drawFrame(gcn::Graphics *graphics) override
Draws the background and border.
Definition textfield.cpp:72
void handlePaste()
void autoComplete()
int getValue() const
Return the value for a numeric field.
void drawCaret(gcn::Graphics *graphics, int x) override
void draw(gcn::Graphics *graphics) override
Draws the text field.
Definition textfield.cpp:51
AutoCompleteLister * mAutoComplete
Definition textfield.h:167
bool mLoseFocusOnTab
Definition textfield.h:164
TextField(const std::string &text=std::string(), bool loseFocusOnTab=true)
Constructor, initializes the text field with the given string.
Definition textfield.cpp:38
int mMaximum
Definition textfield.h:163
void setNumeric(bool numeric)
Determine whether the field should be numeric or not.
Definition textfield.cpp:83
const Skin & getSkin(SkinType skinType) const
Definition theme.cpp:434
static const gcn::Color & getThemeColor(int type)
Gets the color associated with the type in the default palette (0).
Definition theme.cpp:313
@ CARET
Definition theme.h:225
@ TEXT
Definition theme.h:214
void drawSkin(Graphics *graphics, SkinType type, const WidgetState &state) const
Definition theme.cpp:373
Graphics * graphics
Definition client.cpp:104
bool insertFromClipboard(std::string &text, std::string::size_type &pos)
Attempts to retrieve text from the clipboard buffer and inserts it in text at position \pos.
Gui * gui
The GUI system.
Definition gui.cpp:50
@ ENTER
Definition sdlinput.h:78
@ TAB
Definition sdlinput.h:77
@ LEFT
Definition sdlinput.h:119
@ HOME
Definition sdlinput.h:91
@ RIGHT
Definition sdlinput.h:120
@ UP
Definition sdlinput.h:121
@ BACKSPACE
Definition sdlinput.h:98
@ DOWN
Definition sdlinput.h:122
@ END
Definition sdlinput.h:94
@ DELETE_KEY
Definition sdlinput.h:93
bool isWordSeparator(char chr)
Tells wether the character is a word separator.
std::string autocomplete(const std::vector< std::string > &candidates, std::string base)
Returns the most approaching string of base from candidates.
bool atBegining() const
Definition textfield.h:41
bool atEnd() const
Definition textfield.h:44
void toEnd()
Definition textfield.h:50
bool matchesLastEntry(const std::string &text)
Definition textfield.h:56
std::list< std::string > history
Command history.
Definition textfield.h:32
bool empty() const
Definition textfield.h:38
std::list< std::string >::iterator current
History iterator.
Definition textfield.h:33
void addEntry(const std::string &text)
Definition textfield.h:53
int width
Definition theme.h:148
int height
Definition theme.h:149