Files
wxWidgets/src/univ/themes/win32.cpp
Vadim Zeitlin ebd98179c5 Use wxT() instead of _T() in XTI code.
_T() is deprecated and doesn't work with Solaris compiler, use wxT() instead.

Also change one occurrence of _T() inside a comment in wx/debug.h.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@70306 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2012-01-09 18:48:39 +00:00

3816 lines
109 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/univ/themes/win32.cpp
// Purpose: wxUniversal theme implementing Win32-like LNF
// Author: Vadim Zeitlin
// Modified by:
// Created: 06.08.00
// RCS-ID: $Id$
// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ===========================================================================
// declarations
// ===========================================================================
// ---------------------------------------------------------------------------
// headers
// ---------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include "wx/univ/theme.h"
#if wxUSE_THEME_WIN32
#ifndef WX_PRECOMP
#include "wx/timer.h"
#include "wx/intl.h"
#include "wx/dc.h"
#include "wx/window.h"
#include "wx/dcmemory.h"
#include "wx/dcclient.h"
#include "wx/button.h"
#include "wx/bmpbuttn.h"
#include "wx/listbox.h"
#include "wx/checklst.h"
#include "wx/combobox.h"
#include "wx/scrolbar.h"
#include "wx/slider.h"
#include "wx/textctrl.h"
#include "wx/toolbar.h"
#include "wx/statusbr.h"
#ifdef __WXMSW__
// for COLOR_* constants
#include "wx/msw/private.h"
#endif
#include "wx/menu.h"
#include "wx/settings.h"
#include "wx/toplevel.h"
#include "wx/image.h"
#endif // WX_PRECOMP
#include "wx/notebook.h"
#include "wx/spinbutt.h"
#include "wx/artprov.h"
#ifdef wxUSE_TOGGLEBTN
#include "wx/tglbtn.h"
#endif // wxUSE_TOGGLEBTN
#include "wx/univ/scrtimer.h"
#include "wx/univ/stdrend.h"
#include "wx/univ/inpcons.h"
#include "wx/univ/inphand.h"
#include "wx/univ/colschem.h"
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
static const int BORDER_THICKNESS = 2;
static const size_t NUM_STATUSBAR_GRIP_BANDS = 3;
static const size_t WIDTH_STATUSBAR_GRIP_BAND = 4;
static const size_t STATUSBAR_GRIP_SIZE =
WIDTH_STATUSBAR_GRIP_BAND*NUM_STATUSBAR_GRIP_BANDS;
static const wxCoord SLIDER_MARGIN = 6; // margin around slider
static const wxCoord SLIDER_THUMB_LENGTH = 18;
static const wxCoord SLIDER_TICK_LENGTH = 6;
// wxWin32Renderer: draw the GUI elements in Win32 style
// ----------------------------------------------------------------------------
class wxWin32Renderer : public wxStdRenderer
{
public:
// ctor
wxWin32Renderer(const wxColourScheme *scheme);
// reimplement the renderer methods which are different for this theme
virtual void DrawLabel(wxDC& dc,
const wxString& label,
const wxRect& rect,
int flags = 0,
int alignment = wxALIGN_LEFT | wxALIGN_TOP,
int indexAccel = -1,
wxRect *rectBounds = NULL);
virtual void DrawButtonLabel(wxDC& dc,
const wxString& label,
const wxBitmap& image,
const wxRect& rect,
int flags = 0,
int alignment = wxALIGN_LEFT | wxALIGN_TOP,
int indexAccel = -1,
wxRect *rectBounds = NULL);
virtual void DrawButtonBorder(wxDC& dc,
const wxRect& rect,
int flags = 0,
wxRect *rectIn = NULL);
virtual void DrawArrow(wxDC& dc,
wxDirection dir,
const wxRect& rect,
int flags = 0);
virtual void DrawScrollbarThumb(wxDC& dc,
wxOrientation orient,
const wxRect& rect,
int flags = 0);
virtual void DrawScrollbarShaft(wxDC& dc,
wxOrientation orient,
const wxRect& rect,
int flags = 0);
#if wxUSE_TOOLBAR
virtual void DrawToolBarButton(wxDC& dc,
const wxString& label,
const wxBitmap& bitmap,
const wxRect& rect,
int flags = 0,
long style = 0,
int tbarStyle = 0);
#endif // wxUSE_TOOLBAR
#if wxUSE_NOTEBOOK
virtual void DrawTab(wxDC& dc,
const wxRect& rect,
wxDirection dir,
const wxString& label,
const wxBitmap& bitmap = wxNullBitmap,
int flags = 0,
int indexAccel = -1);
#endif // wxUSE_NOTEBOOK
#if wxUSE_SLIDER
virtual void DrawSliderShaft(wxDC& dc,
const wxRect& rect,
int lenThumb,
wxOrientation orient,
int flags = 0,
long style = 0,
wxRect *rectShaft = NULL);
virtual void DrawSliderThumb(wxDC& dc,
const wxRect& rect,
wxOrientation orient,
int flags = 0,
long style = 0);
virtual void DrawSliderTicks(wxDC& dc,
const wxRect& rect,
int lenThumb,
wxOrientation orient,
int start,
int end,
int step = 1,
int flags = 0,
long style = 0);
#endif // wxUSE_SLIDER
#if wxUSE_MENUS
virtual void DrawMenuBarItem(wxDC& dc,
const wxRect& rect,
const wxString& label,
int flags = 0,
int indexAccel = -1);
virtual void DrawMenuItem(wxDC& dc,
wxCoord y,
const wxMenuGeometryInfo& geometryInfo,
const wxString& label,
const wxString& accel,
const wxBitmap& bitmap = wxNullBitmap,
int flags = 0,
int indexAccel = -1);
virtual void DrawMenuSeparator(wxDC& dc,
wxCoord y,
const wxMenuGeometryInfo& geomInfo);
#endif // wxUSE_MENUS
#if wxUSE_STATUSBAR
virtual void DrawStatusField(wxDC& dc,
const wxRect& rect,
const wxString& label,
int flags = 0, int style = 0);
#endif // wxUSE_STATUSBAR
virtual void GetComboBitmaps(wxBitmap *bmpNormal,
wxBitmap *bmpFocus,
wxBitmap *bmpPressed,
wxBitmap *bmpDisabled);
virtual void AdjustSize(wxSize *size, const wxWindow *window);
virtual bool AreScrollbarsInsideBorder() const;
virtual wxSize GetScrollbarArrowSize() const
{ return m_sizeScrollbarArrow; }
virtual wxSize GetCheckBitmapSize() const
{ return wxSize(13, 13); }
virtual wxSize GetRadioBitmapSize() const
{ return wxSize(12, 12); }
virtual wxCoord GetCheckItemMargin() const
{ return 0; }
#if wxUSE_TOOLBAR
virtual wxSize GetToolBarButtonSize(wxCoord *separator) const
{ if ( separator ) *separator = 5; return wxSize(16, 15); }
virtual wxSize GetToolBarMargin() const
{ return wxSize(4, 4); }
#endif // wxUSE_TOOLBAR
#if wxUSE_TEXTCTRL
virtual wxRect GetTextTotalArea(const wxTextCtrl *text,
const wxRect& rect) const;
virtual wxRect GetTextClientArea(const wxTextCtrl *text,
const wxRect& rect,
wxCoord *extraSpaceBeyond) const;
#endif // wxUSE_TEXTCTRL
#if wxUSE_NOTEBOOK
virtual wxSize GetTabIndent() const { return wxSize(2, 2); }
virtual wxSize GetTabPadding() const { return wxSize(6, 5); }
#endif // wxUSE_NOTEBOOK
#if wxUSE_SLIDER
virtual wxCoord GetSliderDim() const { return SLIDER_THUMB_LENGTH + 2*BORDER_THICKNESS; }
virtual wxCoord GetSliderTickLen() const { return SLIDER_TICK_LENGTH; }
virtual wxRect GetSliderShaftRect(const wxRect& rect,
int lenThumb,
wxOrientation orient,
long style = 0) const;
virtual wxSize GetSliderThumbSize(const wxRect& rect,
int lenThumb,
wxOrientation orient) const;
#endif // wxUSE_SLIDER
virtual wxSize GetProgressBarStep() const { return wxSize(16, 32); }
#if wxUSE_MENUS
virtual wxSize GetMenuBarItemSize(const wxSize& sizeText) const;
virtual wxMenuGeometryInfo *GetMenuGeometry(wxWindow *win,
const wxMenu& menu) const;
#endif // wxUSE_MENUS
protected:
// overridden wxStdRenderer methods
virtual void DrawFrameWithLabel(wxDC& dc,
const wxString& label,
const wxRect& rectFrame,
const wxRect& rectText,
int flags,
int alignment,
int indexAccel);
virtual void DrawCheckItemBitmap(wxDC& dc,
const wxBitmap& bitmap,
const wxRect& rect,
int flags);
// draw the border used for scrollbar arrows
void DrawArrowBorder(wxDC& dc, wxRect *rect, bool isPressed = false);
// public DrawArrow()s helper
void DrawArrow(wxDC& dc, const wxRect& rect,
ArrowDirection arrowDir, ArrowStyle arrowStyle);
// DrawArrowButton is used by DrawScrollbar and DrawComboButton
void DrawArrowButton(wxDC& dc, const wxRect& rect,
ArrowDirection arrowDir,
ArrowStyle arrowStyle);
// draw a normal or transposed line (useful for using the same code fo both
// horizontal and vertical widgets)
void DrawLine(wxDC& dc,
wxCoord x1, wxCoord y1,
wxCoord x2, wxCoord y2,
bool transpose = false)
{
if ( transpose )
dc.DrawLine(y1, x1, y2, x2);
else
dc.DrawLine(x1, y1, x2, y2);
}
// get the standard check/radio button bitmap
wxBitmap GetIndicator(IndicatorType indType, int flags);
virtual wxBitmap GetCheckBitmap(int flags)
{ return GetIndicator(IndicatorType_Check, flags); }
virtual wxBitmap GetRadioBitmap(int flags)
{ return GetIndicator(IndicatorType_Radio, flags); }
virtual wxBitmap GetFrameButtonBitmap(FrameButtonType type);
#if wxUSE_SLIDER
// Fill the arguments with true or false if this slider has labels on
// left/right side (or top/bottom for horizontal sliders) respectively
static
void GetSliderLabelsSides(wxOrientation orient, long style,
bool *left, bool *right)
{
// should we draw ticks at all?
if ( !(style & wxSL_AUTOTICKS) )
{
*left =
*right = false;
return;
}
// should we draw them on both sides?
if ( style & wxSL_BOTH )
{
*left =
*right = true;
return;
}
// we draw them on one side only, determine which one
if ( ((style & wxSL_TOP) && (orient == wxHORIZONTAL)) ||
((style & wxSL_LEFT) && (orient == wxVERTICAL)) )
{
*left = true;
*right = false;
}
else if ( ((style & wxSL_BOTTOM) && (orient == wxHORIZONTAL)) ||
((style & wxSL_RIGHT) && (orient == wxVERTICAL)) )
{
*left = false;
*right = true;
}
else
{
wxFAIL_MSG( "inconsistent wxSlider flags" );
*left =
*right = false;
}
}
#endif // wxUSE_SLIDER
private:
// the sizing parameters (TODO make them changeable)
wxSize m_sizeScrollbarArrow;
// the checked and unchecked bitmaps for DrawCheckItemBitmap()
wxBitmap m_bmpCheckBitmaps[IndicatorStatus_Max];
// the bitmaps returned by GetIndicator()
wxBitmap m_bmpIndicators[IndicatorType_Max]
[IndicatorState_MaxMenu]
[IndicatorStatus_Max];
// titlebar icons:
wxBitmap m_bmpFrameButtons[FrameButton_Max];
// standard defaults for the above bitmaps
static const char **ms_xpmChecked[IndicatorStatus_Max];
static const char **ms_xpmIndicators[IndicatorType_Max]
[IndicatorState_MaxMenu]
[IndicatorStatus_Max];
static const char **ms_xpmFrameButtons[FrameButton_Max];
// first row is for the normal state, second - for the disabled
wxBitmap m_bmpArrows[Arrow_StateMax][Arrow_Max];
};
// ----------------------------------------------------------------------------
// wxWin32InputHandler and derived classes: process the keyboard and mouse
// messages according to Windows standards
// ----------------------------------------------------------------------------
class wxWin32InputHandler : public wxInputHandler
{
public:
wxWin32InputHandler() { }
virtual bool HandleKey(wxInputConsumer *control,
const wxKeyEvent& event,
bool pressed);
virtual bool HandleMouse(wxInputConsumer *control,
const wxMouseEvent& event);
};
#if wxUSE_SCROLLBAR
class wxWin32ScrollBarInputHandler : public wxStdScrollBarInputHandler
{
public:
wxWin32ScrollBarInputHandler(wxRenderer *renderer,
wxInputHandler *handler);
virtual bool HandleMouse(wxInputConsumer *control,
const wxMouseEvent& event);
virtual bool HandleMouseMove(wxInputConsumer *control,
const wxMouseEvent& event);
virtual bool OnScrollTimer(wxScrollBar *scrollbar,
const wxControlAction& action);
protected:
virtual void Highlight(wxScrollBar * WXUNUSED(scrollbar),
bool WXUNUSED(doIt))
{
// we don't highlight anything
}
// the first and last event which caused the thumb to move
wxMouseEvent m_eventStartDrag,
m_eventLastDrag;
// have we paused the scrolling because the mouse moved?
bool m_scrollPaused;
// we remember the interval of the timer to be able to restart it
int m_interval;
};
#endif // wxUSE_SCROLLBAR
#if wxUSE_CHECKBOX
class wxWin32CheckboxInputHandler : public wxStdInputHandler
{
public:
wxWin32CheckboxInputHandler(wxInputHandler *handler)
: wxStdInputHandler(handler) { }
virtual bool HandleKey(wxInputConsumer *control,
const wxKeyEvent& event,
bool pressed);
};
#endif // wxUSE_CHECKBOX
#if wxUSE_TEXTCTRL
class wxWin32TextCtrlInputHandler : public wxStdInputHandler
{
public:
wxWin32TextCtrlInputHandler(wxInputHandler *handler)
: wxStdInputHandler(handler) { }
virtual bool HandleKey(wxInputConsumer *control,
const wxKeyEvent& event,
bool pressed);
};
#endif // wxUSE_TEXTCTRL
class wxWin32StatusBarInputHandler : public wxStdInputHandler
{
public:
wxWin32StatusBarInputHandler(wxInputHandler *handler);
virtual bool HandleMouse(wxInputConsumer *consumer,
const wxMouseEvent& event);
virtual bool HandleMouseMove(wxInputConsumer *consumer,
const wxMouseEvent& event);
protected:
// is the given point over the statusbar grip?
bool IsOnGrip(wxWindow *statbar, const wxPoint& pt) const;
private:
// the cursor we had replaced with the resize one
wxCursor m_cursorOld;
// was the mouse over the grip last time we checked?
bool m_isOnGrip;
};
class wxWin32SystemMenuEvtHandler;
class wxWin32FrameInputHandler : public wxStdInputHandler
{
public:
wxWin32FrameInputHandler(wxInputHandler *handler);
virtual ~wxWin32FrameInputHandler();
virtual bool HandleMouse(wxInputConsumer *control,
const wxMouseEvent& event);
virtual bool HandleActivation(wxInputConsumer *consumer, bool activated);
#if wxUSE_MENUS
void PopupSystemMenu(wxTopLevelWindow *window) const;
#endif // wxUSE_MENUS
private:
// was the mouse over the grip last time we checked?
wxWin32SystemMenuEvtHandler *m_menuHandler;
};
// ----------------------------------------------------------------------------
// wxWin32ColourScheme: uses (default) Win32 colours
// ----------------------------------------------------------------------------
class wxWin32ColourScheme : public wxColourScheme
{
public:
virtual wxColour Get(StdColour col) const;
virtual wxColour GetBackground(wxWindow *win) const;
};
// ----------------------------------------------------------------------------
// wxWin32ArtProvider
// ----------------------------------------------------------------------------
class wxWin32ArtProvider : public wxArtProvider
{
protected:
virtual wxBitmap CreateBitmap(const wxArtID& id,
const wxArtClient& client,
const wxSize& size);
};
// ----------------------------------------------------------------------------
// wxWin32Theme
// ----------------------------------------------------------------------------
WX_DEFINE_ARRAY_PTR(wxInputHandler *, wxArrayHandlers);
class wxWin32Theme : public wxTheme
{
public:
wxWin32Theme();
virtual ~wxWin32Theme();
virtual wxRenderer *GetRenderer();
virtual wxArtProvider *GetArtProvider();
virtual wxInputHandler *GetInputHandler(const wxString& control,
wxInputConsumer *consumer);
virtual wxColourScheme *GetColourScheme();
private:
wxWin32Renderer *m_renderer;
wxWin32ArtProvider *m_artProvider;
// the names of the already created handlers and the handlers themselves
// (these arrays are synchronized)
wxSortedArrayString m_handlerNames;
wxArrayHandlers m_handlers;
wxWin32ColourScheme *m_scheme;
WX_DECLARE_THEME(win32)
};
// ----------------------------------------------------------------------------
// standard bitmaps
// ----------------------------------------------------------------------------
// frame buttons bitmaps
static const char *frame_button_close_xpm[] = {
"12 10 2 1",
" c None",
"X c black",
" ",
" XX XX ",
" XX XX ",
" XXXX ",
" XX ",
" XXXX ",
" XX XX ",
" XX XX ",
" ",
" "};
static const char *frame_button_help_xpm[] = {
"12 10 2 1",
" c None",
"X c #000000",
" XXXX ",
" XX XX ",
" XX XX ",
" XX ",
" XX ",
" XX ",
" ",
" XX ",
" XX ",
" "};
static const char *frame_button_maximize_xpm[] = {
"12 10 2 1",
" c None",
"X c #000000",
" XXXXXXXXX ",
" XXXXXXXXX ",
" X X ",
" X X ",
" X X ",
" X X ",
" X X ",
" X X ",
" XXXXXXXXX ",
" "};
static const char *frame_button_minimize_xpm[] = {
"12 10 2 1",
" c None",
"X c #000000",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" XXXXXX ",
" XXXXXX ",
" "};
static const char *frame_button_restore_xpm[] = {
"12 10 2 1",
" c None",
"X c #000000",
" XXXXXX ",
" XXXXXX ",
" X X ",
" XXXXXX X ",
" XXXXXX X ",
" X XXX ",
" X X ",
" X X ",
" XXXXXX ",
" "};
const char **wxWin32Renderer::ms_xpmFrameButtons[FrameButton_Max] =
{
frame_button_close_xpm,
frame_button_minimize_xpm,
frame_button_maximize_xpm,
frame_button_restore_xpm,
frame_button_help_xpm,
};
// menu bitmaps
static const char *checked_menu_xpm[] = {
/* columns rows colors chars-per-pixel */
"9 9 2 1",
"w c None",
"b c black",
/* pixels */
"wwwwwwwww",
"wwwwwwwbw",
"wwwwwwbbw",
"wbwwwbbbw",
"wbbwbbbww",
"wbbbbbwww",
"wwbbbwwww",
"wwwbwwwww",
"wwwwwwwww"
};
static const char *selected_checked_menu_xpm[] = {
/* columns rows colors chars-per-pixel */
"9 9 2 1",
"w c None",
"b c white",
/* pixels */
"wwwwwwwww",
"wwwwwwwbw",
"wwwwwwbbw",
"wbwwwbbbw",
"wbbwbbbww",
"wbbbbbwww",
"wwbbbwwww",
"wwwbwwwww",
"wwwwwwwww"
};
static const char *disabled_checked_menu_xpm[] = {
/* columns rows colors chars-per-pixel */
"9 9 3 1",
"w c None",
"b c #7f7f7f",
"W c #e0e0e0",
/* pixels */
"wwwwwwwww",
"wwwwwwwbw",
"wwwwwwbbW",
"wbwwwbbbW",
"wbbwbbbWW",
"wbbbbbWWw",
"wwbbbWWww",
"wwwbWWwww",
"wwwwWwwww"
};
static const char *selected_disabled_checked_menu_xpm[] = {
/* columns rows colors chars-per-pixel */
"9 9 2 1",
"w c None",
"b c #7f7f7f",
/* pixels */
"wwwwwwwww",
"wwwwwwwbw",
"wwwwwwbbw",
"wbwwwbbbw",
"wbbwbbbww",
"wbbbbbwww",
"wwbbbwwww",
"wwwbwwwww",
"wwwwwwwww"
};
// checkbox and radiobox bitmaps below
static const char *checked_xpm[] = {
/* columns rows colors chars-per-pixel */
"13 13 5 1",
"w c white",
"b c black",
"d c #7f7f7f",
"g c #c0c0c0",
"h c #e0e0e0",
/* pixels */
"ddddddddddddh",
"dbbbbbbbbbbgh",
"dbwwwwwwwwwgh",
"dbwwwwwwwbwgh",
"dbwwwwwwbbwgh",
"dbwbwwwbbbwgh",
"dbwbbwbbbwwgh",
"dbwbbbbbwwwgh",
"dbwwbbbwwwwgh",
"dbwwwbwwwwwgh",
"dbwwwwwwwwwgh",
"dgggggggggggh",
"hhhhhhhhhhhhh"
};
static const char *pressed_checked_xpm[] = {
/* columns rows colors chars-per-pixel */
"13 13 4 1",
"b c black",
"d c #7f7f7f",
"g c #c0c0c0",
"h c #e0e0e0",
/* pixels */
"ddddddddddddh",
"dbbbbbbbbbbgh",
"dbggggggggggh",
"dbgggggggbggh",
"dbggggggbbggh",
"dbgbgggbbbggh",
"dbgbbgbbbgggh",
"dbgbbbbbggggh",
"dbggbbbgggggh",
"dbgggbggggggh",
"dbggggggggggh",
"dgggggggggggh",
"hhhhhhhhhhhhh"
};
static const char *pressed_disabled_checked_xpm[] = {
/* columns rows colors chars-per-pixel */
"13 13 4 1",
"b c black",
"d c #7f7f7f",
"g c #c0c0c0",
"h c #e0e0e0",
/* pixels */
"ddddddddddddh",
"dbbbbbbbbbbgh",
"dbggggggggggh",
"dbgggggggdggh",
"dbggggggddggh",
"dbgdgggdddggh",
"dbgddgdddgggh",
"dbgdddddggggh",
"dbggdddgggggh",
"dbgggdggggggh",
"dbggggggggggh",
"dgggggggggggh",
"hhhhhhhhhhhhh"
};
static const char *checked_item_xpm[] = {
/* columns rows colors chars-per-pixel */
"13 13 3 1",
"w c white",
"b c black",
"d c #808080",
/* pixels */
"wwwwwwwwwwwww",
"wdddddddddddw",
"wdwwwwwwwwwdw",
"wdwwwwwwwbwdw",
"wdwwwwwwbbwdw",
"wdwbwwwbbbwdw",
"wdwbbwbbbwwdw",
"wdwbbbbbwwwdw",
"wdwwbbbwwwwdw",
"wdwwwbwwwwwdw",
"wdwwwwwwwwwdw",
"wdddddddddddw",
"wwwwwwwwwwwww"
};
static const char *unchecked_xpm[] = {
/* columns rows colors chars-per-pixel */
"13 13 5 1",
"w c white",
"b c black",
"d c #7f7f7f",
"g c #c0c0c0",
"h c #e0e0e0",
/* pixels */
"ddddddddddddh",
"dbbbbbbbbbbgh",
"dbwwwwwwwwwgh",
"dbwwwwwwwwwgh",
"dbwwwwwwwwwgh",
"dbwwwwwwwwwgh",
"dbwwwwwwwwwgh",
"dbwwwwwwwwwgh",
"dbwwwwwwwwwgh",
"dbwwwwwwwwwgh",
"dbwwwwwwwwwgh",
"dgggggggggggh",
"hhhhhhhhhhhhh"
};
static const char *pressed_unchecked_xpm[] = {
/* columns rows colors chars-per-pixel */
"13 13 4 1",
"b c black",
"d c #7f7f7f",
"g c #c0c0c0",
"h c #e0e0e0",
/* pixels */
"ddddddddddddh",
"dbbbbbbbbbbgh",
"dbggggggggggh",
"dbggggggggggh",
"dbggggggggggh",
"dbggggggggggh",
"dbggggggggggh",
"dbggggggggggh",
"dbggggggggggh",
"dbggggggggggh",
"dbggggggggggh",
"dbggggggggggh",
"hhhhhhhhhhhhh"
};
static const char *unchecked_item_xpm[] = {
/* columns rows colors chars-per-pixel */
"13 13 2 1",
"w c white",
"d c #808080",
/* pixels */
"wwwwwwwwwwwww",
"wdddddddddddw",
"wdwwwwwwwwwdw",
"wdwwwwwwwwwdw",
"wdwwwwwwwwwdw",
"wdwwwwwwwwwdw",
"wdwwwwwwwwwdw",
"wdwwwwwwwwwdw",
"wdwwwwwwwwwdw",
"wdwwwwwwwwwdw",
"wdwwwwwwwwwdw",
"wdddddddddddw",
"wwwwwwwwwwwww"
};
static const char *undetermined_xpm[] = {
/* columns rows colors chars-per-pixel */
"13 13 5 1",
"A c #030303",
"B c #838383",
"C c #C3C3C3",
"D c #FBFBFB",
"E c #DBDBDB",
/* pixels */
"BBBBBBBBBBBBD",
"BAAAAAAAAAAED",
"BACDCDCDCDCED",
"BADCDCDCDBDED",
"BACDCDCDBBCED",
"BADBDCEBBBDED",
"BACBBDBBBDCED",
"BADBBBBBDCDED",
"BACDBBBDCDCED",
"BADCDBDCDCDED",
"BACDCDCDCDCED",
"BEEEEEEEEEEED",
"DDDDDDDDDDDDD"
};
static const char *pressed_undetermined_xpm[] = {
/* columns rows colors chars-per-pixel */
"13 13 5 1",
"A c #040404",
"B c #848484",
"C c #C4C4C4",
"D c #FCFCFC",
"E c #DCDCDC",
/* pixels */
"BBBBBBBBBBBBD",
"BAAAAAAAAAAED",
"BACCCCCCCCCCD",
"BACCCCCCCACED",
"BACCCCCCAACED",
"BACACCCAAACED",
"BACAACAAACCED",
"BACAAAAACCCED",
"BACCAAACCCCCD",
"BACCCACCCCCED",
"BACCCCCCCCCED",
"BEEEEEEEEEEED",
"DDDDDDDDDDDDD"
};
static const char *checked_radio_xpm[] = {
/* columns rows colors chars-per-pixel */
"12 12 6 1",
" c None",
"w c white",
"b c black",
"d c #7f7f7f",
"g c #c0c0c0",
"h c #e0e0e0",
/* pixels */
" dddd ",
" ddbbbbdd ",
" dbbwwwwbbh ",
" dbwwwwwwgh ",
"dbwwwbbwwwgh",
"dbwwbbbbwwgh",
"dbwwbbbbwwgh",
"dbwwwbbwwwgh",
" dbwwwwwwgh ",
" dggwwwwggh ",
" hhgggghh ",
" hhhh "
};
static const char *pressed_checked_radio_xpm[] = {
/* columns rows colors chars-per-pixel */
"12 12 6 1",
" c None",
"w c white",
"b c black",
"d c #7f7f7f",
"g c #c0c0c0",
"h c #e0e0e0",
/* pixels */
" dddd ",
" ddbbbbdd ",
" dbbggggbbh ",
" dbgggggggh ",
"dbgggbbggggh",
"dbggbbbbgggh",
"dbggbbbbgggh",
"dbgggbbggggh",
" dbgggggggh ",
" dggggggggh ",
" hhgggghh ",
" hhhh "
};
static const char *pressed_disabled_checked_radio_xpm[] = {
/* columns rows colors chars-per-pixel */
"12 12 6 1",
" c None",
"w c white",
"b c black",
"d c #7f7f7f",
"g c #c0c0c0",
"h c #e0e0e0",
/* pixels */
" dddd ",
" ddbbbbdd ",
" dbbggggbbh ",
" dbgggggggh ",
"dbgggddggggh",
"dbggddddgggh",
"dbggddddgggh",
"dbgggddggggh",
" dbgggggggh ",
" dggggggggh ",
" hhgggghh ",
" hhhh ",
};
static const char *unchecked_radio_xpm[] = {
/* columns rows colors chars-per-pixel */
"12 12 6 1",
" c None",
"w c white",
"b c black",
"d c #7f7f7f",
"g c #c0c0c0",
"h c #e0e0e0",
/* pixels */
" dddd ",
" ddbbbbdd ",
" dbbwwwwbbh ",
" dbwwwwwwgh ",
"dbwwwwwwwwgh",
"dbwwwwwwwwgh",
"dbwwwwwwwwgh",
"dbwwwwwwwwgh",
" dbwwwwwwgh ",
" dggwwwwggh ",
" hhgggghh ",
" hhhh "
};
static const char *pressed_unchecked_radio_xpm[] = {
/* columns rows colors chars-per-pixel */
"12 12 6 1",
" c None",
"w c white",
"b c black",
"d c #7f7f7f",
"g c #c0c0c0",
"h c #e0e0e0",
/* pixels */
" dddd ",
" ddbbbbdd ",
" dbbggggbbh ",
" dbgggggggh ",
"dbgggggggggh",
"dbgggggggggh",
"dbgggggggggh",
"dbgggggggggh",
" dbgggggggh ",
" dggggggggh ",
" hhgggghh ",
" hhhh "
};
const char **wxWin32Renderer::ms_xpmIndicators[IndicatorType_Max]
[IndicatorState_MaxMenu]
[IndicatorStatus_Max] =
{
// checkboxes first
{
// normal state
{ checked_xpm, unchecked_xpm, undetermined_xpm },
// pressed state
{ pressed_checked_xpm, pressed_unchecked_xpm, pressed_undetermined_xpm },
// disabled state
{ pressed_disabled_checked_xpm, pressed_unchecked_xpm, pressed_disabled_checked_xpm },
},
// radio
{
// normal state
{ checked_radio_xpm, unchecked_radio_xpm, NULL },
// pressed state
{ pressed_checked_radio_xpm, pressed_unchecked_radio_xpm, NULL },
// disabled state
{ pressed_disabled_checked_radio_xpm, pressed_unchecked_radio_xpm, NULL },
},
// menu
{
// normal state
{ checked_menu_xpm, NULL, NULL },
// selected state
{ selected_checked_menu_xpm, NULL, NULL },
// disabled state
{ disabled_checked_menu_xpm, NULL, NULL },
// disabled selected state
{ selected_disabled_checked_menu_xpm, NULL, NULL },
}
};
const char **wxWin32Renderer::ms_xpmChecked[IndicatorStatus_Max] =
{
checked_item_xpm,
unchecked_item_xpm
};
// ============================================================================
// implementation
// ============================================================================
WX_IMPLEMENT_THEME(wxWin32Theme, win32, wxTRANSLATE("Win32 theme"));
// ----------------------------------------------------------------------------
// wxWin32Theme
// ----------------------------------------------------------------------------
wxWin32Theme::wxWin32Theme()
{
m_scheme = NULL;
m_renderer = NULL;
m_artProvider = NULL;
}
wxWin32Theme::~wxWin32Theme()
{
delete m_renderer;
delete m_scheme;
delete m_artProvider;
}
wxRenderer *wxWin32Theme::GetRenderer()
{
if ( !m_renderer )
{
m_renderer = new wxWin32Renderer(GetColourScheme());
}
return m_renderer;
}
wxArtProvider *wxWin32Theme::GetArtProvider()
{
if ( !m_artProvider )
{
m_artProvider = new wxWin32ArtProvider;
}
return m_artProvider;
}
wxInputHandler *
wxWin32Theme::GetInputHandler(const wxString& control,
wxInputConsumer *consumer)
{
wxInputHandler *handler = NULL;
int n = m_handlerNames.Index(control);
if ( n == wxNOT_FOUND )
{
static wxWin32InputHandler s_handlerDef;
wxInputHandler * const
handlerStd = consumer->DoGetStdInputHandler(&s_handlerDef);
// create a new handler
if ( control == wxINP_HANDLER_TOPLEVEL )
{
static wxWin32FrameInputHandler s_handler(handlerStd);
handler = &s_handler;
}
#if wxUSE_CHECKBOX
else if ( control == wxINP_HANDLER_CHECKBOX )
{
static wxWin32CheckboxInputHandler s_handler(handlerStd);
handler = &s_handler;
}
#endif // wxUSE_CHECKBOX
#if wxUSE_SCROLLBAR
else if ( control == wxINP_HANDLER_SCROLLBAR )
{
static wxWin32ScrollBarInputHandler
s_handler(GetRenderer(), handlerStd);
handler = &s_handler;
}
#endif // wxUSE_SCROLLBAR
#if wxUSE_STATUSBAR
else if ( control == wxINP_HANDLER_STATUSBAR )
{
static wxWin32StatusBarInputHandler s_handler(handlerStd);
handler = &s_handler;
}
#endif // wxUSE_STATUSBAR
#if wxUSE_TEXTCTRL
else if ( control == wxINP_HANDLER_TEXTCTRL )
{
static wxWin32TextCtrlInputHandler s_handler(handlerStd);
handler = &s_handler;
}
#endif // wxUSE_TEXTCTRL
else // no special handler for this control
{
handler = handlerStd;
}
n = m_handlerNames.Add(control);
m_handlers.Insert(handler, n);
}
else // we already have it
{
handler = m_handlers[n];
}
return handler;
}
wxColourScheme *wxWin32Theme::GetColourScheme()
{
if ( !m_scheme )
{
m_scheme = new wxWin32ColourScheme;
}
return m_scheme;
}
// ============================================================================
// wxWin32ColourScheme
// ============================================================================
wxColour wxWin32ColourScheme::GetBackground(wxWindow *win) const
{
wxColour col;
if ( win->UseBgCol() )
{
// use the user specified colour
col = win->GetBackgroundColour();
}
if ( !win->ShouldInheritColours() )
{
#if wxUSE_TEXTCTRL
wxTextCtrl *text = wxDynamicCast(win, wxTextCtrl);
#endif // wxUSE_TEXTCTRL
#if wxUSE_LISTBOX
wxListBox* listBox = wxDynamicCast(win, wxListBox);
#endif // wxUSE_LISTBOX
#if wxUSE_TEXTCTRL
if ( text
#if wxUSE_LISTBOX
|| listBox
#endif
)
{
if ( !win->IsEnabled() ) // not IsEditable()
col = Get(CONTROL);
else
{
if ( !col.IsOk() )
{
// doesn't depend on the state
col = Get(WINDOW);
}
}
}
#endif // wxUSE_TEXTCTRL
if (!col.IsOk())
col = Get(CONTROL); // Most controls should be this colour, not WINDOW
}
else
{
int flags = win->GetStateFlags();
// the colour set by the user should be used for the normal state
// and for the states for which we don't have any specific colours
if ( !col.IsOk() || (flags & wxCONTROL_PRESSED) != 0 )
{
#if wxUSE_SCROLLBAR
if ( wxDynamicCast(win, wxScrollBar) )
col = Get(flags & wxCONTROL_PRESSED ? SCROLLBAR_PRESSED
: SCROLLBAR);
else
#endif // wxUSE_SCROLLBAR
col = Get(CONTROL);
}
}
return col;
}
wxColour wxWin32ColourScheme::Get(wxWin32ColourScheme::StdColour col) const
{
switch ( col )
{
// use the system colours under Windows
#if defined(__WXMSW__)
case WINDOW: return wxColour(GetSysColor(COLOR_WINDOW));
case CONTROL_PRESSED:
case CONTROL_CURRENT:
case CONTROL: return wxColour(GetSysColor(COLOR_BTNFACE));
case CONTROL_TEXT: return wxColour(GetSysColor(COLOR_BTNTEXT));
#if defined(COLOR_3DLIGHT)
case SCROLLBAR: return wxColour(GetSysColor(COLOR_3DLIGHT));
#else
case SCROLLBAR: return wxColour(0xe0e0e0);
#endif
case SCROLLBAR_PRESSED: return wxColour(GetSysColor(COLOR_BTNTEXT));
case HIGHLIGHT: return wxColour(GetSysColor(COLOR_HIGHLIGHT));
case HIGHLIGHT_TEXT: return wxColour(GetSysColor(COLOR_HIGHLIGHTTEXT));
#if defined(COLOR_3DDKSHADOW)
case SHADOW_DARK: return wxColour(GetSysColor(COLOR_3DDKSHADOW));
#else
case SHADOW_DARK: return wxColour(GetSysColor(COLOR_3DHADOW));
#endif
case CONTROL_TEXT_DISABLED:
case SHADOW_HIGHLIGHT: return wxColour(GetSysColor(COLOR_BTNHIGHLIGHT));
case SHADOW_IN: return wxColour(GetSysColor(COLOR_BTNFACE));
case CONTROL_TEXT_DISABLED_SHADOW:
case SHADOW_OUT: return wxColour(GetSysColor(COLOR_BTNSHADOW));
case TITLEBAR: return wxColour(GetSysColor(COLOR_INACTIVECAPTION));
case TITLEBAR_ACTIVE: return wxColour(GetSysColor(COLOR_ACTIVECAPTION));
case TITLEBAR_TEXT: return wxColour(GetSysColor(COLOR_INACTIVECAPTIONTEXT));
case TITLEBAR_ACTIVE_TEXT: return wxColour(GetSysColor(COLOR_CAPTIONTEXT));
case DESKTOP: return wxColour(0x808000);
case FRAME: return wxColour(GetSysColor(COLOR_APPWORKSPACE));
#else // !__WXMSW__
// use the standard Windows colours elsewhere
case WINDOW: return *wxWHITE;
case CONTROL_PRESSED:
case CONTROL_CURRENT:
case CONTROL: return wxColour(0xc0c0c0);
case CONTROL_TEXT: return *wxBLACK;
case SCROLLBAR: return wxColour(0xe0e0e0);
case SCROLLBAR_PRESSED: return *wxBLACK;
case HIGHLIGHT: return wxColour(0x800000);
case HIGHLIGHT_TEXT: return wxColour(0xffffff);
case SHADOW_DARK: return *wxBLACK;
case CONTROL_TEXT_DISABLED:return wxColour(0xe0e0e0);
case SHADOW_HIGHLIGHT: return wxColour(0xffffff);
case SHADOW_IN: return wxColour(0xc0c0c0);
case CONTROL_TEXT_DISABLED_SHADOW:
case SHADOW_OUT: return wxColour(0x7f7f7f);
case TITLEBAR: return wxColour(0xaeaaae);
case TITLEBAR_ACTIVE: return wxColour(0x820300);
case TITLEBAR_TEXT: return wxColour(0xc0c0c0);
case TITLEBAR_ACTIVE_TEXT:return *wxWHITE;
case DESKTOP: return wxColour(0x808000);
case FRAME: return wxColour(0x808080);
#endif // __WXMSW__
case GAUGE: return Get(HIGHLIGHT);
case MAX:
default:
wxFAIL_MSG(wxT("invalid standard colour"));
return *wxBLACK;
}
}
// ============================================================================
// wxWin32Renderer
// ============================================================================
// ----------------------------------------------------------------------------
// construction
// ----------------------------------------------------------------------------
wxWin32Renderer::wxWin32Renderer(const wxColourScheme *scheme)
: wxStdRenderer(scheme)
{
// init data
m_sizeScrollbarArrow = wxSize(16, 16);
// init the arrow bitmaps
static const size_t ARROW_WIDTH = 7;
static const size_t ARROW_LENGTH = 4;
wxMask *mask;
wxMemoryDC dcNormal,
dcDisabled,
dcInverse;
for ( size_t n = 0; n < Arrow_Max; n++ )
{
bool isVertical = n > Arrow_Right;
int w, h;
if ( isVertical )
{
w = ARROW_WIDTH;
h = ARROW_LENGTH;
}
else
{
h = ARROW_WIDTH;
w = ARROW_LENGTH;
}
// disabled arrow is larger because of the shadow
m_bmpArrows[Arrow_Normal][n].Create(w, h);
m_bmpArrows[Arrow_Disabled][n].Create(w + 1, h + 1);
dcNormal.SelectObject(m_bmpArrows[Arrow_Normal][n]);
dcDisabled.SelectObject(m_bmpArrows[Arrow_Disabled][n]);
dcNormal.SetBackground(*wxWHITE_BRUSH);
dcDisabled.SetBackground(*wxWHITE_BRUSH);
dcNormal.Clear();
dcDisabled.Clear();
dcNormal.SetPen(m_penBlack);
dcDisabled.SetPen(m_penDarkGrey);
// calculate the position of the point of the arrow
wxCoord x1, y1;
if ( isVertical )
{
x1 = (ARROW_WIDTH - 1)/2;
y1 = n == Arrow_Up ? 0 : ARROW_LENGTH - 1;
}
else // horizontal
{
x1 = n == Arrow_Left ? 0 : ARROW_LENGTH - 1;
y1 = (ARROW_WIDTH - 1)/2;
}
wxCoord x2 = x1,
y2 = y1;
if ( isVertical )
x2++;
else
y2++;
for ( size_t i = 0; i < ARROW_LENGTH; i++ )
{
dcNormal.DrawLine(x1, y1, x2, y2);
dcDisabled.DrawLine(x1, y1, x2, y2);
if ( isVertical )
{
x1--;
x2++;
if ( n == Arrow_Up )
{
y1++;
y2++;
}
else // down arrow
{
y1--;
y2--;
}
}
else // left or right arrow
{
y1--;
y2++;
if ( n == Arrow_Left )
{
x1++;
x2++;
}
else
{
x1--;
x2--;
}
}
}
// draw the shadow for the disabled one
dcDisabled.SetPen(m_penHighlight);
switch ( n )
{
case Arrow_Left:
y1 += 2;
dcDisabled.DrawLine(x1, y1, x2, y2);
break;
case Arrow_Right:
x1 = ARROW_LENGTH - 1;
y1 = (ARROW_WIDTH - 1)/2 + 1;
x2 = 0;
y2 = ARROW_WIDTH;
dcDisabled.DrawLine(x1, y1, x2, y2);
dcDisabled.DrawLine(++x1, y1, x2, ++y2);
break;
case Arrow_Up:
x1 += 2;
dcDisabled.DrawLine(x1, y1, x2, y2);
break;
case Arrow_Down:
x1 = ARROW_WIDTH - 1;
y1 = 1;
x2 = (ARROW_WIDTH - 1)/2;
y2 = ARROW_LENGTH;
dcDisabled.DrawLine(x1, y1, x2, y2);
dcDisabled.DrawLine(++x1, y1, x2, ++y2);
break;
}
// create the inverted bitmap but only for the right arrow as we only
// use it for the menus
if ( n == Arrow_Right )
{
m_bmpArrows[Arrow_Inverted][n].Create(w, h);
dcInverse.SelectObject(m_bmpArrows[Arrow_Inverted][n]);
dcInverse.Clear();
dcInverse.Blit(0, 0, w, h,
&dcNormal, 0, 0,
wxXOR);
dcInverse.SelectObject(wxNullBitmap);
mask = new wxMask(m_bmpArrows[Arrow_Inverted][n], *wxBLACK);
m_bmpArrows[Arrow_Inverted][n].SetMask(mask);
m_bmpArrows[Arrow_InvertedDisabled][n].Create(w, h);
dcInverse.SelectObject(m_bmpArrows[Arrow_InvertedDisabled][n]);
dcInverse.Clear();
dcInverse.Blit(0, 0, w, h,
&dcDisabled, 0, 0,
wxXOR);
dcInverse.SelectObject(wxNullBitmap);
mask = new wxMask(m_bmpArrows[Arrow_InvertedDisabled][n], *wxBLACK);
m_bmpArrows[Arrow_InvertedDisabled][n].SetMask(mask);
}
dcNormal.SelectObject(wxNullBitmap);
dcDisabled.SelectObject(wxNullBitmap);
mask = new wxMask(m_bmpArrows[Arrow_Normal][n], *wxWHITE);
m_bmpArrows[Arrow_Normal][n].SetMask(mask);
mask = new wxMask(m_bmpArrows[Arrow_Disabled][n], *wxWHITE);
m_bmpArrows[Arrow_Disabled][n].SetMask(mask);
m_bmpArrows[Arrow_Pressed][n] = m_bmpArrows[Arrow_Normal][n];
}
}
bool wxWin32Renderer::AreScrollbarsInsideBorder() const
{
return true;
}
// ----------------------------------------------------------------------------
// label
// ----------------------------------------------------------------------------
void wxWin32Renderer::DrawLabel(wxDC& dc,
const wxString& label,
const wxRect& rect,
int flags,
int alignment,
int indexAccel,
wxRect *rectBounds)
{
// the underscores are not drawn for focused controls in wxMSW
if ( flags & wxCONTROL_FOCUSED )
{
indexAccel = -1;
}
if ( flags & wxCONTROL_DISABLED )
{
// the combination of wxCONTROL_SELECTED and wxCONTROL_DISABLED
// currently only can happen for a menu item and it seems that Windows
// doesn't draw the shadow in this case, so we don't do it neither
if ( flags & wxCONTROL_SELECTED )
{
// just make the label text greyed out
dc.SetTextForeground(m_penDarkGrey.GetColour());
flags &= ~wxCONTROL_DISABLED;
}
}
wxStdRenderer::DrawLabel(dc, label, rect, flags, alignment,
indexAccel, rectBounds);
}
void wxWin32Renderer::DrawFrameWithLabel(wxDC& dc,
const wxString& label,
const wxRect& rectFrame,
const wxRect& rectText,
int flags,
int alignment,
int indexAccel)
{
wxString label2;
label2 << wxT(' ') << label << wxT(' ');
if ( indexAccel != -1 )
{
// adjust it as we prepended a space
indexAccel++;
}
wxStdRenderer::DrawFrameWithLabel(dc, label2, rectFrame, rectText,
flags, alignment, indexAccel);
}
void wxWin32Renderer::DrawButtonLabel(wxDC& dc,
const wxString& label,
const wxBitmap& image,
const wxRect& rect,
int flags,
int alignment,
int indexAccel,
wxRect *rectBounds)
{
// the underscores are not drawn for focused controls in wxMSW
if ( flags & wxCONTROL_PRESSED )
{
indexAccel = -1;
}
wxStdRenderer::DrawButtonLabel(dc, label, image, rect, flags, alignment,
indexAccel, rectBounds);
}
void wxWin32Renderer::DrawButtonBorder(wxDC& dc,
const wxRect& rectTotal,
int flags,
wxRect *rectIn)
{
wxRect rect = rectTotal;
wxPen penOut(*wxBLACK);
if ( flags & wxCONTROL_PRESSED )
{
// button pressed: draw a double border around it
DrawRect(dc, &rect, penOut);
DrawRect(dc, &rect, m_penDarkGrey);
}
else // button not pressed
{
if ( flags & (wxCONTROL_FOCUSED | wxCONTROL_ISDEFAULT) )
{
// button either default or focused (or both): add an extra border
// around it
DrawRect(dc, &rect, penOut);
}
// now draw a normal button border
DrawRaisedBorder(dc, &rect);
}
if ( rectIn )
*rectIn = rect;
}
// ----------------------------------------------------------------------------
// (check)listbox items
// ----------------------------------------------------------------------------
void wxWin32Renderer::DrawCheckItemBitmap(wxDC& dc,
const wxBitmap& bitmap,
const wxRect& rect,
int flags)
{
wxBitmap bmp;
if ( bitmap.IsOk() )
{
bmp = bitmap;
}
else // use default bitmap
{
IndicatorStatus i = flags & wxCONTROL_CHECKED
? IndicatorStatus_Checked
: IndicatorStatus_Unchecked;
if ( !m_bmpCheckBitmaps[i].IsOk() )
{
m_bmpCheckBitmaps[i] = wxBitmap(ms_xpmChecked[i]);
}
bmp = m_bmpCheckBitmaps[i];
}
dc.DrawBitmap(bmp, rect.x, rect.y + (rect.height - bmp.GetHeight()) / 2 - 1,
true /* use mask */);
}
// ----------------------------------------------------------------------------
// check/radio buttons
// ----------------------------------------------------------------------------
wxBitmap wxWin32Renderer::GetIndicator(IndicatorType indType, int flags)
{
IndicatorState indState;
IndicatorStatus indStatus;
GetIndicatorsFromFlags(flags, indState, indStatus);
wxBitmap& bmp = m_bmpIndicators[indType][indState][indStatus];
if ( !bmp.IsOk() )
{
const char **xpm = ms_xpmIndicators[indType][indState][indStatus];
if ( xpm )
{
// create and cache it
bmp = wxBitmap(xpm);
}
}
return bmp;
}
// ----------------------------------------------------------------------------
// toolbar stuff
// ----------------------------------------------------------------------------
#if wxUSE_TOOLBAR
void wxWin32Renderer::DrawToolBarButton(wxDC& dc,
const wxString& label,
const wxBitmap& bitmap,
const wxRect& rectOrig,
int flags,
long style,
int tbarStyle)
{
if (style == wxTOOL_STYLE_BUTTON)
{
wxRect rect = rectOrig;
rect.Deflate(BORDER_THICKNESS);
if ( flags & wxCONTROL_PRESSED )
{
DrawBorder(dc, wxBORDER_SUNKEN, rect, flags);
}
else if ( flags & wxCONTROL_CURRENT )
{
DrawBorder(dc, wxBORDER_RAISED, rect, flags);
}
if(tbarStyle & wxTB_TEXT)
{
if(tbarStyle & wxTB_HORIZONTAL)
{
dc.DrawLabel(label, bitmap, rect, wxALIGN_CENTRE);
}
else
{
dc.DrawLabel(label, bitmap, rect, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL);
}
}
else
{
int xpoint = (rect.GetLeft() + rect.GetRight() + 1 - bitmap.GetWidth()) / 2;
int ypoint = (rect.GetTop() + rect.GetBottom() + 1 - bitmap.GetHeight()) / 2;
dc.DrawBitmap(bitmap, xpoint, ypoint, bitmap.GetMask() != NULL);
}
}
else if (style == wxTOOL_STYLE_SEPARATOR)
{
// leave a small gap aroudn the line, also account for the toolbar
// border itself
if(rectOrig.height > rectOrig.width)
{
// horizontal
DrawVerticalLine(dc, rectOrig.x + rectOrig.width/2,
rectOrig.y + 2*BORDER_THICKNESS,
rectOrig.GetBottom() - BORDER_THICKNESS);
}
else
{
// vertical
DrawHorizontalLine(dc, rectOrig.y + rectOrig.height/2,
rectOrig.x + 2*BORDER_THICKNESS,
rectOrig.GetRight() - BORDER_THICKNESS);
}
}
// don't draw wxTOOL_STYLE_CONTROL
}
#endif // wxUSE_TOOLBAR
// ----------------------------------------------------------------------------
// notebook
// ----------------------------------------------------------------------------
#if wxUSE_NOTEBOOK
void wxWin32Renderer::DrawTab(wxDC& dc,
const wxRect& rectOrig,
wxDirection dir,
const wxString& label,
const wxBitmap& bitmap,
int flags,
int indexAccel)
{
#define SELECT_FOR_VERTICAL(X,Y) ( isVertical ? Y : X )
#define REVERSE_FOR_VERTICAL(X,Y) \
SELECT_FOR_VERTICAL(X,Y) \
, \
SELECT_FOR_VERTICAL(Y,X)
wxRect rect = rectOrig;
bool isVertical = ( dir == wxLEFT ) || ( dir == wxRIGHT );
// the current tab is drawn indented (to the top for default case) and
// bigger than the other ones
const wxSize indent = GetTabIndent();
if ( flags & wxCONTROL_SELECTED )
{
rect.Inflate( SELECT_FOR_VERTICAL( indent.x , 0),
SELECT_FOR_VERTICAL( 0, indent.y ));
switch ( dir )
{
default:
wxFAIL_MSG(wxT("invaild notebook tab orientation"));
// fall through
case wxTOP:
rect.y -= indent.y;
// fall through
case wxBOTTOM:
rect.height += indent.y;
break;
case wxLEFT:
rect.x -= indent.x;
// fall through
case wxRIGHT:
rect.width += indent.x;
break;
}
}
// draw the text, image and the focus around them (if necessary)
wxRect rectLabel( REVERSE_FOR_VERTICAL(rect.x,rect.y),
REVERSE_FOR_VERTICAL(rect.width,rect.height)
);
rectLabel.Deflate(1, 1);
if ( isVertical )
{
// draw it horizontally into memory and rotate for screen
wxMemoryDC dcMem;
wxBitmap bitmapRotated,
bitmapMem( rectLabel.x + rectLabel.width,
rectLabel.y + rectLabel.height );
dcMem.SelectObject(bitmapMem);
dcMem.SetBackground(dc.GetBackground());
dcMem.SetFont(dc.GetFont());
dcMem.SetTextForeground(dc.GetTextForeground());
dcMem.Clear();
bitmapRotated =
#if wxUSE_IMAGE
wxBitmap( wxImage( bitmap.ConvertToImage() ).Rotate90(dir==wxLEFT) )
#else
bitmap
#endif // wxUSE_IMAGE
;
DrawButtonLabel(dcMem, label, bitmapRotated, rectLabel,
flags, wxALIGN_CENTRE, indexAccel);
dcMem.SelectObject(wxNullBitmap);
bitmapMem = bitmapMem.GetSubBitmap(rectLabel);
#if wxUSE_IMAGE
bitmapMem = wxBitmap(wxImage(bitmapMem.ConvertToImage()).Rotate90(dir==wxRIGHT));
#endif // wxUSE_IMAGE
dc.DrawBitmap(bitmapMem, rectLabel.y, rectLabel.x, false);
}
else
{
DrawButtonLabel(dc, label, bitmap, rectLabel,
flags, wxALIGN_CENTRE, indexAccel);
}
// now draw the tab border itself (maybe use DrawRoundedRectangle()?)
static const wxCoord CUTOFF = 2; // radius of the rounded corner
wxCoord x = SELECT_FOR_VERTICAL(rect.x,rect.y),
y = SELECT_FOR_VERTICAL(rect.y,rect.x),
x2 = SELECT_FOR_VERTICAL(rect.GetRight(),rect.GetBottom()),
y2 = SELECT_FOR_VERTICAL(rect.GetBottom(),rect.GetRight());
// FIXME: all this code will break if the tab indent or the border width,
// it is tied to the fact that both of them are equal to 2
switch ( dir )
{
default:
// default is top
case wxLEFT:
// left orientation looks like top but IsVertical makes x and y reversed
case wxTOP:
// top is not vertical so use coordinates in written order
dc.SetPen(m_penHighlight);
dc.DrawLine(REVERSE_FOR_VERTICAL(x, y2),
REVERSE_FOR_VERTICAL(x, y + CUTOFF));
dc.DrawLine(REVERSE_FOR_VERTICAL(x, y + CUTOFF),
REVERSE_FOR_VERTICAL(x + CUTOFF, y));
dc.DrawLine(REVERSE_FOR_VERTICAL(x + CUTOFF, y),
REVERSE_FOR_VERTICAL(x2 - CUTOFF + 1, y));
dc.SetPen(m_penBlack);
dc.DrawLine(REVERSE_FOR_VERTICAL(x2, y2),
REVERSE_FOR_VERTICAL(x2, y + CUTOFF));
dc.DrawLine(REVERSE_FOR_VERTICAL(x2, y + CUTOFF),
REVERSE_FOR_VERTICAL(x2 - CUTOFF, y));
dc.SetPen(m_penDarkGrey);
dc.DrawLine(REVERSE_FOR_VERTICAL(x2 - 1, y2),
REVERSE_FOR_VERTICAL(x2 - 1, y + CUTOFF - 1));
if ( flags & wxCONTROL_SELECTED )
{
dc.SetPen(m_penLightGrey);
// overwrite the part of the border below this tab
dc.DrawLine(REVERSE_FOR_VERTICAL(x + 1, y2 + 1),
REVERSE_FOR_VERTICAL(x2 - 1, y2 + 1));
// and the shadow of the tab to the left of us
dc.DrawLine(REVERSE_FOR_VERTICAL(x + 1, y + CUTOFF + 1),
REVERSE_FOR_VERTICAL(x + 1, y2 + 1));
}
break;
case wxRIGHT:
// right orientation looks like bottom but IsVertical makes x and y reversed
case wxBOTTOM:
// bottom is not vertical so use coordinates in written order
dc.SetPen(m_penHighlight);
// we need to continue one pixel further to overwrite the corner of
// the border for the selected tab
dc.DrawLine(REVERSE_FOR_VERTICAL(x, y - (flags & wxCONTROL_SELECTED ? 1 : 0)),
REVERSE_FOR_VERTICAL(x, y2 - CUTOFF));
dc.DrawLine(REVERSE_FOR_VERTICAL(x, y2 - CUTOFF),
REVERSE_FOR_VERTICAL(x + CUTOFF, y2));
dc.SetPen(m_penBlack);
dc.DrawLine(REVERSE_FOR_VERTICAL(x + CUTOFF, y2),
REVERSE_FOR_VERTICAL(x2 - CUTOFF + 1, y2));
dc.DrawLine(REVERSE_FOR_VERTICAL(x2, y),
REVERSE_FOR_VERTICAL(x2, y2 - CUTOFF));
dc.DrawLine(REVERSE_FOR_VERTICAL(x2, y2 - CUTOFF),
REVERSE_FOR_VERTICAL(x2 - CUTOFF, y2));
dc.SetPen(m_penDarkGrey);
dc.DrawLine(REVERSE_FOR_VERTICAL(x + CUTOFF, y2 - 1),
REVERSE_FOR_VERTICAL(x2 - CUTOFF + 1, y2 - 1));
dc.DrawLine(REVERSE_FOR_VERTICAL(x2 - 1, y),
REVERSE_FOR_VERTICAL(x2 - 1, y2 - CUTOFF + 1));
if ( flags & wxCONTROL_SELECTED )
{
dc.SetPen(m_penLightGrey);
// overwrite the part of the (double!) border above this tab
dc.DrawLine(REVERSE_FOR_VERTICAL(x + 1, y - 1),
REVERSE_FOR_VERTICAL(x2 - 1, y - 1));
dc.DrawLine(REVERSE_FOR_VERTICAL(x + 1, y - 2),
REVERSE_FOR_VERTICAL(x2 - 1, y - 2));
// and the shadow of the tab to the left of us
dc.DrawLine(REVERSE_FOR_VERTICAL(x + 1, y2 - CUTOFF),
REVERSE_FOR_VERTICAL(x + 1, y - 1));
}
break;
}
#undef SELECT_FOR_VERTICAL
#undef REVERSE_FOR_VERTICAL
}
#endif // wxUSE_NOTEBOOK
#if wxUSE_SLIDER
// ----------------------------------------------------------------------------
// slider
// ----------------------------------------------------------------------------
wxSize
wxWin32Renderer::GetSliderThumbSize(const wxRect& WXUNUSED(rect),
int lenThumb,
wxOrientation orient) const
{
wxSize size;
wxCoord width = wxMax (lenThumb, SLIDER_THUMB_LENGTH) / 2;
wxCoord height = wxMax (lenThumb, SLIDER_THUMB_LENGTH);
if (orient == wxHORIZONTAL)
{
size.x = width;
size.y = height;
}
else
{ // == wxVERTICAL
size.x = height;
size.y = width;
}
return size;
}
wxRect wxWin32Renderer::GetSliderShaftRect(const wxRect& rectOrig,
int lenThumb,
wxOrientation orient,
long style) const
{
bool left, right;
GetSliderLabelsSides(orient, style, &left, &right);
wxRect rect = rectOrig;
wxSize sizeThumb = GetSliderThumbSize (rect, lenThumb, orient);
if (orient == wxHORIZONTAL)
{
rect.x += SLIDER_MARGIN;
if (left & right)
{
rect.y += wxMax ((rect.height - 2*BORDER_THICKNESS) / 2, sizeThumb.y/2);
}
else if (left)
{
rect.y += wxMax ((rect.height - 2*BORDER_THICKNESS - sizeThumb.y/2), sizeThumb.y/2);
}
else
{
rect.y += sizeThumb.y/2;
}
rect.width -= 2*SLIDER_MARGIN;
rect.height = 2*BORDER_THICKNESS;
}
else // == wxVERTICAL
{
rect.y += SLIDER_MARGIN;
if (left & right)
{
rect.x += wxMax ((rect.width - 2*BORDER_THICKNESS) / 2, sizeThumb.x/2);
}
else if (left)
{
rect.x += wxMax ((rect.width - 2*BORDER_THICKNESS - sizeThumb.x/2), sizeThumb.x/2);
}
else
{
rect.x += sizeThumb.x/2;
}
rect.width = 2*BORDER_THICKNESS;
rect.height -= 2*SLIDER_MARGIN;
}
return rect;
}
void wxWin32Renderer::DrawSliderShaft(wxDC& dc,
const wxRect& rectOrig,
int lenThumb,
wxOrientation orient,
int flags,
long style,
wxRect *rectShaft)
{
/* show shaft geometry
shaft
+-------------+
| |
| XXX | <-- x1
| XXX |
| XXX |
| XXX |
| XXX | <-- x2
| |
+-------------+
^ ^
| |
y1 y2
*/
if (flags & wxCONTROL_FOCUSED)
DrawFocusRect(NULL, dc, rectOrig);
wxRect rect = GetSliderShaftRect(rectOrig, lenThumb, orient, style);
if (rectShaft) *rectShaft = rect;
DrawSunkenBorder(dc, &rect);
}
void wxWin32Renderer::DrawSliderThumb(wxDC& dc,
const wxRect& rect,
wxOrientation orient,
int flags,
long style)
{
/* show thumb geometry
H <--- y1
H H B
H H B
H H B <--- y3
H D B
H D B
H D B
H D B where H is highlight colour
H D B D dark grey
H D B B black
H D B
H D B
H D B <--- y4
H D B
H D B
B <--- y2
^ ^ ^
| | |
x1 x3 x2
The interior of this shape is filled with the hatched brush if the thumb
is pressed.
*/
DrawBackground(dc, wxNullColour, rect, flags);
bool left, right;
GetSliderLabelsSides(orient, style, &left, &right);
bool isVertical = orient == wxVERTICAL;
wxCoord sizeArrow = (isVertical ? rect.height : rect.width) / 2;
wxCoord c = ((isVertical ? rect.height : rect.width) - 2*sizeArrow);
wxCoord x1, x2, x3, y1, y2, y3, y4;
x1 = (isVertical ? rect.y : rect.x);
x2 = (isVertical ? rect.GetBottom() : rect.GetRight());
x3 = (x1-1+c) + sizeArrow;
y1 = (isVertical ? rect.x : rect.y);
y2 = (isVertical ? rect.GetRight() : rect.GetBottom());
y3 = (left ? (y1-1+c) + sizeArrow : y1);
y4 = (right ? (y2+1-c) - sizeArrow : y2);
dc.SetPen(m_penBlack);
if (left)
{
DrawLine(dc, x3+1-c, y1, x2, y3, isVertical);
}
DrawLine(dc, x2, y3, x2, y4, isVertical);
if (right)
{
DrawLine(dc, x3+1-c, y2, x2, y4, isVertical);
}
else
{
DrawLine(dc, x1, y2, x2, y2, isVertical);
}
dc.SetPen(m_penDarkGrey);
DrawLine(dc, x2-1, y3+1, x2-1, y4-1, isVertical);
if (right)
{
DrawLine(dc, x3+1-c, y2-1, x2-1, y4, isVertical);
}
else
{
DrawLine(dc, x1+1, y2-1, x2-1, y2-1, isVertical);
}
dc.SetPen(m_penHighlight);
if (left)
{
DrawLine(dc, x1, y3, x3, y1, isVertical);
DrawLine(dc, x3+1-c, y1+1, x2-1, y3, isVertical);
}
else
{
DrawLine(dc, x1, y1, x2, y1, isVertical);
}
DrawLine(dc, x1, y3, x1, y4, isVertical);
if (right)
{
DrawLine(dc, x1, y4, x3+c, y2+c, isVertical);
}
if (flags & wxCONTROL_PRESSED)
{
// TODO: MSW fills the entire area inside, not just the rect
wxRect rectInt = rect;
if ( isVertical )
{
rectInt.SetLeft(y3);
rectInt.SetRight(y4);
}
else
{
rectInt.SetTop(y3);
rectInt.SetBottom(y4);
}
rectInt.Deflate(2);
#if !defined(__WXMGL__)
static const char *stipple_xpm[] = {
/* columns rows colors chars-per-pixel */
"2 2 2 1",
" c None",
"w c white",
/* pixels */
"w ",
" w",
};
#else
// VS: MGL can only do 8x8 stipple brushes
static const char *stipple_xpm[] = {
/* columns rows colors chars-per-pixel */
"8 8 2 1",
" c None",
"w c white",
/* pixels */
"w w w w ",
" w w w w",
"w w w w ",
" w w w w",
"w w w w ",
" w w w w",
"w w w w ",
" w w w w",
};
#endif
dc.SetBrush(wxBrush(stipple_xpm));
dc.SetTextForeground(wxSCHEME_COLOUR(m_scheme, SHADOW_HIGHLIGHT));
dc.SetTextBackground(wxSCHEME_COLOUR(m_scheme, CONTROL));
dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(rectInt);
}
}
void wxWin32Renderer::DrawSliderTicks(wxDC& dc,
const wxRect& rect,
int lenThumb,
wxOrientation orient,
int start,
int end,
int step,
int WXUNUSED(flags),
long style)
{
/* show ticks geometry
left right
ticks shaft ticks
---- XX ---- <-- x1
---- XX ----
---- XX ----
---- XX ---- <-- x2
^ ^ ^ ^
| | | |
y3 y1 y2 y4
*/
// empty slider?
if ( end == start )
return;
bool left, right;
GetSliderLabelsSides(orient, style, &left, &right);
bool isVertical = orient == wxVERTICAL;
// default thumb size
wxSize sizeThumb = GetSliderThumbSize (rect, 0, orient);
wxCoord defaultLen = (isVertical ? sizeThumb.x : sizeThumb.y);
// normal thumb size
sizeThumb = GetSliderThumbSize (rect, lenThumb, orient);
wxCoord widthThumb = (isVertical ? sizeThumb.y : sizeThumb.x);
wxRect rectShaft = GetSliderShaftRect (rect, lenThumb, orient, style);
wxCoord x1, x2, y1, y2, y3, y4 , len;
x1 = (isVertical ? rectShaft.y : rectShaft.x) + widthThumb/2;
x2 = (isVertical ? rectShaft.GetBottom() : rectShaft.GetRight()) - widthThumb/2;
y1 = (isVertical ? rectShaft.x : rectShaft.y) - defaultLen/2;
y2 = (isVertical ? rectShaft.GetRight() : rectShaft.GetBottom()) + defaultLen/2;
y3 = (isVertical ? rect.x : rect.y);
y4 = (isVertical ? rect.GetRight() : rect.GetBottom());
len = x2 - x1;
dc.SetPen(m_penBlack);
int range = end - start;
for ( int n = 0; n < range; n += step )
{
wxCoord x = x1 + (len*n) / range;
if (left & (y1 > y3))
{
DrawLine(dc, x, y1, x, y3, orient == wxVERTICAL);
}
if (right & (y4 > y2))
{
DrawLine(dc, x, y2, x, y4, orient == wxVERTICAL);
}
}
// always draw the line at the end position
if (left & (y1 > y3))
{
DrawLine(dc, x2, y1, x2, y3, orient == wxVERTICAL);
}
if (right & (y4 > y2))
{
DrawLine(dc, x2, y2, x2, y4, orient == wxVERTICAL);
}
}
#endif // wxUSE_SLIDER
#if wxUSE_MENUS
// ----------------------------------------------------------------------------
// menu and menubar
// ----------------------------------------------------------------------------
// wxWin32MenuGeometryInfo: the wxMenuGeometryInfo used by wxWin32Renderer
class WXDLLEXPORT wxWin32MenuGeometryInfo : 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 *
wxWin32Renderer::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 = 18;
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 wxWin32Renderer::DrawMenuBarItem(wxDC& dc,
const wxRect& rectOrig,
const wxString& label,
int flags,
int indexAccel)
{
wxRect rect = rectOrig;
rect.height--;
wxDCTextColourChanger colChanger(dc);
if ( flags & wxCONTROL_SELECTED )
{
colChanger.Set(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
const wxColour colBg = wxSCHEME_COLOUR(m_scheme, HIGHLIGHT);
dc.SetBrush(colBg);
dc.SetPen(colBg);
dc.DrawRectangle(rect);
}
// don't draw the focus rect around menu bar items
DrawLabel(dc, label, rect, flags & ~wxCONTROL_FOCUSED,
wxALIGN_CENTRE, indexAccel);
}
void wxWin32Renderer::DrawMenuItem(wxDC& dc,
wxCoord y,
const wxMenuGeometryInfo& gi,
const wxString& label,
const wxString& accel,
const wxBitmap& bitmap,
int flags,
int indexAccel)
{
const wxWin32MenuGeometryInfo& geometryInfo =
(const wxWin32MenuGeometryInfo&)gi;
wxRect rect;
rect.x = 0;
rect.y = y;
rect.width = geometryInfo.GetSize().x;
rect.height = geometryInfo.GetItemHeight();
// draw the selected item specially
wxDCTextColourChanger colChanger(dc);
if ( flags & wxCONTROL_SELECTED )
{
colChanger.Set(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
const wxColour colBg = wxSCHEME_COLOUR(m_scheme, HIGHLIGHT);
dc.SetBrush(colBg);
dc.SetPen(colBg);
dc.DrawRectangle(rect);
}
// draw the bitmap: use the bitmap provided or the standard checkmark for
// the checkable items
wxBitmap bmp = bitmap;
if ( !bmp.IsOk() && (flags & wxCONTROL_CHECKED) )
{
bmp = GetIndicator(IndicatorType_Menu, flags);
}
if ( bmp.IsOk() )
{
rect.SetRight(geometryInfo.GetLabelOffset());
wxControlRenderer::DrawBitmap(dc, bmp, rect);
}
// draw the label
rect.x = geometryInfo.GetLabelOffset();
rect.SetRight(geometryInfo.GetAccelOffset());
DrawLabel(dc, label, rect, flags, wxALIGN_CENTRE_VERTICAL, indexAccel);
// draw the accel string
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 )
{
rect.x = geometryInfo.GetSize().x - MENU_RIGHT_MARGIN;
rect.width = MENU_RIGHT_MARGIN;
ArrowStyle arrowStyle;
if ( flags & wxCONTROL_DISABLED )
arrowStyle = flags & wxCONTROL_SELECTED ? Arrow_InvertedDisabled
: Arrow_Disabled;
else if ( flags & wxCONTROL_SELECTED )
arrowStyle = Arrow_Inverted;
else
arrowStyle = Arrow_Normal;
DrawArrow(dc, rect, Arrow_Right, arrowStyle);
}
}
void wxWin32Renderer::DrawMenuSeparator(wxDC& dc,
wxCoord y,
const wxMenuGeometryInfo& geomInfo)
{
DrawHorizontalLine(dc, y + MENU_VERT_MARGIN, 0, geomInfo.GetSize().x);
}
wxSize wxWin32Renderer::GetMenuBarItemSize(const wxSize& sizeText) const
{
wxSize size = sizeText;
// FIXME: menubar height is configurable under Windows
size.x += 12;
size.y += 6;
return size;
}
wxMenuGeometryInfo *wxWin32Renderer::GetMenuGeometry(wxWindow *win,
const wxMenu& menu) const
{
// 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::compatibility_iterator 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;
wxCoord widthLabel;
dc.GetTextExtent(item->GetItemLabelText(), &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.IsOk() )
{
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
wxWin32MenuGeometryInfo *gi = new wxWin32MenuGeometryInfo;
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;
}
#endif // wxUSE_MENUS
#if wxUSE_STATUSBAR
// ----------------------------------------------------------------------------
// status bar
// ----------------------------------------------------------------------------
void wxWin32Renderer::DrawStatusField(wxDC& dc,
const wxRect& rect,
const wxString& label,
int flags,
int style)
{
wxRect rectIn;
if ( flags & wxCONTROL_SIZEGRIP )
{
// draw the size grip: it is a normal rect except that in the lower
// right corner we have several bands which may be used for dragging
// the status bar corner
//
// each band consists of 4 stripes: m_penHighlight, double
// m_penDarkGrey and transparent one
wxCoord x2 = rect.GetRight(),
y2 = rect.GetBottom();
// draw the upper left part of the rect normally
if (style != wxSB_FLAT)
{
if (style == wxSB_RAISED)
dc.SetPen(m_penHighlight);
else
dc.SetPen(m_penDarkGrey);
dc.DrawLine(rect.GetLeft(), rect.GetTop(), rect.GetLeft(), y2);
dc.DrawLine(rect.GetLeft() + 1, rect.GetTop(), x2, rect.GetTop());
}
// draw the grey stripes of the grip
size_t n;
wxCoord ofs = WIDTH_STATUSBAR_GRIP_BAND - 1;
for ( n = 0; n < NUM_STATUSBAR_GRIP_BANDS; n++, ofs += WIDTH_STATUSBAR_GRIP_BAND )
{
dc.DrawLine(x2 - ofs + 1, y2 - 1, x2, y2 - ofs);
dc.DrawLine(x2 - ofs, y2 - 1, x2, y2 - ofs - 1);
}
// draw the white stripes
dc.SetPen(m_penHighlight);
ofs = WIDTH_STATUSBAR_GRIP_BAND + 1;
for ( n = 0; n < NUM_STATUSBAR_GRIP_BANDS; n++, ofs += WIDTH_STATUSBAR_GRIP_BAND )
{
dc.DrawLine(x2 - ofs + 1, y2 - 1, x2, y2 - ofs);
}
// draw the remaining rect boundaries
if (style != wxSB_FLAT)
{
if (style == wxSB_RAISED)
dc.SetPen(m_penDarkGrey);
else
dc.SetPen(m_penHighlight);
ofs -= WIDTH_STATUSBAR_GRIP_BAND;
dc.DrawLine(x2, rect.GetTop(), x2, y2 - ofs + 1);
dc.DrawLine(rect.GetLeft(), y2, x2 - ofs + 1, y2);
}
rectIn = rect;
rectIn.Deflate(1);
rectIn.width -= STATUSBAR_GRIP_SIZE;
// this will prevent the standard version from drawing any borders
style = wxSB_FLAT;
}
wxStdRenderer::DrawStatusField(dc, rect, label, flags, style);
}
#endif // wxUSE_STATUSBAR
// ----------------------------------------------------------------------------
// combobox
// ----------------------------------------------------------------------------
void wxWin32Renderer::GetComboBitmaps(wxBitmap *bmpNormal,
wxBitmap * WXUNUSED(bmpFocus),
wxBitmap *bmpPressed,
wxBitmap *bmpDisabled)
{
static const wxCoord widthCombo = 16;
static const wxCoord heightCombo = 17;
wxMemoryDC dcMem;
if ( bmpNormal )
{
bmpNormal->Create(widthCombo, heightCombo);
dcMem.SelectObject(*bmpNormal);
DrawArrowButton(dcMem, wxRect(0, 0, widthCombo, heightCombo),
Arrow_Down, Arrow_Normal);
}
if ( bmpPressed )
{
bmpPressed->Create(widthCombo, heightCombo);
dcMem.SelectObject(*bmpPressed);
DrawArrowButton(dcMem, wxRect(0, 0, widthCombo, heightCombo),
Arrow_Down, Arrow_Pressed);
}
if ( bmpDisabled )
{
bmpDisabled->Create(widthCombo, heightCombo);
dcMem.SelectObject(*bmpDisabled);
DrawArrowButton(dcMem, wxRect(0, 0, widthCombo, heightCombo),
Arrow_Down, Arrow_Disabled);
}
}
// ----------------------------------------------------------------------------
// scrollbar
// ----------------------------------------------------------------------------
void wxWin32Renderer::DrawArrowBorder(wxDC& dc, wxRect *rect, bool isPressed)
{
if ( isPressed )
{
DrawRect(dc, rect, m_penDarkGrey);
// the arrow is usually drawn inside border of width 2 and is offset by
// another pixel in both directions when it's pressed - as the border
// in this case is more narrow as well, we have to adjust rect like
// this:
rect->Inflate(-1);
rect->x++;
rect->y++;
}
else // !pressed
{
DrawAntiSunkenBorder(dc, rect);
}
}
void wxWin32Renderer::DrawArrow(wxDC& dc,
wxDirection dir,
const wxRect& rect,
int flags)
{
ArrowStyle arrowStyle;
if ( flags & wxCONTROL_PRESSED )
{
// can't be pressed and disabled
arrowStyle = Arrow_Pressed;
}
else
{
arrowStyle = flags & wxCONTROL_DISABLED ? Arrow_Disabled : Arrow_Normal;
}
DrawArrowButton(dc, rect, GetArrowDirection(dir), arrowStyle);
}
void wxWin32Renderer::DrawArrow(wxDC& dc,
const wxRect& rect,
ArrowDirection arrowDir,
ArrowStyle arrowStyle)
{
const wxBitmap& bmp = m_bmpArrows[arrowStyle][arrowDir];
// under Windows the arrows always have the same size so just centre it in
// the provided rectangle
wxCoord x = rect.x + (rect.width - bmp.GetWidth()) / 2,
y = rect.y + (rect.height - bmp.GetHeight()) / 2;
// Windows does it like this...
if ( arrowDir == Arrow_Left )
x--;
// draw it
dc.DrawBitmap(bmp, x, y, true /* use mask */);
}
void wxWin32Renderer::DrawArrowButton(wxDC& dc,
const wxRect& rectAll,
ArrowDirection arrowDir,
ArrowStyle arrowStyle)
{
wxRect rect = rectAll;
DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
DrawArrowBorder(dc, &rect, arrowStyle == Arrow_Pressed);
DrawArrow(dc, rect, arrowDir, arrowStyle);
}
void wxWin32Renderer::DrawScrollbarThumb(wxDC& dc,
wxOrientation WXUNUSED(orient),
const wxRect& rect,
int WXUNUSED(flags))
{
// we don't use the flags, the thumb never changes appearance
wxRect rectThumb = rect;
DrawArrowBorder(dc, &rectThumb);
DrawBackground(dc, wxNullColour, rectThumb);
}
void wxWin32Renderer::DrawScrollbarShaft(wxDC& dc,
wxOrientation WXUNUSED(orient),
const wxRect& rectBar,
int flags)
{
wxColourScheme::StdColour col = flags & wxCONTROL_PRESSED
? wxColourScheme::SCROLLBAR_PRESSED
: wxColourScheme::SCROLLBAR;
DrawBackground(dc, m_scheme->Get(col), rectBar);
}
// ----------------------------------------------------------------------------
// standard icons
// ----------------------------------------------------------------------------
/* Copyright (c) Julian Smart */
static const char *error_xpm[]={
/* columns rows colors chars-per-pixel */
"32 32 70 1",
"- c #BF0101",
"b c #361F1F",
"& c #C08484",
"X c #BF3333",
"# c #C08181",
"% c #C01111",
"d c #C51515",
"s c #551818",
"O c #C07E7E",
": c #C00E0E",
"u c #E28A8A",
"2 c #C81F1F",
"8 c #FFFFFF",
"p c #E59494",
"< c #BB0101",
"y c #DA6A6A",
"A c #4C4C4C",
"9 c #F7DFDF",
"@ c #BF5353",
"w c #FAE9E9",
"F c #272727",
"5 c #D24A4A",
". c #C06363",
"n c #BF8282",
"7 c #F2C9C9",
"t c #C09292",
"M c #3E3E3E",
"x c #4D4D4D",
"4 c #CA2A2A",
"h c #E79F9F",
"* c #C05454",
"D c #711212",
"V c #737373",
"$ c #BF3232",
"N c #900B0B",
"6 c #BD0303",
"3 c #DF7F7F",
"K c #6F1212",
"C c #BD0000",
"m c #950909",
"P c #8A8A8A",
"j c #D75F5F",
" c None",
"e c #F4D4D4",
"S c #BF2020",
"L c #747474",
"G c #842C2C",
"c c #ECB4B4",
"l c #2E2121",
"g c #BF7E7E",
"k c #9B0808",
"= c #BF0505",
"a c #B10303",
"q c #7E2020",
"1 c #642222",
"J c #676767",
"B c #322020",
"; c #C00303",
"i c #242424",
"o c #C00000",
"> c #BF1F1F",
", c #842B2B",
"f c #701212",
"0 c #BE0000",
"r c #960909",
"H c #686868",
"v c #BC0000",
"Z c #671414",
"+ c #C02020",
"z c #CD3535",
/* pixels */
" ",
" ",
" .XoooOO ",
" .+ooooooooo@# ",
" $oooooooooooo%& ",
" *=-ooooooooooooo;: ",
" *oooooooooooooooooo> ",
" =ooooooooooooooooooo, ",
" $-ooooooooooooooooooo<1 ",
" .oooooo2334ooo533oooooo6 ",
" +ooooooo789oo2883oooooo0q ",
" oooooooo2w83o78eoooooooor ",
" toooooooooy88u884oooooooori ",
" Xooooooooooe888poooooooooas ",
" ooooooooooo4889doooooooooof ",
" ooooooooooo588w2oooooooooofi ",
" oooooooooodw8887oooooooooofi ",
" goooooooooh8w588jooooooookli ",
" tooooooooz885op8wdooooooorix ",
" oooooood98cood98cooooooori ",
" @oooooop8w2ooo5885ooooovbi ",
" n%ooooooooooooooooooooomiM ",
" &;oooooooooooooooooooNBiV ",
" :ooooooooooooooooooCZiA ",
" nSooooooooooooooooCDiF ",
" nG<oooooooooooooNZiiH ",
" 160ooooooooovmBiFH ",
" nqrraoookrrbiiA ",
" nJisKKKliiiML ",
" nPiiix ",
" ",
" "
};
/* Copyright (c) Julian Smart */
static const char *info_xpm[]={
/* columns rows colors chars-per-pixel */
"32 32 17 1",
"* c #A1A3FB",
"X c #FFFFFF",
"O c #191EF4",
"= c #777AF9",
": c #4D51F7",
" c None",
"- c #2328F5",
"+ c #4247F6",
"; c #C1C2FC",
". c #C0C0C0",
"& c #E0E1FE",
"% c #242424",
"> c #2D32F5",
"o c #CBCCFD",
"# c #0309F3",
"@ c #8C8FFA",
"$ c #EAEBFE",
/* pixels */
" ....... ",
" ...XXXXXXX... ",
" ..XXXXXXXXXXXXX.. ",
" .XXXXXXXXXXXXXXXXX. ",
" .XXXXXXXXoO+XXXXXXXX. ",
" .XXXXXXXXX@#OXXXXXXXXX. ",
" .XXXXXXXXXX$@oXXXXXXXXXX. ",
" .XXXXXXXXXXXXXXXXXXXXXXX.% ",
" .XXXXXXXXX&*=-XXXXXXXXXX.%% ",
".XXXXXXXXXX;:#>XXXXXXXXXXX.% ",
".XXXXXXXXXXX;#+XXXXXXXXXXX.% ",
".XXXXXXXXXXX;#+XXXXXXXXXXX.%% ",
" .XXXXXXXXXX;#+XXXXXXXXXX.%%% ",
" .XXXXXXXXXX;#+XXXXXXXXXX.%%% ",
" .XXXXXXXXXX;#+XXXXXXXXXX.%% ",
" .XXXXXXXX*-##+XXXXXXXX.%%% ",
" .XXXXXXXXXXXXXXXXXXX.%%%% ",
" .XXXXXXXXXXXXXXXXX.%%%% ",
" ..XXXXXXXXXXXXX..%%%% ",
" %...XXXXXXXX..%%%%% ",
" %%%..XXXXXX.%%%%% ",
" %%%.XXXXX.%%% ",
" %.XXXX.%% ",
" .XXX.%% ",
" .XX.%% ",
" .X.%% ",
" ..%% ",
" .%% ",
" %% ",
" % ",
" ",
" "
};
/* Copyright (c) Julian Smart */
static const char *question_xpm[]={
/* columns rows colors chars-per-pixel */
"32 32 16 1",
"O c #A3A3FF",
"X c #FFFFFF",
"% c #CACAFF",
"- c #4141FF",
"= c #6060FF",
"* c #2B2BFF",
"@ c #B5B5FF",
" c None",
"# c #1616FF",
"+ c #8181FF",
"$ c #0000FF",
". c #C0C0C0",
"; c #5555FF",
": c #242424",
"o c #E7E7FF",
"& c #7575FF",
/* pixels */
" ....... ",
" ...XXXXXXX... ",
" ..XXXXXXXXXXXXX.. ",
" .XXXXXXoO++@XXXXXX. ",
" .XXXXXXO#$$$$#%XXXXX. ",
" .XXXXXX@$$#&&#$#oXXXXX. ",
" .XXXXXXX*$$%XX%$$=XXXXXX. ",
" .XXXXXXX+-;XXXX$$-XXXXXX.: ",
" .XXXXXXXXXXXXX+$$&XXXXXX.:: ",
".XXXXXXXXXXXXo;$$*oXXXXXXX.: ",
".XXXXXXXXXXXo*$$*oXXXXXXXX.: ",
".XXXXXXXXXXX+$$*oXXXXXXXXX.:: ",
" .XXXXXXXXXX-$$oXXXXXXXXX.::: ",
" .XXXXXXXXXXX--XXXXXXXXXX.::: ",
" .XXXXXXXXXXXXXXXXXXXXXXX.:: ",
" .XXXXXXXXX-$$XXXXXXXXX.::: ",
" .XXXXXXXX-$$XXXXXXXX.:::: ",
" .XXXXXXXO++XXXXXXX.:::: ",
" ..XXXXXXXXXXXXX..:::: ",
" :...XXXXXXXX..::::: ",
" :::..XXXXXX.::::: ",
" :::.XXXXX.::: ",
" :.XXXX.:: ",
" .XXX.:: ",
" .XX.:: ",
" .X.:: ",
" ..:: ",
" .:: ",
" :: ",
" : ",
" ",
" "
};
/* Copyright (c) Julian Smart */
static const char *warning_xpm[]={
/* columns rows colors chars-per-pixel */
"32 32 9 1",
"@ c Black",
"o c #A6A800",
"+ c #8A8C00",
"$ c #B8BA00",
" c None",
"O c #6E7000",
"X c #DCDF00",
". c #C00000",
"# c #373800",
/* pixels */
" ",
" ",
" ",
" . ",
" ... ",
" ... ",
" ..... ",
" ...X.. ",
" ..XXX.. ",
" ...XXX... ",
" ..XXXXX.. ",
" ..XXXXXX... ",
" ...XXoO+XX.. ",
" ..XXXO@#XXX.. ",
" ..XXXXO@#XXX... ",
" ...XXXXO@#XXXX.. ",
" ..XXXXXO@#XXXX... ",
" ...XXXXXo@OXXXXX.. ",
" ...XXXXXXo@OXXXXXX.. ",
" ..XXXXXXX$@OXXXXXX... ",
" ...XXXXXXXX@XXXXXXXX.. ",
" ...XXXXXXXXXXXXXXXXXX... ",
" ..XXXXXXXXXXOXXXXXXXXX.. ",
" ...XXXXXXXXXO@#XXXXXXXXX.. ",
" ..XXXXXXXXXXX#XXXXXXXXXX... ",
" ...XXXXXXXXXXXXXXXXXXXXXXX.. ",
" ...XXXXXXXXXXXXXXXXXXXXXXXX... ",
" .............................. ",
" .............................. ",
" ",
" ",
" "
};
wxBitmap wxWin32ArtProvider::CreateBitmap(const wxArtID& id,
const wxArtClient& WXUNUSED(client),
const wxSize& WXUNUSED(size))
{
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;
}
#if wxUSE_TEXTCTRL
// ----------------------------------------------------------------------------
// text control geometry
// ----------------------------------------------------------------------------
wxRect
wxWin32Renderer::GetTextTotalArea(const wxTextCtrl *text,
const wxRect& rect) const
{
wxRect rectTotal = wxStdRenderer::GetTextTotalArea(text, rect);
// this is strange but it's what Windows does
rectTotal.height++;
return rectTotal;
}
wxRect
wxWin32Renderer::GetTextClientArea(const wxTextCtrl *text,
const wxRect& rect,
wxCoord *extraSpaceBeyond) const
{
wxRect rectText = rect;
// undo GetTextTotalArea()
if ( rectText.height > 0 )
rectText.height--;
return wxStdRenderer::GetTextClientArea(text, rect, extraSpaceBeyond);
}
#endif // wxUSE_TEXTCTRL
// ----------------------------------------------------------------------------
// size adjustments
// ----------------------------------------------------------------------------
void wxWin32Renderer::AdjustSize(wxSize *size, const wxWindow *window)
{
#if wxUSE_SCROLLBAR
if ( wxDynamicCast(window, wxScrollBar) )
{
/*
Don't adjust the size for a scrollbar as its DoGetBestClientSize
already has the correct size set. Any size changes here would get
added to the best size, making the scrollbar larger.
Also skip border width adjustments, they don't make sense for us.
*/
return;
}
#endif // wxUSE_SCROLLBAR
#if wxUSE_BMPBUTTON
if ( wxDynamicCast(window, wxBitmapButton) )
{
// do nothing
} else
#endif // wxUSE_BMPBUTTON
#if wxUSE_BUTTON || wxUSE_TOGGLEBTN
if ( 0
# if wxUSE_BUTTON
|| wxDynamicCast(window, wxButton)
# endif // wxUSE_BUTTON
# if wxUSE_TOGGLEBTN
|| wxDynamicCast(window, wxToggleButton)
# endif // wxUSE_TOGGLEBTN
)
{
if ( !(window->GetWindowStyle() & wxBU_EXACTFIT) )
{
// TODO: don't harcode all this
size->x += 3*window->GetCharWidth();
wxCoord heightBtn = (11*(window->GetCharHeight() + 8))/10;
if ( size->y < heightBtn - 8 )
size->y = heightBtn;
else
size->y += 9;
}
// for compatibility with other ports, the buttons default size is never
// less than the standard one, but not when display not PDAs.
if (wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA)
{
if ( !(window->GetWindowStyle() & wxBU_EXACTFIT) )
{
wxSize szDef = wxButton::GetDefaultSize();
if ( size->x < szDef.x )
size->x = szDef.x;
}
}
// no border width adjustments for buttons
return;
}
#endif // wxUSE_BUTTON || wxUSE_TOGGLEBTN
wxStdRenderer::AdjustSize(size, window);
}
wxBitmap wxWin32Renderer::GetFrameButtonBitmap(FrameButtonType type)
{
wxBitmap& bmp = m_bmpFrameButtons[type];
if ( !bmp.IsOk() )
{
bmp = wxBitmap(ms_xpmFrameButtons[type]);
}
return bmp;
}
// ============================================================================
// wxInputHandler
// ============================================================================
// ----------------------------------------------------------------------------
// wxWin32InputHandler
// ----------------------------------------------------------------------------
bool wxWin32InputHandler::HandleKey(wxInputConsumer * WXUNUSED(control),
const wxKeyEvent& WXUNUSED(event),
bool WXUNUSED(pressed))
{
return false;
}
bool wxWin32InputHandler::HandleMouse(wxInputConsumer *control,
const wxMouseEvent& event)
{
// clicking on the control gives it focus
if ( event.ButtonDown() )
{
wxWindow * const win = control->GetInputWindow();
if ( win->CanAcceptFocus() && wxWindow::FindFocus() != win )
{
win->SetFocus();
return true;
}
}
return false;
}
#if wxUSE_SCROLLBAR
// ----------------------------------------------------------------------------
// wxWin32ScrollBarInputHandler
// ----------------------------------------------------------------------------
wxWin32ScrollBarInputHandler::
wxWin32ScrollBarInputHandler(wxRenderer *renderer, wxInputHandler *handler)
: wxStdScrollBarInputHandler(renderer, handler)
{
m_scrollPaused = false;
m_interval = 0;
}
bool wxWin32ScrollBarInputHandler::OnScrollTimer(wxScrollBar *scrollbar,
const wxControlAction& action)
{
// stop if went beyond the position of the original click (this can only
// happen when we scroll by pages)
bool stop = false;
if ( action == wxACTION_SCROLL_PAGE_DOWN )
{
stop = scrollbar->HitTestBar(m_ptStartScrolling) != wxHT_SCROLLBAR_BAR_2;
}
else if ( action == wxACTION_SCROLL_PAGE_UP )
{
stop = scrollbar->HitTestBar(m_ptStartScrolling) != wxHT_SCROLLBAR_BAR_1;
}
if ( stop )
{
StopScrolling(scrollbar);
scrollbar->Refresh();
return false;
}
return wxStdScrollBarInputHandler::OnScrollTimer(scrollbar, action);
}
bool wxWin32ScrollBarInputHandler::HandleMouse(wxInputConsumer *control,
const wxMouseEvent& event)
{
// remember the current state
bool wasDraggingThumb = m_htLast == wxHT_SCROLLBAR_THUMB;
// do process the message
bool rc = wxStdScrollBarInputHandler::HandleMouse(control, event);
// analyse the changes
if ( !wasDraggingThumb && (m_htLast == wxHT_SCROLLBAR_THUMB) )
{
// we just started dragging the thumb, remember its initial position to
// be able to restore it if the drag is cancelled later
m_eventStartDrag = event;
}
return rc;
}
bool wxWin32ScrollBarInputHandler::HandleMouseMove(wxInputConsumer *control,
const wxMouseEvent& event)
{
// we don't highlight scrollbar elements, so there is no need to process
// mouse move events normally - only do it while mouse is captured (i.e.
// when we're dragging the thumb or pressing on something)
if ( !m_winCapture )
return false;
if ( event.Entering() )
{
// we're not interested in this at all
return false;
}
wxScrollBar *scrollbar = wxStaticCast(control->GetInputWindow(), wxScrollBar);
wxHitTest ht;
if ( m_scrollPaused )
{
// check if the mouse returned to its original location
if ( event.Leaving() )
{
// it surely didn't
return false;
}
ht = scrollbar->HitTestBar(event.GetPosition());
if ( ht == m_htLast )
{
// yes it did, resume scrolling
m_scrollPaused = false;
if ( m_timerScroll )
{
// we were scrolling by line/page, restart timer
m_timerScroll->Start(m_interval);
Press(scrollbar, true);
}
else // we were dragging the thumb
{
// restore its last location
HandleThumbMove(scrollbar, m_eventLastDrag);
}
return true;
}
}
else // normal case, scrolling hasn't been paused
{
// if we're scrolling the scrollbar because the arrow or the shaft was
// pressed, check that the mouse stays on the same scrollbar element
#if 0
// Always let thumb jump back if we leave the scrollbar
if ( event.Moving() )
{
ht = scrollbar->HitTestBar(event.GetPosition());
}
else // event.Leaving()
{
ht = wxHT_NOWHERE;
}
#else
// Jump back only if we get far away from it
wxPoint pos = event.GetPosition();
if (scrollbar->HasFlag( wxVERTICAL ))
{
if (pos.x > -40 && pos.x < scrollbar->GetSize().x+40)
pos.x = 5;
}
else
{
if (pos.y > -40 && pos.y < scrollbar->GetSize().y+40)
pos.y = 5;
}
ht = scrollbar->HitTestBar(pos);
#endif
// if we're dragging the thumb and the mouse stays in the scrollbar, it
// is still ok - we only want to catch the case when the mouse leaves
// the scrollbar here
if ( m_htLast == wxHT_SCROLLBAR_THUMB && ht != wxHT_NOWHERE )
{
ht = wxHT_SCROLLBAR_THUMB;
}
if ( ht != m_htLast )
{
// what were we doing? 2 possibilities: either an arrow/shaft was
// pressed in which case we have a timer and so we just stop it or
// we were dragging the thumb
if ( m_timerScroll )
{
// pause scrolling
m_interval = m_timerScroll->GetInterval();
m_timerScroll->Stop();
m_scrollPaused = true;
// unpress the arrow
Press(scrollbar, false);
}
else // we were dragging the thumb
{
// remember the current thumb position to be able to restore it
// if the mouse returns to it later
m_eventLastDrag = event;
// and restore the original position (before dragging) of the
// thumb for now
HandleThumbMove(scrollbar, m_eventStartDrag);
}
return true;
}
}
return wxStdInputHandler::HandleMouseMove(control, event);
}
#endif // wxUSE_SCROLLBAR
#if wxUSE_CHECKBOX
// ----------------------------------------------------------------------------
// wxWin32CheckboxInputHandler
// ----------------------------------------------------------------------------
bool wxWin32CheckboxInputHandler::HandleKey(wxInputConsumer *control,
const wxKeyEvent& event,
bool pressed)
{
if ( pressed )
{
wxControlAction action;
int keycode = event.GetKeyCode();
switch ( keycode )
{
case WXK_SPACE:
action = wxACTION_CHECKBOX_TOGGLE;
break;
case WXK_SUBTRACT:
case WXK_NUMPAD_SUBTRACT:
action = wxACTION_CHECKBOX_CHECK;
break;
case WXK_ADD:
case WXK_NUMPAD_ADD:
case WXK_NUMPAD_EQUAL:
action = wxACTION_CHECKBOX_CLEAR;
break;
}
if ( !action.IsEmpty() )
{
control->PerformAction(action);
return true;
}
}
return false;
}
#endif // wxUSE_CHECKBOX
#if wxUSE_TEXTCTRL
// ----------------------------------------------------------------------------
// wxWin32TextCtrlInputHandler
// ----------------------------------------------------------------------------
bool wxWin32TextCtrlInputHandler::HandleKey(wxInputConsumer *control,
const wxKeyEvent& event,
bool pressed)
{
// handle only MSW-specific text bindings here, the others are handled in
// the base class
if ( pressed )
{
int keycode = event.GetKeyCode();
wxControlAction action;
if ( keycode == WXK_DELETE && event.ShiftDown() )
{
action = wxACTION_TEXT_CUT;
}
else if ( keycode == WXK_INSERT )
{
if ( event.ControlDown() )
action = wxACTION_TEXT_COPY;
else if ( event.ShiftDown() )
action = wxACTION_TEXT_PASTE;
}
if ( action != wxACTION_NONE )
{
control->PerformAction(action);
return true;
}
}
return wxStdInputHandler::HandleKey(control, event, pressed);
}
#endif // wxUSE_TEXTCTRL
#if wxUSE_STATUSBAR
// ----------------------------------------------------------------------------
// wxWin32StatusBarInputHandler
// ----------------------------------------------------------------------------
wxWin32StatusBarInputHandler::
wxWin32StatusBarInputHandler(wxInputHandler *handler)
: wxStdInputHandler(handler)
{
m_isOnGrip = false;
}
bool wxWin32StatusBarInputHandler::IsOnGrip(wxWindow *statbar,
const wxPoint& pt) const
{
if ( statbar->HasFlag(wxST_SIZEGRIP) &&
statbar->GetParent()->HasFlag(wxRESIZE_BORDER) )
{
wxTopLevelWindow *
parentTLW = wxDynamicCast(statbar->GetParent(), wxTopLevelWindow);
wxCHECK_MSG( parentTLW, false,
wxT("the status bar should be a child of a TLW") );
// a maximized window can't be resized anyhow
if ( !parentTLW->IsMaximized() )
{
// VZ: I think that the standard Windows behaviour is to only
// show the resizing cursor when the mouse is on top of the
// grip itself but apparently different Windows versions behave
// differently (?) and it seems a better UI to allow resizing
// the status bar even when the mouse is above the grip
wxSize sizeSbar = statbar->GetSize();
int diff = sizeSbar.x - pt.x;
return diff >= 0 && diff < (wxCoord)STATUSBAR_GRIP_SIZE;
}
}
return false;
}
bool wxWin32StatusBarInputHandler::HandleMouse(wxInputConsumer *consumer,
const wxMouseEvent& event)
{
if ( event.Button(1) )
{
if ( event.ButtonDown(1) )
{
wxWindow *statbar = consumer->GetInputWindow();
if ( IsOnGrip(statbar, event.GetPosition()) )
{
wxTopLevelWindow *tlw = wxDynamicCast(statbar->GetParent(),
wxTopLevelWindow);
if ( tlw )
{
tlw->PerformAction(wxACTION_TOPLEVEL_RESIZE,
wxHT_TOPLEVEL_BORDER_SE);
statbar->SetCursor(m_cursorOld);
return true;
}
}
}
}
return wxStdInputHandler::HandleMouse(consumer, event);
}
bool wxWin32StatusBarInputHandler::HandleMouseMove(wxInputConsumer *consumer,
const wxMouseEvent& event)
{
wxWindow *statbar = consumer->GetInputWindow();
bool isOnGrip = IsOnGrip(statbar, event.GetPosition());
if ( isOnGrip != m_isOnGrip )
{
m_isOnGrip = isOnGrip;
if ( isOnGrip )
{
m_cursorOld = statbar->GetCursor();
statbar->SetCursor(wxCURSOR_SIZENWSE);
}
else
{
statbar->SetCursor(m_cursorOld);
}
}
return wxStdInputHandler::HandleMouseMove(consumer, event);
}
#endif // wxUSE_STATUSBAR
// ----------------------------------------------------------------------------
// wxWin32FrameInputHandler
// ----------------------------------------------------------------------------
class wxWin32SystemMenuEvtHandler : public wxEvtHandler
{
public:
wxWin32SystemMenuEvtHandler(wxWin32FrameInputHandler *handler);
void Attach(wxInputConsumer *consumer);
void Detach();
private:
DECLARE_EVENT_TABLE()
void OnSystemMenu(wxCommandEvent &event);
void OnCloseFrame(wxCommandEvent &event);
void OnClose(wxCloseEvent &event);
wxWin32FrameInputHandler *m_inputHnd;
wxTopLevelWindow *m_wnd;
#if wxUSE_ACCEL
wxAcceleratorTable m_oldAccelTable;
#endif
};
wxWin32SystemMenuEvtHandler::
wxWin32SystemMenuEvtHandler(wxWin32FrameInputHandler *handler)
{
m_inputHnd = handler;
m_wnd = NULL;
}
void wxWin32SystemMenuEvtHandler::Attach(wxInputConsumer *consumer)
{
wxASSERT_MSG( m_wnd == NULL, wxT("can't attach the handler twice!") );
m_wnd = wxStaticCast(consumer->GetInputWindow(), wxTopLevelWindow);
m_wnd->PushEventHandler(this);
#if wxUSE_ACCEL
// VS: This code relies on using generic implementation of
// wxAcceleratorTable in wxUniv!
wxAcceleratorTable table = *m_wnd->GetAcceleratorTable();
m_oldAccelTable = table;
table.Add(wxAcceleratorEntry(wxACCEL_ALT, WXK_SPACE, wxID_SYSTEM_MENU));
table.Add(wxAcceleratorEntry(wxACCEL_ALT, WXK_F4, wxID_CLOSE_FRAME));
m_wnd->SetAcceleratorTable(table);
#endif
}
void wxWin32SystemMenuEvtHandler::Detach()
{
if ( m_wnd )
{
#if wxUSE_ACCEL
m_wnd->SetAcceleratorTable(m_oldAccelTable);
#endif
m_wnd->RemoveEventHandler(this);
m_wnd = NULL;
}
}
BEGIN_EVENT_TABLE(wxWin32SystemMenuEvtHandler, wxEvtHandler)
EVT_MENU(wxID_SYSTEM_MENU, wxWin32SystemMenuEvtHandler::OnSystemMenu)
EVT_MENU(wxID_CLOSE_FRAME, wxWin32SystemMenuEvtHandler::OnCloseFrame)
EVT_CLOSE(wxWin32SystemMenuEvtHandler::OnClose)
END_EVENT_TABLE()
void wxWin32SystemMenuEvtHandler::OnSystemMenu(wxCommandEvent &WXUNUSED(event))
{
#if wxUSE_ACCEL
wxAcceleratorTable table = *m_wnd->GetAcceleratorTable();
m_wnd->SetAcceleratorTable(wxNullAcceleratorTable);
#endif
#if wxUSE_MENUS
m_inputHnd->PopupSystemMenu(m_wnd);
#endif // wxUSE_MENUS
#if wxUSE_ACCEL
m_wnd->SetAcceleratorTable(table);
#endif
}
void wxWin32SystemMenuEvtHandler::OnCloseFrame(wxCommandEvent &WXUNUSED(event))
{
m_wnd->PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK,
wxTOPLEVEL_BUTTON_CLOSE);
}
void wxWin32SystemMenuEvtHandler::OnClose(wxCloseEvent &event)
{
m_wnd = NULL;
event.Skip();
}
wxWin32FrameInputHandler::wxWin32FrameInputHandler(wxInputHandler *handler)
: wxStdInputHandler(handler)
{
m_menuHandler = new wxWin32SystemMenuEvtHandler(this);
}
wxWin32FrameInputHandler::~wxWin32FrameInputHandler()
{
if ( m_menuHandler )
{
m_menuHandler->Detach();
delete m_menuHandler;
}
}
bool wxWin32FrameInputHandler::HandleMouse(wxInputConsumer *consumer,
const wxMouseEvent& event)
{
if ( event.LeftDClick() || event.LeftDown() || event.RightDown() )
{
wxTopLevelWindow *tlw =
wxStaticCast(consumer->GetInputWindow(), wxTopLevelWindow);
long hit = tlw->HitTest(event.GetPosition());
if ( event.LeftDClick() && hit == wxHT_TOPLEVEL_TITLEBAR )
{
tlw->PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK,
tlw->IsMaximized() ? wxTOPLEVEL_BUTTON_RESTORE
: wxTOPLEVEL_BUTTON_MAXIMIZE);
return true;
}
else if ( tlw->GetWindowStyle() & wxSYSTEM_MENU )
{
if ( (event.LeftDown() && hit == wxHT_TOPLEVEL_ICON) ||
(event.RightDown() &&
(hit == wxHT_TOPLEVEL_TITLEBAR ||
hit == wxHT_TOPLEVEL_ICON)) )
{
#if wxUSE_MENUS
PopupSystemMenu(tlw);
#endif // wxUSE_MENUS
return true;
}
}
}
return wxStdInputHandler::HandleMouse(consumer, event);
}
#if wxUSE_MENUS
void wxWin32FrameInputHandler::PopupSystemMenu(wxTopLevelWindow *window) const
{
wxMenu menu;
if ( window->GetWindowStyle() & wxMAXIMIZE_BOX )
menu.Append(wxID_RESTORE_FRAME , _("&Restore"));
menu.Append(wxID_MOVE_FRAME , _("&Move"));
if ( window->GetWindowStyle() & wxRESIZE_BORDER )
menu.Append(wxID_RESIZE_FRAME , _("&Size"));
if ( wxSystemSettings::HasFeature(wxSYS_CAN_ICONIZE_FRAME) )
menu.Append(wxID_ICONIZE_FRAME , _("Mi&nimize"));
if ( window->GetWindowStyle() & wxMAXIMIZE_BOX )
menu.Append(wxID_MAXIMIZE_FRAME , _("Ma&ximize"));
menu.AppendSeparator();
menu.Append(wxID_CLOSE_FRAME, _("&Close") + wxT("\t") + _("Alt+") + wxT("F4"));
if ( window->GetWindowStyle() & wxMAXIMIZE_BOX )
{
if ( window->IsMaximized() )
{
menu.Enable(wxID_MAXIMIZE_FRAME, false);
menu.Enable(wxID_MOVE_FRAME, false);
if ( window->GetWindowStyle() & wxRESIZE_BORDER )
menu.Enable(wxID_RESIZE_FRAME, false);
}
else
menu.Enable(wxID_RESTORE_FRAME, false);
}
window->PopupMenu(&menu, wxPoint(0, 0));
}
#endif // wxUSE_MENUS
bool wxWin32FrameInputHandler::HandleActivation(wxInputConsumer *consumer,
bool activated)
{
if ( consumer->GetInputWindow()->GetWindowStyle() & wxSYSTEM_MENU )
{
// always detach if active frame changed:
m_menuHandler->Detach();
if ( activated )
{
m_menuHandler->Attach(consumer);
}
}
return wxStdInputHandler::HandleActivation(consumer, activated);
}
#endif // wxUSE_THEME_WIN32