]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/textctrl.cpp
Slightly improve wx[Generic]RichMessageDialog layout.
[wxWidgets.git] / src / gtk / textctrl.cpp
index 7e5b5f5472b761bfa86711b3d290f2e9f38b6317..f5a78bdf8d1ac02f480c5259ba70d55574eab6ca 100644 (file)
@@ -22,6 +22,7 @@
     #include "wx/math.h"
 #endif
 
     #include "wx/math.h"
 #endif
 
+#include "wx/scopeguard.h"
 #include "wx/strconv.h"
 #include "wx/fontutil.h"        // for wxNativeFontInfo (GetNativeFontInfo())
 
 #include "wx/strconv.h"
 #include "wx/fontutil.h"        // for wxNativeFontInfo (GetNativeFontInfo())
 
@@ -149,7 +150,7 @@ static void wxGtkTextApplyTagsFromAttr(GtkWidget *text,
                                           gtk_text_iter_get_line(start) );
         gtk_text_iter_forward_line(&para_end);
 
                                           gtk_text_iter_get_line(start) );
         gtk_text_iter_forward_line(&para_end);
 
-        wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXALIGNMENT", start, end);
+        wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXALIGNMENT", &para_start, &para_end);
 
         GtkJustification align;
         switch (attr.GetAlignment())
 
         GtkJustification align;
         switch (attr.GetAlignment())
@@ -195,7 +196,7 @@ static void wxGtkTextApplyTagsFromAttr(GtkWidget *text,
                                           gtk_text_iter_get_line(start) );
         gtk_text_iter_forward_line(&para_end);
 
                                           gtk_text_iter_get_line(start) );
         gtk_text_iter_forward_line(&para_end);
 
-        wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXINDENT", start, end);
+        wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXINDENT", &para_start, &para_end);
 
         // Convert indent from 1/10th of a mm into pixels
         float factor =
 
         // Convert indent from 1/10th of a mm into pixels
         float factor =
@@ -239,14 +240,14 @@ static void wxGtkTextApplyTagsFromAttr(GtkWidget *text,
                                           gtk_text_iter_get_line(start) );
         gtk_text_iter_forward_line(&para_end);
 
                                           gtk_text_iter_get_line(start) );
         gtk_text_iter_forward_line(&para_end);
 
-        wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXTABS", start, end);
+        wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXTABS", &para_start, &para_end);
 
         const wxArrayInt& tabs = attr.GetTabs();
 
 
         const wxArrayInt& tabs = attr.GetTabs();
 
-        wxString tagname = _T("WXTABS");
+        wxString tagname = wxT("WXTABS");
         g_snprintf(buf, sizeof(buf), "WXTABS");
         for (size_t i = 0; i < tabs.GetCount(); i++)
         g_snprintf(buf, sizeof(buf), "WXTABS");
         for (size_t i = 0; i < tabs.GetCount(); i++)
-            tagname += wxString::Format(_T(" %d"), tabs[i]);
+            tagname += wxString::Format(wxT(" %d"), tabs[i]);
 
         const wxWX2MBbuf buftag = tagname.utf8_str();
 
 
         const wxWX2MBbuf buftag = tagname.utf8_str();
 
@@ -350,7 +351,7 @@ extern "C" {
 static void
 au_check_word( GtkTextIter *s, GtkTextIter *e )
 {
 static void
 au_check_word( GtkTextIter *s, GtkTextIter *e )
 {
-    static const char *URIPrefixes[] =
+    static const char *const URIPrefixes[] =
     {
         "http://",
         "ftp://",
     {
         "http://",
         "ftp://",
@@ -494,6 +495,27 @@ au_delete_range_callback(GtkTextBuffer * WXUNUSED(buffer),
 }
 }
 
 }
 }
 
+//-----------------------------------------------------------------------------
+//  "populate_popup" from text control and "unmap" from its poup menu
+//-----------------------------------------------------------------------------
+
+extern "C" {
+static void
+gtk_textctrl_popup_unmap( GtkMenu *WXUNUSED(menu), wxTextCtrl* win )
+{
+    win->GTKEnableFocusOutEvent();
+}
+}
+
+extern "C" {
+static void
+gtk_textctrl_populate_popup( GtkEntry *WXUNUSED(entry), GtkMenu *menu, wxTextCtrl *win )
+{
+    win->GTKDisableFocusOutEvent();
+
+    g_signal_connect (menu, "unmap", G_CALLBACK (gtk_textctrl_popup_unmap), win );
+}
+}
 
 //-----------------------------------------------------------------------------
 //  "changed"
 
 //-----------------------------------------------------------------------------
 //  "changed"
@@ -501,7 +523,7 @@ au_delete_range_callback(GtkTextBuffer * WXUNUSED(buffer),
 
 extern "C" {
 static void
 
 extern "C" {
 static void
-gtk_text_changed_callback( GtkWidget * WXUNUSED(widget), wxTextCtrl *win )
+gtk_text_changed_callback( GtkWidget *WXUNUSED(widget), wxTextCtrl *win )
 {
     if ( win->IgnoreTextUpdate() )
         return;
 {
     if ( win->IgnoreTextUpdate() )
         return;
@@ -600,16 +622,10 @@ void wxTextCtrl::Init()
 
     m_text = NULL;
     m_showPositionOnThaw = NULL;
 
     m_text = NULL;
     m_showPositionOnThaw = NULL;
-    m_gdkHandCursor = NULL;
-    m_gdkXTermCursor = NULL;
 }
 
 wxTextCtrl::~wxTextCtrl()
 {
 }
 
 wxTextCtrl::~wxTextCtrl()
 {
-    if(m_gdkHandCursor)
-        gdk_cursor_unref(m_gdkHandCursor);
-    if(m_gdkXTermCursor)
-        gdk_cursor_unref(m_gdkXTermCursor);
 }
 
 wxTextCtrl::wxTextCtrl( wxWindow *parent,
 }
 
 wxTextCtrl::wxTextCtrl( wxWindow *parent,
@@ -671,7 +687,7 @@ bool wxTextCtrl::Create( wxWindow *parent,
 
         GTKSetWrapMode();
 
 
         GTKSetWrapMode();
 
-        GtkScrolledWindowSetBorder(m_widget, style);
+        GTKScrolledWindowSetBorder(m_widget, style);
 
         gtk_widget_add_events( GTK_WIDGET(m_text), GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK );
 
 
         gtk_widget_add_events( GTK_WIDGET(m_text), GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK );
 
@@ -682,11 +698,15 @@ bool wxTextCtrl::Create( wxWindow *parent,
         // a single-line text control: no need for scrollbars
         m_widget =
         m_text = gtk_entry_new();
         // a single-line text control: no need for scrollbars
         m_widget =
         m_text = gtk_entry_new();
+        // work around probable bug in GTK+ 2.18 when calling WriteText on a
+        // new, empty control, see http://trac.wxwidgets.org/ticket/11409
+        gtk_entry_get_text((GtkEntry*)m_text);
 
         if (style & wxNO_BORDER)
             g_object_set (m_text, "has-frame", FALSE, NULL);
 
         if (style & wxNO_BORDER)
             g_object_set (m_text, "has-frame", FALSE, NULL);
-            
+
     }
     }
+    g_object_ref(m_widget);
 
     m_parent->DoAddChild( this );
 
 
     m_parent->DoAddChild( this );
 
@@ -711,6 +731,11 @@ bool wxTextCtrl::Create( wxWindow *parent,
                           G_CALLBACK (gtk_text_changed_callback), this);
     }
 
                           G_CALLBACK (gtk_text_changed_callback), this);
     }
 
+    // Catch to disable focus out handling
+    g_signal_connect (m_text, "populate_popup",
+                      G_CALLBACK (gtk_textctrl_populate_popup),
+                      this);
+
     if (!value.empty())
     {
         SetValue( value );
     if (!value.empty())
     {
         SetValue( value );
@@ -732,8 +757,6 @@ bool wxTextCtrl::Create( wxWindow *parent,
         if (style & wxTE_AUTO_URL)
         {
             GtkTextIter start, end;
         if (style & wxTE_AUTO_URL)
         {
             GtkTextIter start, end;
-            m_gdkHandCursor = gdk_cursor_new(GDK_HAND2);
-            m_gdkXTermCursor = gdk_cursor_new(GDK_XTERM);
 
             // We create our wxUrl tag here for slight efficiency gain - we
             // don't have to check for the tag existance in callbacks,
 
             // We create our wxUrl tag here for slight efficiency gain - we
             // don't have to check for the tag existance in callbacks,
@@ -791,6 +814,11 @@ GtkEditable *wxTextCtrl::GetEditable() const
     return GTK_EDITABLE(m_text);
 }
 
     return GTK_EDITABLE(m_text);
 }
 
+GtkEntry *wxTextCtrl::GetEntry() const
+{
+    return GTK_ENTRY(m_text);
+}
+
 // ----------------------------------------------------------------------------
 // flags handling
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // flags handling
 // ----------------------------------------------------------------------------
@@ -959,16 +987,16 @@ void wxTextCtrl::DoSetValue( const wxString &value, int flags )
     {
         if ( !(flags & SetValue_SendEvent) )
             EnableTextChangedEvents(false);
     {
         if ( !(flags & SetValue_SendEvent) )
             EnableTextChangedEvents(false);
-        
+
         gtk_text_buffer_set_text( m_buffer, "", 0 );
         gtk_text_buffer_set_text( m_buffer, "", 0 );
-            
+
         if ( !(flags & SetValue_SendEvent) )
             EnableTextChangedEvents(true);
         if ( !(flags & SetValue_SendEvent) )
             EnableTextChangedEvents(true);
-            
+
         return;
     }
 
         return;
     }
 
-#ifdef wxUSE_UNICODE
+#if wxUSE_UNICODE
     const wxCharBuffer buffer(value.utf8_str());
 #else
     wxFontEncoding enc = m_defaultStyle.HasFont()
     const wxCharBuffer buffer(value.utf8_str());
 #else
     wxFontEncoding enc = m_defaultStyle.HasFont()
@@ -1006,9 +1034,6 @@ void wxTextCtrl::DoSetValue( const wxString &value, int flags )
     {
         EnableTextChangedEvents(true);
     }
     {
         EnableTextChangedEvents(true);
     }
-
-    // This was added after discussion on the list
-    SetInsertionPoint(0);
 }
 
 void wxTextCtrl::WriteText( const wxString &text )
 }
 
 void wxTextCtrl::WriteText( const wxString &text )
@@ -1024,7 +1049,7 @@ void wxTextCtrl::WriteText( const wxString &text )
         return;
     }
 
         return;
     }
 
-#ifdef wxUSE_UNICODE
+#if wxUSE_UNICODE
     const wxCharBuffer buffer(text.utf8_str());
 #else
     // check if we have a specific style for the current position
     const wxCharBuffer buffer(text.utf8_str());
 #else
     // check if we have a specific style for the current position
@@ -1228,6 +1253,7 @@ bool wxTextCtrl::Enable( bool enable )
     }
 
     gtk_widget_set_sensitive( m_text, enable );
     }
 
     gtk_widget_set_sensitive( m_text, enable );
+    SetCursor(enable ? wxCursor(wxCURSOR_IBEAM) : wxCursor());
 
     return true;
 }
 
     return true;
 }
@@ -1320,8 +1346,7 @@ void wxTextCtrl::SetSelection( long from, long to )
         gtk_text_buffer_get_iter_at_offset( m_buffer, &fromi, from );
         gtk_text_buffer_get_iter_at_offset( m_buffer, &toi, to );
 
         gtk_text_buffer_get_iter_at_offset( m_buffer, &fromi, from );
         gtk_text_buffer_get_iter_at_offset( m_buffer, &toi, to );
 
-        gtk_text_buffer_place_cursor( m_buffer, &toi );
-        gtk_text_buffer_move_mark_by_name( m_buffer, "selection_bound", &fromi );
+        gtk_text_buffer_select_range( m_buffer, &fromi, &toi );
     }
     else // single line
     {
     }
     else // single line
     {
@@ -1589,7 +1614,7 @@ void wxTextCtrl::ChangeFontGlobally()
     //
     // TODO: it can be implemented much more efficiently for GTK2
     wxASSERT_MSG( IsMultiLine(),
     //
     // TODO: it can be implemented much more efficiently for GTK2
     wxASSERT_MSG( IsMultiLine(),
-                  _T("shouldn't be called for single line controls") );
+                  wxT("shouldn't be called for single line controls") );
 
     wxString value = GetValue();
     if ( !value.empty() )
 
     wxString value = GetValue();
     if ( !value.empty() )
@@ -1641,7 +1666,7 @@ bool wxTextCtrl::SetStyle( long start, long end, const wxTextAttr& style )
         gint l = gtk_text_buffer_get_char_count( m_buffer );
 
         wxCHECK_MSG( start >= 0 && end <= l, false,
         gint l = gtk_text_buffer_get_char_count( m_buffer );
 
         wxCHECK_MSG( start >= 0 && end <= l, false,
-                     _T("invalid range in wxTextCtrl::SetStyle") );
+                     wxT("invalid range in wxTextCtrl::SetStyle") );
 
         GtkTextIter starti, endi;
         gtk_text_buffer_get_iter_at_offset( m_buffer, &starti, start );
 
         GtkTextIter starti, endi;
         gtk_text_buffer_get_iter_at_offset( m_buffer, &starti, start );
@@ -1656,6 +1681,50 @@ bool wxTextCtrl::SetStyle( long start, long end, const wxTextAttr& style )
     return false;
 }
 
     return false;
 }
 
+bool wxTextCtrl::GetStyle(long position, wxTextAttr& style)
+{
+    if ( !IsMultiLine() )
+    {
+        // no styles for GtkEntry
+        return false;
+    }
+
+    gint l = gtk_text_buffer_get_char_count( m_buffer );
+
+    wxCHECK_MSG( position >= 0 && position <= l, false,
+                 _T("invalid range in wxTextCtrl::GetStyle") );
+
+    GtkTextIter positioni;
+    gtk_text_buffer_get_iter_at_offset(m_buffer, &positioni, position);
+
+    // Obtain a copy of the default attributes
+    GtkTextAttributes * const
+        pattr = gtk_text_view_get_default_attributes(GTK_TEXT_VIEW(m_text));
+    wxON_BLOCK_EXIT1( g_free, pattr );
+
+    // And query GTK for the attributes at the given position using it as base
+    if ( !gtk_text_iter_get_attributes(&positioni, pattr) )
+    {
+        style = m_defaultStyle;
+    }
+    else // have custom attributes
+    {
+        style.SetBackgroundColour(pattr->appearance.bg_color);
+        style.SetTextColour(pattr->appearance.fg_color);
+
+        const wxGtkString
+            pangoFontString(pango_font_description_to_string(pattr->font));
+
+        wxFont font;
+        if ( font.SetNativeFontInfo(wxString(pangoFontString)) )
+            style.SetFont(font);
+
+        // TODO: set alignment, tabs and indents
+    }
+
+    return true;
+}
+
 void wxTextCtrl::DoApplyWidgetStyle(GtkRcStyle *style)
 {
     gtk_widget_modify_style(m_text, style);
 void wxTextCtrl::DoApplyWidgetStyle(GtkRcStyle *style)
 {
     gtk_widget_modify_style(m_text, style);
@@ -1796,13 +1865,11 @@ void wxTextCtrl::OnUrlMouseEvent(wxMouseEvent& event)
     gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(m_text), &end, x, y);
     if (!gtk_text_iter_has_tag(&end, tag))
     {
     gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(m_text), &end, x, y);
     if (!gtk_text_iter_has_tag(&end, tag))
     {
-        gdk_window_set_cursor(gtk_text_view_get_window(GTK_TEXT_VIEW(m_text),
-                              GTK_TEXT_WINDOW_TEXT), m_gdkXTermCursor);
+        SetCursor(wxCursor(wxCURSOR_IBEAM));
         return;
     }
 
         return;
     }
 
-    gdk_window_set_cursor(gtk_text_view_get_window(GTK_TEXT_VIEW(m_text),
-                          GTK_TEXT_WINDOW_TEXT), m_gdkHandCursor);
+    SetCursor(wxCursor(wxCURSOR_HAND));
 
     start = end;
     if(!gtk_text_iter_begins_tag(&start, tag))
 
     start = end;
     if(!gtk_text_iter_begins_tag(&start, tag))