X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/3216dbf5dccab8ed6dc0245b7e5c998738ef51d7..b2edef6f2f587d957eabbc17364382293707340f:/src/univ/themes/gtk.cpp diff --git a/src/univ/themes/gtk.cpp b/src/univ/themes/gtk.cpp index 6bacb6303d..ab9a0db5b4 100644 --- a/src/univ/themes/gtk.cpp +++ b/src/univ/themes/gtk.cpp @@ -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" @@ -40,16 +42,21 @@ #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) @@ -70,7 +77,8 @@ public: virtual void DrawBackground(wxDC& dc, const wxColour& col, const wxRect& rect, - int flags = 0); + int flags = 0, + wxWindow *window = NULL ); virtual void DrawLabel(wxDC& dc, const wxString& label, const wxRect& rect, @@ -249,8 +257,6 @@ public: 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, @@ -331,7 +337,8 @@ protected: // draw the background with any colour, not only the default one(s) void DoDrawBackground(wxDC& dc, const wxColour& col, - const wxRect& rect); + const wxRect& rect, + wxWindow *window = NULL); // DrawBorder() helpers: all of them shift and clip the DC after drawing // the border @@ -425,6 +432,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(); @@ -550,6 +567,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 // ---------------------------------------------------------------------------- @@ -563,6 +592,7 @@ public: virtual ~wxGTKTheme(); virtual wxRenderer *GetRenderer(); + virtual wxArtProvider *GetArtProvider(); virtual wxInputHandler *GetInputHandler(const wxString& control); virtual wxColourScheme *GetColourScheme(); @@ -572,6 +602,8 @@ private: wxGTKRenderer *m_renderer; + wxGTKArtProvider *m_artProvider; + // the names of the already created handlers and the handlers themselves // (these arrays are synchronized) wxSortedArrayString m_handlerNames; @@ -599,6 +631,7 @@ wxGTKTheme::wxGTKTheme() m_scheme = NULL; m_renderer = NULL; m_handlerDefault = NULL; + m_artProvider = NULL; } wxGTKTheme::~wxGTKTheme() @@ -613,6 +646,7 @@ wxGTKTheme::~wxGTKTheme() delete m_handlerDefault; delete m_renderer; delete m_scheme; + wxArtProvider::RemoveProvider(m_artProvider); } wxRenderer *wxGTKTheme::GetRenderer() @@ -625,6 +659,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 ) @@ -1215,6 +1259,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); } @@ -1273,11 +1321,12 @@ 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); wxRect rectLabel = rect; - wxCoord shift = rectBitmap.width + 2*GetCheckItemMargin(); + wxCoord shift = rectBitmap.width + 2*GetCheckItemMargin(); rectLabel.x += shift; rectLabel.width -= shift; DrawItem(dc, label, rectLabel, flags); @@ -1582,11 +1631,15 @@ void wxGTKRenderer::DrawToolBarButton(wxDC& dc, if ( flags & wxCONTROL_PRESSED ) { - DrawBorder(dc, wxBORDER_SUNKEN, rect, flags); + 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); + DrawBorder(dc, wxBORDER_RAISED, rect, flags, &rect); + + DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL_CURRENT), rect); } dc.DrawLabel(label, bitmap, rect, wxALIGN_CENTRE); @@ -1890,45 +1943,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; + + wxMenuItem *item = node->GetData(); + if ( item->IsSeparator() ) + { + h = MENU_SEPARATOR_HEIGHT; + } + else // not separator + { + h = heightText; - return NULL; + 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; } // ---------------------------------------------------------------------------- @@ -2011,7 +2284,8 @@ void wxGTKRenderer::GetComboBitmaps(wxBitmap *bmpNormal, void wxGTKRenderer::DoDrawBackground(wxDC& dc, const wxColour& col, - const wxRect& rect) + const wxRect& rect, + wxWindow *window ) { wxBrush brush(col, wxSOLID); dc.SetBrush(brush); @@ -2022,10 +2296,11 @@ void wxGTKRenderer::DoDrawBackground(wxDC& dc, void wxGTKRenderer::DrawBackground(wxDC& dc, const wxColour& col, const wxRect& rect, - int flags) + int flags, + wxWindow *window ) { wxColour colBg = col.Ok() ? col : GetBackgroundColour(flags); - DoDrawBackground(dc, colBg, rect); + DoDrawBackground(dc, colBg, rect, window ); } // ---------------------------------------------------------------------------- @@ -4139,27 +4414,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; }