]> git.saurik.com Git - wxWidgets.git/blobdiff - src/univ/themes/gtk.cpp
Undo/Redo update handlers now set the text as well
[wxWidgets.git] / src / univ / themes / gtk.cpp
index 73ff1f53227e31ba07488c98db4f4c035004ba94..0fb2adda78faca0d8cf33afa426fa59afbf66168 100644 (file)
@@ -30,6 +30,8 @@
     #include "wx/dcmemory.h"
     #include "wx/window.h"
 
+    #include "wx/menu.h"
+
     #include "wx/bmpbuttn.h"
     #include "wx/button.h"
     #include "wx/checkbox.h"
     #include "wx/scrolbar.h"
     #include "wx/slider.h"
     #include "wx/textctrl.h"
+    #include "wx/toolbar.h"
+
+    #include "wx/settings.h"
 #endif // WX_PRECOMP
 
 #include "wx/notebook.h"
 #include "wx/spinbutt.h"
+#include "wx/toplevel.h"
+#include "wx/artprov.h"
 
 #include "wx/univ/renderer.h"
 #include "wx/univ/inphand.h"
 #include "wx/univ/colschem.h"
 #include "wx/univ/theme.h"
-#include "wx/toplevel.h"
+
+class WXDLLEXPORT wxGTKMenuGeometryInfo;
 
 // ----------------------------------------------------------------------------
 // constants (to be removed, for testing only)
@@ -152,6 +160,12 @@ public:
                                  wxAlignment align = wxALIGN_LEFT,
                                  int indexAccel = -1);
 
+    virtual void DrawToolBarButton(wxDC& dc,
+                                   const wxString& label,
+                                   const wxBitmap& bitmap,
+                                   const wxRect& rect,
+                                   int flags);
+
     virtual void DrawTextLine(wxDC& dc,
                               const wxString& text,
                               const wxRect& rect,
@@ -239,11 +253,10 @@ public:
     // titlebars
     virtual wxRect GetFrameClientArea(const wxRect& rect, int flags) const;
     virtual wxSize GetFrameTotalSize(const wxSize& clientSize, int flags) const;
+    virtual wxSize GetFrameMinSize(int flags) const;
     virtual wxSize GetFrameIconSize() const;
     virtual int HitTestFrame(const wxRect& rect, const wxPoint& pt, int flags) const;
     
-    virtual wxIcon GetStdIcon(int which) const;
-
     virtual void GetComboBitmaps(wxBitmap *bmpNormal,
                                  wxBitmap *bmpFocus,
                                  wxBitmap *bmpPressed,
@@ -274,11 +287,16 @@ public:
     virtual wxCoord GetCheckItemMargin() const
         { return 2; }
 
+    virtual wxSize GetToolBarButtonSize(wxCoord *separator) const
+        { if ( separator ) *separator = 5; return wxSize(16, 15); }
+    virtual wxSize GetToolBarMargin() const
+        { return wxSize(6, 6); }
+
     virtual wxRect GetTextTotalArea(const wxTextCtrl *text,
-                                    const wxRect& rect);
+                                    const wxRect& rect) const;
     virtual wxRect GetTextClientArea(const wxTextCtrl *text,
                                      const wxRect& rect,
-                                     wxCoord *extraSpaceBeyond);
+                                     wxCoord *extraSpaceBeyond) const;
 
     virtual wxSize GetTabIndent() const { return wxSize(2, 2); }
     virtual wxSize GetTabPadding() const { return wxSize(6, 6); }
@@ -384,7 +402,7 @@ protected:
     }
 
     // get the line wrap indicator bitmap
-    wxBitmap GetLineWrapBitmap();
+    wxBitmap GetLineWrapBitmap() const;
 
     // DrawCheckBitmap and DrawRadioBitmap helpers
 
@@ -412,6 +430,16 @@ protected:
                                   wxAlignment align,
                                   int indexAccel);
 
+    // common part of DrawMenuItem() and DrawMenuBarItem()
+    void DoDrawMenuItem(wxDC& dc,
+                        const wxRect& rect,
+                        const wxString& label,
+                        int flags,
+                        int indexAccel,
+                        const wxString& accel = _T(""),
+                        const wxBitmap& bitmap = wxNullBitmap,
+                        const wxGTKMenuGeometryInfo *geometryInfo = NULL);
+
     // initialize the combo bitmaps
     void InitComboBitmaps();
 
@@ -537,6 +565,18 @@ public:
     virtual wxColour GetBackground(wxWindow *win) const;
 };
 
+// ----------------------------------------------------------------------------
+// wxGTKArtProvider
+// ----------------------------------------------------------------------------
+
+class wxGTKArtProvider : public wxArtProvider
+{
+protected:
+    virtual wxBitmap CreateBitmap(const wxArtID& id,
+                                  const wxArtClient& client,
+                                  const wxSize& size);
+};
+
 // ----------------------------------------------------------------------------
 // wxGTKTheme
 // ----------------------------------------------------------------------------
@@ -550,6 +590,7 @@ public:
     virtual ~wxGTKTheme();
 
     virtual wxRenderer *GetRenderer();
+    virtual wxArtProvider *GetArtProvider();
     virtual wxInputHandler *GetInputHandler(const wxString& control);
     virtual wxColourScheme *GetColourScheme();
 
@@ -558,6 +599,8 @@ private:
     wxInputHandler *GetDefaultInputHandler();
 
     wxGTKRenderer *m_renderer;
+    
+    wxGTKArtProvider *m_artProvider;
 
     // the names of the already created handlers and the handlers themselves
     // (these arrays are synchronized)
@@ -612,6 +655,16 @@ wxRenderer *wxGTKTheme::GetRenderer()
     return m_renderer;
 }
 
+wxArtProvider *wxGTKTheme::GetArtProvider()
+{
+    if ( !m_artProvider )
+    {
+        m_artProvider = new wxGTKArtProvider;
+    }
+
+    return m_artProvider;
+}
+
 wxColourScheme *wxGTKTheme::GetColourScheme()
 {
     if ( !m_scheme )
@@ -677,6 +730,10 @@ wxInputHandler *wxGTKTheme::GetInputHandler(const wxString& control)
         else if ( control == wxINP_HANDLER_NOTEBOOK )
             handler = new wxStdNotebookInputHandler(GetDefaultInputHandler());
 #endif // wxUSE_NOTEBOOK
+#if wxUSE_TOOLBAR
+        else if ( control == wxINP_HANDLER_TOOLBAR )
+            handler = new wxStdToolbarInputHandler(GetDefaultInputHandler());
+#endif // wxUSE_TOOLBAR
         else if ( control == wxINP_HANDLER_TOPLEVEL )
             handler = new wxStdFrameInputHandler(GetDefaultInputHandler());
         else
@@ -763,6 +820,8 @@ wxColour wxGTKColourScheme::Get(wxGTKColourScheme::StdColour col) const
         case HIGHLIGHT:         return wxColour(0x9c0000);
         case HIGHLIGHT_TEXT:    return wxColour(0xffffff);
 
+        case GAUGE:             return Get(CONTROL_CURRENT);
+
         case MAX:
         default:
             wxFAIL_MSG(_T("invalid standard colour"));
@@ -1196,6 +1255,10 @@ void wxGTKRenderer::DrawButtonLabel(wxDC& dc,
         dc.DrawLabel(label, rectShadow, alignment, indexAccel);
         dc.SetTextForeground(wxSCHEME_COLOUR(m_scheme, CONTROL_TEXT_DISABLED));
     }
+    else
+    {
+        dc.SetTextForeground(wxSCHEME_COLOUR(m_scheme, CONTROL_TEXT));
+    }
 
     dc.DrawLabel(label, image, rect, alignment, indexAccel, rectBounds);
 }
@@ -1254,6 +1317,7 @@ void wxGTKRenderer::DrawCheckItem(wxDC& dc,
     wxRect rectBitmap = rect;
     rectBitmap.x -= 1;
     rectBitmap.width = GetCheckBitmapSize().x;
+
     // never draw the focus rect around the check indicators here
     DrawCheckButton(dc, _T(""), bitmap, rectBitmap, flags & ~wxCONTROL_FOCUSED);
 
@@ -1421,7 +1485,7 @@ wxBitmap wxGTKRenderer::GetCheckBitmap(int flags)
     return m_bitmapsCheckbox[row][col];
 }
 
-wxBitmap wxGTKRenderer::GetLineWrapBitmap()
+wxBitmap wxGTKRenderer::GetLineWrapBitmap() const
 {
     if ( !m_bmpLineWrap.Ok() )
     {
@@ -1440,7 +1504,7 @@ wxBitmap wxGTKRenderer::GetLineWrapBitmap()
         }
         else
         {
-            m_bmpLineWrap = bmpLineWrap;
+            wxConstCast(this, wxGTKRenderer)->m_bmpLineWrap = bmpLineWrap;
         }
     }
 
@@ -1549,12 +1613,41 @@ void wxGTKRenderer::DrawRadioButton(wxDC& dc,
                              flags, align, indexAccel);
 }
 
+void wxGTKRenderer::DrawToolBarButton(wxDC& dc,
+                                      const wxString& label,
+                                      const wxBitmap& bitmap,
+                                      const wxRect& rectOrig,
+                                      int flags)
+{
+    // we don't draw the separators at all
+    if ( !label.empty() || bitmap.Ok() )
+    {
+        wxRect rect = rectOrig;
+        rect.Deflate(BORDER_THICKNESS);
+
+        if ( flags & wxCONTROL_PRESSED )
+        {
+            DrawBorder(dc, wxBORDER_SUNKEN, rect, flags, &rect);
+
+            DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL_PRESSED), rect);
+        }
+        else if ( flags & wxCONTROL_CURRENT )
+        {
+            DrawBorder(dc, wxBORDER_RAISED, rect, flags, &rect);
+
+            DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL_CURRENT), rect);
+        }
+
+        dc.DrawLabel(label, bitmap, rect, wxALIGN_CENTRE);
+    }
+}
+
 // ----------------------------------------------------------------------------
 // text control
 // ----------------------------------------------------------------------------
 
 wxRect wxGTKRenderer::GetTextTotalArea(const wxTextCtrl *text,
-                                       const wxRect& rect)
+                                       const wxRect& rect) const
 {
     wxRect rectTotal = rect;
     rectTotal.Inflate(2*BORDER_THICKNESS);
@@ -1563,10 +1656,10 @@ wxRect wxGTKRenderer::GetTextTotalArea(const wxTextCtrl *text,
 
 wxRect wxGTKRenderer::GetTextClientArea(const wxTextCtrl *text,
                                         const wxRect& rect,
-                                        wxCoord *extraSpaceBeyond)
+                                        wxCoord *extraSpaceBeyond) const
 {
     wxRect rectText = rect;
-    rectText.Inflate(-2*BORDER_THICKNESS);
+    rectText.Deflate(2*BORDER_THICKNESS);
 
     if ( text->WrapLines() )
     {
@@ -1846,45 +1939,265 @@ void wxGTKRenderer::DrawSliderThumb(wxDC& dc,
 // menu and menubar
 // ----------------------------------------------------------------------------
 
+// wxGTKMenuGeometryInfo: the wxMenuGeometryInfo used by wxGTKRenderer
+class WXDLLEXPORT wxGTKMenuGeometryInfo : public wxMenuGeometryInfo
+{
+public:
+    virtual wxSize GetSize() const { return m_size; }
+
+    wxCoord GetLabelOffset() const { return m_ofsLabel; }
+    wxCoord GetAccelOffset() const { return m_ofsAccel; }
+
+    wxCoord GetItemHeight() const { return m_heightItem; }
+
+private:
+    // the total size of the menu
+    wxSize m_size;
+
+    // the offset of the start of the menu item label
+    wxCoord m_ofsLabel;
+
+    // the offset of the start of the accel label
+    wxCoord m_ofsAccel;
+
+    // the height of a normal (not separator) item
+    wxCoord m_heightItem;
+
+    friend wxMenuGeometryInfo *
+        wxGTKRenderer::GetMenuGeometry(wxWindow *, const wxMenu&) const;
+};
+
+// FIXME: all constants are hardcoded but shouldn't be
+static const wxCoord MENU_LEFT_MARGIN = 9;
+static const wxCoord MENU_RIGHT_MARGIN = 6;
+
+static const wxCoord MENU_HORZ_MARGIN = 6;
+static const wxCoord MENU_VERT_MARGIN = 3;
+
+// the margin around bitmap/check marks (on each side)
+static const wxCoord MENU_BMP_MARGIN = 2;
+
+// the margin between the labels and accel strings
+static const wxCoord MENU_ACCEL_MARGIN = 8;
+
+// the separator height in pixels: in fact, strangely enough, the real height
+// is 2 but Windows adds one extra pixel in the bottom margin, so take it into
+// account here
+static const wxCoord MENU_SEPARATOR_HEIGHT = 3;
+
+// the size of the standard checkmark bitmap
+static const wxCoord MENU_CHECK_SIZE = 9;
+
 void wxGTKRenderer::DrawMenuBarItem(wxDC& dc,
                                     const wxRect& rect,
                                     const wxString& label,
                                     int flags,
                                     int indexAccel)
 {
-    DrawLabel(dc, label, rect, flags, wxALIGN_CENTRE, indexAccel);
+    DoDrawMenuItem(dc, rect, label, flags, indexAccel);
 }
 
 void wxGTKRenderer::DrawMenuItem(wxDC& dc,
                                  wxCoord y,
-                                 const wxMenuGeometryInfo& geometryInfo,
+                                 const wxMenuGeometryInfo& gi,
                                  const wxString& label,
                                  const wxString& accel,
                                  const wxBitmap& bitmap,
                                  int flags,
                                  int indexAccel)
 {
-    wxFAIL_MSG(_T("TODO"));
+    const wxGTKMenuGeometryInfo& geomInfo = (const wxGTKMenuGeometryInfo&)gi;
+
+    wxRect rect;
+    rect.x = 0;
+    rect.y = y;
+    rect.width = geomInfo.GetSize().x;
+    rect.height = geomInfo.GetItemHeight();
+
+    DoDrawMenuItem(dc, rect, label, flags, indexAccel, accel, bitmap, &geomInfo);
+}
+
+void wxGTKRenderer::DoDrawMenuItem(wxDC& dc,
+                                   const wxRect& rectOrig,
+                                   const wxString& label,
+                                   int flags,
+                                   int indexAccel,
+                                   const wxString& accel,
+                                   const wxBitmap& bitmap,
+                                   const wxGTKMenuGeometryInfo *geometryInfo)
+{
+    wxRect rect = rectOrig;
+
+    // draw the selected item specially
+    if ( flags & wxCONTROL_SELECTED )
+    {
+        wxRect rectIn;
+        DrawBorder(dc, wxBORDER_RAISED, rect, flags, &rectIn);
+
+        DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL_CURRENT), rectIn);
+    }
+
+    rect.Deflate(MENU_HORZ_MARGIN, MENU_VERT_MARGIN);
+
+    // draw the bitmap: use the bitmap provided or the standard checkmark for
+    // the checkable items
+    if ( geometryInfo )
+    {
+        wxBitmap bmp = bitmap;
+        if ( !bmp.Ok() && (flags & wxCONTROL_CHECKABLE) )
+        {
+            bmp = GetCheckBitmap(flags);
+        }
+
+        if ( bmp.Ok() )
+        {
+            rect.SetRight(geometryInfo->GetLabelOffset());
+            wxControlRenderer::DrawBitmap(dc, bmp, rect);
+        }
+    }
+    //else: menubar items don't have bitmaps
+
+    // draw the label
+    if ( geometryInfo )
+    {
+        rect.x = geometryInfo->GetLabelOffset();
+        rect.SetRight(geometryInfo->GetAccelOffset());
+    }
+
+    DrawLabel(dc, label, rect, flags, wxALIGN_CENTRE_VERTICAL, indexAccel);
+
+    // draw the accel string
+    if ( !accel.empty() )
+    {
+        // menubar items shouldn't have them
+        wxCHECK_RET( geometryInfo, _T("accel strings only valid for menus") );
+
+        rect.x = geometryInfo->GetAccelOffset();
+        rect.SetRight(geometryInfo->GetSize().x);
+
+        // NB: no accel index here
+        DrawLabel(dc, accel, rect, flags, wxALIGN_CENTRE_VERTICAL);
+    }
+
+    // draw the submenu indicator
+    if ( flags & wxCONTROL_ISSUBMENU )
+    {
+        wxCHECK_RET( geometryInfo, _T("wxCONTROL_ISSUBMENU only valid for menus") );
+
+        rect.x = geometryInfo->GetSize().x - MENU_RIGHT_MARGIN;
+        rect.width = MENU_RIGHT_MARGIN;
+
+        DrawArrow(dc, wxRIGHT, rect, flags);
+    }
 }
 
 void wxGTKRenderer::DrawMenuSeparator(wxDC& dc,
                                       wxCoord y,
                                       const wxMenuGeometryInfo& geomInfo)
 {
-    wxFAIL_MSG(_T("TODO"));
+    DrawHorizontalLine(dc, y + MENU_VERT_MARGIN, 0, geomInfo.GetSize().x);
 }
 
 wxSize wxGTKRenderer::GetMenuBarItemSize(const wxSize& sizeText) const
 {
-    return sizeText;
+    wxSize size = sizeText;
+
+    // TODO: make this configurable
+    size.x += 2*MENU_HORZ_MARGIN;
+    size.y += 2*MENU_VERT_MARGIN;
+
+    return size;
 }
 
 wxMenuGeometryInfo *wxGTKRenderer::GetMenuGeometry(wxWindow *win,
                                                    const wxMenu& menu) const
 {
-    wxFAIL_MSG(_T("TODO"));
+    // prepare the dc: for now we draw all the items with the system font
+    wxClientDC dc(win);
+    dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
+
+    // the height of a normal item
+    wxCoord heightText = dc.GetCharHeight();
+
+    // the total height
+    wxCoord height = 0;
+
+    // the max length of label and accel strings: the menu width is the sum of
+    // them, even if they're for different items (as the accels should be
+    // aligned)
+    //
+    // the max length of the bitmap is never 0 as Windows always leaves enough
+    // space for a check mark indicator
+    wxCoord widthLabelMax = 0,
+            widthAccelMax = 0,
+            widthBmpMax = MENU_LEFT_MARGIN;
+
+    for ( wxMenuItemList::Node *node = menu.GetMenuItems().GetFirst();
+          node;
+          node = node->GetNext() )
+    {
+        // height of this item
+        wxCoord h;
 
-    return NULL;
+        wxMenuItem *item = node->GetData();
+        if ( item->IsSeparator() )
+        {
+            h = MENU_SEPARATOR_HEIGHT;
+        }
+        else // not separator
+        {
+            h = heightText;
+
+            wxCoord widthLabel;
+            dc.GetTextExtent(item->GetLabel(), &widthLabel, NULL);
+            if ( widthLabel > widthLabelMax )
+            {
+                widthLabelMax = widthLabel;
+            }
+
+            wxCoord widthAccel;
+            dc.GetTextExtent(item->GetAccelString(), &widthAccel, NULL);
+            if ( widthAccel > widthAccelMax )
+            {
+                widthAccelMax = widthAccel;
+            }
+
+            const wxBitmap& bmp = item->GetBitmap();
+            if ( bmp.Ok() )
+            {
+                wxCoord widthBmp = bmp.GetWidth();
+                if ( widthBmp > widthBmpMax )
+                    widthBmpMax = widthBmp;
+            }
+            //else if ( item->IsCheckable() ): no need to check for this as
+            // MENU_LEFT_MARGIN is big enough to show the check mark
+        }
+
+        h += 2*MENU_VERT_MARGIN;
+
+        // remember the item position and height
+        item->SetGeometry(height, h);
+
+        height += h;
+    }
+
+    // bundle the metrics into a struct and return it
+    wxGTKMenuGeometryInfo *gi = new wxGTKMenuGeometryInfo;
+
+    gi->m_ofsLabel = widthBmpMax + 2*MENU_BMP_MARGIN;
+    gi->m_ofsAccel = gi->m_ofsLabel + widthLabelMax;
+    if ( widthAccelMax > 0 )
+    {
+        // if we actually have any accesl, add a margin
+        gi->m_ofsAccel += MENU_ACCEL_MARGIN;
+    }
+
+    gi->m_heightItem = heightText + 2*MENU_VERT_MARGIN;
+
+    gi->m_size.x = gi->m_ofsAccel + widthAccelMax + MENU_RIGHT_MARGIN;
+    gi->m_size.y = height;
+
+    return gi;
 }
 
 // ----------------------------------------------------------------------------
@@ -2395,7 +2708,7 @@ void wxGTKRenderer::AdjustSize(wxSize *size, const wxWindow *window)
             size->y += 4;
         }
     } else
-#endif wxUSE_BUTTON
+#endif //wxUSE_BUTTON
     if ( wxDynamicCast(window, wxScrollBar) )
     {
         // we only set the width of vert scrollbars and height of the
@@ -2471,6 +2784,11 @@ wxSize wxGTKRenderer::GetFrameTotalSize(const wxSize& clientSize, int flags) con
     return clientSize;
 }
 
+wxSize wxGTKRenderer::GetFrameMinSize(int flags) const
+{
+    return wxSize(0,0);
+}
+
 wxSize wxGTKRenderer::GetFrameIconSize() const
 {
     return wxSize(-1, -1);
@@ -4090,27 +4408,19 @@ static char *question_xpm[] = {
 "$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$."
 };
 
-
-wxIcon wxGTKRenderer::GetStdIcon(int which) const
+wxBitmap wxGTKArtProvider::CreateBitmap(const wxArtID& id,
+                                        const wxArtClient& WXUNUSED(client),
+                                        const wxSize& WXUNUSED(size))
 {
-    switch(which)
-    {
-        case wxICON_INFORMATION:
-            return wxIcon(info_xpm);
-
-        case wxICON_QUESTION:
-            return wxIcon(question_xpm);
-
-        case wxICON_EXCLAMATION:
-            return wxIcon(warning_xpm);
-
-        default:
-            wxFAIL_MSG(wxT("requested non existent standard icon"));
-            // still fall through
-
-        case wxICON_HAND:
-            return wxIcon(error_xpm);
-    }
+    if ( id == wxART_INFORMATION )
+        return wxBitmap(info_xpm);
+    if ( id == wxART_ERROR )
+        return wxBitmap(error_xpm);
+    if ( id == wxART_WARNING )
+        return wxBitmap(warning_xpm);
+    if ( id == wxART_QUESTION )
+        return wxBitmap(question_xpm);
+    return wxNullBitmap;
 }