More support for drawing native column headers, adds more states

(selected, mouse-over) and also optionally drawing the contents of the
header (label and/or bitmap, sort arrow) in a consistent way.  Also
added a method to determine the default height of the column header.
This is based on work done for OSAF.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41201 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2006-09-13 20:28:43 +00:00
parent 245243ec13
commit 4b94ddc44c
6 changed files with 397 additions and 32 deletions

View File

@@ -55,8 +55,10 @@ enum
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
@@ -86,6 +88,24 @@ struct WXDLLEXPORT wxSplitterRenderParams
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
{
@@ -131,7 +151,22 @@ public:
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,
@@ -264,8 +299,21 @@ public:
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,

View File

@@ -49,7 +49,16 @@ public:
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,
@@ -194,10 +203,11 @@ wxRendererGeneric::DrawShadedRect(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;
@@ -206,6 +216,10 @@ wxRendererGeneric::DrawHeaderButton(wxWindow * WXUNUSED(win),
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);
@@ -221,8 +235,180 @@ wxRendererGeneric::DrawHeaderButton(wxWindow * WXUNUSED(win),
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),

View File

@@ -46,7 +46,8 @@ public:
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,
@@ -183,7 +184,8 @@ void
wxRendererGTK::DrawHeaderButton(wxWindow *win,
wxDC& dc,
const wxRect& rect,
int flags)
int flags,
wxHeaderButtonParams* params)
{
GtkWidget *button = GetButtonWidget();
@@ -201,6 +203,8 @@ wxRendererGTK::DrawHeaderButton(wxWindow *win,
"button",
dc.LogicalToDeviceX(rect.x), rect.y, rect.width, rect.height
);
DrawHeaderButtonContents(win, dc, rect, flags, params);
}
// draw a ">" or "v" button

View File

@@ -36,7 +36,10 @@ public:
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,
@@ -125,14 +128,11 @@ wxRendererNative& wxRendererNative::GetDefault()
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);
@@ -179,11 +179,28 @@ void wxRendererMac::DrawHeaderButton( wxWindow *win,
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
@@ -191,7 +208,33 @@ void wxRendererMac::DrawHeaderButton( wxWindow *win,
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,

View File

@@ -68,6 +68,12 @@
#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)
@@ -115,7 +121,10 @@ public:
virtual void DrawHeaderButton(wxWindow *win,
wxDC& dc,
const wxRect& rect,
int flags = 0);
int flags = 0,
wxHeaderButtonParams* params = NULL);
virtual int GetHeaderButtonHeight(wxWindow *win);
virtual void DrawTreeItemButton(wxWindow *win,
wxDC& dc,
const wxRect& rect,
@@ -276,12 +285,13 @@ void
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;
}
@@ -304,8 +314,41 @@ wxRendererXP::DrawHeaderButton(wxWindow *win,
&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,

View File

@@ -34,8 +34,10 @@ enum
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
@@ -73,6 +75,29 @@ struct wxSplitterRenderParams
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
@@ -102,11 +127,12 @@ struct wxRendererVersion
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
@@ -128,11 +154,26 @@ public:
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,