FifeGUI 0.2.0
A C++ GUI library designed for games.
textfield.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/textfield.hpp"
6
7#include <algorithm>
8#include <string>
9
10#include "fifechan/font.hpp"
11#include "fifechan/graphics.hpp"
12#include "fifechan/key.hpp"
13#include "fifechan/mouseinput.hpp"
14#include "fifechan/text.hpp"
15#include "fifechan/utf8stringeditor.hpp"
16
17namespace fcn
18{
19 TextField::TextField() : mText(new Text()), mStringEditor(new UTF8StringEditor)
20 {
21 mText->addRow("");
22
23 setFocusable(true);
24
25 addMouseListener(this);
26 addKeyListener(this);
27 }
28
29 TextField::TextField(std::string const & text) : mText(new Text(text)), mStringEditor(new UTF8StringEditor)
30 {
32
33 setFocusable(true);
34
35 addMouseListener(this);
36 addKeyListener(this);
37 }
38
39 TextField::~TextField()
40 {
41 delete mText;
42 delete mStringEditor;
43 }
44
45 void TextField::setText(std::string const & text)
46 {
47 mText->setContent(text);
48 }
49
50 void TextField::draw(Graphics* graphics)
51 {
52 Color const faceColor = getBaseColor();
53 Color highlightColor;
54 Color shadowColor;
55 int const alpha = getBaseColor().a;
56 highlightColor = faceColor + 0x303030;
57 highlightColor.a = alpha;
58 shadowColor = faceColor - 0x303030;
59 shadowColor.a = alpha;
60
61 // Draw a border.
62 graphics->setColor(shadowColor);
63 graphics->drawLine(0, 0, getWidth() - 1, 0);
64 graphics->drawLine(0, 1, 0, getHeight() - 2);
65 graphics->setColor(highlightColor);
66 graphics->drawLine(getWidth() - 1, 1, getWidth() - 1, getHeight() - 1);
67 graphics->drawLine(0, getHeight() - 1, getWidth() - 1, getHeight() - 1);
68
69 // Push a clip area so the other drawings don't need to worry
70 // about the border.
71 graphics->pushClipArea(Rectangle(1, 1, getWidth() - 2, getHeight() - 2));
72
73 graphics->setColor(getBackgroundColor());
74 graphics->fillRectangle(0, 0, getWidth(), getHeight());
75
76 if (isFocused()) {
77 graphics->setColor(getSelectionColor());
78 graphics->drawRectangle(0, 0, getWidth() - 2, getHeight() - 2);
79 graphics->drawRectangle(1, 1, getWidth() - 4, getHeight() - 4);
80 }
81
82 if (isFocused() && isEditable()) {
83 drawCaret(graphics, mText->getCaretX(getFont()) - mXScroll);
84 }
85
86 graphics->setColor(getForegroundColor());
87 graphics->setFont(getFont());
88
89 Rectangle const & dim = mText->getCaretDimension(getFont());
90 if (mText->getNumberOfRows() != 0) {
91 graphics->drawText(mText->getRow(0), 1 - mXScroll, 1);
92 }
93
94 graphics->popClipArea();
95 }
96
97 void TextField::drawCaret(Graphics* graphics, int x)
98 {
99 // Check the current clip area as a clip area with a different
100 // size than the widget might have been pushed (which is the
101 // case in the draw method when we push a clip area after we have
102 // drawn a border).
103 // Warning: not using a ref will result in truncation.
104 ClipRectangle const & clipArea = graphics->getCurrentClipArea();
105
106 graphics->setColor(getForegroundColor());
107 graphics->drawLine(x, clipArea.height - 2, x, 1);
108 }
109
111 {
112 if (mouseEvent.getButton() == MouseEvent::Button::Left) {
113 mText->setCaretPosition(mouseEvent.getX() + mXScroll, mouseEvent.getY(), getFont());
114 fixScroll();
115 }
116 }
117
119 {
120 mouseEvent.consume();
121 }
122
124 {
125
126 Key const key = keyEvent.getKey();
127
128 if (key.getValue() == Key::Left && getCaretPosition() > 0) {
130 } else if (key.getValue() == Key::Right && getCaretPosition() < getText().size()) {
132 } else if (
133 key.getValue() == Key::Delete && getCaretPosition() < getText().size() && mText->getNumberOfRows() > 0) {
135 } else if (key.getValue() == Key::Backspace && getCaretPosition() > 0 && mText->getNumberOfRows() > 0) {
138 } else if (key.getValue() == Key::Enter) {
140 } else if (key.getValue() == Key::Home) {
142 } else if (key.getValue() == Key::End) {
143 setCaretPosition(getText().size());
144 } else if (
145 // Add character to text, if key is really an ASCII character
146 // or is greater than 8bits long and the character is not
147 // the tab key.
148 (key.isCharacter() || (key.getValue() > 255 && mText->getNumberOfRows() > 0)) &&
149 key.getValue() != Key::Tab) {
151 }
152
153 if (key.getValue() != Key::Tab) {
154 // consume all characters except TAB which is needed
155 // for traversing through widgets in a container.
156 keyEvent.consume();
157 }
158
159 fixScroll();
160 }
161
162 void TextField::resizeToContent(bool recursion)
163 {
164 static_cast<void>(recursion);
166 }
167
169 {
171 }
172
174 {
175 Rectangle const & dim = mText->getDimension(getFont());
176 setWidth(dim.width + 8);
177 adjustHeight();
178
179 fixScroll();
180 }
181
183 {
184 setHeight(getFont()->getHeight() + 4);
185 }
186
188 {
189 if (isFocused()) {
190 int const caretX = mText->getCaretDimension(getFont()).x;
191
192 if (caretX - mXScroll >= getWidth() - 4) {
193 mXScroll = caretX - getWidth() + 4;
194 } else if (caretX - mXScroll <= 0) {
195 mXScroll = caretX - getWidth() / 2;
196
197 mXScroll = std::max(mXScroll, 0);
198 }
199 }
200 }
201
202 void TextField::setCaretPosition(unsigned int position)
203 {
204 mText->setCaretPosition(position);
205 }
206
207 unsigned int TextField::getCaretPosition() const
208 {
209 return mText->getCaretPosition();
210 }
211
212 std::string TextField::getText() const
213 {
214 return mText->getContent();
215 }
216
218 {
219 return mEditable;
220 }
221
222 void TextField::setEditable(bool editable)
223 {
224 mEditable = editable;
225 }
226} // namespace fcn
A rectangle specifically used for clipping rendering regions.
Color.
Definition color.hpp:56
uint8_t a
Alpha color component (0-255).
Definition color.hpp:322
Abstract interface providing primitive drawing functions (lines, rectangles, etc.).
Definition graphics.hpp:57
virtual void popClipArea()
Removes the top most clip area from the stack.
Definition graphics.cpp:55
void drawText(std::string const &text, int x, int y)
Draws text with a default left alignment.
Definition graphics.hpp:362
virtual ClipRectangle const & getCurrentClipArea()
Gets the current clip area.
Definition graphics.cpp:65
virtual bool pushClipArea(Rectangle area)
Pushes a clip area onto the stack.
Definition graphics.cpp:18
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 drawRectangle(Rectangle const &rectangle)=0
Draws a simple, non-filled rectangle with a one pixel width.
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 adjustSizeImpl()
Adjusts the size of the button to fit the caption.
void setCaretPosition(unsigned int position)
Sets the caret position.
bool mEditable
True if the text field is editable, false otherwise.
void mousePressed(MouseEvent &mouseEvent) override
Called when a mouse button has been pressed on the widget area.
virtual void drawCaret(Graphics *graphics, int x)
Draws the caret.
Definition textfield.cpp:97
UTF8StringEditor * mStringEditor
String editor for UTF8 support.
unsigned int getCaretPosition() const
Gets the caret position.
void fixScroll()
Scrolls the text horizontally so that the caret shows if needed.
int mXScroll
Holds the amount scrolled in x.
void keyPressed(KeyEvent &keyEvent) override
Called if a key is pressed when the widget has keyboard focus.
void resizeToContent()
Resizes the widget's size to fit the content exactly, calls recursively all childs.
Definition widget.hpp:1417
void mouseDragged(MouseEvent &mouseEvent) override
Called when the mouse has moved and the mouse has previously been pressed on the widget.
virtual void setText(std::string const &text)
Sets the text of the text field.
Definition textfield.cpp:45
virtual std::string getText() const
Gets the text of the text field.
void setEditable(bool editable)
Sets the text field to be editable or not.
void adjustSize() override
Adjusts the size of the text field to fit the text.
bool isEditable() const
Checks if the text field is editable.
void adjustHeight()
Adjusts the height of the text field to fit caption.
void draw(Graphics *graphics) override
Draws the widget.
Definition textfield.cpp:50
Text * mText
Holds the text of the text field.
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 eraseChar(std::string &text, int byteOffset)
Erase character at specified byte offset.
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.
Color const & getBaseColor() const
Gets the base color.
Definition widget.cpp:596
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 bool isFocused() const
Checks if the widget is focused.
Definition widget.cpp:497
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 setWidth(int width)
Sets the width of the widget.
Definition widget.cpp:162
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
void distributeActionEvent()
Distributes an action event to all action listeners of the widget.
Definition widget.cpp:1113
int getHeight() const
Gets the height of the widget.
Definition widget.cpp:183
void setHeight(int height)
Sets the height of the widget.
Definition widget.cpp:175
Color const & getSelectionColor() const
Gets the selection color.
Definition widget.cpp:626