@@ -21,6 +21,11 @@ TextBox::TextBox(float width):
21
21
m_text.setFillColor (Theme::input.textColor );
22
22
m_text.setCharacterSize (Theme::textSize);
23
23
24
+ m_placeholder.setFont (Theme::getFont ());
25
+ m_placeholder.setPosition (offset, offset);
26
+ m_placeholder.setFillColor (Theme::input.textPlaceholderColor );
27
+ m_placeholder.setCharacterSize (Theme::textSize);
28
+
24
29
// Build cursor
25
30
m_cursor.setPosition (offset, offset);
26
31
m_cursor.setSize (sf::Vector2f (1 .f , Theme::getLineSpacing ()));
@@ -127,6 +132,11 @@ void TextBox::onKeyPressed(const sf::Event::KeyEvent& key)
127
132
break ;
128
133
129
134
case sf::Keyboard::BackSpace:
135
+ if (!m_selectedText.isEmpty ())
136
+ {
137
+ deleteSelectedText ();
138
+ break ;
139
+ }
130
140
// Erase character before cursor
131
141
if (m_cursorPos > 0 )
132
142
{
@@ -139,6 +149,11 @@ void TextBox::onKeyPressed(const sf::Event::KeyEvent& key)
139
149
break ;
140
150
141
151
case sf::Keyboard::Delete:
152
+ if (!m_selectedText.isEmpty ())
153
+ {
154
+ deleteSelectedText ();
155
+ break ;
156
+ }
142
157
// Erase character after cursor
143
158
if (m_cursorPos < m_text.getString ().getSize ())
144
159
{
@@ -162,10 +177,19 @@ void TextBox::onKeyPressed(const sf::Event::KeyEvent& key)
162
177
triggerCallback ();
163
178
break ;
164
179
180
+ case sf::Keyboard::A:
181
+ if (key.control )
182
+ {
183
+ setSelectedText (0 , m_text.getString ().getSize ());
184
+ }
185
+ break ;
186
+
165
187
// Ctrl+V: paste clipboard
166
188
case sf::Keyboard::V:
167
189
if (key.control )
168
190
{
191
+ // Delete selected text and write clipboard string over it.
192
+ deleteSelectedText ();
169
193
sf::String string = m_text.getString ();
170
194
sf::String clipboardString = sf::Clipboard::getString ();
171
195
// Trim clipboard content if needed
@@ -180,6 +204,27 @@ void TextBox::onKeyPressed(const sf::Event::KeyEvent& key)
180
204
}
181
205
break ;
182
206
207
+ case sf::Keyboard::C:
208
+ if (key.control )
209
+ {
210
+ if (!m_selectedText.isEmpty ())
211
+ {
212
+ sf::Clipboard::setString (m_selectedText);
213
+ }
214
+ }
215
+ break ;
216
+
217
+ case sf::Keyboard::X:
218
+ if (key.control )
219
+ {
220
+ if (!m_selectedText.isEmpty ())
221
+ {
222
+ sf::Clipboard::setString (m_selectedText);
223
+ deleteSelectedText ();
224
+ }
225
+ }
226
+ break ;
227
+
183
228
default :
184
229
break ;
185
230
}
@@ -201,10 +246,46 @@ void TextBox::onMousePressed(float x, float)
201
246
}
202
247
203
248
249
+ void TextBox::onMouseReleased (float x, float y)
250
+ {
251
+ for (int i = m_text.getString ().getSize (); i >= 0 ; --i)
252
+ {
253
+ // Place cursor after the character under the mouse
254
+ sf::Vector2f glyph_pos = m_text.findCharacterPos (i);
255
+ if (glyph_pos.x <= x)
256
+ {
257
+ setSelectedText (m_cursorPos, i);
258
+ setCursor (i);
259
+ break ;
260
+ }
261
+ }
262
+ }
263
+
264
+
265
+ void TextBox::onMouseMoved (float x, float y)
266
+ {
267
+ if (sf::Mouse::isButtonPressed (sf::Mouse::Left))
268
+ {
269
+ for (int i = m_text.getString ().getSize (); i >= 0 ; --i)
270
+ {
271
+ // Place cursor after the character under the mouse
272
+ sf::Vector2f glyph_pos = m_text.findCharacterPos (i);
273
+ if (glyph_pos.x <= x)
274
+ {
275
+ setSelectedText (m_cursorPos, i);
276
+ break ;
277
+ }
278
+ }
279
+ }
280
+ }
281
+
282
+
204
283
void TextBox::onTextEntered (sf::Uint32 unicode)
205
284
{
206
285
if (unicode > 30 && (unicode < 127 || unicode > 159 ))
207
286
{
287
+ // Delete selected text when a new input is received
288
+ deleteSelectedText ();
208
289
sf::String string = m_text.getString ();
209
290
if (string.getSize () < m_maxLength)
210
291
{
@@ -220,6 +301,12 @@ void TextBox::onTextEntered(sf::Uint32 unicode)
220
301
void TextBox::onStateChanged (State state)
221
302
{
222
303
m_box.applyState (state);
304
+
305
+ // Discard selection when focus is lost
306
+ if (state != State::StateFocused)
307
+ {
308
+ setSelectedText (0 ,0 );
309
+ }
223
310
}
224
311
225
312
@@ -230,9 +317,27 @@ void TextBox::draw(sf::RenderTarget& target, sf::RenderStates states) const
230
317
231
318
// Crop the text with GL Scissor
232
319
glEnable (GL_SCISSOR_TEST);
320
+
233
321
sf::Vector2f pos = getAbsolutePosition ();
234
322
glScissor (pos.x + Theme::borderSize, target.getSize ().y - (pos.y + getSize ().y ), getSize ().x , getSize ().y );
235
- target.draw (m_text, states);
323
+
324
+ if (m_text.getString ().isEmpty ())
325
+ {
326
+ target.draw (m_placeholder, states);
327
+ }
328
+ else
329
+ {
330
+ // Draw selection indicator
331
+ if (!m_selectedText.isEmpty ())
332
+ {
333
+ sf::RectangleShape selRect;
334
+ selRect.setPosition (m_text.findCharacterPos (m_selectionFirst));
335
+ selRect.setSize ({m_text.findCharacterPos (m_selectionLast).x - m_text.findCharacterPos (m_selectionFirst).x , m_cursor.getSize ().y });
336
+ selRect.setFillColor (Theme::input.textSelectionColor );
337
+ target.draw (selRect, states);
338
+ }
339
+ target.draw (m_text, states);
340
+ }
236
341
237
342
glDisable (GL_SCISSOR_TEST);
238
343
@@ -253,4 +358,51 @@ void TextBox::draw(sf::RenderTarget& target, sf::RenderStates states) const
253
358
}
254
359
}
255
360
361
+
362
+ void TextBox::setSelectedText (size_t from, size_t to)
363
+ {
364
+ if (from != to)
365
+ {
366
+ m_selectionLast = std::max (from, to);
367
+ m_selectionFirst = std::min (from, to);
368
+ m_selectedText = m_text.getString ().substring (m_selectionFirst, m_selectionLast - m_selectionFirst);
369
+ }
370
+ else
371
+ {
372
+ m_selectionFirst = m_selectionLast = 0 ;
373
+ m_selectedText.clear ();
374
+ }
375
+ }
376
+
377
+ const sf::String& TextBox::getSelectedText () const
378
+ {
379
+ return m_selectedText;
380
+ }
381
+
382
+
383
+ void TextBox::deleteSelectedText ()
384
+ {
385
+ // Delete if any selected text
386
+ if (!m_selectedText.isEmpty ())
387
+ {
388
+ sf::String str = m_text.getString ();
389
+ str.erase (m_selectionFirst, m_selectionLast - m_selectionFirst);
390
+ setCursor (m_selectionFirst);
391
+ setSelectedText (0 ,0 );
392
+ m_text.setString (str);
393
+ }
394
+ }
395
+
396
+
397
+ void TextBox::setPlaceholder (const sf::String& placeholder)
398
+ {
399
+ m_placeholder.setString (placeholder);
400
+ }
401
+
402
+
403
+ const sf::String& TextBox::getPlaceholder () const
404
+ {
405
+ return m_placeholder.getString ();
406
+ }
407
+
256
408
}
0 commit comments