1/*
2 * Copyright (C) 2009 Kevin Ollivier  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#include "scrollbar_render.h"
29
30#include <wx/defs.h>
31
32#include <wx/dc.h>
33#include <wx/dcgraph.h>
34#include <wx/graphics.h>
35#include <wx/renderer.h>
36#include <wx/window.h>
37
38#include <wx/msw/private.h>
39#include <wx/msw/uxtheme.h>
40
41// constants
42#define SP_BUTTON          1
43#define SP_THUMBHOR        2
44#define SP_THUMBVERT       3
45#define SP_TRACKENDHOR      4
46#define SP_TRACKENDVERT     7
47#define SP_GRIPPERHOR       8
48#define SP_GRIPPERVERT      9
49
50#define TS_NORMAL           1
51#define TS_HOVER            2
52#define TS_ACTIVE           3
53#define TS_DISABLED         4
54
55#define TS_UP_BUTTON       0
56#define TS_DOWN_BUTTON     4
57#define TS_LEFT_BUTTON     8
58#define TS_RIGHT_BUTTON    12
59
60#if wxUSE_GRAPHICS_CONTEXT
61// TODO remove this dependency (gdiplus needs the macros)
62// we need to undef because the macros are being defined in WebCorePrefix.h
63// but GdiPlus.h is not accepting them
64#undef max
65#define max(a,b)            (((a) > (b)) ? (a) : (b))
66
67#undef min
68#define min(a,b)            (((a) < (b)) ? (a) : (b))
69
70#include <wx/dcgraph.h>
71#include "gdiplus.h"
72using namespace Gdiplus;
73#endif // wxUSE_GRAPHICS_CONTEXT
74
75class GraphicsHDC
76{
77public:
78    GraphicsHDC(wxDC* dc)
79    {
80#if wxUSE_GRAPHICS_CONTEXT
81        m_graphics = NULL;
82        wxGCDC* gcdc = wxDynamicCast(dc, wxGCDC);
83        if (gcdc) {
84            m_graphics = (Graphics*)gcdc->GetGraphicsContext()->GetNativeContext();
85            m_hdc = m_graphics->GetHDC();
86        }
87        else
88#endif
89            m_hdc = GetHdcOf(*dc);
90    }
91
92    ~GraphicsHDC()
93    {
94#if wxUSE_GRAPHICS_CONTEXT
95        if (m_graphics)
96            m_graphics->ReleaseHDC(m_hdc);
97#endif
98    }
99
100    operator HDC() const { return m_hdc; }
101
102private:
103    HDC         m_hdc;
104#if wxUSE_GRAPHICS_CONTEXT
105    Graphics*   m_graphics;
106#endif
107};
108
109int getTSStateForPart(wxScrollbarPart part, wxScrollbarPart focusPart, wxScrollbarPart hoverPart, int flags = 0)
110{
111    int xpState = TS_NORMAL;
112    if (flags & wxCONTROL_DISABLED)
113        xpState = TS_DISABLED;
114    else if (part == focusPart)
115        xpState = TS_ACTIVE;
116    else if (part == hoverPart)
117        xpState = TS_HOVER;
118
119    return xpState;
120}
121
122void wxRenderer_DrawScrollbar(wxWindow* window, wxDC& dc,
123                             const wxRect& rect, wxOrientation orient, int current, wxScrollbarPart focusPart, wxScrollbarPart hoverPart, int max, int step, int flags)
124{
125    wxUxThemeEngine *engine = wxUxThemeEngine::Get();
126    HTHEME hTheme = (HTHEME)engine->OpenThemeData(0, L"SCROLLBAR");
127
128    bool horiz = orient == wxHORIZONTAL;
129    int part = 0;
130    if (horiz)
131        part = SP_TRACKENDHOR;
132    else
133        part = SP_TRACKENDVERT;
134
135    int xpState = TS_NORMAL;
136    wxRect transRect = rect;
137
138#if USE(WXGC)
139    // when going from GdiPlus -> Gdi, any GdiPlus transformations are lost
140    // so we need to alter the coordinates to reflect their transformed point.
141    double xtrans = 0;
142    double ytrans = 0;
143
144    wxGCDC* gcdc = wxDynamicCast(&dc, wxGCDC);
145    wxGraphicsContext* gc = gcdc->GetGraphicsContext();
146    gc->GetTransform().TransformPoint(&xtrans, &ytrans);
147
148    transRect.x += (int)xtrans;
149    transRect.y += (int)ytrans;
150#endif
151
152    RECT r;
153    wxCopyRectToRECT(transRect, r);
154
155    // Unlike Mac, on MSW you draw the scrollbar piece by piece.
156    // so we draw the track first, then the buttons
157    if (hTheme)
158    {
159        engine->DrawThemeBackground(hTheme, GraphicsHDC(&dc), part, xpState, &r, 0);
160
161        int buttonSize = 16;
162
163        part = SP_BUTTON;
164        xpState = getTSStateForPart(wxSCROLLPART_BACKBTNSTART, focusPart, hoverPart, flags);
165        xpState += horiz ? TS_LEFT_BUTTON : TS_UP_BUTTON;
166        RECT buttonRect = r;
167        buttonRect.bottom = buttonRect.top + buttonSize;
168        buttonRect.right = buttonRect.left + buttonSize;
169        engine->DrawThemeBackground(hTheme, GraphicsHDC(&dc), part, xpState, &buttonRect, 0);
170
171        xpState = getTSStateForPart(wxSCROLLPART_FWDBTNEND, focusPart, hoverPart, flags);
172        xpState += horiz ? TS_RIGHT_BUTTON : TS_DOWN_BUTTON;
173        buttonRect = r;
174        buttonRect.top = buttonRect.bottom - buttonSize;
175        buttonRect.left = buttonRect.right - buttonSize;
176        engine->DrawThemeBackground(hTheme, GraphicsHDC(&dc), part, xpState, &buttonRect, 0);
177
178        part = horiz ? SP_THUMBHOR : SP_THUMBVERT;
179
180        int physicalLength = horiz ? rect.width : rect.height;
181        physicalLength -= buttonSize*2;
182        int thumbStart = 0;
183        int thumbLength = 0;
184        calcThumbStartAndLength(physicalLength, max,
185                            current, step, &thumbStart, &thumbLength);
186        buttonRect = r;
187        if (horiz) {
188            buttonRect.left = buttonRect.left + thumbStart + buttonSize;
189            buttonRect.right = buttonRect.left + thumbLength;
190        } else {
191            buttonRect.top = buttonRect.top + thumbStart + buttonSize;
192            buttonRect.bottom = buttonRect.top + thumbLength;
193        }
194
195        xpState = getTSStateForPart(wxSCROLLPART_THUMB, focusPart, hoverPart, flags);
196        engine->DrawThemeBackground(hTheme, GraphicsHDC(&dc), part, xpState, &buttonRect, 0);
197
198        // draw the gripper
199        int thickness = ::GetSystemMetrics(SM_CXVSCROLL) / 2;
200
201        buttonRect.left += ((buttonRect.right - buttonRect.left) - thickness) / 2;
202        buttonRect.top += ((buttonRect.bottom - buttonRect.top) - thickness) / 2;
203        buttonRect.right = buttonRect.left + thickness;
204        buttonRect.bottom = buttonRect.top + thickness;
205
206        if (horiz)
207            part = SP_GRIPPERHOR;
208        else
209            part = SP_GRIPPERVERT;
210
211        engine->DrawThemeBackground(hTheme, GraphicsHDC(&dc), part, xpState, &buttonRect, 0);
212    }
213}
214