]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/textctrl.cpp
added translation of mac system into language, adaption of search paths
[wxWidgets.git] / src / gtk / textctrl.cpp
index 841605437b58d24d1ae87b7bb8ae2a111c46e3c1..f16643b0c74218275e3ac7100832e24fa35324e6 100644 (file)
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <ctype.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <ctype.h>
+#include <math.h>               // for fabs
 
 #include "gdk/gdk.h"
 #include "gtk/gtk.h"
 
 #include "gdk/gdk.h"
 #include "gtk/gtk.h"
@@ -80,7 +81,6 @@ gtk_scrollbar_changed_callback( GtkWidget *WXUNUSED(widget), wxTextCtrl *win )
 // "focus_in_event"
 //-----------------------------------------------------------------------------
 
 // "focus_in_event"
 //-----------------------------------------------------------------------------
 
-wxWindow *FindFocusedChild(wxWindow *win);
 extern wxWindow  *g_focusWindow;
 extern bool       g_blockEventsOnDrag;
 // extern bool g_isIdle;
 extern wxWindow  *g_focusWindow;
 extern bool       g_blockEventsOnDrag;
 // extern bool g_isIdle;
@@ -97,11 +97,9 @@ static gint gtk_text_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(ev
 
     g_focusWindow = win;
 
 
     g_focusWindow = win;
 
-    wxPanel *panel = wxDynamicCast(win->GetParent(), wxPanel);
-    if (panel)
-    {
-        panel->SetLastFocus(win);
-    }
+    // notify the parent that we got the focus
+    wxChildFocusEvent eventFocus(win);
+    (void)win->GetEventHandler()->ProcessEvent(eventFocus);
 
 #ifdef HAVE_XIM
     if (win->m_ic)
 
 #ifdef HAVE_XIM
     if (win->m_ic)
@@ -124,7 +122,6 @@ static gint gtk_text_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(ev
 
     if (win->GetEventHandler()->ProcessEvent( event ))
     {
 
     if (win->GetEventHandler()->ProcessEvent( event ))
     {
-        gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
         return TRUE;
     }
 
         return TRUE;
     }
 
@@ -152,7 +149,7 @@ static gint gtk_text_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(e
     g_sendActivateEvent = 0;
 #endif
 
     g_sendActivateEvent = 0;
 #endif
 
-    wxWindow *winFocus = FindFocusedChild(win);
+    wxWindow *winFocus = wxFindFocusedChild(win);
     if ( winFocus )
         win = winFocus;
 
     if ( winFocus )
         win = winFocus;
 
@@ -179,7 +176,6 @@ static gint gtk_text_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(e
 
     if (win->GetEventHandler()->ProcessEvent( event ))
     {
 
     if (win->GetEventHandler()->ProcessEvent( event ))
     {
-        gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
         return TRUE;
     }
 
         return TRUE;
     }
 
@@ -393,11 +389,21 @@ bool wxTextCtrl::Create( wxWindow *parent,
     gtk_signal_connect( GTK_OBJECT(m_text), "changed",
       GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
 
     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() );
+    /* we don't set a valid background colour, because the window
+       manager should use a default one */
+    m_backgroundColour = wxColour();
+
+    wxColour colFg = parent->GetForegroundColour();
+    SetForegroundColour( colFg );
 
     m_cursor = wxCursor( wxCURSOR_IBEAM );
 
 
     m_cursor = wxCursor( wxCURSOR_IBEAM );
 
+    // FIXME: is the bg colour correct here?
+    wxTextAttr attrDef( colFg,
+                        wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW),
+                        parent->GetFont() );
+    SetDefaultStyle( attrDef );
+
     Show( TRUE );
 
     return TRUE;
     Show( TRUE );
 
     return TRUE;
@@ -479,33 +485,53 @@ void wxTextCtrl::WriteText( const wxString &text )
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
-    if (text.IsEmpty()) return;
+    if ( text.empty() )
+        return;
 
 
-    if (m_windowStyle & wxTE_MULTILINE)
+#if wxUSE_UNICODE
+    wxWX2MBbuf buf = text.mbc_str();
+    const char *txt = buf;
+    size_t txtlen = strlen(buf);
+#else
+    const char *txt = text;
+    size_t txtlen = text.length();
+#endif
+
+    if ( m_windowStyle & wxTE_MULTILINE )
     {
         /* this moves the cursor pos to behind the inserted text */
         gint len = GTK_EDITABLE(m_text)->current_pos;
 
     {
         /* this moves the cursor pos to behind the inserted text */
         gint len = GTK_EDITABLE(m_text)->current_pos;
 
-#if wxUSE_UNICODE
-        wxWX2MBbuf buf = text.mbc_str();
-        gtk_editable_insert_text( GTK_EDITABLE(m_text), buf, strlen(buf), &len );
-#else
-        gtk_editable_insert_text( GTK_EDITABLE(m_text), text, text.Length(), &len );
-#endif
+        // if we have any special style, use it
+        if ( !m_defaultStyle.IsDefault() )
+        {
+            GdkFont *font = m_defaultStyle.HasFont()
+                                ? m_defaultStyle.GetFont().GetInternalFont()
+                                : NULL;
+
+            GdkColor *colFg = m_defaultStyle.HasTextColour()
+                                ? m_defaultStyle.GetTextColour().GetColor()
+                                : NULL;
+
+            GdkColor *colBg = m_defaultStyle.HasBackgroundColour()
+                                ? m_defaultStyle.GetBackgroundColour().GetColor()
+                                : NULL;
+
+            gtk_text_insert( GTK_TEXT(m_text), font, colFg, colBg, txt, txtlen );
+        }
+        else // no style
+        {
+            gtk_editable_insert_text( GTK_EDITABLE(m_text), txt, txtlen, &len );
+        }
 
         /* bring editable's cursor uptodate. bug in GTK. */
         GTK_EDITABLE(m_text)->current_pos = gtk_text_get_point( GTK_TEXT(m_text) );
     }
 
         /* bring editable's cursor uptodate. bug in GTK. */
         GTK_EDITABLE(m_text)->current_pos = gtk_text_get_point( GTK_TEXT(m_text) );
     }
-    else
+    else // single line
     {
         /* this moves the cursor pos to behind the inserted text */
         gint len = GTK_EDITABLE(m_text)->current_pos;
     {
         /* this moves the cursor pos to behind the inserted text */
         gint len = GTK_EDITABLE(m_text)->current_pos;
-#if wxUSE_UNICODE
-        wxWX2MBbuf buf = text.mbc_str();
-        gtk_editable_insert_text( GTK_EDITABLE(m_text), buf, strlen(buf), &len );
-#else
-        gtk_editable_insert_text( GTK_EDITABLE(m_text), text, text.Length(), &len );
-#endif
+        gtk_editable_insert_text( GTK_EDITABLE(m_text), txt, txtlen, &len );
 
         /* bring editable's cursor uptodate. bug in GTK. */
         GTK_EDITABLE(m_text)->current_pos += text.Len();
 
         /* bring editable's cursor uptodate. bug in GTK. */
         GTK_EDITABLE(m_text)->current_pos += text.Len();
@@ -519,40 +545,51 @@ void wxTextCtrl::AppendText( const wxString &text )
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
-    if (text.IsEmpty()) return;
+    if ( text.empty() )
+        return;
+
+#if wxUSE_UNICODE
+    wxWX2MBbuf buf = text.mbc_str();
+    const char *txt = buf;
+    size_t txtlen = strlen(buf);
+#else
+    const char *txt = text;
+    size_t txtlen = text.length();
+#endif
 
     if (m_windowStyle & wxTE_MULTILINE)
     {
 
     if (m_windowStyle & wxTE_MULTILINE)
     {
-        bool hasSpecialAttributes = m_font.Ok() ||
-                                    m_foregroundColour.Ok() ||
-                                    m_backgroundColour.Ok();
-        if ( hasSpecialAttributes )
+        if ( !m_defaultStyle.IsDefault() )
         {
         {
-             gtk_text_insert( GTK_TEXT(m_text),
-                              m_font.GetInternalFont(),
-                              m_foregroundColour.GetColor(),
-                              m_backgroundColour.GetColor(),
-                              text.mbc_str(), text.length());
+            wxFont font = m_defaultStyle.HasFont() ? m_defaultStyle.GetFont()
+                                                   : m_font;
+            GdkFont *fnt = font.Ok() ? font.GetInternalFont() : NULL;
 
 
+            wxColour col = m_defaultStyle.HasTextColour()
+                                ? m_defaultStyle.GetTextColour()
+                                : m_foregroundColour;
+            GdkColor *colFg = col.Ok() ? col.GetColor() : NULL;
+
+            col = m_defaultStyle.HasBackgroundColour()
+                    ? m_defaultStyle.GetBackgroundColour()
+                    : m_backgroundColour;
+            GdkColor *colBg = col.Ok() ? col.GetColor() : NULL;
+
+            gtk_text_insert( GTK_TEXT(m_text), fnt, colFg, colBg, txt, txtlen );
         }
         }
-        else
+        else // no style
         {
             /* we'll insert at the last position */
             gint len = gtk_text_get_length( GTK_TEXT(m_text) );
         {
             /* we'll insert at the last position */
             gint len = gtk_text_get_length( GTK_TEXT(m_text) );
-#if wxUSE_UNICODE
-            wxWX2MBbuf buf = text.mbc_str();
-            gtk_editable_insert_text( GTK_EDITABLE(m_text), buf, strlen(buf), &len );
-#else
-            gtk_editable_insert_text( GTK_EDITABLE(m_text), text, text.Length(), &len );
-#endif
+            gtk_editable_insert_text( GTK_EDITABLE(m_text), txt, txtlen, &len );
         }
 
         /* bring editable's cursor uptodate. bug in GTK. */
         GTK_EDITABLE(m_text)->current_pos = gtk_text_get_point( GTK_TEXT(m_text) );
     }
         }
 
         /* bring editable's cursor uptodate. bug in GTK. */
         GTK_EDITABLE(m_text)->current_pos = gtk_text_get_point( GTK_TEXT(m_text) );
     }
-    else
+    else // single line
     {
     {
-        gtk_entry_append_text( GTK_ENTRY(m_text), text.mbc_str() );
+        gtk_entry_append_text( GTK_ENTRY(m_text), txt );
     }
 }
 
     }
 }
 
@@ -754,6 +791,7 @@ bool wxTextCtrl::Enable( bool enable )
     if (m_windowStyle & wxTE_MULTILINE)
     {
         gtk_text_set_editable( GTK_TEXT(m_text), enable );
     if (m_windowStyle & wxTE_MULTILINE)
     {
         gtk_text_set_editable( GTK_TEXT(m_text), enable );
+        OnParentEnable(enable);
     }
     else
     {
     }
     else
     {
@@ -763,6 +801,26 @@ bool wxTextCtrl::Enable( bool enable )
     return TRUE;
 }
 
     return TRUE;
 }
 
+// wxGTK-specific: called recursively by Enable,
+// to give widgets an oppprtunity to correct their colours after they
+// have been changed by Enable
+void wxTextCtrl::OnParentEnable( bool enable )
+{
+    // If we have a custom background colour, we use this colour in both
+    // disabled and enabled mode, or we end up with a different colour under the
+    // text.
+    wxColour oldColour = GetBackgroundColour();
+    if (oldColour.Ok())
+    {
+        // Need to set twice or it'll optimize the useful stuff out
+        if (oldColour == * wxWHITE)
+            SetBackgroundColour(*wxBLACK);
+        else
+            SetBackgroundColour(*wxWHITE);
+        SetBackgroundColour(oldColour);
+    }
+}
+
 void wxTextCtrl::DiscardEdits()
 {
     m_modified = FALSE;
 void wxTextCtrl::DiscardEdits()
 {
     m_modified = FALSE;
@@ -866,27 +924,6 @@ void wxTextCtrl::Paste()
 #endif
 }
 
 #endif
 }
 
-bool wxTextCtrl::CanCopy() const
-{
-    // Can copy if there's a selection
-    long from, to;
-    GetSelection(& from, & to);
-    return (from != to) ;
-}
-
-bool wxTextCtrl::CanCut() const
-{
-    // Can cut if there's a selection
-    long from, to;
-    GetSelection(& from, & to);
-    return (from != to) && (IsEditable());
-}
-
-bool wxTextCtrl::CanPaste() const
-{
-    return IsEditable() ;
-}
-
 // Undo/redo
 void wxTextCtrl::Undo()
 {
 // Undo/redo
 void wxTextCtrl::Undo()
 {
@@ -1020,6 +1057,8 @@ bool wxTextCtrl::SetFont( const wxFont &font )
     {
         m_updateFont = TRUE;
 
     {
         m_updateFont = TRUE;
 
+        m_defaultStyle.SetFont(font);
+
         ChangeFontGlobally();
     }
 
         ChangeFontGlobally();
     }
 
@@ -1036,10 +1075,10 @@ void wxTextCtrl::ChangeFontGlobally()
     wxString value = GetValue();
     if ( !value.IsEmpty() )
     {
     wxString value = GetValue();
     if ( !value.IsEmpty() )
     {
+        m_updateFont = FALSE;
+
         Clear();
         AppendText(value);
         Clear();
         AppendText(value);
-
-        m_updateFont = FALSE;
     }
 }
 
     }
 }
 
@@ -1049,19 +1088,23 @@ void wxTextCtrl::UpdateFontIfNeeded()
         ChangeFontGlobally();
 }
 
         ChangeFontGlobally();
 }
 
-bool wxTextCtrl::SetForegroundColour( const wxColour &WXUNUSED(colour) )
+bool wxTextCtrl::SetForegroundColour(const wxColour& colour)
 {
 {
-    wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
+    if ( !wxControl::SetForegroundColour(colour) )
+        return FALSE;
 
 
-    // doesn't work
-    return FALSE;
+    // update default fg colour too
+    m_defaultStyle.SetTextColour(colour);
+
+    return TRUE;
 }
 
 bool wxTextCtrl::SetBackgroundColour( const wxColour &colour )
 {
     wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
 
 }
 
 bool wxTextCtrl::SetBackgroundColour( const wxColour &colour )
 {
     wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
 
-    wxControl::SetBackgroundColour( colour );
+    if ( !wxControl::SetBackgroundColour( colour ) )
+        return FALSE;
 
     if (!m_widget->window)
         return FALSE;
 
     if (!m_widget->window)
         return FALSE;
@@ -1087,9 +1130,72 @@ bool wxTextCtrl::SetBackgroundColour( const wxColour &colour )
         gdk_window_clear( window );
     }
 
         gdk_window_clear( window );
     }
 
+    // change active background color too
+    m_defaultStyle.SetBackgroundColour( colour );
+
     return TRUE;
 }
 
     return TRUE;
 }
 
+bool wxTextCtrl::SetStyle( long start, long end, const wxTextAttr &style )
+{
+    /* VERY dirty way to do that - removes the required text and re-adds it
+       with styling (FIXME) */
+    if ( m_windowStyle & wxTE_MULTILINE )
+    {
+        if ( style.IsDefault() )
+        {
+            // nothing to do
+            return TRUE;
+        }
+
+        gint l = gtk_text_get_length( GTK_TEXT(m_text) );
+
+        wxCHECK_MSG( start >= 0 && end <= l, FALSE,
+                     _T("invalid range in wxTextCtrl::SetStyle") );
+
+        gint old_pos = gtk_editable_get_position( GTK_EDITABLE(m_text) );
+        char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), start, end );
+        wxString tmp(text,*wxConvCurrent);
+        g_free( text );
+
+        gtk_editable_delete_text( GTK_EDITABLE(m_text), start, end );
+        gtk_editable_set_position( GTK_EDITABLE(m_text), start );
+
+#if wxUSE_UNICODE
+        wxWX2MBbuf buf = tmp.mbc_str();
+        const char *txt = buf;
+        size_t txtlen = strlen(buf);
+#else
+        const char *txt = tmp;
+        size_t txtlen = tmp.length();
+#endif
+
+        GdkFont *font = style.HasFont()
+                            ? style.GetFont().GetInternalFont()
+                            : NULL;
+
+        GdkColor *colFg = style.HasTextColour()
+                            ? style.GetTextColour().GetColor()
+                            : NULL;
+
+        GdkColor *colBg = style.HasBackgroundColour()
+                            ? style.GetBackgroundColour().GetColor()
+                            : NULL;
+
+        gtk_text_insert( GTK_TEXT(m_text), font, colFg, colBg, txt, txtlen );
+
+        /* does not seem to help under GTK+ 1.2 !!!
+        gtk_editable_set_position( GTK_EDITABLE(m_text), old_pos ); */
+        SetInsertionPoint( old_pos );
+        return TRUE;
+    }
+    else // singe line
+    {
+        // cannot do this for GTK+'s Entry widget
+        return FALSE;
+    }
+}
+
 void wxTextCtrl::ApplyWidgetStyle()
 {
     if (m_windowStyle & wxTE_MULTILINE)
 void wxTextCtrl::ApplyWidgetStyle()
 {
     if (m_windowStyle & wxTE_MULTILINE)
@@ -1186,3 +1292,81 @@ wxSize wxTextCtrl::DoGetBestSize() const
     wxSize ret( wxControl::DoGetBestSize() );
     return wxSize(80, ret.y);
 }
     wxSize ret( wxControl::DoGetBestSize() );
     return wxSize(80, ret.y);
 }
+
+// ----------------------------------------------------------------------------
+// freeze/thaw
+// ----------------------------------------------------------------------------
+
+void wxTextCtrl::Freeze()
+{
+    if ( HasFlag(wxTE_MULTILINE) )
+    {
+        gtk_text_freeze(GTK_TEXT(m_text));
+    }
+}
+
+void wxTextCtrl::Thaw()
+{
+    if ( HasFlag(wxTE_MULTILINE) )
+    {
+        GTK_TEXT(m_text)->vadj->value = 0.0;
+
+        gtk_text_thaw(GTK_TEXT(m_text));
+    }
+}
+
+// ----------------------------------------------------------------------------
+// scrolling
+// ----------------------------------------------------------------------------
+
+GtkAdjustment *wxTextCtrl::GetVAdj() const
+{
+    return HasFlag(wxTE_MULTILINE) ? GTK_TEXT(m_text)->vadj : NULL;
+}
+
+bool wxTextCtrl::DoScroll(GtkAdjustment *adj, int diff)
+{
+    float value = adj->value + diff;
+
+    if ( value < 0 )
+        value = 0;
+
+    float upper = adj->upper - adj->page_size;
+    if ( value > upper )
+        value = upper;
+
+    // did we noticeably change the scroll position?
+    if ( fabs(adj->value - value) < 0.2 )
+    {
+        // well, this is what Robert does in wxScrollBar, so it must be good...
+        return FALSE;
+    }
+
+    adj->value = value;
+
+    gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed");
+
+    return TRUE;
+}
+
+bool wxTextCtrl::ScrollLines(int lines)
+{
+    GtkAdjustment *adj = GetVAdj();
+    if ( !adj )
+        return FALSE;
+
+    // this is hardcoded to 10 in GTK+ 1.2 (great idea)
+    static const int KEY_SCROLL_PIXELS = 10;
+
+    return DoScroll(adj, lines*KEY_SCROLL_PIXELS);
+}
+
+bool wxTextCtrl::ScrollPages(int pages)
+{
+    GtkAdjustment *adj = GetVAdj();
+    if ( !adj )
+        return FALSE;
+
+    return DoScroll(adj, (int)ceil(pages*adj->page_increment));
+}
+