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 wxCHECK_RET( entry
->text_max_length
, wxT("shouldn't be called") );
57 // check that we don't overflow the max length limit
59 // FIXME: this doesn't work when we paste a string which is going to be
61 if ( entry
->text_length
== entry
->text_max_length
)
63 // we don't need to run the base class version at all
64 g_signal_stop_emission_by_name (editable
, "insert_text");
66 text
->SendMaxLenEvent();
72 // ============================================================================
73 // wxTextEntry implementation
74 // ============================================================================
76 // ----------------------------------------------------------------------------
78 // ----------------------------------------------------------------------------
80 void wxTextEntry::WriteText(const wxString
& value
)
82 GtkEditable
* const edit
= GetEditable();
84 // remove the selection if there is one and suppress the text change event
85 // generated by this: we only want to generate one event for this change,
88 EventsSuppressor
noevents(this);
89 gtk_editable_delete_selection(edit
);
92 // insert new text at the cursor position
93 gint len
= gtk_editable_get_position(edit
);
94 gtk_editable_insert_text
97 wxGTK_CONV_FONT(value
, GetEditableWindow()->GetFont()),
98 -1, // text: length: compute it using strlen()
99 &len
// will be updated to position after the text end
102 // and move cursor to the end of new text
103 gtk_editable_set_position(edit
, len
);
106 wxString
wxTextEntry::DoGetValue() const
108 const wxGtkString
value(gtk_editable_get_chars(GetEditable(), 0, -1));
110 return wxGTK_CONV_BACK_FONT(value
,
111 const_cast<wxTextEntry
*>(this)->GetEditableWindow()->GetFont());
114 void wxTextEntry::Remove(long from
, long to
)
116 gtk_editable_delete_text(GetEditable(), from
, to
);
119 // ----------------------------------------------------------------------------
120 // clipboard operations
121 // ----------------------------------------------------------------------------
123 void wxTextEntry::Copy()
125 gtk_editable_copy_clipboard(GetEditable());
128 void wxTextEntry::Cut()
130 gtk_editable_cut_clipboard(GetEditable());
133 void wxTextEntry::Paste()
135 gtk_editable_paste_clipboard(GetEditable());
138 // ----------------------------------------------------------------------------
140 // ----------------------------------------------------------------------------
142 void wxTextEntry::Undo()
144 // TODO: not implemented
147 void wxTextEntry::Redo()
149 // TODO: not implemented
152 bool wxTextEntry::CanUndo() const
157 bool wxTextEntry::CanRedo() const
162 // ----------------------------------------------------------------------------
164 // ----------------------------------------------------------------------------
166 void wxTextEntry::SetInsertionPoint(long pos
)
168 gtk_editable_set_position(GetEditable(), pos
);
171 long wxTextEntry::GetInsertionPoint() const
173 return gtk_editable_get_position(GetEditable());
176 long wxTextEntry::GetLastPosition() const
178 // this can't be implemented for arbitrary GtkEditable so only do it for
180 GtkEntry
* const entry
= GTK_ENTRY(GetEditable());
182 return entry
? entry
->text_length
: - 1;
185 // ----------------------------------------------------------------------------
187 // ----------------------------------------------------------------------------
189 void wxTextEntry::SetSelection(long from
, long to
)
191 // in wx convention, (-1, -1) means the entire range but GTK+ translates -1
192 // (or any negative number for that matter) into last position so we need
193 // to translate manually
194 if ( from
== -1 && to
== -1 )
197 // for compatibility with MSW, exchange from and to parameters so that the
198 // insertion point is set to the start of the selection and not its end as
199 // GTK+ does by default
200 gtk_editable_select_region(GetEditable(), to
, from
);
203 void wxTextEntry::GetSelection(long *from
, long *to
) const
206 if ( gtk_editable_get_selection_bounds(GetEditable(), &start
, &end
) )
208 // the output must always be in order, although in GTK+ it isn't
218 // for compatibility with MSW return the empty selection at cursor
220 end
= GetInsertionPoint();
230 // ----------------------------------------------------------------------------
232 // ----------------------------------------------------------------------------
234 bool wxTextEntry::AutoComplete(const wxArrayString
& choices
)
236 GtkEntry
* const entry
= GTK_ENTRY(GetEditable());
237 wxCHECK_MSG(entry
, false, "auto completion doesn't work with this control");
239 GtkListStore
* const store
= gtk_list_store_new(1, G_TYPE_STRING
);
242 for ( wxArrayString::const_iterator i
= choices
.begin();
246 gtk_list_store_append(store
, &iter
);
247 gtk_list_store_set(store
, &iter
,
248 0, (const gchar
*)i
->utf8_str(),
252 GtkEntryCompletion
* const completion
= gtk_entry_completion_new();
253 gtk_entry_completion_set_model(completion
, GTK_TREE_MODEL(store
));
254 gtk_entry_completion_set_text_column(completion
, 0);
255 gtk_entry_set_completion(entry
, completion
);
256 g_object_unref(completion
);
260 // ----------------------------------------------------------------------------
262 // ----------------------------------------------------------------------------
264 bool wxTextEntry::IsEditable() const
266 return gtk_editable_get_editable(GetEditable());
269 void wxTextEntry::SetEditable(bool editable
)
271 gtk_editable_set_editable(GetEditable(), editable
);
274 // ----------------------------------------------------------------------------
276 // ----------------------------------------------------------------------------
278 void wxTextEntry::SetMaxLength(unsigned long len
)
280 GtkEntry
* const entry
= GTK_ENTRY(GetEditable());
284 gtk_entry_set_max_length(entry
, len
);
286 // there is a bug in GTK+ 1.2.x: "changed" signal is emitted even if we had
287 // tried to enter more text than allowed by max text length and the text
288 // wasn't really changed
290 // to detect this and generate TEXT_MAXLEN event instead of TEXT_CHANGED
291 // one in this case we also catch "insert_text" signal
293 // when max len is set to 0 we disconnect our handler as it means that we
294 // shouldn't check anything any more
301 G_CALLBACK(wx_gtk_insert_text_callback
),
305 else // no max length
307 g_signal_handlers_disconnect_by_func
310 (gpointer
)wx_gtk_insert_text_callback
,
316 void wxTextEntry::SendMaxLenEvent()
318 // remember that the next changed signal is to be ignored to avoid
319 // generating a dummy wxEVT_COMMAND_TEXT_UPDATED event
320 //IgnoreNextTextUpdate();
322 wxWindow
* const win
= GetEditableWindow();
323 wxCommandEvent
event(wxEVT_COMMAND_TEXT_MAXLEN
, win
->GetId());
324 event
.SetEventObject(win
);
325 event
.SetString(GetValue());
326 win
->HandleWindowEvent(event
);
329 // ----------------------------------------------------------------------------
331 // ----------------------------------------------------------------------------
333 bool wxTextEntry::DoSetMargins(const wxPoint
& margins
)
335 #if GTK_CHECK_VERSION(2,10,0)
336 GtkEntry
* entry
= GetEntry();
341 const GtkBorder
* oldBorder
= gtk_entry_get_inner_border(entry
);
342 GtkBorder
* newBorder
;
346 newBorder
= gtk_border_copy(oldBorder
);
350 #if GTK_CHECK_VERSION(2,14,0)
351 newBorder
= gtk_border_new();
353 newBorder
= g_slice_new0(GtkBorder
);
355 // Use some reasonable defaults for initial margins
357 newBorder
->right
= 2;
359 // These numbers seem to let the text remain vertically centered
360 // in common use scenarios when margins.y == -1.
362 newBorder
->bottom
= 3;
365 if ( margins
.x
!= -1 )
366 newBorder
->left
= (gint
) margins
.x
;
368 if ( margins
.y
!= -1 )
369 newBorder
->top
= (gint
) margins
.y
;
371 gtk_entry_set_inner_border(entry
, newBorder
);
373 #if GTK_CHECK_VERSION(2,14,0)
374 gtk_border_free(newBorder
);
376 g_slice_free(GtkBorder
, newBorder
);
381 wxUnusedVar(margins
);
386 wxPoint
wxTextEntry::DoGetMargins() const
388 #if GTK_CHECK_VERSION(2,10,0)
389 GtkEntry
* entry
= GetEntry();
392 return wxPoint(-1, -1);
394 const GtkBorder
* border
= gtk_entry_get_inner_border(entry
);
397 return wxPoint(-1, -1);
399 return wxPoint((wxCoord
) border
->left
, (wxCoord
) border
->top
);
401 return wxPoint(-1, -1);
405 #endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX