wxCONTROL_CHECKED = 0x00000040, // (check/radio button) is checked
wxCONTROL_CHECKABLE = 0x00000080, // (menu) item can be checked
wxCONTROL_UNDETERMINED = wxCONTROL_CHECKABLE, // (check) undetermined state
+ wxCONTROL_UPICON = 0x00000100, // header button has an up arrow icon
+ wxCONTROL_DOWNICON = 0x00000200, // header button has a down arrow icon
- wxCONTROL_FLAGS_MASK = 0x000000ff,
+ wxCONTROL_FLAGS_MASK = 0x000002ff,
// this is a pseudo flag not used directly by wxRenderer but rather by some
// controls internally
const bool isHotSensitive;
};
+
+// extra optional parameters for DrawHeaderButton
+struct WXDLLEXPORT wxHeaderButtonParams
+{
+ wxHeaderButtonParams()
+ : m_labelAlignment(wxALIGN_LEFT)
+ { }
+
+ wxColour m_arrowColour;
+ wxColour m_selectionColour;
+ wxString m_labelText;
+ wxFont m_labelFont;
+ wxColour m_labelColour;
+ wxBitmap m_labelBitmap;
+ int m_labelAlignment;
+};
+
+
// wxRendererNative interface version
struct WXDLLEXPORT wxRendererVersion
{
virtual void DrawHeaderButton(wxWindow *win,
wxDC& dc,
const wxRect& rect,
- int flags = 0) = 0;
+ int flags = 0,
+ wxHeaderButtonParams* params=NULL) = 0;
+
+
+ // Draw the contents of a header control button (label, sort arrows, etc.)
+ // Normally only called by DrawHeaderButton.
+ virtual void DrawHeaderButtonContents(wxWindow *win,
+ wxDC& dc,
+ const wxRect& rect,
+ int flags = 0,
+ wxHeaderButtonParams* params=NULL) = 0;
+
+ // Returns the default height of a header button, either a fixed platform
+ // height if available, or a generic height based on the window's font.
+ virtual int GetHeaderButtonHeight(wxWindow *win) = 0;
+
// draw the expanded/collapsed icon for a tree control item
virtual void DrawTreeItemButton(wxWindow *win,
virtual void DrawHeaderButton(wxWindow *win,
wxDC& dc,
const wxRect& rect,
- int flags = 0)
- { m_rendererNative.DrawHeaderButton(win, dc, rect, flags); }
+ int flags = 0,
+ wxHeaderButtonParams* params = NULL)
+ { m_rendererNative.DrawHeaderButton(win, dc, rect, flags, params); }
+
+
+ virtual void DrawHeaderButtonContents(wxWindow *win,
+ wxDC& dc,
+ const wxRect& rect,
+ int flags = 0,
+ wxHeaderButtonParams* params = NULL)
+ { m_rendererNative.DrawHeaderButtonContents(win, dc, rect, flags, params); }
+
+
+ virtual int GetHeaderButtonHeight(wxWindow *win)
+ { return m_rendererNative.GetHeaderButtonHeight(win); }
virtual void DrawTreeItemButton(wxWindow *win,
wxDC& dc,
virtual void DrawHeaderButton(wxWindow *win,
wxDC& dc,
const wxRect& rect,
- int flags = 0);
+ int flags = 0,
+ wxHeaderButtonParams* params = NULL);
+
+ virtual void DrawHeaderButtonContents(wxWindow *win,
+ wxDC& dc,
+ const wxRect& rect,
+ int flags = 0,
+ wxHeaderButtonParams* params = NULL);
+
+ virtual int GetHeaderButtonHeight(wxWindow *win);
virtual void DrawTreeItemButton(wxWindow *win,
wxDC& dc,
// ----------------------------------------------------------------------------
void
-wxRendererGeneric::DrawHeaderButton(wxWindow * WXUNUSED(win),
+wxRendererGeneric::DrawHeaderButton(wxWindow* win,
wxDC& dc,
const wxRect& rect,
- int WXUNUSED(flags))
+ int flags,
+ wxHeaderButtonParams* params)
{
const int CORNER = 1;
w = rect.width,
h = rect.height;
+ dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)));
+ dc.SetPen(*wxTRANSPARENT_PEN);
+ dc.DrawRectangle(rect);
+
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.SetPen(m_penBlack);
dc.DrawRectangle( x, y, 1, h ); // left (outer)
dc.DrawLine( x, y+h-1, x+1, y+h-1 );
dc.DrawLine( x+w-1, y, x+w-1, y+1 );
+
+ DrawHeaderButtonContents(win, dc, rect, flags, params);
}
+void
+wxRendererGeneric::DrawHeaderButtonContents(wxWindow *win,
+ wxDC& dc,
+ const wxRect& rect,
+ int flags,
+ wxHeaderButtonParams* params)
+{
+ // Mark this item as selected. For the generic version we'll just draw an
+ // underline
+ if ( flags & wxCONTROL_SELECTED )
+ {
+ // draw a line at the bottom of the header button, overlaying the
+ // native hot-tracking line (on XP)
+ const int penwidth = 3;
+ int y = rect.y + rect.height + 1 - penwidth;
+ wxColour c = (params && params->m_selectionColour.Ok()) ?
+ params->m_selectionColour : wxColour(0x66, 0x66, 0x66);
+ wxPen pen(c, penwidth);
+ pen.SetCap(wxCAP_BUTT);
+ dc.SetPen(pen);
+ dc.DrawLine(rect.x, y, rect.x + rect.width, y);
+ }
+
+ // Draw an up or down arrow
+ int arrowSpace = 0;
+ if (flags & (wxCONTROL_UPICON | wxCONTROL_DOWNICON) )
+ {
+ wxRect ar = rect;
+
+ // make a rect for the arrow
+ ar.height = 4;
+ ar.width = 8;
+ ar.y += (rect.height - ar.height)/2;
+ ar.x = ar.x + rect.width - 3*ar.width/2;
+ arrowSpace = 3*ar.width/2; // space to preserve when drawing the label
+
+ wxPoint triPt[3];
+ if ( flags & wxCONTROL_UPICON )
+ {
+ triPt[0].x = ar.width / 2;
+ triPt[0].y = 0;
+ triPt[1].x = ar.width;
+ triPt[1].y = ar.height;
+ triPt[2].x = 0;
+ triPt[2].y = ar.height;
+ }
+ else
+ {
+ triPt[0].x = 0;
+ triPt[0].y = 0;
+ triPt[1].x = ar.width;
+ triPt[1].y = 0;
+ triPt[2].x = ar.width / 2;
+ triPt[2].y = ar.height;
+ }
+
+ wxColour c = (params && params->m_arrowColour.Ok()) ?
+ params->m_arrowColour : wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW);
+ dc.SetPen(wxPen(c));
+ dc.SetBrush(wxBrush(c));
+ dc.DrawPolygon( 3, triPt, ar.x, ar.y);
+ }
+
+ const int margin = 5; // number of pixels to reserve on either side of the label
+ int bmpWidth = 0;
+ int txtEnd = 0;
+
+ if ( params && params->m_labelBitmap.Ok() )
+ bmpWidth = params->m_labelBitmap.GetWidth() + 2;
+
+ // Draw a label if one is given
+ if ( params && !params->m_labelText.empty() )
+ {
+ wxFont font = params->m_labelFont.Ok() ?
+ params->m_labelFont : win->GetFont();
+ wxColour clr = params->m_labelColour.Ok() ?
+ params->m_labelColour : win->GetForegroundColour();
+
+ wxString label( params->m_labelText );
+
+ dc.SetFont(font);
+ dc.SetTextForeground(clr);
+ dc.SetBackgroundMode(wxTRANSPARENT);
+
+ int tw, th, td, x, y;
+ dc.GetTextExtent( label, &tw, &th, &td);
+ y = rect.y + wxMax(0, (rect.height - (th+td)) / 2);
+
+ // truncate and add an ellipsis (...) if the text is too wide.
+ int targetWidth = rect.width - arrowSpace - bmpWidth - 2*margin;
+ if ( tw > targetWidth )
+ {
+ int ellipsisWidth;
+ dc.GetTextExtent( wxT("..."), &ellipsisWidth, NULL);
+ do {
+ label.Truncate( label.length() - 1 );
+ dc.GetTextExtent( label, &tw, &th);
+ } while (tw + ellipsisWidth > targetWidth && label.length() );
+ label.append( wxT("...") );
+ tw += ellipsisWidth;
+ }
+
+ switch (params->m_labelAlignment)
+ {
+ default:
+ case wxALIGN_LEFT:
+ x = rect.x + margin;
+ break;
+ case wxALIGN_CENTER:
+ x = rect.x + wxMax(0, (rect.width - arrowSpace - tw - bmpWidth)/2);
+ break;
+ case wxALIGN_RIGHT:
+ x = rect.x + wxMax(0, rect.width - arrowSpace - margin - tw - bmpWidth);
+ break;
+ }
+
+ dc.DrawText(label, x, y);
+ txtEnd = x + tw + 2;
+ }
+
+ // draw the bitmap if there is one
+ if ( params && params->m_labelBitmap.Ok() )
+ {
+ int w, h, x, y;
+ w = params->m_labelBitmap.GetWidth();
+ h = params->m_labelBitmap.GetHeight();
+
+ y = rect.y + wxMax(1, (rect.height - h) / 2);
+
+ // if there is a text label, then put the bitmap at the end of the label
+ if ( txtEnd != 0 )
+ {
+ x = txtEnd;
+ }
+ // otherwise use the alignment flags
+ else
+ {
+ switch (params->m_labelAlignment)
+ {
+ default:
+ case wxALIGN_LEFT:
+ x = rect.x + margin;
+ break;
+ case wxALIGN_CENTER:
+ x = rect.x + wxMax(1, (rect.width - arrowSpace - w)/2);
+ break;
+ case wxALIGN_RIGHT:
+ x = rect.x + wxMax(1, rect.width - arrowSpace - margin - w);
+ break;
+ }
+ }
+ dc.DrawBitmap(params->m_labelBitmap, x, y, true);
+ }
+}
+
+
+int wxRendererGeneric::GetHeaderButtonHeight(wxWindow *win)
+{
+ // Copied and adapted from src/generic/listctrl.cpp
+ const int HEADER_OFFSET_Y = 1;
+ const int EXTRA_HEIGHT = 4;
+
+ int w=0, h=14, d=0;
+ if (win)
+ win->GetTextExtent(wxT("Hg"), &w, &h, &d);
+
+ return h + d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
+}
+
+
// draw the plus or minus sign
void
wxRendererGeneric::DrawTreeItemButton(wxWindow * WXUNUSED(win),
virtual void DrawHeaderButton(wxWindow *win,
wxDC& dc,
const wxRect& rect,
- int flags = 0);
+ int flags = 0,
+ wxHeaderButtonParams* params = NULL);
// draw the expanded/collapsed icon for a tree control item
virtual void DrawTreeItemButton(wxWindow *win,
wxRendererGTK::DrawHeaderButton(wxWindow *win,
wxDC& dc,
const wxRect& rect,
- int flags)
+ int flags,
+ wxHeaderButtonParams* params)
{
GtkWidget *button = GetButtonWidget();
"button",
dc.LogicalToDeviceX(rect.x), rect.y, rect.width, rect.height
);
+
+ DrawHeaderButtonContents(win, dc, rect, flags, params);
}
// draw a ">" or "v" button
virtual void DrawHeaderButton( wxWindow *win,
wxDC& dc,
const wxRect& rect,
- int flags = 0 );
+ int flags = 0,
+ wxHeaderButtonParams* params = NULL );
+ virtual int GetHeaderButtonHeight(wxWindow *win);
+
// draw the expanded/collapsed icon for a tree control item
virtual void DrawTreeItemButton( wxWindow *win,
wxDC& dc,
void wxRendererMac::DrawHeaderButton( wxWindow *win,
wxDC& dc,
const wxRect& rect,
- int flags )
+ int flags,
+ wxHeaderButtonParams* params )
{
- int major, minor;
-
- wxGetOsVersion( &major, &minor );
-
- const wxCoord x = dc.XLOG2DEV(rect.x - 1);
- const wxCoord y = dc.YLOG2DEV(rect.y - 1);
+ const wxCoord x = dc.XLOG2DEV(rect.x /*- 1*/);
+ const wxCoord y = dc.YLOG2DEV(rect.y /*- 1*/);
const wxCoord w = dc.XLOG2DEVREL(rect.width);
const wxCoord h = dc.YLOG2DEVREL(rect.height);
memset( &drawInfo, 0, sizeof(drawInfo) );
drawInfo.version = 0;
- drawInfo.state = (flags & wxCONTROL_DISABLED) ? kThemeStateInactive : kThemeStateActive;
drawInfo.kind = kThemeListHeaderButton;
- drawInfo.value = 0;
+ drawInfo.state = (flags & wxCONTROL_DISABLED) ? kThemeStateInactive : kThemeStateActive;
+ drawInfo.value = (flags & wxCONTROL_SELECTED) ? kThemeButtonOn : kThemeButtonOff;
drawInfo.adornment = kThemeAdornmentNone;
+
+ // The down arrow is drawn automatically, change it to an up arrow if needed.
+ if ( flags & wxCONTROL_UPICON )
+ drawInfo.adornment = kThemeAdornmentHeaderButtonSortUp;
+
HIThemeDrawButton( &headerRect, &drawInfo, cgContext, kHIThemeOrientationNormal, &labelRect );
+
+ // If we don't want any arrows we need to draw over the one already there
+ if ( (flags & wxCONTROL_SELECTED) && !(flags & (wxCONTROL_UPICON|wxCONTROL_DOWNICON)) )
+ {
+ // clip to the header rectangle
+ CGContextSaveGState( cgContext );
+ CGContextClipToRect( cgContext, headerRect );
+ // but draw bigger than that so the arrow will get clipped off
+ headerRect.size.width += 25;
+ HIThemeDrawButton( &headerRect, &drawInfo, cgContext, kHIThemeOrientationNormal, &labelRect );
+ CGContextRestoreGState( cgContext );
+ }
}
#if wxMAC_USE_CORE_GRAPHICS
QDEndCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
#endif
}
+
+ // Reserve room for the arrows before writing the label, and turn off the
+ // flags we've already handled
+ wxRect newRect(rect);
+ if ( (flags & wxCONTROL_SELECTED) && (flags & (wxCONTROL_UPICON|wxCONTROL_DOWNICON)) )
+ {
+ newRect.width -= 12;
+ }
+ flags &= ~(wxCONTROL_SELECTED | wxCONTROL_UPICON | wxCONTROL_DOWNICON);
+
+ DrawHeaderButtonContents(win, dc, newRect, flags, params);
+}
+
+
+int wxRendererMac::GetHeaderButtonHeight(wxWindow* WXUNUSED(win))
+{
+ SInt32 standardHeight;
+ OSStatus errStatus;
+
+ errStatus = GetThemeMetric( kThemeMetricListHeaderHeight, &standardHeight );
+ if (errStatus == noErr)
+ {
+ return standardHeight;
+ }
+ return -1;
}
+
void wxRendererMac::DrawTreeItemButton( wxWindow *win,
wxDC& dc,
const wxRect& rect,
#define HIS_NORMAL 1
#define HIS_HOT 2
#define HIS_PRESSED 3
+
+ #define TMT_HEIGHT 2417
+
+ #define HP_HEADERSORTARROW 4
+ #define HSAS_SORTEDUP 1
+ #define HSAS_SORTEDDOWN 2
#endif
#if defined(__WXWINCE__) && !defined(DFCS_FLAT)
static wxRendererNative& Get();
virtual void DrawHeaderButton(wxWindow *win,
- wxDC& dc,
- const wxRect& rect,
- int flags = 0);
+ wxDC& dc,
+ const wxRect& rect,
+ int flags = 0,
+ wxHeaderButtonParams* params = NULL);
+ virtual int GetHeaderButtonHeight(wxWindow *win);
+
virtual void DrawTreeItemButton(wxWindow *win,
wxDC& dc,
const wxRect& rect,
wxRendererXP::DrawHeaderButton(wxWindow *win,
wxDC& dc,
const wxRect& rect,
- int flags)
+ int flags,
+ wxHeaderButtonParams* params)
{
wxUxThemeHandle hTheme(win, L"HEADER");
if ( !hTheme )
{
- m_rendererNative.DrawHeaderButton(win, dc, rect, flags);
+ m_rendererNative.DrawHeaderButton(win, dc, rect, flags, params);
return;
}
&r,
NULL
);
+
+ // NOTE: Using the theme to draw HP_HEADERSORTARROW doesn't do anything.
+ // Why? If this can be fixed then draw the sort arrows using the theme
+ // and then clear those flags before calling DrawHeaderButtonContents.
+
+ // Add any extras that are specified in flags and params
+ DrawHeaderButtonContents(win, dc, rect, flags, params);
+}
+
+
+int
+wxRendererXP::GetHeaderButtonHeight(wxWindow *win)
+{
+ wxUxThemeHandle hTheme(win, L"HEADER");
+ if ( !hTheme )
+ {
+ return m_rendererNative.GetHeaderButtonHeight(win);
+ }
+
+ HRESULT hr;
+ int value = -1;
+
+ hr = wxUxThemeEngine::Get()->GetThemeMetric( hTheme,
+ NULL,
+ HP_HEADERITEM,
+ HIS_NORMAL,
+ TMT_HEIGHT,
+ &value );
+ if ( hr == S_OK )
+ return value;
+ else
+ return 20;
}
+
void
wxRendererXP::DrawTreeItemButton(wxWindow *win,
wxDC& dc,
wxCONTROL_CHECKED = 0x00000040, // (check/radio button) is checked
wxCONTROL_CHECKABLE = 0x00000080, // (menu) item can be checked
wxCONTROL_UNDETERMINED = wxCONTROL_CHECKABLE, // (check) undetermined state
+ wxCONTROL_UPICON = 0x00000100, // header button has an up arrow icon
+ wxCONTROL_DOWNICON = 0x00000200, // header button has a down arrow icon
- wxCONTROL_FLAGS_MASK = 0x000000ff,
+ wxCONTROL_FLAGS_MASK = 0x000002ff,
// this is a pseudo flag not used directly by wxRenderer but rather by some
// controls internally
+DocStr(wxHeaderButtonParams,
+"Extra (optional) parameters for `wx.RendererNative.DrawHeaderButton`", "");
+
+struct wxHeaderButtonParams
+{
+ wxHeaderButtonParams();
+ ~wxHeaderButtonParams();
+
+ // So wxColour_helper will be used when assigning to the colour items in the struct
+ %typemap(in) wxColour* (wxColour temp) {
+ $1 = &temp;
+ if ( ! wxColour_helper($input, &$1)) SWIG_fail;
+ }
+ wxColour m_arrowColour;
+ wxColour m_selectionColour;
+ wxString m_labelText;
+ wxFont m_labelFont;
+ wxColour m_labelColour;
+ wxBitmap m_labelBitmap;
+ int m_labelAlignment;
+};
+
+
DocStr(wxRendererVersion,
"This simple struct represents the `wx.RendererNative` interface
DocStr(wxRendererNative,
-"One of the design principles of wxWidgets is to use the native widgets
-on every platform in order to be as close to the native look and feel
-on every platform. However there are still cases when some generic
-widgets are needed for various reasons, but it can sometimes take a
-lot of messy work to make them conform to the native LnF.
+"One of the design principles of wxWidgets is to use the native
+widgets on every platform in order to be as close as possible to
+the native look and feel on every platform. However there are
+still cases when some generic widgets are needed for various
+reasons, but it can sometimes take a lot of messy work to make
+them conform to the native LnF.
The wx.RendererNative class is a collection of functions that have
platform-specific implementations for drawing certain parts of
virtual void , DrawHeaderButton(wxWindow *win,
wxDC& dc,
const wxRect& rect,
- int flags = 0),
+ int flags = 0,
+ wxHeaderButtonParams* params=NULL),
"Draw the header control button (such as what is used by `wx.ListCtrl`
in report mode.)", "");
-
+ DocDeclStr(
+ virtual void , DrawHeaderButtonContents(wxWindow *win,
+ wxDC& dc,
+ const wxRect& rect,
+ int flags = 0,
+ wxHeaderButtonParams* params=NULL),
+ "Draw the contents of a header control button, (label, sort
+arrows, etc.) Normally this is only called by `DrawHeaderButton`.", "");
+
+ DocDeclStr(
+ virtual int , GetHeaderButtonHeight(wxWindow *win),
+ "Returns the default height of a header button, either a fixed platform
+height if available, or a generic height based on the window's font.", "");
+
+
DocDeclStr(
virtual void , DrawTreeItemButton(wxWindow *win,
wxDC& dc,