]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk1/textctrl.cpp
Added Mac OS X resource file handling:
[wxWidgets.git] / src / gtk1 / textctrl.cpp
index ddd7432d18896c8ada5671d70251eefd6a393e73..c525be6c9c14d736179c88565927e77ede32238e 100644 (file)
@@ -14,7 +14,9 @@
 #include "wx/textctrl.h"
 #include "wx/utils.h"
 #include "wx/intl.h"
 #include "wx/textctrl.h"
 #include "wx/utils.h"
 #include "wx/intl.h"
+#include "wx/log.h"
 #include "wx/settings.h"
 #include "wx/settings.h"
+#include "wx/panel.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -51,6 +53,7 @@ gtk_text_changed_callback( GtkWidget *WXUNUSED(widget), wxTextCtrl *win )
         wxapp_install_idle_handler();
 
     win->SetModified();
         wxapp_install_idle_handler();
 
     win->SetModified();
+    win->UpdateFontIfNeeded();
 
     wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, win->GetId() );
     event.SetString( win->GetValue() );
 
     wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, win->GetId() );
     event.SetString( win->GetValue() );
@@ -73,6 +76,116 @@ gtk_scrollbar_changed_callback( GtkWidget *WXUNUSED(widget), wxTextCtrl *win )
     win->CalculateScrollbar();
 }
 
     win->CalculateScrollbar();
 }
 
+//-----------------------------------------------------------------------------
+// "focus_in_event"
+//-----------------------------------------------------------------------------
+
+wxWindow *FindFocusedChild(wxWindow *win);
+extern wxWindow  *g_focusWindow;
+extern bool       g_blockEventsOnDrag;
+// extern bool g_isIdle;
+
+static gint gtk_text_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
+{
+    // Necessary?
+#if 0
+    if (g_isIdle)
+        wxapp_install_idle_handler();
+#endif
+    if (!win->m_hasVMT) return FALSE;
+    if (g_blockEventsOnDrag) return FALSE;
+
+    g_focusWindow = win;
+
+    wxPanel *panel = wxDynamicCast(win->GetParent(), wxPanel);
+    if (panel)
+    {
+        panel->SetLastFocus(win);
+    }
+
+#ifdef HAVE_XIM
+    if (win->m_ic)
+        gdk_im_begin(win->m_ic, win->m_wxwindow->window);
+#endif
+
+#if 0
+#ifdef wxUSE_CARET
+    // caret needs to be informed about focus change
+    wxCaret *caret = win->GetCaret();
+    if ( caret )
+    {
+        caret->OnSetFocus();
+    }
+#endif // wxUSE_CARET
+#endif
+
+    wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
+    event.SetEventObject( win );
+
+    if (win->GetEventHandler()->ProcessEvent( event ))
+    {
+        gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "focus_out_event"
+//-----------------------------------------------------------------------------
+
+static gint gtk_text_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
+{
+#if 0
+    if (g_isIdle)
+        wxapp_install_idle_handler();
+#endif
+
+    if (!win->m_hasVMT) return FALSE;
+    if (g_blockEventsOnDrag) return FALSE;
+
+#if 0
+    // if the focus goes out of our app alltogether, OnIdle() will send
+    // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
+    // g_sendActivateEvent to -1
+    g_sendActivateEvent = 0;
+#endif
+
+    wxWindow *winFocus = FindFocusedChild(win);
+    if ( winFocus )
+        win = winFocus;
+
+    g_focusWindow = (wxWindow *)NULL;
+
+#ifdef HAVE_XIM
+    if (win->m_ic)
+        gdk_im_end();
+#endif
+
+#if 0
+#ifdef wxUSE_CARET
+    // caret needs to be informed about focus change
+    wxCaret *caret = win->GetCaret();
+    if ( caret )
+    {
+        caret->OnKillFocus();
+    }
+#endif // wxUSE_CARET
+#endif
+
+    wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
+    event.SetEventObject( win );
+
+    if (win->GetEventHandler()->ProcessEvent( event ))
+    {
+        gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
 //-----------------------------------------------------------------------------
 //  wxTextCtrl
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 //  wxTextCtrl
 //-----------------------------------------------------------------------------
@@ -95,9 +208,12 @@ BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
     EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
 END_EVENT_TABLE()
 
     EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
 END_EVENT_TABLE()
 
-wxTextCtrl::wxTextCtrl()
+void wxTextCtrl::Init()
 {
     m_modified = FALSE;
 {
     m_modified = FALSE;
+    m_updateFont = FALSE;
+    m_text =
+    m_vScrollbar = (GtkWidget *)NULL;
 }
 
 wxTextCtrl::wxTextCtrl( wxWindow *parent,
 }
 
 wxTextCtrl::wxTextCtrl( wxWindow *parent,
@@ -109,7 +225,8 @@ wxTextCtrl::wxTextCtrl( wxWindow *parent,
                         const wxValidator& validator,
                         const wxString &name )
 {
                         const wxValidator& validator,
                         const wxString &name )
 {
-    m_modified = FALSE;
+    Init();
+
     Create( parent, id, value, pos, size, style, validator, name );
 }
 
     Create( parent, id, value, pos, size, style, validator, name );
 }
 
@@ -210,14 +327,24 @@ bool wxTextCtrl::Create( wxWindow *parent,
     if (multi_line)
         gtk_widget_show(m_text);
 
     if (multi_line)
         gtk_widget_show(m_text);
 
-    /* we want to be notified about text changes */
-    gtk_signal_connect( GTK_OBJECT(m_text), "changed",
-      GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
-
     if (multi_line)
     {
         gtk_signal_connect(GTK_OBJECT(GTK_TEXT(m_text)->vadj), "changed",
           (GtkSignalFunc) gtk_scrollbar_changed_callback, (gpointer) this );
     if (multi_line)
     {
         gtk_signal_connect(GTK_OBJECT(GTK_TEXT(m_text)->vadj), "changed",
           (GtkSignalFunc) gtk_scrollbar_changed_callback, (gpointer) this );
+
+        gtk_signal_connect( GTK_OBJECT(GTK_TEXT(m_text)), "focus_in_event",
+              GTK_SIGNAL_FUNC(gtk_text_focus_in_callback), (gpointer)this );
+
+        gtk_signal_connect( GTK_OBJECT(GTK_TEXT(m_text)), "focus_out_event",
+                           GTK_SIGNAL_FUNC(gtk_text_focus_out_callback), (gpointer)this );
+    }
+    else
+    {
+        gtk_signal_connect( GTK_OBJECT(m_text), "focus_in_event",
+              GTK_SIGNAL_FUNC(gtk_text_focus_in_callback), (gpointer)this );
+
+        gtk_signal_connect( GTK_OBJECT(m_text), "focus_out_event",
+                           GTK_SIGNAL_FUNC(gtk_text_focus_out_callback), (gpointer)this );
     }
 
     if (!value.IsEmpty())
     }
 
     if (!value.IsEmpty())
@@ -262,6 +389,10 @@ bool wxTextCtrl::Create( wxWindow *parent,
             gtk_text_set_editable( GTK_TEXT(m_text), 1 );
     }
 
             gtk_text_set_editable( GTK_TEXT(m_text), 1 );
     }
 
+    /* we want to be notified about text changes */
+    gtk_signal_connect( GTK_OBJECT(m_text), "changed",
+      GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
+
     SetBackgroundColour( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW) );
     SetForegroundColour( parent->GetForegroundColour() );
 
     SetBackgroundColour( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW) );
     SetForegroundColour( parent->GetForegroundColour() );
 
@@ -319,24 +450,29 @@ void wxTextCtrl::SetValue( const wxString &value )
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
-    wxString tmp = wxT("");
-    if (!value.IsNull()) tmp = value;
     if (m_windowStyle & wxTE_MULTILINE)
     {
         gint len = gtk_text_get_length( GTK_TEXT(m_text) );
         gtk_editable_delete_text( GTK_EDITABLE(m_text), 0, len );
         len = 0;
 #if wxUSE_UNICODE
     if (m_windowStyle & wxTE_MULTILINE)
     {
         gint len = gtk_text_get_length( GTK_TEXT(m_text) );
         gtk_editable_delete_text( GTK_EDITABLE(m_text), 0, len );
         len = 0;
 #if wxUSE_UNICODE
-        wxWX2MBbuf tmpbuf = tmp.mbc_str();
+        wxWX2MBbuf tmpbuf = value.mbc_str();
         gtk_editable_insert_text( GTK_EDITABLE(m_text), tmpbuf, strlen(tmpbuf), &len );
 #else
         gtk_editable_insert_text( GTK_EDITABLE(m_text), tmpbuf, strlen(tmpbuf), &len );
 #else
-        gtk_editable_insert_text( GTK_EDITABLE(m_text), tmp.mbc_str(), tmp.Length(), &len );
+        gtk_editable_insert_text( GTK_EDITABLE(m_text), value.mbc_str(), value.Length(), &len );
 #endif
     }
     else
     {
 #endif
     }
     else
     {
-        gtk_entry_set_text( GTK_ENTRY(m_text), tmp.mbc_str() );
+        gtk_entry_set_text( GTK_ENTRY(m_text), value.mbc_str() );
     }
     }
+
+    // GRG, Jun/2000: Changed this after a lot of discussion in
+    //   the lists. wxWindows 2.2 will have a set of flags to
+    //   customize this behaviour.
+    SetInsertionPoint(0);
+
+    m_modified = FALSE;
 }
 
 void wxTextCtrl::WriteText( const wxString &text )
 }
 
 void wxTextCtrl::WriteText( const wxString &text )
@@ -607,6 +743,26 @@ void wxTextCtrl::SetEditable( bool editable )
         gtk_entry_set_editable( GTK_ENTRY(m_text), editable );
 }
 
         gtk_entry_set_editable( GTK_ENTRY(m_text), editable );
 }
 
+bool wxTextCtrl::Enable( bool enable )
+{
+    if (!wxWindowBase::Enable(enable))
+    {
+        // nothing to do
+        return FALSE;
+    }
+
+    if (m_windowStyle & wxTE_MULTILINE)
+    {
+        gtk_text_set_editable( GTK_TEXT(m_text), enable );
+    }
+    else
+    {
+        gtk_widget_set_sensitive( m_text, enable );
+    }
+
+    return TRUE;
+}
+
 void wxTextCtrl::DiscardEdits()
 {
     m_modified = FALSE;
 void wxTextCtrl::DiscardEdits()
 {
     m_modified = FALSE;
@@ -616,6 +772,14 @@ void wxTextCtrl::SetSelection( long from, long to )
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
+    if ( (m_windowStyle & wxTE_MULTILINE) &&
+         !GTK_TEXT(m_text)->line_start_cache )
+    {
+        // tell the programmer that it didn't work
+        wxLogDebug(_T("Can't call SetSelection() before realizing the control"));
+        return;
+    }
+
     gtk_editable_select_region( GTK_EDITABLE(m_text), (gint)from, (gint)to );
 }
 
     gtk_editable_select_region( GTK_EDITABLE(m_text), (gint)from, (gint)to );
 }
 
@@ -715,7 +879,7 @@ bool wxTextCtrl::CanCut() const
     // Can cut if there's a selection
     long from, to;
     GetSelection(& from, & to);
     // Can cut if there's a selection
     long from, to;
     GetSelection(& from, & to);
-    return (from != to) ;
+    return (from != to) && (IsEditable());
 }
 
 bool wxTextCtrl::CanPaste() const
 }
 
 bool wxTextCtrl::CanPaste() const
@@ -758,8 +922,9 @@ void wxTextCtrl::GetSelection(long* from, long* to) const
 
     if (!(GTK_EDITABLE(m_text)->has_selection))
     {
 
     if (!(GTK_EDITABLE(m_text)->has_selection))
     {
-        if (from) *from = 0;
-        if (to)   *to = 0;
+        long i = GetInsertionPoint();
+        if (from) *from = i;
+        if (to)   *to = i;
         return;
     }
 
         return;
     }
 
@@ -792,6 +957,7 @@ void wxTextCtrl::OnChar( wxKeyEvent &key_event )
     {
         wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
         event.SetEventObject(this);
     {
         wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
         event.SetEventObject(this);
+        event.SetString(GetValue());
         if (GetEventHandler()->ProcessEvent(event)) return;
     }
 
         if (GetEventHandler()->ProcessEvent(event)) return;
     }
 
@@ -838,20 +1004,37 @@ bool wxTextCtrl::SetFont( const wxFont &font )
 
     if ( m_windowStyle & wxTE_MULTILINE )
     {
 
     if ( m_windowStyle & wxTE_MULTILINE )
     {
-        // for compatibility with other ports: the font is a global controls
-        // characteristic, so change the font globally
-        wxString value = GetValue();
-        if ( !value.IsEmpty() )
-        {
-            Clear();
+        m_updateFont = TRUE;
 
 
-            AppendText(value);
-        }
+        ChangeFontGlobally();
     }
 
     return TRUE;
 }
 
     }
 
     return TRUE;
 }
 
+void wxTextCtrl::ChangeFontGlobally()
+{
+    // this method is very inefficient and hence should be called as rarely as
+    // possible!
+    wxASSERT_MSG( (m_windowStyle & wxTE_MULTILINE) && m_updateFont,
+                  _T("shouldn't be called for single line controls") );
+
+    wxString value = GetValue();
+    if ( !value.IsEmpty() )
+    {
+        Clear();
+        AppendText(value);
+
+        m_updateFont = FALSE;
+    }
+}
+
+void wxTextCtrl::UpdateFontIfNeeded()
+{
+    if ( m_updateFont )
+        ChangeFontGlobally();
+}
+
 bool wxTextCtrl::SetForegroundColour( const wxColour &WXUNUSED(colour) )
 {
     wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
 bool wxTextCtrl::SetForegroundColour( const wxColour &WXUNUSED(colour) )
 {
     wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );