From 4c85ab7569677ff535c258c7f25ad428ba1ed406 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Thu, 24 Mar 2005 00:22:04 +0000
Subject: [PATCH] added wxRendererNative::DrawDropArrow (patch 1166596)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@33010 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/renderer.tex | 14 ++++++-
 include/wx/renderer.h      | 14 ++++++-
 src/generic/renderg.cpp    | 39 +++++++++++++++----
 src/gtk/renderer.cpp       | 78 ++++++++++++++++++++++++++++++++++----
 src/gtk1/renderer.cpp      | 78 ++++++++++++++++++++++++++++++++++----
 5 files changed, 198 insertions(+), 25 deletions(-)

diff --git a/docs/latex/wx/renderer.tex b/docs/latex/wx/renderer.tex
index e65bb60e90..0f5a4111a2 100644
--- a/docs/latex/wx/renderer.tex
+++ b/docs/latex/wx/renderer.tex
@@ -98,7 +98,19 @@ Virtual destructor as for any base class.
 Draw a button like the one used by \helpref{wxComboBox}{wxcombobox} to show a
 drop down window. The usual appearance is a downwards pointing arrow.
 
-\arg{flags} may have the \texttt{wxCONTROL\_PRESSED} bit set.
+\arg{flags} may have the \texttt{wxCONTROL\_PRESSED} or \texttt{wxCONTROL\_CURRENT} bit set.
+
+
+\membersection{wxRendererNative::DrawDropArrow}\label{wxrenderernativedrawdroparrow}
+
+\func{void}{DrawDropArrow}{\param{wxWindow *}{win}, \param{wxDC\& }{dc}, \param{const wxRect\& }{rect}, \param{int }{flags}}
+
+Draw a drop down arrow that is suitable for use outside a combo box. Arrow will have
+transparent background.
+
+\arg{rect} is not entirely filled by the arrow. Instead, you should use bounding
+rectangle of a drop down button which arrow matches the size you need.
+\arg{flags} may have the \texttt{wxCONTROL\_PRESSED} or \texttt{wxCONTROL\_CURRENT} bit set.
 
 
 \membersection{wxRendererNative::DrawHeaderButton}\label{wxrenderernativedrawheaderbutton}
diff --git a/include/wx/renderer.h b/include/wx/renderer.h
index f8c8c14d8a..3f60878665 100644
--- a/include/wx/renderer.h
+++ b/include/wx/renderer.h
@@ -156,12 +156,19 @@ public:
 
     // draw a combobox dropdown button
     //
-    // flags may only use wxCONTROL_PRESSED
+    // flags may use wxCONTROL_PRESSED and wxCONTROL_CURRENT
     virtual void DrawComboBoxDropButton(wxWindow *win,
                                         wxDC& dc,
                                         const wxRect& rect,
                                         int flags = 0) = 0;
 
+    // draw a dropdown arrow
+    //
+    // flags may use wxCONTROL_PRESSED and wxCONTROL_CURRENT
+    virtual void DrawDropArrow(wxWindow *win,
+                               wxDC& dc,
+                               const wxRect& rect,
+                               int flags = 0) = 0;
 
     // geometry functions
     // ------------------
@@ -259,6 +266,11 @@ public:
                                         int flags = 0)
         { m_rendererNative.DrawComboBoxDropButton(win, dc, rect, flags); }
 
+    virtual void DrawDropArrow(wxWindow *win,
+                               wxDC& dc,
+                               const wxRect& rect,
+                               int flags = 0)
+        { m_rendererNative.DrawDropArrow(win, dc, rect, flags); }
 
     virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win)
         { return m_rendererNative.GetSplitterParams(win); }
diff --git a/src/generic/renderg.cpp b/src/generic/renderg.cpp
index 2a6c00da5f..4a9a929eb1 100644
--- a/src/generic/renderg.cpp
+++ b/src/generic/renderg.cpp
@@ -73,6 +73,10 @@ public:
                                         const wxRect& rect,
                                         int flags = 0);
 
+    virtual void DrawDropArrow(wxWindow *win,
+                               wxDC& dc,
+                               const wxRect& rect,
+                               int flags = 0);
 
     virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
 
@@ -343,28 +347,49 @@ wxRendererGeneric::DrawSplitterSash(wxWindow *win,
     }
 }
 
+// ----------------------------------------------------------------------------
+// button drawing
+// ----------------------------------------------------------------------------
+
 void
 wxRendererGeneric::DrawComboBoxDropButton(wxWindow *win,
                                           wxDC& dc,
                                           const wxRect& rect,
                                           int WXUNUSED(flags))
 {
-    dc.SetBrush(wxBrush(win->GetBackgroundColour()));
-    dc.SetPen(wxPen(win->GetBackgroundColour()));
-    dc.DrawRectangle(rect);
+    // FIXME: Is it worth to do a better implementation?
+    // Generic wxComboDropButton should be drawn using
+    // combination of wxBitmapButton and DrawDropArrow
+    // anyway.
+    DrawDropArrow(win,dc,rect);
+}
+
 
+void
+wxRendererGeneric::DrawDropArrow(wxWindow *win,
+                                 wxDC& dc,
+                                 const wxRect& rect,
+                                 int WXUNUSED(flags))
+{
+    // This generic implementation should be good
+    // enough for Windows platforms (including XP).
+
+    int arrowHalf = rect.width/5;
+    int rectMid = rect.width / 2;
+    int arrowTopY = (rect.height/2) - (arrowHalf/2);
+
+    // This should always result in arrow with odd width.
     wxPoint pt[] =
     {
-        wxPoint(0,0),
-        wxPoint(rect.width, 0),
-        wxPoint(rect.width/2, rect.height - 2)
+        wxPoint(rectMid - arrowHalf, arrowTopY),
+        wxPoint(rectMid + arrowHalf, arrowTopY),
+        wxPoint(rectMid, arrowTopY + arrowHalf)
     };
     dc.SetBrush(wxBrush(win->GetForegroundColour()));
     dc.SetPen(wxPen(win->GetForegroundColour()));
     dc.DrawPolygon(WXSIZEOF(pt), pt, rect.x, rect.y);
 }
 
-
 // ----------------------------------------------------------------------------
 // A module to allow cleanup of generic renderer.
 // ----------------------------------------------------------------------------
diff --git a/src/gtk/renderer.cpp b/src/gtk/renderer.cpp
index baae5fe61b..8b545e1c39 100644
--- a/src/gtk/renderer.cpp
+++ b/src/gtk/renderer.cpp
@@ -79,6 +79,11 @@ public:
                                         const wxRect& rect,
                                         int flags = 0);
 
+    virtual void DrawDropArrow(wxWindow *win,
+                               wxDC& dc,
+                               const wxRect& rect,
+                               int flags = 0);
+
     virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
 
 private:
@@ -394,20 +399,35 @@ wxRendererGTK::DrawSplitterSash(wxWindow *win,
 #endif // GTK+ 2.x/1.x
 }
 
-void wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
-                                            wxDC& dc,
-                                            const wxRect& rect,
-                                            int flags)
+void
+wxRendererGTK::DrawDropArrow(wxWindow *win,
+                             wxDC& dc,
+                             const wxRect& rect,
+                             int flags)
 {
     GtkWidget *button = GetButtonWidget();
 
-    // device context must inherit from wxWindowDC
-    // (so it must be wxClientDC, wxMemoryDC or wxPaintDC)
+    // If we give GTK_PIZZA(win->m_wxwindow)->bin_window as
+    // a window for gtk_paint_xxx function, then it won't
+    // work for wxMemoryDC. So that is why we assume wxDC
+    // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
+    // are derived from it) and use its m_window.
     wxWindowDC& wdc = (wxWindowDC&)dc;
 
-    // only doing debug-time checking here (it should probably be enough)
+    // only doing debug-time checking here (it should
+    // probably be enough)
     wxASSERT ( wdc.IsKindOf(CLASSINFO(wxWindowDC)) );
 
+    // draw arrow so that there is even space horizontally
+    // on both sides
+    int arrowX = rect.width/4 + 1;
+    int arrowWidth = rect.width - (arrowX*2);
+
+    // scale arrow's height accoording to the width
+    int arrowHeight = rect.width/3;
+    int arrowY = (rect.height-arrowHeight)/2 +
+                 ((rect.height-arrowHeight) & 1);
+
     GtkStateType state;
 
     if ( flags & wxCONTROL_CURRENT )
@@ -429,7 +449,49 @@ void wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
         "arrow",
         GTK_ARROW_DOWN,
         FALSE,
-        rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2
+        rect.x + arrowX,
+        rect.y + arrowY,
+        arrowWidth,
+        arrowHeight
     );
 }
 
+void
+wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
+                                      wxDC& dc,
+                                      const wxRect& rect,
+                                      int flags)
+{
+    GtkWidget *button = GetButtonWidget();
+
+    // for reason why we do this, see DrawDropArrow
+    wxWindowDC& wdc = (wxWindowDC&)dc;
+    wxASSERT ( wdc.IsKindOf(CLASSINFO(wxWindowDC)) );
+
+    // draw button
+    GtkStateType state;
+
+    if ( flags & wxCONTROL_CURRENT )
+        state = GTK_STATE_PRELIGHT;
+    else if ( flags & wxCONTROL_DISABLED )
+        state = GTK_STATE_INSENSITIVE;
+    else
+        state = GTK_STATE_NORMAL;
+
+    gtk_paint_box
+    (
+        button->style,
+        wdc.m_window,
+        state,
+        flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
+        NULL,
+        button,
+        "button",
+        rect.x, rect.y, rect.width, rect.height
+    );
+
+    // draw arrow on button
+    DrawDropArrow(win,dc,rect,flags);
+
+}
+
diff --git a/src/gtk1/renderer.cpp b/src/gtk1/renderer.cpp
index baae5fe61b..8b545e1c39 100644
--- a/src/gtk1/renderer.cpp
+++ b/src/gtk1/renderer.cpp
@@ -79,6 +79,11 @@ public:
                                         const wxRect& rect,
                                         int flags = 0);
 
+    virtual void DrawDropArrow(wxWindow *win,
+                               wxDC& dc,
+                               const wxRect& rect,
+                               int flags = 0);
+
     virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
 
 private:
@@ -394,20 +399,35 @@ wxRendererGTK::DrawSplitterSash(wxWindow *win,
 #endif // GTK+ 2.x/1.x
 }
 
-void wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
-                                            wxDC& dc,
-                                            const wxRect& rect,
-                                            int flags)
+void
+wxRendererGTK::DrawDropArrow(wxWindow *win,
+                             wxDC& dc,
+                             const wxRect& rect,
+                             int flags)
 {
     GtkWidget *button = GetButtonWidget();
 
-    // device context must inherit from wxWindowDC
-    // (so it must be wxClientDC, wxMemoryDC or wxPaintDC)
+    // If we give GTK_PIZZA(win->m_wxwindow)->bin_window as
+    // a window for gtk_paint_xxx function, then it won't
+    // work for wxMemoryDC. So that is why we assume wxDC
+    // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
+    // are derived from it) and use its m_window.
     wxWindowDC& wdc = (wxWindowDC&)dc;
 
-    // only doing debug-time checking here (it should probably be enough)
+    // only doing debug-time checking here (it should
+    // probably be enough)
     wxASSERT ( wdc.IsKindOf(CLASSINFO(wxWindowDC)) );
 
+    // draw arrow so that there is even space horizontally
+    // on both sides
+    int arrowX = rect.width/4 + 1;
+    int arrowWidth = rect.width - (arrowX*2);
+
+    // scale arrow's height accoording to the width
+    int arrowHeight = rect.width/3;
+    int arrowY = (rect.height-arrowHeight)/2 +
+                 ((rect.height-arrowHeight) & 1);
+
     GtkStateType state;
 
     if ( flags & wxCONTROL_CURRENT )
@@ -429,7 +449,49 @@ void wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
         "arrow",
         GTK_ARROW_DOWN,
         FALSE,
-        rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2
+        rect.x + arrowX,
+        rect.y + arrowY,
+        arrowWidth,
+        arrowHeight
     );
 }
 
+void
+wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
+                                      wxDC& dc,
+                                      const wxRect& rect,
+                                      int flags)
+{
+    GtkWidget *button = GetButtonWidget();
+
+    // for reason why we do this, see DrawDropArrow
+    wxWindowDC& wdc = (wxWindowDC&)dc;
+    wxASSERT ( wdc.IsKindOf(CLASSINFO(wxWindowDC)) );
+
+    // draw button
+    GtkStateType state;
+
+    if ( flags & wxCONTROL_CURRENT )
+        state = GTK_STATE_PRELIGHT;
+    else if ( flags & wxCONTROL_DISABLED )
+        state = GTK_STATE_INSENSITIVE;
+    else
+        state = GTK_STATE_NORMAL;
+
+    gtk_paint_box
+    (
+        button->style,
+        wdc.m_window,
+        state,
+        flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
+        NULL,
+        button,
+        "button",
+        rect.x, rect.y, rect.width, rect.height
+    );
+
+    // draw arrow on button
+    DrawDropArrow(win,dc,rect,flags);
+
+}
+
-- 
2.50.0

