FifeGUI 0.2.0
A C++ GUI library designed for games.
textbox.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later OR BSD-3-Clause
2// SPDX-FileCopyrightText: 2004 - 2008 Olof Naessén and Per Larsson
3// SPDX-FileCopyrightText: 2013 - 2026 Fifengine contributors
4
5#include <fifechan/widgets/textbox.hpp>
6
7#include <fifechan/font.hpp>
8#include <fifechan/graphics.hpp>
9#include <fifechan/key.hpp>
10#include <fifechan/mouseinput.hpp>
11#include <fifechan/text.hpp>
12#include <fifechan/utf8stringeditor.hpp>
13#include <fifechan/util/utf8/utf8.hpp>
14
15#include <cassert>
16#include <string>
17
18namespace fcn
19{
20 TextBox::TextBox(std::string const & text) : mText(new Text(text)), mStringEditor(new UTF8StringEditor)
21 {
22 setFocusable(true);
23
24 addMouseListener(this);
25 addKeyListener(this);
27 }
28
29 TextBox::~TextBox()
30 {
31 delete mText;
32 delete mStringEditor;
33 }
34
35 void TextBox::setText(std::string const & text)
36 {
37 mText->setContent(text);
39 }
40
41 void TextBox::draw(Graphics* graphics)
42 {
43 if (mOpaque) {
44 graphics->setColor(getBackgroundColor());
45 graphics->fillRectangle(0, 0, getWidth(), getHeight());
46 }
47
48 if (isFocused() && isEditable()) {
49 drawCaret(graphics, mText->getCaretX(getFont()), mText->getCaretY(getFont()));
50 }
51
52 graphics->setColor(getForegroundColor());
53 graphics->setFont(getFont());
54
55 unsigned int i = 0;
56 for (i = 0; i < mText->getNumberOfRows(); i++) {
57 // Move the text one pixel so we can have a caret before a letter.
58 graphics->drawText(mText->getRow(i), 1, i * getFont()->getHeight());
59 }
60 }
61
62 void TextBox::drawCaret(Graphics* graphics, int x, int y)
63 {
64 graphics->setColor(getForegroundColor());
65 graphics->drawLine(x, y, x, y + getFont()->getHeight());
66 }
67
69 {
70 if (mouseEvent.getButton() == MouseEvent::Button::Left) {
71 mText->setCaretPosition(mouseEvent.getX(), mouseEvent.getY(), getFont());
72 mouseEvent.consume();
73 }
74 }
75
77 {
78 mouseEvent.consume();
79 }
80
82 {
83 Key const key = keyEvent.getKey();
84
85 if (key.getValue() == Key::Left) {
86 if (getCaretColumn() == 0) {
87 if (getCaretRow() > 0) {
90 }
91 } else {
93 }
94 } else if (key.getValue() == Key::Right) {
95 if (getCaretColumn() < getTextRow(getCaretRow()).size()) {
97 } else {
98 if (getCaretRow() < getNumberOfRows() - 1) {
101 }
102 }
103 } else if (key.getValue() == Key::Down) {
105 } else if (key.getValue() == Key::Up) {
107 } else if (key.getValue() == Key::Home) {
109 } else if (key.getValue() == Key::End) {
111 } else if (key.getValue() == Key::Enter && mEditable) {
112 mText->insertRow(
114 getCaretRow() + 1);
115
116 mText->getRow(getCaretRow()).resize(getCaretColumn());
119 } else if (key.getValue() == Key::Backspace && getCaretColumn() != 0 && mEditable) {
120 std::string& currRow = mText->getRow(getCaretRow());
123 } else if (key.getValue() == Key::Backspace && getCaretColumn() == 0 && getCaretRow() != 0 && mEditable) {
124 /*setCaretColumn(mText->getRow(getCaretRow() - 1).size());
125 mText->getRow(getCaretRow() - 1) += getTextRow(getCaretRow());
126 mText->eraseRow(getCaretRow());
127 setCaretRow(getCaretRow() - 1);*/
128 unsigned const newCaretColumn = getTextRow(getCaretRow() - 1).size();
129 // setCaretColumn(getTextRow(getCaretRow() - 1).size());
130 mText->getRow(getCaretRow() - 1) += getTextRow(getCaretRow());
131 mText->eraseRow(getCaretRow());
133 setCaretColumn(newCaretColumn);
134 } else if (
135 key.getValue() == Key::Delete && getCaretColumn() < static_cast<int>(getTextRow(getCaretRow()).size()) &&
136 mEditable) {
138 } else if (
139 key.getValue() == Key::Delete && getCaretColumn() == static_cast<int>(getTextRow(getCaretRow()).size()) &&
140 getCaretRow() < (static_cast<int>(getNumberOfRows()) - 1) && mEditable) {
141 mText->getRow(getCaretRow()) += getTextRow((getCaretRow() + 1));
142 mText->eraseRow(getCaretRow() + 1);
143 } else if (key.getValue() == Key::PageUp) {
144 Widget* par = getParent();
145
146 if (par != nullptr) {
147 int const rowsPerPage = par->getChildrenArea().height / getFont()->getHeight();
149 int const newCaretRow = getCaretRow() - rowsPerPage;
150 if (newCaretRow >= 0) {
151 setCaretRow(newCaretRow);
152 } else {
153 setCaretRow(0);
154 }
156 }
157 } else if (key.getValue() == Key::PageDown) {
158 Widget* par = getParent();
159
160 if (par != nullptr) {
161 int const rowsPerPage = par->getChildrenArea().height / getFont()->getHeight();
163 setCaretRow(getCaretRow() + rowsPerPage);
164
165 if (getCaretRow() >= static_cast<int>(getNumberOfRows())) {
167 }
168
170 }
171 } else if (key.getValue() == Key::Tab && mEditable) {
172 // FIXME: jump X spaces, so getCaretColumn() % TAB_SIZE = 0 and X <= TAB_SIZE
173 mText->getRow(getCaretRow()).insert(getCaretColumn(), std::string(" "));
175 } else if ((key.isCharacter() || key.getValue() > 255) && mEditable) {
178 }
179
182 assert(
183 utf8::is_valid(getTextRow(getCaretRow()).begin(), getTextRow(getCaretRow()).end()) ==
184 utf8::internal::UTF8_OK);
185 assert(
186 utf8::is_valid(getTextRow(getCaretRow()).begin(), getTextRow(getCaretRow()).begin() + getCaretColumn()) ==
187 utf8::internal::UTF8_OK);
188 keyEvent.consume();
189 }
190
191 void TextBox::resizeToContent(bool recursion)
192 {
193 static_cast<void>(recursion);
195 }
196
198 {
200 }
201
203 {
204 Rectangle const & dim = mText->getDimension(getFont());
205 setSize(dim.width, dim.height);
206 }
207
208 void TextBox::setCaretPosition(unsigned int position)
209 {
210 mText->setCaretPosition(position);
211 }
212
213 unsigned int TextBox::getCaretPosition() const
214 {
215 return mText->getCaretPosition();
216 }
217
218 void TextBox::setCaretRowColumn(int row, int column)
219 {
220 mText->setCaretRow(row);
221 mText->setCaretColumn(column);
222 }
223
225 {
226 mText->setCaretRow(row);
227 }
228
229 unsigned int TextBox::getCaretRow() const
230 {
231 return mText->getCaretRow();
232 }
233
234 void TextBox::setCaretColumn(int column)
235 {
236 mText->setCaretColumn(column);
237 }
238
239 unsigned int TextBox::getCaretColumn() const
240 {
241 return mText->getCaretColumn();
242 }
243
244 std::string TextBox::getTextRow(int row) const
245 {
246 return mText->getRow(row);
247 }
248
249 void TextBox::setTextRow(int row, std::string const & text)
250 {
251 mText->setRow(row, text);
253 }
254
255 unsigned int TextBox::getNumberOfRows() const
256 {
257 return mText->getNumberOfRows();
258 }
259
260 std::string TextBox::getText() const
261 {
262 return mText->getContent();
263 }
264
266 {
268 }
269
271 {
272 showPart(mText->getCaretDimension(getFont()));
273 }
274
275 void TextBox::setEditable(bool editable)
276 {
277 mEditable = editable;
278 }
279
281 {
282 return mEditable;
283 }
284
285 void TextBox::addRow(std::string const & row)
286 {
287 mText->addRow(row);
289 }
290
291 bool TextBox::isOpaque() const
292 {
293 return mOpaque;
294 }
295
296 void TextBox::setOpaque(bool opaque)
297 {
298 mOpaque = opaque;
299 }
300
302 {
303 // no need to clip the column, mStringEditor handles it automatically
305 }
306
308 {
310 if (row < 0) {
311 row = 0;
312 } else if (row >= getNumberOfRows()) {
313 row = getNumberOfRows() - 1;
314 }
315 setCaretRow(row);
317 }
318
319 void TextBox::setCaretRowColumnUTF8(int row, int column)
320 {
321 setCaretRowUTF8(row);
322 setCaretColumnUTF8(column);
323 }
324} // namespace fcn
virtual int getHeight() const =0
Gets the height of the glyphs in the font.
Abstract interface providing primitive drawing functions (lines, rectangles, etc.).
Definition graphics.hpp:57
void drawText(std::string const &text, int x, int y)
Draws text with a default left alignment.
Definition graphics.hpp:362
virtual void setFont(Font *font)
Sets the font to use when drawing text.
Definition graphics.cpp:79
virtual void drawLine(int x1, int y1, int x2, int y2)=0
Draws a line.
virtual void setColor(Color const &color)=0
Sets the color to use when drawing.
virtual void fillRectangle(Rectangle const &rectangle)=0
Draws a filled rectangle.
void consume()
Marks the event as consumed.
Represents a key event.
Definition keyevent.hpp:22
Key const & getKey() const
Gets the key of the event.
Definition keyevent.cpp:39
Represents a keyboard key or character code.
Definition key.hpp:20
int getValue() const
Gets the value of the key.
Definition key.cpp:28
bool isCharacter() const
Checks if a key is a character.
Definition key.cpp:11
Represents a mouse event.
int getX() const
Gets the x coordinate of the mouse event.
int getY() const
Gets the y coordinate of the mouse event.
MouseEvent::Button getButton() const
Gets the button of the mouse event.
Represents a rectangular area (X, Y, Width, Height).
Definition rectangle.hpp:20
int width
Holds the width of the rectangle.
int height
Holds the height of the rectangle.
void fontChanged() override
Called when the font has changed.
Definition textbox.cpp:265
virtual void scrollToCaret()
Scrolls the text to the caret if the text box is in a scroll area.
Definition textbox.cpp:270
void setCaretColumnUTF8(int column)
Sets caret column (UTF-8 aware).
Definition textbox.cpp:301
virtual void addRow(std::string const &row)
Adds a row of text to the end of the text.
Definition textbox.cpp:285
void keyPressed(KeyEvent &keyEvent) override
Called if a key is pressed when the widget has keyboard focus.
Definition textbox.cpp:81
std::string getTextRow(int row) const
Gets a certain row from the text.
Definition textbox.cpp:244
Text * mText
Holds the text of the text box.
Definition textbox.hpp:261
void setCaretRowColumn(int row, int column)
Sets the row and the column where the caret should be currently located.
Definition textbox.cpp:218
void draw(Graphics *graphics) override
Draws the widget.
Definition textbox.cpp:41
void setTextRow(int row, std::string const &text)
Sets the text of a certain row of the text.
Definition textbox.cpp:249
bool mEditable
True if the text box is editable, false otherwise.
Definition textbox.hpp:266
void adjustSizeImpl()
Adjusts the size of the button to fit the caption.
Definition textbox.cpp:202
unsigned int getCaretPosition() const
Gets the caret position in the text.
Definition textbox.cpp:213
virtual void drawCaret(Graphics *graphics, int x, int y)
Draws the caret.
Definition textbox.cpp:62
bool mOpaque
True if the text box is opaque, false otherwise.
Definition textbox.hpp:271
std::string getText() const
Gets the text of the text box.
Definition textbox.cpp:260
void setCaretColumn(int column)
Sets the column where the caret should be currently located.
Definition textbox.cpp:234
TextBox(std::string const &text="")
Constructor.
Definition textbox.cpp:20
unsigned int getCaretColumn() const
Gets the column where the caret is currently located.
Definition textbox.cpp:239
void setCaretRow(int row)
Sets the row where the caret should be currently located.
Definition textbox.cpp:224
void resizeToContent()
Resizes the widget's size to fit the content exactly, calls recursively all childs.
Definition widget.hpp:1417
void mousePressed(MouseEvent &mouseEvent) override
Called when a mouse button has been pressed on the widget area.
Definition textbox.cpp:68
void setEditable(bool editable)
Sets the text box to be editable or not.
Definition textbox.cpp:275
void adjustSize() override
Adjusts the text box's size to fit the text.
Definition textbox.cpp:197
void setCaretRowUTF8(int row)
Sets caret row (UTF-8 aware).
Definition textbox.cpp:307
void mouseDragged(MouseEvent &mouseEvent) override
Called when the mouse has moved and the mouse has previously been pressed on the widget.
Definition textbox.cpp:76
unsigned int getCaretRow() const
Gets the row number where the caret is currently located.
Definition textbox.cpp:229
void setText(std::string const &text)
Sets the text of the text box.
Definition textbox.cpp:35
bool isOpaque() const
Checks if the text box is opaque.
Definition textbox.cpp:291
void setOpaque(bool opaque)
Sets the text box to be opaque or not.
Definition textbox.cpp:296
UTF8StringEditor * mStringEditor
UTF8StringEditor for UTF8 support.
Definition textbox.hpp:276
unsigned int getNumberOfRows() const
Gets the number of rows in the text.
Definition textbox.cpp:255
bool isEditable() const
Checks if the text box is editable.
Definition textbox.cpp:280
void setCaretPosition(unsigned int position)
Sets the position of the caret in the text.
Definition textbox.cpp:208
void setCaretRowColumnUTF8(int row, int column)
Sets the caret row and column (UTF-8 aware).
Definition textbox.cpp:319
Helper class for text manipulation within widgets.
Definition text.hpp:28
Utility for editing and handling UTF-8 encoded strings.
static int insertChar(std::string &text, int byteOffset, int ch)
Insert a character at specified byte offset.
static int countChars(std::string const &text, int byteOffset)
Counts characters up to byteOffset.
static int eraseChar(std::string &text, int byteOffset)
Erase character at specified byte offset.
static int getOffset(std::string const &text, int charIndex)
Gets byte offset for character index.
static int nextChar(std::string const &text, int byteOffset)
Returns byte offset of the next character.
static int prevChar(std::string const &text, int byteOffset)
Returns byte offset of the previous character.
void setFocusable(bool focusable)
Sets the widget to be focusable, or not.
Definition widget.cpp:506
int getWidth() const
Gets the width of the widget.
Definition widget.cpp:170
virtual Widget * getParent() const
Gets the widget's parent container.
Definition widget.cpp:157
virtual Rectangle getChildrenArea()
Gets the area of the widget occupied by the widget's children.
Definition widget.cpp:992
virtual bool isFocused() const
Checks if the widget is focused.
Definition widget.cpp:497
virtual void showPart(Rectangle rectangle)
Shows a certain part of a widget in the widget's parent.
Definition widget.cpp:1131
Widget()
Constructor.
Definition widget.cpp:36
void setSize(int width, int height)
Sets the size of the widget.
Definition widget.cpp:855
Color const & getBackgroundColor() const
Gets the background color.
Definition widget.cpp:616
void addMouseListener(MouseListener *mouseListener)
Adds a mouse listener to the widget.
Definition widget.cpp:754
void addKeyListener(KeyListener *keyListener)
Adds a key listener to the widget.
Definition widget.cpp:734
Color const & getForegroundColor() const
Gets the foreground color.
Definition widget.cpp:606
Font * getFont() const
Gets the font set for the widget.
Definition widget.cpp:796
int getHeight() const
Gets the height of the widget.
Definition widget.cpp:183