FifeGUI 0.3.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// Corresponding header include
6#include "fifechan/widgets/textfield.hpp"
7
8// Standard library includes
9#include <algorithm>
10#include <string>
11
12// Project headers (subdirs before local)
13#include "fifechan/events/textinputevent.hpp"
14#include "fifechan/font.hpp"
15#include "fifechan/graphics.hpp"
16#include "fifechan/key.hpp"
17#include "fifechan/mouseinput.hpp"
18#include "fifechan/text.hpp"
19#include "fifechan/utf8stringeditor.hpp"
20
21namespace fcn
22{
23 TextField::TextField() : mText(new Text()), mStringEditor(new UTF8StringEditor)
24 {
25 mText->addRow("");
26
27 setFocusable(true);
28
29 addMouseListener(this);
30 addKeyListener(this);
31 }
32
33 TextField::TextField(std::string const & text) : mText(new Text(text)), mStringEditor(new UTF8StringEditor)
34 {
36
37 setFocusable(true);
38
39 addMouseListener(this);
40 addKeyListener(this);
41 }
42
43 TextField::~TextField()
44 {
45 delete mText;
46 delete mStringEditor;
47 }
48
49 void TextField::setText(std::string const & text)
50 {
51 mText->setContent(text);
52 }
53
54 void TextField::draw(Graphics* graphics)
55 {
56 Color const faceColor = getBaseColor();
57 Color highlightColor;
58 Color shadowColor;
59 int const alpha = getBaseColor().a;
60 highlightColor = faceColor + 0x303030;
61 highlightColor.a = alpha;
62 shadowColor = faceColor - 0x303030;
63 shadowColor.a = alpha;
64
65 // Draw a border.
66 graphics->setColor(shadowColor);
67 graphics->drawLine(0, 0, getWidth() - 1, 0);
68 graphics->drawLine(0, 1, 0, getHeight() - 2);
69 graphics->setColor(highlightColor);
70 graphics->drawLine(getWidth() - 1, 1, getWidth() - 1, getHeight() - 1);
71 graphics->drawLine(0, getHeight() - 1, getWidth() - 1, getHeight() - 1);
72
73 // Push a clip area so the other drawings don't need to worry
74 // about the border.
75 graphics->pushClipArea(Rectangle(1, 1, getWidth() - 2, getHeight() - 2));
76
77 graphics->setColor(getBackgroundColor());
78 graphics->fillRectangle(0, 0, getWidth(), getHeight());
79
80 if (isFocused()) {
81 graphics->setColor(getSelectionColor());
82 graphics->drawRectangle(0, 0, getWidth() - 2, getHeight() - 2);
83 graphics->drawRectangle(1, 1, getWidth() - 4, getHeight() - 4);
84 }
85
86 if (isFocused() && isEditable()) {
87 drawCaret(graphics, mText->getCaretX(getFont()) - mXScroll);
88 }
89
90 graphics->setColor(getForegroundColor());
91 graphics->setFont(getFont());
92
93 Rectangle const & dim = mText->getCaretDimension(getFont());
94 if (mText->getNumberOfRows() != 0) {
95 graphics->drawText(mText->getRow(0), 1 - mXScroll, 1);
96 }
97
98 graphics->popClipArea();
99 }
100
101 void TextField::drawCaret(Graphics* graphics, int x)
102 {
103 // Check the current clip area as a clip area with a different
104 // size than the widget might have been pushed (which is the
105 // case in the draw method when we push a clip area after we have
106 // drawn a border).
107 // Warning: not using a ref will result in truncation.
108 ClipRectangle const & clipArea = graphics->getCurrentClipArea();
109
110 graphics->setColor(getForegroundColor());
111 graphics->drawLine(x, clipArea.height - 2, x, 1);
112 }
113
115 {
116 if (mouseEvent.getButton() == MouseEvent::Button::Left) {
117 mText->setCaretPosition(mouseEvent.getX() + mXScroll, mouseEvent.getY(), getFont());
118 fixScroll();
119 }
120 }
121
123 {
124 mouseEvent.consume();
125 }
126
128 {
129
130 Key const key = keyEvent.getKey();
131
132 if (key.getValue() == fcn::Key::LEFT && getCaretPosition() > 0) {
134 } else if (key.getValue() == fcn::Key::RIGHT && getCaretPosition() < getText().size()) {
136 } else if (
137 key.getValue() == fcn::Key::KEY_DELETE && getCaretPosition() < getText().size() &&
138 mText->getNumberOfRows() > 0) {
140 } else if (key.getValue() == fcn::Key::BACKSPACE && getCaretPosition() > 0 && mText->getNumberOfRows() > 0) {
143 } else if (key.getValue() == fcn::Key::KEY_RETURN) {
145 } else if (key.getValue() == fcn::Key::HOME) {
147 } else if (key.getValue() == fcn::Key::END) {
148 setCaretPosition(getText().size());
149 }
150 // Printable characters are handled by textInput(TextInputEvent&).
151
152 if (key.getValue() != fcn::Key::TAB) {
153 // consume all characters except TAB which is needed
154 // for traversing through widgets in a container.
155 keyEvent.consume();
156 }
157
158 fixScroll();
159 }
160
162 {
163 std::string const & text = event.getText();
164 if (!text.empty() && mText->getNumberOfRows() > 0) {
165 std::string& row = mText->getRow(0);
166 row.insert(getCaretPosition(), text);
167 setCaretPosition(getCaretPosition() + text.size());
168 fixScroll();
169 }
170 }
171
172 void TextField::resizeToContent(bool recursion)
173 {
174 static_cast<void>(recursion);
176 }
177
179 {
181 }
182
184 {
185 Rectangle const & dim = mText->getDimension(getFont());
186 setWidth(dim.width + 8);
187 adjustHeight();
188
189 fixScroll();
190 }
191
193 {
194 setHeight(getFont()->getHeight() + 4);
195 }
196
198 {
199 if (isFocused()) {
200 int const caretX = mText->getCaretDimension(getFont()).x;
201
202 if (caretX - mXScroll >= getWidth() - 4) {
203 mXScroll = caretX - getWidth() + 4;
204 } else if (caretX - mXScroll <= 0) {
205 mXScroll = caretX - (getWidth() / 2);
206
207 mXScroll = std::max(mXScroll, 0);
208 }
209 }
210 }
211
212 void TextField::setCaretPosition(unsigned int position)
213 {
214 mText->setCaretPosition(position);
215 }
216
217 unsigned int TextField::getCaretPosition() const
218 {
219 return mText->getCaretPosition();
220 }
221
222 std::string TextField::getText() const
223 {
224 return mText->getContent();
225 }
226
228 {
229 return mEditable;
230 }
231
232 void TextField::setEditable(bool editable)
233 {
234 mEditable = editable;
235 }
236} // namespace fcn
A rectangle specifically used for clipping rendering regions.
Color.
Definition color.hpp:58
uint8_t a
Alpha color component (0-255).
Definition color.hpp:350
Abstract interface providing primitive drawing functions (lines, rectangles, etc.).
Definition graphics.hpp:58
virtual void popClipArea()
Removes the top most clip area from the stack.
Definition graphics.cpp:65
void drawText(std::string const &text, int x, int y)
Draws text with a default left alignment.
Definition graphics.hpp:401
virtual ClipRectangle const & getCurrentClipArea()
Gets the current clip area.
Definition graphics.cpp:74
virtual bool pushClipArea(Rectangle area)
Pushes a clip area onto the stack.
Definition graphics.cpp:25
virtual void setFont(Font *font)
Sets the font to use when drawing text.
Definition graphics.cpp:91
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 this event as consumed.
Represents a key event.
Definition keyevent.hpp:26
Key const & getKey() const
Gets the key of the event.
Definition keyevent.cpp:48
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:22
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 down on the widget area.
virtual void drawCaret(Graphics *graphics, int x)
Draws the caret.
UTF8StringEditor * mStringEditor
String editor for UTF8 support.
unsigned int getCaretPosition() const
Gets the caret position.
void fixScroll()
Ensures the caret remains visible by adjusting horizontal scroll.
int mXScroll
Horizontal scroll offset in pixels.
void resizeToContent(bool recursion=true) override
Resizes the widget's size to fit the content exactly, calls recursively all childs.
void keyPressed(KeyEvent &keyEvent) override
Called if a key is pressed when the widget has keyboard focus.
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:49
virtual std::string getText() const
Gets the text of the text field.
void textInput(TextInputEvent &event) override
Called when text input (IME, dead-key, paste) is received.
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:54
Text * mText
Holds the text of the text field.
Text input event for IME (input method editor) composition, dead keys, and pasted text.
Helper class for text manipulation within widgets.
Definition text.hpp:32
Utility for editing and handling UTF-8 encoded strings.
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:742
void setFocusable(bool focusable)
Sets the widget to be focusable, or not.
Definition widget.cpp:646
int getWidth() const
Gets the width of the widget.
Definition widget.cpp:252
virtual bool isFocused() const
Checks if the widget is focused.
Definition widget.cpp:624
Color const & getBackgroundColor() const
Gets the background color.
Definition widget.cpp:762
void addMouseListener(MouseListener *mouseListener)
Adds a mouse listener to the widget.
Definition widget.cpp:907
virtual void setWidth(int width)
Sets the width of the widget.
Definition widget.cpp:244
void addKeyListener(KeyListener *keyListener)
Adds a key listener to the widget.
Definition widget.cpp:885
Color const & getForegroundColor() const
Gets the foreground color.
Definition widget.cpp:752
Font * getFont() const
Gets the font set for the widget.
Definition widget.cpp:1000
void distributeActionEvent()
Distributes an action event to all action listeners of the widget.
Definition widget.cpp:1291
int getHeight() const
Gets the height of the widget.
Definition widget.cpp:265
virtual void setHeight(int height)
Sets the height of the widget.
Definition widget.cpp:257
Color const & getSelectionColor() const
Gets the selection color.
Definition widget.cpp:772
Used replacement tokens by configure_file():