]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/textentry.cpp
Supress SetFocus() warning in wxVListBoxComboPopup
[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
9a83f860 55 wxCHECK_RET( entry->text_max_length, wxT("shouldn't be called") );
0ec1179b
VZ
56
57 // check that we don't overflow the max length limit
58 //
59 // FIXME: this doesn't work when we paste a string which is going to be
60 // truncated
61 if ( entry->text_length == entry->text_max_length )
62 {
63 // we don't need to run the base class version at all
64 g_signal_stop_emission_by_name (editable, "insert_text");
65
66 text->SendMaxLenEvent();
67 }
68}
69
70} // extern "C"
71
72// ============================================================================
73// wxTextEntry implementation
74// ============================================================================
75
76// ----------------------------------------------------------------------------
77// text operations
78// ----------------------------------------------------------------------------
79
80void wxTextEntry::WriteText(const wxString& value)
81{
82 GtkEditable * const edit = GetEditable();
83
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,
86 // not two
87 {
88 EventsSuppressor noevents(this);
89 gtk_editable_delete_selection(edit);
90 }
91
92 // insert new text at the cursor position
93 gint len = gtk_editable_get_position(edit);
94 gtk_editable_insert_text
95 (
96 edit,
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
100 );
101
102 // and move cursor to the end of new text
103 gtk_editable_set_position(edit, len);
104}
105
135b23b2 106wxString wxTextEntry::DoGetValue() const
0ec1179b
VZ
107{
108 const wxGtkString value(gtk_editable_get_chars(GetEditable(), 0, -1));
109
ec592d7f
VZ
110 return wxGTK_CONV_BACK_FONT(value,
111 const_cast<wxTextEntry *>(this)->GetEditableWindow()->GetFont());
0ec1179b
VZ
112}
113
114void wxTextEntry::Remove(long from, long to)
115{
116 gtk_editable_delete_text(GetEditable(), from, to);
117}
118
119// ----------------------------------------------------------------------------
120// clipboard operations
121// ----------------------------------------------------------------------------
122
123void wxTextEntry::Copy()
124{
125 gtk_editable_copy_clipboard(GetEditable());
126}
127
128void wxTextEntry::Cut()
129{
130 gtk_editable_cut_clipboard(GetEditable());
131}
132
133void wxTextEntry::Paste()
134{
135 gtk_editable_paste_clipboard(GetEditable());
136}
137
138// ----------------------------------------------------------------------------
139// undo/redo
140// ----------------------------------------------------------------------------
141
142void wxTextEntry::Undo()
143{
144 // TODO: not implemented
145}
146
147void wxTextEntry::Redo()
148{
149 // TODO: not implemented
150}
151
152bool wxTextEntry::CanUndo() const
153{
154 return false;
155}
156
157bool wxTextEntry::CanRedo() const
158{
159 return false;
160}
161
162// ----------------------------------------------------------------------------
163// insertion point
164// ----------------------------------------------------------------------------
165
166void wxTextEntry::SetInsertionPoint(long pos)
167{
168 gtk_editable_set_position(GetEditable(), pos);
169}
170
171long wxTextEntry::GetInsertionPoint() const
172{
173 return gtk_editable_get_position(GetEditable());
174}
175
176long wxTextEntry::GetLastPosition() const
177{
178 // this can't be implemented for arbitrary GtkEditable so only do it for
179 // GtkEntries
180 GtkEntry * const entry = GTK_ENTRY(GetEditable());
181
182 return entry ? entry->text_length : - 1;
183}
184
185// ----------------------------------------------------------------------------
186// selection
187// ----------------------------------------------------------------------------
188
189void wxTextEntry::SetSelection(long from, long to)
190{
e0721133
VZ
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 )
195 from = 0;
196
8b2e0e6d
VZ
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);
0ec1179b
VZ
201}
202
203void wxTextEntry::GetSelection(long *from, long *to) const
204{
205 gint start, end;
206 if ( gtk_editable_get_selection_bounds(GetEditable(), &start, &end) )
207 {
208 // the output must always be in order, although in GTK+ it isn't
209 if ( start > end )
210 {
211 gint tmp = start;
212 start = end;
213 end = tmp;
214 }
215 }
216 else // no selection
217 {
218 // for compatibility with MSW return the empty selection at cursor
219 start =
220 end = GetInsertionPoint();
221 }
222
223 if ( from )
224 *from = start;
225
226 if ( to )
227 *to = end;
228}
229
230// ----------------------------------------------------------------------------
ecaed0bc
VZ
231// auto completion
232// ----------------------------------------------------------------------------
233
0c3d1aa7 234bool wxTextEntry::AutoComplete(const wxArrayString& choices)
ecaed0bc
VZ
235{
236 GtkEntry * const entry = GTK_ENTRY(GetEditable());
0c3d1aa7 237 wxCHECK_MSG(entry, false, "auto completion doesn't work with this control");
ecaed0bc
VZ
238
239 GtkListStore * const store = gtk_list_store_new(1, G_TYPE_STRING);
240 GtkTreeIter iter;
241
242 for ( wxArrayString::const_iterator i = choices.begin();
243 i != choices.end();
244 ++i )
245 {
246 gtk_list_store_append(store, &iter);
247 gtk_list_store_set(store, &iter,
248 0, (const gchar *)i->utf8_str(),
249 -1);
250 }
251
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);
0c3d1aa7 257 return true;
ecaed0bc
VZ
258}
259
260// ----------------------------------------------------------------------------
0ec1179b
VZ
261// editable status
262// ----------------------------------------------------------------------------
263
264bool wxTextEntry::IsEditable() const
265{
266 return gtk_editable_get_editable(GetEditable());
267}
268
269void wxTextEntry::SetEditable(bool editable)
270{
271 gtk_editable_set_editable(GetEditable(), editable);
272}
273
274// ----------------------------------------------------------------------------
275// max text length
276// ----------------------------------------------------------------------------
277
278void wxTextEntry::SetMaxLength(unsigned long len)
279{
280 GtkEntry * const entry = GTK_ENTRY(GetEditable());
281 if ( !entry )
282 return;
283
284 gtk_entry_set_max_length(entry, len);
285
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
289 //
290 // to detect this and generate TEXT_MAXLEN event instead of TEXT_CHANGED
291 // one in this case we also catch "insert_text" signal
292 //
293 // when max len is set to 0 we disconnect our handler as it means that we
294 // shouldn't check anything any more
295 if ( len )
296 {
297 g_signal_connect
298 (
299 entry,
300 "insert_text",
301 G_CALLBACK(wx_gtk_insert_text_callback),
302 this
303 );
304 }
305 else // no max length
306 {
307 g_signal_handlers_disconnect_by_func
308 (
309 entry,
310 (gpointer)wx_gtk_insert_text_callback,
311 this
312 );
313 }
314}
315
316void wxTextEntry::SendMaxLenEvent()
317{
318 // remember that the next changed signal is to be ignored to avoid
319 // generating a dummy wxEVT_COMMAND_TEXT_UPDATED event
320 //IgnoreNextTextUpdate();
321
ec592d7f 322 wxWindow * const win = GetEditableWindow();
0ec1179b
VZ
323 wxCommandEvent event(wxEVT_COMMAND_TEXT_MAXLEN, win->GetId());
324 event.SetEventObject(win);
325 event.SetString(GetValue());
937013e0 326 win->HandleWindowEvent(event);
0ec1179b
VZ
327}
328
0847e36e
JS
329// ----------------------------------------------------------------------------
330// margins support
331// ----------------------------------------------------------------------------
332
333bool wxTextEntry::DoSetMargins(const wxPoint& margins)
334{
335#if GTK_CHECK_VERSION(2,10,0)
336 GtkEntry* entry = GetEntry();
337
338 if ( !entry )
339 return false;
340
341 const GtkBorder* oldBorder = gtk_entry_get_inner_border(entry);
342 GtkBorder* newBorder;
343
344 if ( oldBorder )
345 {
346 newBorder = gtk_border_copy(oldBorder);
347 }
348 else
349 {
350 #if GTK_CHECK_VERSION(2,14,0)
351 newBorder = gtk_border_new();
352 #else
c39b6e1e 353 newBorder = g_slice_new0(GtkBorder);
0847e36e
JS
354 #endif
355 // Use some reasonable defaults for initial margins
356 newBorder->left = 2;
357 newBorder->right = 2;
358
359 // These numbers seem to let the text remain vertically centered
360 // in common use scenarios when margins.y == -1.
361 newBorder->top = 3;
362 newBorder->bottom = 3;
363 }
364
365 if ( margins.x != -1 )
366 newBorder->left = (gint) margins.x;
367
368 if ( margins.y != -1 )
369 newBorder->top = (gint) margins.y;
370
371 gtk_entry_set_inner_border(entry, newBorder);
372
c39b6e1e
JS
373#if GTK_CHECK_VERSION(2,14,0)
374 gtk_border_free(newBorder);
375#else
376 g_slice_free(GtkBorder, newBorder);
377#endif
378
0847e36e
JS
379 return true;
380#else
381 wxUnusedVar(margins);
382 return false;
383#endif
384}
385
386wxPoint wxTextEntry::DoGetMargins() const
387{
388#if GTK_CHECK_VERSION(2,10,0)
389 GtkEntry* entry = GetEntry();
390
391 if ( !entry )
392 return wxPoint(-1, -1);
393
394 const GtkBorder* border = gtk_entry_get_inner_border(entry);
395
396 if ( !border )
397 return wxPoint(-1, -1);
398
399 return wxPoint((wxCoord) border->left, (wxCoord) border->top);
400#else
401 return wxPoint(-1, -1);
402#endif
403}
404
96a4cdeb 405#endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX