]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/textentry.cpp
Add wxTextCtrl::PositionToCoords() functions for wxMSW and wxGTK.
[wxWidgets.git] / src / gtk / textentry.cpp
CommitLineData
0ec1179b
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/gtk/textentry.cpp
3// Purpose: wxTextEntry implementation for wxGTK
4// Author: Vadim Zeitlin
5// Created: 2007-09-24
6// RCS-ID: $Id$
7// Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
8// Licence: wxWindows licence
9///////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
19// for compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
96a4cdeb
VZ
26#if wxUSE_TEXTCTRL || wxUSE_COMBOBOX
27
0ec1179b 28#ifndef WX_PRECOMP
d290d2fe
RR
29 #include "wx/window.h"
30 #include "wx/textctrl.h"
0ec1179b
VZ
31#endif //WX_PRECOMP
32
33#include "wx/textentry.h"
34
35#include "wx/gtk/private.h"
36
37// ============================================================================
38// signal handlers implementation
39// ============================================================================
40
41extern "C"
42{
43
44// "insert_text" handler for GtkEntry
45static void
46wx_gtk_insert_text_callback(GtkEditable *editable,
e4161a2a
VZ
47 const gchar * WXUNUSED(new_text),
48 gint WXUNUSED(new_text_length),
49 gint * WXUNUSED(position),
0ec1179b
VZ
50 wxTextEntry *text)
51{
52 // we should only be called if we have a max len limit at all
53 GtkEntry *entry = GTK_ENTRY (editable);
54
385e8575
PC
55 const int text_length = gtk_entry_get_text_length(entry);
56#if GTK_CHECK_VERSION(3,0,0) || defined(GSEAL_ENABLE)
57 const int text_max_length = gtk_entry_buffer_get_max_length(gtk_entry_get_buffer(entry));
58#else
59 const int text_max_length = entry->text_max_length;
60#endif
61 wxCHECK_RET(text_max_length, "shouldn't be called");
0ec1179b
VZ
62
63 // check that we don't overflow the max length limit
64 //
65 // FIXME: this doesn't work when we paste a string which is going to be
66 // truncated
385e8575 67 if (text_length == text_max_length)
0ec1179b
VZ
68 {
69 // we don't need to run the base class version at all
70 g_signal_stop_emission_by_name (editable, "insert_text");
71
72 text->SendMaxLenEvent();
73 }
74}
75
76} // extern "C"
77
78// ============================================================================
79// wxTextEntry implementation
80// ============================================================================
81
82// ----------------------------------------------------------------------------
83// text operations
84// ----------------------------------------------------------------------------
85
86void wxTextEntry::WriteText(const wxString& value)
87{
88 GtkEditable * const edit = GetEditable();
89
90 // remove the selection if there is one and suppress the text change event
91 // generated by this: we only want to generate one event for this change,
92 // not two
93 {
94 EventsSuppressor noevents(this);
95 gtk_editable_delete_selection(edit);
96 }
97
98 // insert new text at the cursor position
99 gint len = gtk_editable_get_position(edit);
100 gtk_editable_insert_text
101 (
102 edit,
103 wxGTK_CONV_FONT(value, GetEditableWindow()->GetFont()),
104 -1, // text: length: compute it using strlen()
105 &len // will be updated to position after the text end
106 );
107
108 // and move cursor to the end of new text
109 gtk_editable_set_position(edit, len);
110}
111
135b23b2 112wxString wxTextEntry::DoGetValue() const
0ec1179b
VZ
113{
114 const wxGtkString value(gtk_editable_get_chars(GetEditable(), 0, -1));
115
ec592d7f
VZ
116 return wxGTK_CONV_BACK_FONT(value,
117 const_cast<wxTextEntry *>(this)->GetEditableWindow()->GetFont());
0ec1179b
VZ
118}
119
120void wxTextEntry::Remove(long from, long to)
121{
122 gtk_editable_delete_text(GetEditable(), from, to);
123}
124
125// ----------------------------------------------------------------------------
126// clipboard operations
127// ----------------------------------------------------------------------------
128
129void wxTextEntry::Copy()
130{
131 gtk_editable_copy_clipboard(GetEditable());
132}
133
134void wxTextEntry::Cut()
135{
136 gtk_editable_cut_clipboard(GetEditable());
137}
138
139void wxTextEntry::Paste()
140{
141 gtk_editable_paste_clipboard(GetEditable());
142}
143
144// ----------------------------------------------------------------------------
145// undo/redo
146// ----------------------------------------------------------------------------
147
148void wxTextEntry::Undo()
149{
150 // TODO: not implemented
151}
152
153void wxTextEntry::Redo()
154{
155 // TODO: not implemented
156}
157
158bool wxTextEntry::CanUndo() const
159{
160 return false;
161}
162
163bool wxTextEntry::CanRedo() const
164{
165 return false;
166}
167
168// ----------------------------------------------------------------------------
169// insertion point
170// ----------------------------------------------------------------------------
171
172void wxTextEntry::SetInsertionPoint(long pos)
173{
174 gtk_editable_set_position(GetEditable(), pos);
175}
176
177long wxTextEntry::GetInsertionPoint() const
178{
179 return gtk_editable_get_position(GetEditable());
180}
181
182long wxTextEntry::GetLastPosition() const
183{
184 // this can't be implemented for arbitrary GtkEditable so only do it for
185 // GtkEntries
186 GtkEntry * const entry = GTK_ENTRY(GetEditable());
187
385e8575 188 return entry ? gtk_entry_get_text_length(entry) : -1;
0ec1179b
VZ
189}
190
191// ----------------------------------------------------------------------------
192// selection
193// ----------------------------------------------------------------------------
194
195void wxTextEntry::SetSelection(long from, long to)
196{
e0721133
VZ
197 // in wx convention, (-1, -1) means the entire range but GTK+ translates -1
198 // (or any negative number for that matter) into last position so we need
199 // to translate manually
200 if ( from == -1 && to == -1 )
201 from = 0;
202
8b2e0e6d
VZ
203 // for compatibility with MSW, exchange from and to parameters so that the
204 // insertion point is set to the start of the selection and not its end as
205 // GTK+ does by default
206 gtk_editable_select_region(GetEditable(), to, from);
0ec1179b
VZ
207}
208
209void wxTextEntry::GetSelection(long *from, long *to) const
210{
211 gint start, end;
212 if ( gtk_editable_get_selection_bounds(GetEditable(), &start, &end) )
213 {
214 // the output must always be in order, although in GTK+ it isn't
215 if ( start > end )
216 {
217 gint tmp = start;
218 start = end;
219 end = tmp;
220 }
221 }
222 else // no selection
223 {
224 // for compatibility with MSW return the empty selection at cursor
225 start =
226 end = GetInsertionPoint();
227 }
228
229 if ( from )
230 *from = start;
231
232 if ( to )
233 *to = end;
234}
235
236// ----------------------------------------------------------------------------
ecaed0bc
VZ
237// auto completion
238// ----------------------------------------------------------------------------
239
574479e8 240bool wxTextEntry::DoAutoCompleteStrings(const wxArrayString& choices)
ecaed0bc
VZ
241{
242 GtkEntry * const entry = GTK_ENTRY(GetEditable());
0c3d1aa7 243 wxCHECK_MSG(entry, false, "auto completion doesn't work with this control");
ecaed0bc
VZ
244
245 GtkListStore * const store = gtk_list_store_new(1, G_TYPE_STRING);
246 GtkTreeIter iter;
247
248 for ( wxArrayString::const_iterator i = choices.begin();
249 i != choices.end();
250 ++i )
251 {
252 gtk_list_store_append(store, &iter);
253 gtk_list_store_set(store, &iter,
254 0, (const gchar *)i->utf8_str(),
255 -1);
256 }
257
258 GtkEntryCompletion * const completion = gtk_entry_completion_new();
259 gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(store));
260 gtk_entry_completion_set_text_column(completion, 0);
261 gtk_entry_set_completion(entry, completion);
262 g_object_unref(completion);
0c3d1aa7 263 return true;
ecaed0bc
VZ
264}
265
266// ----------------------------------------------------------------------------
0ec1179b
VZ
267// editable status
268// ----------------------------------------------------------------------------
269
270bool wxTextEntry::IsEditable() const
271{
272 return gtk_editable_get_editable(GetEditable());
273}
274
275void wxTextEntry::SetEditable(bool editable)
276{
277 gtk_editable_set_editable(GetEditable(), editable);
278}
279
280// ----------------------------------------------------------------------------
281// max text length
282// ----------------------------------------------------------------------------
283
284void wxTextEntry::SetMaxLength(unsigned long len)
285{
286 GtkEntry * const entry = GTK_ENTRY(GetEditable());
287 if ( !entry )
288 return;
289
290 gtk_entry_set_max_length(entry, len);
291
292 // there is a bug in GTK+ 1.2.x: "changed" signal is emitted even if we had
293 // tried to enter more text than allowed by max text length and the text
294 // wasn't really changed
295 //
296 // to detect this and generate TEXT_MAXLEN event instead of TEXT_CHANGED
297 // one in this case we also catch "insert_text" signal
298 //
299 // when max len is set to 0 we disconnect our handler as it means that we
300 // shouldn't check anything any more
301 if ( len )
302 {
303 g_signal_connect
304 (
305 entry,
306 "insert_text",
307 G_CALLBACK(wx_gtk_insert_text_callback),
308 this
309 );
310 }
311 else // no max length
312 {
313 g_signal_handlers_disconnect_by_func
314 (
315 entry,
316 (gpointer)wx_gtk_insert_text_callback,
317 this
318 );
319 }
320}
321
322void wxTextEntry::SendMaxLenEvent()
323{
324 // remember that the next changed signal is to be ignored to avoid
325 // generating a dummy wxEVT_COMMAND_TEXT_UPDATED event
326 //IgnoreNextTextUpdate();
327
ec592d7f 328 wxWindow * const win = GetEditableWindow();
0ec1179b
VZ
329 wxCommandEvent event(wxEVT_COMMAND_TEXT_MAXLEN, win->GetId());
330 event.SetEventObject(win);
331 event.SetString(GetValue());
937013e0 332 win->HandleWindowEvent(event);
0ec1179b
VZ
333}
334
0847e36e
JS
335// ----------------------------------------------------------------------------
336// margins support
337// ----------------------------------------------------------------------------
338
339bool wxTextEntry::DoSetMargins(const wxPoint& margins)
340{
341#if GTK_CHECK_VERSION(2,10,0)
342 GtkEntry* entry = GetEntry();
343
344 if ( !entry )
345 return false;
346
347 const GtkBorder* oldBorder = gtk_entry_get_inner_border(entry);
348 GtkBorder* newBorder;
349
350 if ( oldBorder )
351 {
352 newBorder = gtk_border_copy(oldBorder);
353 }
354 else
355 {
356 #if GTK_CHECK_VERSION(2,14,0)
357 newBorder = gtk_border_new();
358 #else
c39b6e1e 359 newBorder = g_slice_new0(GtkBorder);
0847e36e
JS
360 #endif
361 // Use some reasonable defaults for initial margins
362 newBorder->left = 2;
363 newBorder->right = 2;
364
365 // These numbers seem to let the text remain vertically centered
366 // in common use scenarios when margins.y == -1.
367 newBorder->top = 3;
368 newBorder->bottom = 3;
369 }
370
371 if ( margins.x != -1 )
372 newBorder->left = (gint) margins.x;
373
374 if ( margins.y != -1 )
375 newBorder->top = (gint) margins.y;
376
377 gtk_entry_set_inner_border(entry, newBorder);
378
c39b6e1e
JS
379#if GTK_CHECK_VERSION(2,14,0)
380 gtk_border_free(newBorder);
381#else
382 g_slice_free(GtkBorder, newBorder);
383#endif
384
0847e36e
JS
385 return true;
386#else
387 wxUnusedVar(margins);
388 return false;
389#endif
390}
391
392wxPoint wxTextEntry::DoGetMargins() const
393{
394#if GTK_CHECK_VERSION(2,10,0)
395 GtkEntry* entry = GetEntry();
396
397 if ( !entry )
398 return wxPoint(-1, -1);
399
400 const GtkBorder* border = gtk_entry_get_inner_border(entry);
401
402 if ( !border )
403 return wxPoint(-1, -1);
404
405 return wxPoint((wxCoord) border->left, (wxCoord) border->top);
406#else
407 return wxPoint(-1, -1);
408#endif
409}
410
96a4cdeb 411#endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX