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