Fix cell selection drawing in wxDVC on MSW with system theme

Keyboard focus rect when selecting a column was nearly invisible against the
light background. Now the correct theme parts are used when drawing with UX
theme and the old behavior (white focus rect) is used everywhere else.

See #16414
This commit is contained in:
Tobias Taschner
2015-09-30 19:07:24 +02:00
committed by Vadim Zeitlin
parent 515fcc66e6
commit 4ac0250f90
5 changed files with 121 additions and 87 deletions

View File

@@ -62,6 +62,7 @@ enum
wxCONTROL_EXPANDED = wxCONTROL_SPECIAL, // only for the tree items wxCONTROL_EXPANDED = wxCONTROL_SPECIAL, // only for the tree items
wxCONTROL_SIZEGRIP = wxCONTROL_SPECIAL, // only for the status bar panes wxCONTROL_SIZEGRIP = wxCONTROL_SPECIAL, // only for the status bar panes
wxCONTROL_FLAT = wxCONTROL_SPECIAL, // checkboxes only: flat border wxCONTROL_FLAT = wxCONTROL_SPECIAL, // checkboxes only: flat border
wxCONTROL_CELL = wxCONTROL_SPECIAL, // only for item selection rect
wxCONTROL_CURRENT = 0x00000010, // mouse is currently over the control wxCONTROL_CURRENT = 0x00000010, // mouse is currently over the control
wxCONTROL_SELECTED = 0x00000020, // selected item in e.g. listbox wxCONTROL_SELECTED = 0x00000020, // selected item in e.g. listbox
wxCONTROL_CHECKED = 0x00000040, // (check/radio button) is checked wxCONTROL_CHECKED = 0x00000040, // (check/radio button) is checked

View File

@@ -46,6 +46,9 @@ enum
/** Checkboxes only: flat border. */ /** Checkboxes only: flat border. */
wxCONTROL_FLAT = wxCONTROL_SPECIAL, wxCONTROL_FLAT = wxCONTROL_SPECIAL,
/** Item selection rect only: cell inside selection. */
wxCONTROL_CELL = wxCONTROL_SPECIAL,
/** Mouse is currently over the control. */ /** Mouse is currently over the control. */
wxCONTROL_CURRENT = 0x00000010, wxCONTROL_CURRENT = 0x00000010,
@@ -404,7 +407,8 @@ public:
@c wxCONTROL_FOCUSED may be used to indicate if the control has the focus @c wxCONTROL_FOCUSED may be used to indicate if the control has the focus
(otherwise the selection rectangle is e.g. often grey and not blue). (otherwise the selection rectangle is e.g. often grey and not blue).
This may be ignored by the renderer or deduced by the code directly from This may be ignored by the renderer or deduced by the code directly from
the @a win. the @a win. Additionally @c wxCONTROL_CELL may be used to draw a cell inside
a bigger selection area.
@see DrawItemText() @see DrawItemText()
*/ */

View File

@@ -1801,44 +1801,6 @@ wxBitmap wxDataViewMainWindow::CreateItemBitmap( unsigned int row, int &indent )
#endif // wxUSE_DRAG_AND_DROP #endif // wxUSE_DRAG_AND_DROP
// Draw focus rect for individual cell. Unlike native focus rect, we render
// this in foreground text color (typically white) to enhance contrast and
// make it visible.
static void DrawSelectedCellFocusRect(wxDC& dc, const wxRect& rect)
{
// (This code is based on wxRendererGeneric::DrawFocusRect and modified.)
// draw the pixels manually because the "dots" in wxPen with wxDOT style
// may be short traits and not really dots
//
// note that to behave in the same manner as DrawRect(), we must exclude
// the bottom and right borders from the rectangle
wxCoord x1 = rect.GetLeft(),
y1 = rect.GetTop(),
x2 = rect.GetRight(),
y2 = rect.GetBottom();
wxDCPenChanger pen(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
wxCoord z;
for ( z = x1 + 1; z < x2; z += 2 )
dc.DrawPoint(z, rect.GetTop());
wxCoord shift = z == x2 ? 0 : 1;
for ( z = y1 + shift; z < y2; z += 2 )
dc.DrawPoint(x2, z);
shift = z == y2 ? 0 : 1;
for ( z = x2 - shift; z > x1; z -= 2 )
dc.DrawPoint(z, y2);
shift = z == x1 ? 0 : 1;
for ( z = y2 - shift; z > y1; z -= 2 )
dc.DrawPoint(x1, z);
}
void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
{ {
wxDataViewModel *model = GetModel(); wxDataViewModel *model = GetModel();
@@ -1994,29 +1956,18 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
if (selected || item == m_currentRow) if (selected || item == m_currentRow)
{ {
wxRect rect( x_start, GetLineStart( item ), wxRect rowRect( x_start, GetLineStart( item ),
x_last - x_start, GetLineHeight( item ) ); x_last - x_start, GetLineHeight( item ) );
// draw selection and whole-item focus: bool renderColumnFocus = false;
if ( selected )
{
int flags = wxCONTROL_SELECTED;
if (m_hasFocus)
flags |= wxCONTROL_FOCUSED;
wxRendererNative::Get().DrawItemSelectionRect int flags = wxCONTROL_SELECTED;
( if ( m_hasFocus )
this, flags |= wxCONTROL_FOCUSED;
dc,
rect,
flags
);
}
// draw keyboard focus rect if applicable // draw keyboard focus rect if applicable
if ( item == m_currentRow && m_hasFocus ) if ( item == m_currentRow && m_hasFocus )
{ {
bool renderColumnFocus = false;
if ( m_useCellFocus && m_currentCol && m_currentColSetByKeyboard ) if ( m_useCellFocus && m_currentCol && m_currentColSetByKeyboard )
{ {
@@ -2033,54 +1984,76 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
if ( renderColumnFocus ) if ( renderColumnFocus )
{ {
wxRect colRect(rowRect);
for ( unsigned int i = col_start; i < col_last; i++ ) for ( unsigned int i = col_start; i < col_last; i++ )
{ {
wxDataViewColumn *col = GetOwner()->GetColumnAt(i); wxDataViewColumn *col = GetOwner()->GetColumnAt(i);
if ( col->IsHidden() ) if ( col->IsHidden() )
continue; continue;
rect.width = col->GetWidth(); colRect.width = col->GetWidth();
if ( col == m_currentCol ) if ( col == m_currentCol )
{ {
// make the rect more visible by adding a small // Draw selection rect left of column
// margin around it: {
rect.Deflate(1, 1); wxRect clipRect(rowRect);
clipRect.width = colRect.x;
if ( selected ) wxDCClipper clip(dc, clipRect);
{ wxRendererNative::Get().DrawItemSelectionRect
// DrawFocusRect() uses XOR and is all but (
// invisible against dark-blue background. Use this,
// the same color used for selected text. dc,
DrawSelectedCellFocusRect(dc, rect); rowRect,
flags
);
} }
else
// Draw selection rect right of column
{ {
wxRendererNative::Get().DrawFocusRect wxRect clipRect(rowRect);
( clipRect.x = colRect.x + colRect.width;
this, clipRect.width = rowRect.width - clipRect.x;
dc,
rect, wxDCClipper clip(dc, clipRect);
0 wxRendererNative::Get().DrawItemSelectionRect
); (
this,
dc,
rowRect,
flags
);
} }
// Draw column selection rect
wxRendererNative::Get().DrawItemSelectionRect
(
this,
dc,
colRect,
flags | wxCONTROL_CURRENT | wxCONTROL_CELL
);
break; break;
} }
rect.x += rect.width; colRect.x += colRect.width;
} }
} }
else }
{
// render focus rectangle for the whole row // draw selection and whole-item focus:
wxRendererNative::Get().DrawFocusRect if ( selected && !renderColumnFocus )
( {
this, wxRendererNative::Get().DrawItemSelectionRect
dc, (
rect, this,
selected ? (int)wxCONTROL_SELECTED : 0 dc,
); rowRect,
} flags | wxCONTROL_CURRENT
);
} }
} }
} }

View File

@@ -183,6 +183,46 @@ protected:
static wxRendererGeneric* sm_rendererGeneric; static wxRendererGeneric* sm_rendererGeneric;
}; };
// ----------------------------------------------------------------------------
// misc. drawing functions
// ----------------------------------------------------------------------------
// Draw focus rect for individual cell. Unlike native focus rect, we render
// this in foreground text color (typically white) to enhance contrast and
// make it visible.
static void DrawSelectedCellFocusRect(wxDC& dc, const wxRect& rect)
{
// (This code is based on wxRendererGeneric::DrawFocusRect and modified.)
// draw the pixels manually because the "dots" in wxPen with wxDOT style
// may be short traits and not really dots
//
// note that to behave in the same manner as DrawRect(), we must exclude
// the bottom and right borders from the rectangle
wxCoord x1 = rect.GetLeft(),
y1 = rect.GetTop(),
x2 = rect.GetRight(),
y2 = rect.GetBottom();
wxDCPenChanger pen(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
wxCoord z;
for (z = x1 + 1; z < x2; z += 2)
dc.DrawPoint(z, rect.GetTop());
wxCoord shift = z == x2 ? 0 : 1;
for (z = y1 + shift; z < y2; z += 2)
dc.DrawPoint(x2, z);
shift = z == y2 ? 0 : 1;
for (z = x2 - shift; z > x1; z -= 2)
dc.DrawPoint(z, y2);
shift = z == x1 ? 0 : 1;
for (z = y2 - shift; z > y1; z -= 2)
dc.DrawPoint(x1, z);
}
// ============================================================================ // ============================================================================
// wxRendererGeneric implementation // wxRendererGeneric implementation
// ============================================================================ // ============================================================================
@@ -754,17 +794,27 @@ wxRendererGeneric::DrawItemSelectionRect(wxWindow * win,
} }
dc.SetBrush(brush); dc.SetBrush(brush);
if ((flags & wxCONTROL_CURRENT) && (flags & wxCONTROL_FOCUSED) bool drawFocusRect = (flags & wxCONTROL_CURRENT) && (flags & wxCONTROL_FOCUSED)
#if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON #if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON
&& IsControlActive( (ControlRef)win->GetHandle() ) && IsControlActive( (ControlRef)win->GetHandle() )
#endif #endif
) ;
if ( drawFocusRect && !(flags & wxCONTROL_CELL) )
dc.SetPen( *wxBLACK_PEN ); dc.SetPen( *wxBLACK_PEN );
else else
dc.SetPen( *wxTRANSPARENT_PEN ); dc.SetPen( *wxTRANSPARENT_PEN );
dc.DrawRectangle( rect ); dc.DrawRectangle( rect );
if ( drawFocusRect && (flags & wxCONTROL_CELL) )
{
wxRect focusRect(rect);
focusRect.Deflate(1);
DrawSelectedCellFocusRect(dc, focusRect);
}
// it's unused everywhere except in wxOSX/Carbon // it's unused everywhere except in wxOSX/Carbon
wxUnusedVar(win); wxUnusedVar(win);
} }

View File

@@ -387,6 +387,12 @@ void wxRendererMSWBase::DrawItemSelectionRect(wxWindow *win,
const wxRect& rect, const wxRect& rect,
int flags) int flags)
{ {
if ( flags & wxCONTROL_CELL )
{
m_rendererNative.DrawItemSelectionRect(win, dc, rect, flags);
return;
}
wxBrush brush; wxBrush brush;
if ( flags & wxCONTROL_SELECTED ) if ( flags & wxCONTROL_SELECTED )
{ {