1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/textentry.cpp
3 // Purpose: wxTextEntry implementation for wxGTK
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
26 #if wxUSE_TEXTCTRL || wxUSE_COMBOBOX
29 #include "wx/window.h"
30 #include "wx/textctrl.h"
33 #include "wx/textentry.h"
35 #include "wx/gtk/private.h"
37 // ============================================================================
38 // signal handlers implementation
39 // ============================================================================
44 // "insert_text" handler for GtkEntry
46 wx_gtk_insert_text_callback(GtkEditable
*editable
,
47 const gchar
* WXUNUSED(new_text
),
48 gint
WXUNUSED(new_text_length
),
49 gint
* WXUNUSED(position
),
52 // we should only be called if we have a max len limit at all
53 GtkEntry
*entry
= GTK_ENTRY (editable
);
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
));
59 const int text_max_length
= entry
->text_max_length
;
61 wxCHECK_RET(text_max_length
, "shouldn't be called");
63 // check that we don't overflow the max length limit
65 // FIXME: this doesn't work when we paste a string which is going to be
67 if (text_length
== text_max_length
)
69 // we don't need to run the base class version at all
70 g_signal_stop_emission_by_name (editable
, "insert_text");
72 text
->SendMaxLenEvent();
78 // ============================================================================
79 // wxTextEntry implementation
80 // ============================================================================
82 // ----------------------------------------------------------------------------
84 // ----------------------------------------------------------------------------
86 void wxTextEntry::WriteText(const wxString
& value
)
88 GtkEditable
* const edit
= GetEditable();
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,
94 EventsSuppressor
noevents(this);
95 gtk_editable_delete_selection(edit
);
98 // insert new text at the cursor position
99 gint len
= gtk_editable_get_position(edit
);
100 gtk_editable_insert_text
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
108 // and move cursor to the end of new text
109 gtk_editable_set_position(edit
, len
);
112 wxString
wxTextEntry::DoGetValue() const
114 const wxGtkString
value(gtk_editable_get_chars(GetEditable(), 0, -1));
116 return wxGTK_CONV_BACK_FONT(value
,
117 const_cast<wxTextEntry
*>(this)->GetEditableWindow()->GetFont());
120 void wxTextEntry::Remove(long from
, long to
)
122 gtk_editable_delete_text(GetEditable(), from
, to
);
125 // ----------------------------------------------------------------------------
126 // clipboard operations
127 // ----------------------------------------------------------------------------
129 void wxTextEntry::Copy()
131 gtk_editable_copy_clipboard(GetEditable());
134 void wxTextEntry::Cut()
136 gtk_editable_cut_clipboard(GetEditable());
139 void wxTextEntry::Paste()
141 gtk_editable_paste_clipboard(GetEditable());
144 // ----------------------------------------------------------------------------
146 // ----------------------------------------------------------------------------
148 void wxTextEntry::Undo()
150 // TODO: not implemented
153 void wxTextEntry::Redo()
155 // TODO: not implemented
158 bool wxTextEntry::CanUndo() const
163 bool wxTextEntry::CanRedo() const
168 // ----------------------------------------------------------------------------
170 // ----------------------------------------------------------------------------
172 void wxTextEntry::SetInsertionPoint(long pos
)
174 gtk_editable_set_position(GetEditable(), pos
);
177 long wxTextEntry::GetInsertionPoint() const
179 return gtk_editable_get_position(GetEditable());
182 long wxTextEntry::GetLastPosition() const
184 // this can't be implemented for arbitrary GtkEditable so only do it for
186 GtkEntry
* const entry
= GTK_ENTRY(GetEditable());
188 return entry
? gtk_entry_get_text_length(entry
) : -1;
191 // ----------------------------------------------------------------------------
193 // ----------------------------------------------------------------------------
195 void wxTextEntry::SetSelection(long from
, long to
)
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 )
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
);
208 // avoid reported problem with RHEL 5 GTK+ 2.10 where selection is reset by
209 // a clipboard callback, see #13277
210 if (gtk_check_version(2,12,0))
212 GtkEntry
* entry
= GTK_ENTRY(GetEditable());
214 to
= entry
->text_length
;
215 entry
->selection_bound
= to
;
219 void wxTextEntry::GetSelection(long *from
, long *to
) const
222 if ( gtk_editable_get_selection_bounds(GetEditable(), &start
, &end
) )
224 // the output must always be in order, although in GTK+ it isn't
234 // for compatibility with MSW return the empty selection at cursor
236 end
= GetInsertionPoint();
246 // ----------------------------------------------------------------------------
248 // ----------------------------------------------------------------------------
250 bool wxTextEntry::DoAutoCompleteStrings(const wxArrayString
& choices
)
252 GtkEntry
* const entry
= GTK_ENTRY(GetEditable());
253 wxCHECK_MSG(entry
, false, "auto completion doesn't work with this control");
255 GtkListStore
* const store
= gtk_list_store_new(1, G_TYPE_STRING
);
258 for ( wxArrayString::const_iterator i
= choices
.begin();
262 gtk_list_store_append(store
, &iter
);
263 gtk_list_store_set(store
, &iter
,
264 0, (const gchar
*)i
->utf8_str(),
268 GtkEntryCompletion
* const completion
= gtk_entry_completion_new();
269 gtk_entry_completion_set_model(completion
, GTK_TREE_MODEL(store
));
270 gtk_entry_completion_set_text_column(completion
, 0);
271 gtk_entry_set_completion(entry
, completion
);
272 g_object_unref(completion
);
276 // ----------------------------------------------------------------------------
278 // ----------------------------------------------------------------------------
280 bool wxTextEntry::IsEditable() const
282 return gtk_editable_get_editable(GetEditable()) != 0;
285 void wxTextEntry::SetEditable(bool editable
)
287 gtk_editable_set_editable(GetEditable(), editable
);
290 // ----------------------------------------------------------------------------
292 // ----------------------------------------------------------------------------
294 void wxTextEntry::SetMaxLength(unsigned long len
)
296 GtkEntry
* const entry
= GTK_ENTRY(GetEditable());
300 gtk_entry_set_max_length(entry
, len
);
302 // there is a bug in GTK+ 1.2.x: "changed" signal is emitted even if we had
303 // tried to enter more text than allowed by max text length and the text
304 // wasn't really changed
306 // to detect this and generate TEXT_MAXLEN event instead of TEXT_CHANGED
307 // one in this case we also catch "insert_text" signal
309 // when max len is set to 0 we disconnect our handler as it means that we
310 // shouldn't check anything any more
317 G_CALLBACK(wx_gtk_insert_text_callback
),
321 else // no max length
323 g_signal_handlers_disconnect_by_func
326 (gpointer
)wx_gtk_insert_text_callback
,
332 void wxTextEntry::SendMaxLenEvent()
334 // remember that the next changed signal is to be ignored to avoid
335 // generating a dummy wxEVT_COMMAND_TEXT_UPDATED event
336 //IgnoreNextTextUpdate();
338 wxWindow
* const win
= GetEditableWindow();
339 wxCommandEvent
event(wxEVT_COMMAND_TEXT_MAXLEN
, win
->GetId());
340 event
.SetEventObject(win
);
341 event
.SetString(GetValue());
342 win
->HandleWindowEvent(event
);
345 // ----------------------------------------------------------------------------
347 // ----------------------------------------------------------------------------
349 bool wxTextEntry::DoSetMargins(const wxPoint
& margins
)
351 #if GTK_CHECK_VERSION(2,10,0)
352 GtkEntry
* entry
= GetEntry();
357 const GtkBorder
* oldBorder
= gtk_entry_get_inner_border(entry
);
358 GtkBorder
* newBorder
;
362 newBorder
= gtk_border_copy(oldBorder
);
366 #if GTK_CHECK_VERSION(2,14,0)
367 newBorder
= gtk_border_new();
369 newBorder
= g_slice_new0(GtkBorder
);
371 // Use some reasonable defaults for initial margins
373 newBorder
->right
= 2;
375 // These numbers seem to let the text remain vertically centered
376 // in common use scenarios when margins.y == -1.
378 newBorder
->bottom
= 3;
381 if ( margins
.x
!= -1 )
382 newBorder
->left
= (gint
) margins
.x
;
384 if ( margins
.y
!= -1 )
385 newBorder
->top
= (gint
) margins
.y
;
387 gtk_entry_set_inner_border(entry
, newBorder
);
389 #if GTK_CHECK_VERSION(2,14,0)
390 gtk_border_free(newBorder
);
392 g_slice_free(GtkBorder
, newBorder
);
397 wxUnusedVar(margins
);
402 wxPoint
wxTextEntry::DoGetMargins() const
404 #if GTK_CHECK_VERSION(2,10,0)
405 GtkEntry
* entry
= GetEntry();
408 return wxPoint(-1, -1);
410 const GtkBorder
* border
= gtk_entry_get_inner_border(entry
);
413 return wxPoint(-1, -1);
415 return wxPoint((wxCoord
) border
->left
, (wxCoord
) border
->top
);
417 return wxPoint(-1, -1);
421 #endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX