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
14#include <cassert>
15#include <string>
16
17#include <utf8.h>
18
19namespace fcn
20{
21 TextBox::TextBox(std::string const & text) : mText(new Text(text)), mStringEditor(new UTF8StringEditor)
22 {
23 setFocusable(true);
24
25 addMouseListener(this);
26 addKeyListener(this);
28 }
29
30 TextBox::~TextBox()
31 {
32 delete mText;
33 delete mStringEditor;
34 }
35
36 void TextBox::setText(std::string const & text)
37 {
38 mText->setContent(text);
40 }
41
42 void TextBox::draw(Graphics* graphics)
43 {
44 if (mOpaque) {
45 graphics->setColor(getBackgroundColor());
46 graphics->fillRectangle(0, 0, getWidth(), getHeight());
47 }
48
49 if (isFocused() && isEditable()) {
50 drawCaret(graphics, mText->getCaretX(getFont()), mText->getCaretY(getFont()));
51 }
52
53 graphics->setColor(getForegroundColor());
54 graphics->setFont(getFont());
55
56 unsigned int i = 0;
57 for (i = 0; i < mText->getNumberOfRows(); i++) {
58 // Move the text one pixel so we can have a caret before a letter.
59 graphics->drawText(mText->getRow(i), 1, i * getFont()->getHeight());
60 }
61 }
62
63 void TextBox::drawCaret(Graphics* graphics, int x, int y)
64 {
65 graphics->setColor(getForegroundColor());
66 graphics->drawLine(x, y, x, y + getFont()->getHeight());
67 }
68
70 {
71 if (mouseEvent.getButton() == MouseEvent::Button::Left) {
72 mText->setCaretPosition(mouseEvent.getX(), mouseEvent.getY(), getFont());
73 mouseEvent.consume();
74 }
75 }
76
78 {
79 mouseEvent.consume();
80 }
81
83 {
84 Key const key = keyEvent.getKey();
85
86 if (key.getValue() == Key::Left) {
87 if (getCaretColumn() == 0) {
88 if (getCaretRow() > 0) {
91 }
92 } else {
94 }
95 } else if (key.getValue() == Key::Right) {
96 if (getCaretColumn() < getTextRow(getCaretRow()).size()) {
98 } else {
99 if (getCaretRow() < getNumberOfRows() - 1) {
102 }
103 }
104 } else if (key.getValue() == Key::Down) {
106 } else if (key.getValue() == Key::Up) {
108 } else if (key.getValue() == Key::Home) {
110 } else if (key.getValue() == Key::End) {
112 } else if (key.getValue() == Key::Enter && mEditable) {
113 mText->insertRow(
115 getCaretRow() + 1);
116
117 mText->getRow(getCaretRow()).resize(getCaretColumn());
120 } else if (key.getValue() == Key::Backspace && getCaretColumn() != 0 && mEditable) {
121 std::string& currRow = mText->getRow(getCaretRow());
124 } else if (key.getValue() == Key::Backspace && getCaretColumn() == 0 && getCaretRow() != 0 && mEditable) {
125 /*setCaretColumn(mText->getRow(getCaretRow() - 1).size());
126 mText->getRow(getCaretRow() - 1) += getTextRow(getCaretRow());
127 mText->eraseRow(getCaretRow());
128 setCaretRow(getCaretRow() - 1);*/
129 unsigned const newCaretColumn = getTextRow(getCaretRow() - 1).size();
130 // setCaretColumn(getTextRow(getCaretRow() - 1).size());
131 mText->getRow(getCaretRow() - 1) += getTextRow(getCaretRow());
132 mText->eraseRow(getCaretRow());
134 setCaretColumn(newCaretColumn);
135 } else if (
136 key.getValue() == Key::Delete && getCaretColumn() < static_cast<int>(getTextRow(getCaretRow()).size()) &&
137 mEditable) {
139 } else if (
140 key.getValue() == Key::Delete && getCaretColumn() == static_cast<int>(getTextRow(getCaretRow()).size()) &&
141 getCaretRow() < (static_cast<int>(getNumberOfRows()) - 1) && mEditable) {
142 mText->getRow(getCaretRow()) += getTextRow((getCaretRow() + 1));
143 mText->eraseRow(getCaretRow() + 1);
144 } else if (key.getValue() == Key::PageUp) {
145 Widget* par = getParent();
146
147 if (par != nullptr) {
148 int const rowsPerPage = par->getChildrenArea().height / getFont()->getHeight();
150 int const newCaretRow = getCaretRow() - rowsPerPage;
151 if (newCaretRow >= 0) {
152 setCaretRow(newCaretRow);
153 } else {
154 setCaretRow(0);
155 }
157 }
158 } else if (key.getValue() == Key::PageDown) {
159 Widget* par = getParent();
160
161 if (par != nullptr) {
162 int const rowsPerPage = par->getChildrenArea().height / getFont()->getHeight();
164 setCaretRow(getCaretRow() + rowsPerPage);
165
166 if (getCaretRow() >= static_cast<int>(getNumberOfRows())) {
168 }
169
171 }
172 } else if (key.getValue() == Key::Tab && mEditable) {
173 // FIXME: jump X spaces, so getCaretColumn() % TAB_SIZE = 0 and X <= TAB_SIZE
174 mText->getRow(getCaretRow()).insert(getCaretColumn(), std::string(" "));
176 } else if ((key.isCharacter() || key.getValue() > 255) && mEditable) {
179 }
180
183 assert(utf8::is_valid(getTextRow(getCaretRow()).begin(), getTextRow(getCaretRow()).end()));
184 assert(utf8::is_valid(getTextRow(getCaretRow()).begin(), getTextRow(getCaretRow()).begin() + getCaretColumn()));
185 keyEvent.consume();
186 }
187
188 void TextBox::resizeToContent(bool recursion)
189 {
190 static_cast<void>(recursion);
192 }
193
195 {
197 }
198
200 {
201 Rectangle const & dim = mText->getDimension(getFont());
202 setSize(dim.width, dim.height);
203 }
204
205 void TextBox::setCaretPosition(unsigned int position)
206 {
207 mText->setCaretPosition(position);
208 }
209
210 unsigned int TextBox::getCaretPosition() const
211 {
212 return mText->getCaretPosition();
213 }
214
215 void TextBox::setCaretRowColumn(int row, int column)
216 {
217 mText->setCaretRow(row);
218 mText->setCaretColumn(column);
219 }
220
222 {
223 mText->setCaretRow(row);
224 }
225
226 unsigned int TextBox::getCaretRow() const
227 {
228 return mText->getCaretRow();
229 }
230
231 void TextBox::setCaretColumn(int column)
232 {
233 mText->setCaretColumn(column);
234 }
235
236 unsigned int TextBox::getCaretColumn() const
237 {
238 return mText->getCaretColumn();
239 }
240
241 std::string TextBox::getTextRow(int row) const
242 {
243 return mText->getRow(row);
244 }
245
246 void TextBox::setTextRow(int row, std::string const & text)
247 {
248 mText->setRow(row, text);
250 }
251
252 unsigned int TextBox::getNumberOfRows() const
253 {
254 return mText->getNumberOfRows();
255 }
256
257 std::string TextBox::getText() const
258 {
259 return mText->getContent();
260 }
261
263 {
265 }
266
268 {
269 showPart(mText->getCaretDimension(getFont()));
270 }
271
272 void TextBox::setEditable(bool editable)
273 {
274 mEditable = editable;
275 }
276
278 {
279 return mEditable;
280 }
281
282 void TextBox::addRow(std::string const & row)
283 {
284 mText->addRow(row);
286 }
287
288 bool TextBox::isOpaque() const
289 {
290 return mOpaque;
291 }
292
293 void TextBox::setOpaque(bool opaque)
294 {
295 mOpaque = opaque;
296 }
297
299 {
300 // no need to clip the column, mStringEditor handles it automatically
302 }
303
305 {
307 if (row < 0) {
308 row = 0;
309 } else if (row >= getNumberOfRows()) {
310 row = getNumberOfRows() - 1;
311 }
312 setCaretRow(row);
314 }
315
316 void TextBox::setCaretRowColumnUTF8(int row, int column)
317 {
318 setCaretRowUTF8(row);
319 setCaretColumnUTF8(column);
320 }
321} // 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:262
virtual void scrollToCaret()
Scrolls the text to the caret if the text box is in a scroll area.
Definition textbox.cpp:267
void setCaretColumnUTF8(int column)
Sets caret column (UTF-8 aware).
Definition textbox.cpp:298
virtual void addRow(std::string const &row)
Adds a row of text to the end of the text.
Definition textbox.cpp:282
void keyPressed(KeyEvent &keyEvent) override
Called if a key is pressed when the widget has keyboard focus.
Definition textbox.cpp:82
std::string getTextRow(int row) const
Gets a certain row from the text.
Definition textbox.cpp:241
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:215
void draw(Graphics *graphics) override
Draws the widget.
Definition textbox.cpp:42
void setTextRow(int row, std::string const &text)
Sets the text of a certain row of the text.
Definition textbox.cpp:246
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:199
unsigned int getCaretPosition() const
Gets the caret position in the text.
Definition textbox.cpp:210
virtual void drawCaret(Graphics *graphics, int x, int y)
Draws the caret.
Definition textbox.cpp:63
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:257
void setCaretColumn(int column)
Sets the column where the caret should be currently located.
Definition textbox.cpp:231
TextBox(std::string const &text="")
Constructor.
Definition textbox.cpp:21
unsigned int getCaretColumn() const
Gets the column where the caret is currently located.
Definition textbox.cpp:236
void setCaretRow(int row)
Sets the row where the caret should be currently located.
Definition textbox.cpp:221
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:69
void setEditable(bool editable)
Sets the text box to be editable or not.
Definition textbox.cpp:272
void adjustSize() override
Adjusts the text box's size to fit the text.
Definition textbox.cpp:194
void setCaretRowUTF8(int row)
Sets caret row (UTF-8 aware).
Definition textbox.cpp:304
void mouseDragged(MouseEvent &mouseEvent) override
Called when the mouse has moved and the mouse has previously been pressed on the widget.
Definition textbox.cpp:77
unsigned int getCaretRow() const
Gets the row number where the caret is currently located.
Definition textbox.cpp:226
void setText(std::string const &text)
Sets the text of the text box.
Definition textbox.cpp:36
bool isOpaque() const
Checks if the text box is opaque.
Definition textbox.cpp:288
void setOpaque(bool opaque)
Sets the text box to be opaque or not.
Definition textbox.cpp:293
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:252
bool isEditable() const
Checks if the text box is editable.
Definition textbox.cpp:277
void setCaretPosition(unsigned int position)
Sets the position of the caret in the text.
Definition textbox.cpp:205
void setCaretRowColumnUTF8(int row, int column)
Sets the caret row and column (UTF-8 aware).
Definition textbox.cpp:316
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