Merge branch 'grid-editors-placement'

Fix positions of the checkboxes drawn by wxGridCellBoolRenderer and
shown by wxGridCellBoolEditor so that there is no jump when starting or
stopping to edit grid cells with boolean values.

See https://github.com/wxWidgets/wxWidgets/pull/1662
This commit is contained in:
Vadim Zeitlin
2019-11-29 16:24:07 +01:00
14 changed files with 364 additions and 275 deletions

View File

@@ -99,6 +99,11 @@ public:
virtual bool HasTransparentBackground() wxOVERRIDE { return true; } virtual bool HasTransparentBackground() wxOVERRIDE { return true; }
// This semi-private function is currently used to allow wxMSW checkbox to
// blend in with its parent background colour without changing the
// background colour of the checkbox itself under the other platforms.
virtual void SetTransparentPartColour(const wxColour& WXUNUSED(col)) { }
// wxCheckBox-specific processing after processing the update event // wxCheckBox-specific processing after processing the update event
virtual void DoUpdateWindowUI(wxUpdateUIEvent& event) wxOVERRIDE virtual void DoUpdateWindowUI(wxUpdateUIEvent& event) wxOVERRIDE
{ {

View File

@@ -15,6 +15,8 @@
#if wxUSE_GRID #if wxUSE_GRID
#include "wx/headerctrl.h"
// Internally used (and hence intentionally not exported) event telling wxGrid // Internally used (and hence intentionally not exported) event telling wxGrid
// to hide the currently shown editor. // to hide the currently shown editor.
wxDECLARE_EVENT( wxEVT_GRID_HIDE_EDITOR, wxCommandEvent ); wxDECLARE_EVENT( wxEVT_GRID_HIDE_EDITOR, wxCommandEvent );
@@ -1005,5 +1007,16 @@ private:
wxGridDataTypeInfoArray m_typeinfo; wxGridDataTypeInfoArray m_typeinfo;
}; };
// Returns the rectangle for showing something of the given size in a cell with
// the given alignment.
//
// The function is used by wxGridCellBoolEditor and wxGridCellBoolRenderer to
// draw a check mark and position wxCheckBox respectively.
wxRect
wxGetContentRect(wxSize contentSize,
const wxRect& cellRect,
int hAlign,
int vAlign);
#endif // wxUSE_GRID #endif // wxUSE_GRID
#endif // _WX_GENERIC_GRID_PRIVATE_H_ #endif // _WX_GENERIC_GRID_PRIVATE_H_

View File

@@ -45,6 +45,11 @@ public:
// override some base class virtuals // override some base class virtuals
virtual void SetLabel(const wxString& label) wxOVERRIDE; virtual void SetLabel(const wxString& label) wxOVERRIDE;
virtual void SetTransparentPartColour(const wxColour& col) wxOVERRIDE
{
SetBackgroundColour(col);
}
virtual bool MSWCommand(WXUINT param, WXWORD id) wxOVERRIDE; virtual bool MSWCommand(WXUINT param, WXWORD id) wxOVERRIDE;
virtual void Command(wxCommandEvent& event) wxOVERRIDE; virtual void Command(wxCommandEvent& event) wxOVERRIDE;

View File

@@ -259,7 +259,7 @@ public:
int flags = 0) = 0; int flags = 0) = 0;
// Returns the default size of a check box. // Returns the default size of a check box.
virtual wxSize GetCheckBoxSize(wxWindow *win) = 0; virtual wxSize GetCheckBoxSize(wxWindow *win, int flags = 0) = 0;
// Returns the default size of a check mark. // Returns the default size of a check mark.
virtual wxSize GetCheckMarkSize(wxWindow *win) = 0; virtual wxSize GetCheckMarkSize(wxWindow *win) = 0;
@@ -496,8 +496,8 @@ public:
int flags = 0) wxOVERRIDE int flags = 0) wxOVERRIDE
{ m_rendererNative.DrawCheckMark( win, dc, rect, flags ); } { m_rendererNative.DrawCheckMark( win, dc, rect, flags ); }
virtual wxSize GetCheckBoxSize(wxWindow *win) wxOVERRIDE virtual wxSize GetCheckBoxSize(wxWindow *win, int flags = 0) wxOVERRIDE
{ return m_rendererNative.GetCheckBoxSize(win); } { return m_rendererNative.GetCheckBoxSize(win, flags); }
virtual wxSize GetCheckMarkSize(wxWindow *win) wxOVERRIDE virtual wxSize GetCheckMarkSize(wxWindow *win) wxOVERRIDE
{ return m_rendererNative.GetCheckMarkSize(win); } { return m_rendererNative.GetCheckMarkSize(win); }

View File

@@ -237,7 +237,7 @@ public:
virtual void DrawCheckMark(wxWindow *win, wxDC& dc, virtual void DrawCheckMark(wxWindow *win, wxDC& dc,
const wxRect& rect, int flags = 0 ); const wxRect& rect, int flags = 0 );
virtual wxSize GetCheckBoxSize(wxWindow *win); virtual wxSize GetCheckBoxSize(wxWindow *win, int flags = 0);
virtual wxSize GetCheckMarkSize(wxWindow *win); virtual wxSize GetCheckMarkSize(wxWindow *win);
@@ -573,8 +573,13 @@ public:
@param win A valid, i.e. non-null, window pointer which is used to get @param win A valid, i.e. non-null, window pointer which is used to get
the theme defining the checkbox size under some platforms. the theme defining the checkbox size under some platforms.
@param flags The only acceptable flag is @c wxCONTROL_CELL which means
that just the size of the checkbox itself is returned, without any
margins that are included by default. This parameter is only
available in wxWidgets 3.1.4 or later.
*/ */
virtual wxSize GetCheckBoxSize(wxWindow* win) = 0; virtual wxSize GetCheckBoxSize(wxWindow* win, int flags = 0) = 0;
/** /**
Returns the size of a check mark. Returns the size of a check mark.

View File

@@ -521,6 +521,10 @@ GridFrame::GridFrame()
grid->SetCellEditor(3, 0, new wxGridCellBoolEditor); grid->SetCellEditor(3, 0, new wxGridCellBoolEditor);
grid->SetCellBackgroundColour(3, 0, wxColour(255, 127, 127)); grid->SetCellBackgroundColour(3, 0, wxColour(255, 127, 127));
grid->SetCellRenderer(3, 1, new wxGridCellBoolRenderer);
grid->SetCellEditor(3, 1, new wxGridCellBoolEditor);
grid->SetCellValue(3, 1, "1");
wxGridCellAttr *attr; wxGridCellAttr *attr;
attr = new wxGridCellAttr; attr = new wxGridCellAttr;
attr->SetTextColour(*wxBLUE); attr->SetTextColour(*wxBLUE);

View File

@@ -111,6 +111,9 @@ const int GRID_HASH_SIZE = 100;
// operation // operation
const int DRAG_SENSITIVITY = 3; const int DRAG_SENSITIVITY = 3;
// the space between the cell edge and the checkbox mark
const int GRID_CELL_CHECKBOX_MARGIN = 2;
} // anonymous namespace } // anonymous namespace
#include "wx/arrimpl.cpp" #include "wx/arrimpl.cpp"
@@ -6980,18 +6983,10 @@ void wxGrid::ShowCellEditControl()
if (rect.x < 0) if (rect.x < 0)
nXMove = rect.x; nXMove = rect.x;
#ifndef __WXQT__ #ifdef __WXQT__
// cell is shifted by one pixel
// However, don't allow x or y to become negative
// since the SetSize() method interprets that as
// "don't change."
if (rect.x > 0)
rect.x--;
if (rect.y > 0)
rect.y--;
#else
// Substract 1 pixel in every dimension to fit in the cell area. // Substract 1 pixel in every dimension to fit in the cell area.
// If not, Qt will draw the control outside the cell. // If not, Qt will draw the control outside the cell.
// TODO: Check offsets under Qt.
rect.Deflate(1, 1); rect.Deflate(1, 1);
#endif #endif
@@ -10337,4 +10332,55 @@ wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index)
return editor; return editor;
} }
wxRect
wxGetContentRect(wxSize contentSize,
const wxRect& cellRect,
int hAlign,
int vAlign)
{
// Keep square aspect ratio for the checkbox, but ensure that it fits into
// the available space, even if it's smaller than the standard size.
const wxCoord minSize = wxMin(cellRect.width, cellRect.height);
if ( contentSize.x >= minSize || contentSize.y >= minSize )
{
// It must still have positive size, however.
const int fittingSize = wxMax(1, minSize - 2*GRID_CELL_CHECKBOX_MARGIN);
contentSize.x =
contentSize.y = fittingSize;
}
wxRect contentRect(contentSize);
if ( hAlign & wxALIGN_CENTER_HORIZONTAL )
{
contentRect = contentRect.CentreIn(cellRect, wxHORIZONTAL);
}
else if ( hAlign & wxALIGN_RIGHT )
{
contentRect.SetX(cellRect.x + cellRect.width
- contentSize.x - GRID_CELL_CHECKBOX_MARGIN);
}
else // ( hAlign == wxALIGN_LEFT ) and invalid alignment value
{
contentRect.SetX(cellRect.x + GRID_CELL_CHECKBOX_MARGIN);
}
if ( vAlign & wxALIGN_CENTER_VERTICAL )
{
contentRect = contentRect.CentreIn(cellRect, wxVERTICAL);
}
else if ( vAlign & wxALIGN_BOTTOM )
{
contentRect.SetY(cellRect.y + cellRect.height
- contentRect.y - GRID_CELL_CHECKBOX_MARGIN);
}
else // wxALIGN_TOP
{
contentRect.SetY(cellRect.y + GRID_CELL_CHECKBOX_MARGIN);
}
return contentRect;
}
#endif // wxUSE_GRID #endif // wxUSE_GRID

View File

@@ -31,6 +31,7 @@
#include "wx/tokenzr.h" #include "wx/tokenzr.h"
#include "wx/renderer.h" #include "wx/renderer.h"
#include "wx/generic/private/grid.h"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxGridCellRenderer // wxGridCellRenderer
@@ -936,7 +937,8 @@ wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
// compute it only once (no locks for MT safeness in GUI thread...) // compute it only once (no locks for MT safeness in GUI thread...)
if ( !ms_sizeCheckMark.x ) if ( !ms_sizeCheckMark.x )
{ {
ms_sizeCheckMark = wxRendererNative::Get().GetCheckBoxSize(&grid); ms_sizeCheckMark =
wxRendererNative::Get().GetCheckBoxSize(&grid, wxCONTROL_CELL);
} }
return ms_sizeCheckMark; return ms_sizeCheckMark;
@@ -951,43 +953,13 @@ void wxGridCellBoolRenderer::Draw(wxGrid& grid,
{ {
wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected); wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
// draw a check mark in the centre (ignoring alignment - TODO) int hAlign = wxALIGN_LEFT;
wxSize size = GetBestSize(grid, attr, dc, row, col); int vAlign = wxALIGN_CENTRE_VERTICAL;
attr.GetNonDefaultAlignment(&hAlign, &vAlign);
// don't draw outside the cell const wxRect checkBoxRect =
wxCoord minSize = wxMin(rect.width, rect.height); wxGetContentRect(GetBestSize(grid, attr, dc, row, col),
if ( size.x >= minSize || size.y >= minSize ) rect, hAlign, vAlign);
{
// and even leave (at least) 1 pixel margin
size.x = size.y = minSize;
}
// draw a border around checkmark
int vAlign, hAlign;
attr.GetAlignment(&hAlign, &vAlign);
wxRect rectBorder;
if (hAlign == wxALIGN_CENTRE)
{
rectBorder.x = rect.x + rect.width / 2 - size.x / 2;
rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
rectBorder.width = size.x;
rectBorder.height = size.y;
}
else if (hAlign == wxALIGN_LEFT)
{
rectBorder.x = rect.x + 2;
rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
rectBorder.width = size.x;
rectBorder.height = size.y;
}
else if (hAlign == wxALIGN_RIGHT)
{
rectBorder.x = rect.x + rect.width - size.x - 2;
rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
rectBorder.width = size.x;
rectBorder.height = size.y;
}
bool value; bool value;
if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) ) if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
@@ -1000,11 +972,11 @@ void wxGridCellBoolRenderer::Draw(wxGrid& grid,
value = wxGridCellBoolEditor::IsTrueValue(cellval); value = wxGridCellBoolEditor::IsTrueValue(cellval);
} }
int flags = 0; int flags = wxCONTROL_CELL;
if (value) if (value)
flags |= wxCONTROL_CHECKED; flags |= wxCONTROL_CHECKED;
wxRendererNative::Get().DrawCheckBox( &grid, dc, rectBorder, flags ); wxRendererNative::Get().DrawCheckBox( &grid, dc, checkBoxRect, flags );
} }
#endif // wxUSE_GRID #endif // wxUSE_GRID

View File

@@ -37,7 +37,6 @@
#include "wx/spinctrl.h" #include "wx/spinctrl.h"
#include "wx/tokenzr.h" #include "wx/tokenzr.h"
#include "wx/renderer.h" #include "wx/renderer.h"
#include "wx/headerctrl.h"
#include "wx/datectrl.h" #include "wx/datectrl.h"
#include "wx/generic/gridsel.h" #include "wx/generic/gridsel.h"
@@ -441,38 +440,17 @@ void wxGridCellTextEditor::SetSize(const wxRect& rectOrig)
// Make the edit control large enough to allow for internal margins // Make the edit control large enough to allow for internal margins
// //
// TODO: remove this if the text ctrl sizing is improved esp. for unix // TODO: remove this if the text ctrl sizing is improved
// //
#if defined(__WXGTK__) #if defined(__WXMSW__)
if (rect.x != 0)
{
rect.x += 1;
rect.y += 1;
rect.width -= 1;
rect.height -= 1;
}
#elif defined(__WXMSW__)
if ( rect.x == 0 )
rect.x += 2; rect.x += 2;
else
rect.x += 3;
if ( rect.y == 0 )
rect.y += 2; rect.y += 2;
else
rect.y += 3;
rect.width -= 2; rect.width -= 2;
rect.height -= 2; rect.height -= 2;
#elif defined(__WXOSX__) #elif !defined(__WXGTK__)
rect.x += 1; int extra_x = 2;
rect.y += 1; int extra_y = 2;
rect.width -= 1;
rect.height -= 1;
#else
int extra_x = ( rect.x > 2 ) ? 2 : 1;
int extra_y = ( rect.y > 2 ) ? 2 : 1;
#if defined(__WXMOTIF__) #if defined(__WXMOTIF__)
extra_x *= 2; extra_x *= 2;
@@ -1240,83 +1218,50 @@ void wxGridCellBoolEditor::Create(wxWindow* parent,
void wxGridCellBoolEditor::SetSize(const wxRect& r) void wxGridCellBoolEditor::SetSize(const wxRect& r)
{ {
bool resize = false; int hAlign = wxALIGN_LEFT;
wxSize size = m_control->GetSize(); int vAlign = wxALIGN_CENTRE_VERTICAL;
wxCoord minSize = wxMin(r.width, r.height);
// check if the checkbox is not too big/small for this cell
wxSize sizeBest = m_control->GetBestSize();
if ( !(size == sizeBest) )
{
// reset to default size if it had been made smaller
size = sizeBest;
resize = true;
}
if ( size.x >= minSize || size.y >= minSize )
{
// leave 1 pixel margin
size.x = size.y = minSize - 2;
resize = true;
}
if ( resize )
{
m_control->SetSize(size);
}
// position it in the centre of the rectangle (TODO: support alignment?)
#if defined(__WXGTK__) || defined (__WXMOTIF__)
// the checkbox without label still has some space to the right in wxGTK,
// so shift it to the right
size.x -= 8;
#elif defined(__WXMSW__)
// here too, but in other way
size.x += 1;
size.y -= 2;
#endif
int hAlign = wxALIGN_CENTRE;
int vAlign = wxALIGN_CENTRE;
if (GetCellAttr()) if (GetCellAttr())
GetCellAttr()->GetAlignment(& hAlign, & vAlign); GetCellAttr()->GetNonDefaultAlignment(&hAlign, &vAlign);
int x = 0, y = 0; const wxRect checkBoxRect =
if (hAlign == wxALIGN_LEFT) wxGetContentRect(m_control->GetSize(), r, hAlign, vAlign);
{
x = r.x + 2;
#ifdef __WXMSW__ // Don't resize the checkbox, it should have its default (and fitting)
x += 2; // size, but do move it to the right position.
#endif m_control->Move(checkBoxRect.GetPosition());
y = r.y + r.height / 2 - size.y / 2;
}
else if (hAlign == wxALIGN_RIGHT)
{
x = r.x + r.width - size.x - 2;
y = r.y + r.height / 2 - size.y / 2;
}
else if (hAlign == wxALIGN_CENTRE)
{
x = r.x + r.width / 2 - size.x / 2;
y = r.y + r.height / 2 - size.y / 2;
}
m_control->Move(x, y);
} }
void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr) void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr)
{ {
m_control->Show(show); m_control->Show(show);
// Under MSW we need to set the checkbox background colour to the same
// colour as is used by the cell in order for it to blend in, but using
// just SetBackgroundColour() would be wrong as this would actually change
// the background of the checkbox with e.g. GTK 3, making it unusable in
// any theme where the check mark colour is the same, or close to, our
// background colour -- which happens to be the case for the default GTK 3
// theme, making this a rather serious problem.
//
// One possible workaround would be to set the foreground colour too, but
// wxRendererNative methods used in wxGridCellBoolRenderer don't currently
// take the colours into account, so this would mean that starting to edit
// a boolean field would change its colours, which would be jarring (and
// especially so as we currently set custom colours for all cells, not just
// those that really need them).
//
// A more portable solution could be to create a parent window using the
// background colour if it's different from the default and reparent the
// checkbox under it, so that the parent window colour showed through the
// transparent parts of the checkbox, but this would be more complicated
// for no real gain in practice.
//
// So, finally, just use the bespoke function that will change the
// background under MSW, but doesn't do anything elsewhere.
if ( show ) if ( show )
{ {
wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY; wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY;
CBox()->SetBackgroundColour(colBg); CBox()->SetTransparentPartColour(colBg);
} }
} }

View File

@@ -111,7 +111,7 @@ public:
const wxRect& rect, const wxRect& rect,
int flags = 0) wxOVERRIDE; int flags = 0) wxOVERRIDE;
virtual wxSize GetCheckBoxSize(wxWindow *win) wxOVERRIDE; virtual wxSize GetCheckBoxSize(wxWindow *win, int flags = 0) wxOVERRIDE;
virtual wxSize GetCheckMarkSize(wxWindow *win) wxOVERRIDE; virtual wxSize GetCheckMarkSize(wxWindow *win) wxOVERRIDE;
@@ -731,7 +731,7 @@ wxRendererGeneric::DrawCheckMark(wxWindow *WXUNUSED(win),
dc.DrawCheckMark(rect); dc.DrawCheckMark(rect);
} }
wxSize wxRendererGeneric::GetCheckBoxSize(wxWindow *win) wxSize wxRendererGeneric::GetCheckBoxSize(wxWindow *win, int WXUNUSED(flags))
{ {
wxCHECK_MSG( win, wxSize(0, 0), "Must have a valid window" ); wxCHECK_MSG( win, wxSize(0, 0), "Must have a valid window" );
@@ -740,7 +740,7 @@ wxSize wxRendererGeneric::GetCheckBoxSize(wxWindow *win)
wxSize wxRendererGeneric::GetCheckMarkSize(wxWindow *win) wxSize wxRendererGeneric::GetCheckMarkSize(wxWindow *win)
{ {
return GetCheckBoxSize(win); return GetCheckBoxSize(win, wxCONTROL_CELL);
} }
wxSize wxRendererGeneric::GetExpanderSize(wxWindow *win) wxSize wxRendererGeneric::GetExpanderSize(wxWindow *win)

View File

@@ -146,13 +146,32 @@ bool wxCheckBox::Create(wxWindow *parent,
g_object_ref(m_widget); g_object_ref(m_widget);
SetLabel( label ); SetLabel( label );
if ( style & wxNO_BORDER )
{
gtk_container_set_border_width(GTK_CONTAINER(m_widgetCheckbox), 0);
}
g_signal_connect (m_widgetCheckbox, "toggled", g_signal_connect (m_widgetCheckbox, "toggled",
G_CALLBACK (gtk_checkbox_toggled_callback), this); G_CALLBACK (gtk_checkbox_toggled_callback), this);
m_parent->DoAddChild( this ); m_parent->DoAddChild( this );
#ifdef __WXGTK3__
// CSS added if the window has wxNO_BORDER inside base class PostCreation()
// makes checkbox look broken in the default GTK 3 theme, so avoid doing
// this by temporarily turning this flag off.
if ( style & wxNO_BORDER )
ToggleWindowStyle(wxNO_BORDER);
#endif
PostCreation(size); PostCreation(size);
#ifdef __WXGTK3__
// Turn it back on if necessary.
if ( style & wxNO_BORDER )
ToggleWindowStyle(wxNO_BORDER);
#endif
return true; return true;
} }

View File

@@ -133,7 +133,7 @@ public:
virtual void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags = 0) wxOVERRIDE; virtual void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags = 0) wxOVERRIDE;
virtual wxSize GetCheckBoxSize(wxWindow *win) wxOVERRIDE; virtual wxSize GetCheckBoxSize(wxWindow *win, int flags = 0) wxOVERRIDE;
virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win) wxOVERRIDE; virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win) wxOVERRIDE;
}; };
@@ -552,27 +552,131 @@ wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
DrawDropArrow(win,dc,rect); DrawDropArrow(win,dc,rect);
} }
#ifdef __WXGTK3__ // Helper used by GetCheckBoxSize() and DrawCheckBox().
static void CheckBoxSize(wxGtkStyleContext& sc, int& w, int& h, GtkBorder* extra = NULL) namespace
{ {
struct CheckBoxInfo
{
#ifdef __WXGTK3__
CheckBoxInfo(wxGtkStyleContext& sc, int flags)
{
wxUnusedVar(flags);
sc.AddCheckButton();
if (gtk_check_version(3,20,0) == NULL)
{
sc.Add("check");
gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL, gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL,
"min-width", &w, "min-height", &h, NULL); "min-width", &indicator_width,
"min-height", &indicator_height,
NULL);
GtkBorder border, padding; GtkBorder border, padding;
gtk_style_context_get_border(sc, GTK_STATE_FLAG_NORMAL, &border); gtk_style_context_get_border(sc, GTK_STATE_FLAG_NORMAL, &border);
gtk_style_context_get_padding(sc, GTK_STATE_FLAG_NORMAL, &padding); gtk_style_context_get_padding(sc, GTK_STATE_FLAG_NORMAL, &padding);
border.left += padding.left;
border.right += padding.right; margin_left = border.left + padding.left;
border.top += padding.top; margin_top = border.top + padding.top;
border.bottom += padding.bottom; margin_right = border.right + padding.right;
w += border.left + border.right; margin_bottom = border.bottom + padding.bottom;
h += border.top + border.bottom; }
if (extra) else
*extra = border; {
} GValue value = G_VALUE_INIT;
#endif // __WXGTK3__ g_value_init(&value, G_TYPE_INT);
gtk_style_context_get_style_property(sc, "indicator-size", &value);
indicator_width =
indicator_height = g_value_get_int(&value);
gtk_style_context_get_style_property(sc, "indicator-spacing", &value);
margin_left =
margin_top =
margin_right =
margin_bottom = g_value_get_int(&value);
g_value_unset(&value);
}
}
#else // !__WXGTK3__
CheckBoxInfo(GtkWidget* button, int flags)
{
gint indicator_size, indicator_margin;
gtk_widget_style_get(button,
"indicator_size", &indicator_size,
"indicator_spacing", &indicator_margin,
NULL);
// If wxCONTROL_CELL is set then we want to get the size of wxCheckBox
// control to draw the check mark centered and at the same position as
// wxCheckBox does, so offset the check mark itself by the focus margin
// in the same way as gtk_real_check_button_draw_indicator() does it, see
// https://github.com/GNOME/gtk/blob/GTK_2_16_0/gtk/gtkcheckbutton.c#L374
if ( flags & wxCONTROL_CELL )
{
gint focus_width, focus_pad;
gtk_widget_style_get(button,
"focus-line-width", &focus_width,
"focus-padding", &focus_pad,
NULL);
indicator_margin += focus_width + focus_pad;
}
// In GTK 2 width and height are the same and so are left/right and
// top/bottom.
indicator_width =
indicator_height = indicator_size;
margin_left =
margin_top =
margin_right =
margin_bottom = indicator_margin;
}
#endif // __WXGTK3__/!__WXGTK3__
// Make sure we fit into the provided rectangle, eliminating margins and
// even reducing the size if necessary.
void FitInto(const wxRect& rect)
{
if ( indicator_width > rect.width )
{
indicator_width = rect.width;
margin_left =
margin_right = 0;
}
else if ( indicator_width + margin_left + margin_right > rect.width )
{
margin_left =
margin_right = (rect.width - indicator_width) / 2;
}
if ( indicator_height > rect.height )
{
indicator_height = rect.height;
margin_top =
margin_bottom = 0;
}
else if ( indicator_height + margin_top + margin_bottom > rect.height )
{
margin_top =
margin_bottom = (rect.height - indicator_height) / 2;
}
}
gint indicator_width,
indicator_height;
gint margin_left,
margin_top,
margin_right,
margin_bottom;
};
} // anonymous namespace
wxSize wxSize
wxRendererGTK::GetCheckBoxSize(wxWindow* win) wxRendererGTK::GetCheckBoxSize(wxWindow* win, int flags)
{ {
wxSize size; wxSize size;
// Even though we don't use the window in this implementation, still check // Even though we don't use the window in this implementation, still check
@@ -582,32 +686,16 @@ wxRendererGTK::GetCheckBoxSize(wxWindow* win)
#ifdef __WXGTK3__ #ifdef __WXGTK3__
wxGtkStyleContext sc(win->GetContentScaleFactor()); wxGtkStyleContext sc(win->GetContentScaleFactor());
sc.AddCheckButton();
if (gtk_check_version(3,20,0) == NULL)
{
sc.Add("check");
CheckBoxSize(sc, size.x, size.y);
}
else
{
GValue value = G_VALUE_INIT;
g_value_init(&value, G_TYPE_INT);
gtk_style_context_get_style_property(sc, "indicator-size", &value);
size.x = g_value_get_int(&value);
gtk_style_context_get_style_property(sc, "indicator-spacing", &value);
size.x += 2 * g_value_get_int(&value);
size.y = size.x;
g_value_unset(&value);
}
#else // !__WXGTK3__
gint indicator_size, indicator_spacing;
gtk_widget_style_get(wxGTKPrivate::GetCheckButtonWidget(),
"indicator_size", &indicator_size,
"indicator_spacing", &indicator_spacing,
NULL);
size.x = size.y = indicator_size + indicator_spacing * 2; const CheckBoxInfo info(sc, flags);
#endif // !__WXGTK3__ #else // !__WXGTK3__
GtkWidget* button = wxGTKPrivate::GetCheckButtonWidget();
const CheckBoxInfo info(button, flags);
#endif // __WXGTK3__/!__WXGTK3__
size.x = info.indicator_width + info.margin_left + info.margin_right;
size.y = info.indicator_height + info.margin_top + info.margin_bottom;
return size; return size;
} }
@@ -618,14 +706,63 @@ wxRendererGTK::DrawCheckBox(wxWindow*,
const wxRect& rect, const wxRect& rect,
int flags ) int flags )
{ {
#ifndef __WXGTK3__ #ifdef __WXGTK3__
GtkWidget *button = wxGTKPrivate::GetCheckButtonWidget(); cairo_t* cr = wxGetGTKDrawable(dc);
if (cr == NULL)
return;
gint indicator_size, indicator_spacing; int state = GTK_STATE_FLAG_NORMAL;
gtk_widget_style_get(button, if (flags & wxCONTROL_CHECKED)
"indicator_size", &indicator_size, {
"indicator_spacing", &indicator_spacing, state = GTK_STATE_FLAG_ACTIVE;
NULL); if (gtk_check_version(3,14,0) == NULL)
state = GTK_STATE_FLAG_CHECKED;
}
if (flags & wxCONTROL_DISABLED)
state |= GTK_STATE_FLAG_INSENSITIVE;
if (flags & wxCONTROL_UNDETERMINED)
state |= GTK_STATE_FLAG_INCONSISTENT;
if (flags & wxCONTROL_CURRENT)
state |= GTK_STATE_FLAG_PRELIGHT;
wxGtkStyleContext sc(dc.GetContentScaleFactor());
CheckBoxInfo info(sc, flags);
info.FitInto(rect);
const int w = info.indicator_width + info.margin_left + info.margin_right;
const int h = info.indicator_height + info.margin_top + info.margin_bottom;
const int x = rect.x + (rect.width - w) / 2;
const int y = rect.y + (rect.height - h) / 2;
if (gtk_check_version(3,20,0) == NULL)
{
gtk_style_context_set_state(sc, GtkStateFlags(state));
gtk_render_background(sc, cr, x, y, w, h);
gtk_render_frame(sc, cr, x, y, w, h);
// check is rendered in content area
gtk_render_check(sc, cr,
x + info.margin_left, y + info.margin_top,
info.indicator_width, info.indicator_height);
}
else
{
// need save/restore for GTK+ 3.6 & 3.8
gtk_style_context_save(sc);
gtk_style_context_set_state(sc, GtkStateFlags(state));
gtk_render_background(sc, cr, x, y, w, h);
gtk_render_frame(sc, cr, x, y, w, h);
gtk_style_context_add_class(sc, "check");
gtk_render_check(sc, cr, x, y, w, h);
gtk_style_context_restore(sc);
}
#else // !__WXGTK3__
GtkWidget* button = wxGTKPrivate::GetCheckButtonWidget();
CheckBoxInfo info(button, flags);
info.FitInto(rect);
GtkStateType state; GtkStateType state;
@@ -646,69 +783,7 @@ wxRendererGTK::DrawCheckBox(wxWindow*,
shadow_type = GTK_SHADOW_IN; shadow_type = GTK_SHADOW_IN;
else else
shadow_type = GTK_SHADOW_OUT; shadow_type = GTK_SHADOW_OUT;
#endif
#ifdef __WXGTK3__
cairo_t* cr = wxGetGTKDrawable(dc);
if (cr == NULL)
return;
int state = GTK_STATE_FLAG_NORMAL;
if (flags & wxCONTROL_CHECKED)
{
state = GTK_STATE_FLAG_ACTIVE;
if (gtk_check_version(3,14,0) == NULL)
state = GTK_STATE_FLAG_CHECKED;
}
if (flags & wxCONTROL_DISABLED)
state |= GTK_STATE_FLAG_INSENSITIVE;
if (flags & wxCONTROL_UNDETERMINED)
state |= GTK_STATE_FLAG_INCONSISTENT;
if (flags & wxCONTROL_CURRENT)
state |= GTK_STATE_FLAG_PRELIGHT;
int w, h;
wxGtkStyleContext sc(dc.GetContentScaleFactor());
sc.AddCheckButton();
if (gtk_check_version(3,20,0) == NULL)
{
sc.Add("check");
GtkBorder extra;
CheckBoxSize(sc, w, h, &extra);
int x = rect.x + (rect.width - w) / 2;
int y = rect.y + (rect.height - h) / 2;
gtk_style_context_set_state(sc, GtkStateFlags(state));
gtk_render_background(sc, cr, x, y, w, h);
gtk_render_frame(sc, cr, x, y, w, h);
// check is rendered in content area
x += extra.left;
y += extra.top;
w -= extra.left + extra.right;
h -= extra.top + extra.bottom;
gtk_render_check(sc, cr, x, y, w, h);
}
else
{
GValue value = G_VALUE_INIT;
g_value_init(&value, G_TYPE_INT);
gtk_style_context_get_style_property(sc, "indicator-size", &value);
w = h = g_value_get_int(&value);
g_value_unset(&value);
// need save/restore for GTK+ 3.6 & 3.8
gtk_style_context_save(sc);
gtk_style_context_set_state(sc, GtkStateFlags(state));
const int x = rect.x + (rect.width - w) / 2;
const int y = rect.y + (rect.height - h) / 2;
gtk_render_background(sc, cr, x, y, w, h);
gtk_render_frame(sc, cr, x, y, w, h);
gtk_style_context_add_class(sc, "check");
gtk_render_check(sc, cr, x, y, w, h);
gtk_style_context_restore(sc);
}
#else
GdkWindow* gdk_window = wxGetGTKDrawable(dc); GdkWindow* gdk_window = wxGetGTKDrawable(dc);
if (gdk_window == NULL) if (gdk_window == NULL)
return; return;
@@ -722,11 +797,11 @@ wxRendererGTK::DrawCheckBox(wxWindow*,
NULL, NULL,
button, button,
"cellcheck", "cellcheck",
dc.LogicalToDeviceX(rect.x) + indicator_spacing, dc.LogicalToDeviceX(rect.x) + info.margin_left,
dc.LogicalToDeviceY(rect.y) + indicator_spacing, dc.LogicalToDeviceY(rect.y) + (rect.height - info.indicator_height) / 2,
indicator_size, indicator_size info.indicator_width, info.indicator_height
); );
#endif #endif // __WXGTK3__/!__WXGTK3__
} }
void void

View File

@@ -162,7 +162,7 @@ public:
wxTitleBarButton button, wxTitleBarButton button,
int flags = 0) wxOVERRIDE; int flags = 0) wxOVERRIDE;
virtual wxSize GetCheckBoxSize(wxWindow *win) wxOVERRIDE; virtual wxSize GetCheckBoxSize(wxWindow *win, int flags = 0) wxOVERRIDE;
virtual int GetHeaderButtonHeight(wxWindow *win) wxOVERRIDE; virtual int GetHeaderButtonHeight(wxWindow *win) wxOVERRIDE;
@@ -288,7 +288,7 @@ public:
wxTitleBarButton button, wxTitleBarButton button,
int flags = 0) wxOVERRIDE; int flags = 0) wxOVERRIDE;
virtual wxSize GetCheckBoxSize(wxWindow *win) wxOVERRIDE; virtual wxSize GetCheckBoxSize(wxWindow *win, int flags = 0) wxOVERRIDE;
virtual wxSize GetCheckMarkSize(wxWindow* win) wxOVERRIDE; virtual wxSize GetCheckMarkSize(wxWindow* win) wxOVERRIDE;
@@ -548,7 +548,7 @@ wxRendererMSW::DrawTitleBarBitmap(wxWindow *win,
DoDrawFrameControl(DFC_CAPTION, kind, win, dc, rect, flags); DoDrawFrameControl(DFC_CAPTION, kind, win, dc, rect, flags);
} }
wxSize wxRendererMSW::GetCheckBoxSize(wxWindow* win) wxSize wxRendererMSW::GetCheckBoxSize(wxWindow* win, int WXUNUSED(flags))
{ {
// We must have a valid window in order to return the size which is correct // We must have a valid window in order to return the size which is correct
// for the display this window is on. // for the display this window is on.
@@ -893,7 +893,7 @@ wxRendererXP::DrawTitleBarBitmap(wxWindow *win,
DoDrawButtonLike(hTheme, part, dc, rect, flags); DoDrawButtonLike(hTheme, part, dc, rect, flags);
} }
wxSize wxRendererXP::GetCheckBoxSize(wxWindow* win) wxSize wxRendererXP::GetCheckBoxSize(wxWindow* win, int flags)
{ {
wxCHECK_MSG( win, wxSize(0, 0), "Must have a valid window" ); wxCHECK_MSG( win, wxSize(0, 0), "Must have a valid window" );
@@ -907,7 +907,7 @@ wxSize wxRendererXP::GetCheckBoxSize(wxWindow* win)
return wxSize(checkSize.cx, checkSize.cy); return wxSize(checkSize.cx, checkSize.cy);
} }
} }
return m_rendererNative.GetCheckBoxSize(win); return m_rendererNative.GetCheckBoxSize(win, flags);
} }
wxSize wxRendererXP::GetCheckMarkSize(wxWindow* win) wxSize wxRendererXP::GetCheckMarkSize(wxWindow* win)

View File

@@ -90,7 +90,7 @@ public:
const wxRect& rect, const wxRect& rect,
int flags = 0) wxOVERRIDE; int flags = 0) wxOVERRIDE;
virtual wxSize GetCheckBoxSize(wxWindow* win) wxOVERRIDE; virtual wxSize GetCheckBoxSize(wxWindow* win, int flags = 0) wxOVERRIDE;
virtual void DrawComboBoxDropButton(wxWindow *win, virtual void DrawComboBoxDropButton(wxWindow *win,
wxDC& dc, wxDC& dc,
@@ -491,7 +491,7 @@ wxRendererMac::DrawCheckBox(wxWindow *win,
kind, kThemeAdornmentNone); kind, kThemeAdornmentNone);
} }
wxSize wxRendererMac::GetCheckBoxSize(wxWindow* win) wxSize wxRendererMac::GetCheckBoxSize(wxWindow* win, int WXUNUSED(flags))
{ {
// Even though we don't use the window in this implementation, still check // Even though we don't use the window in this implementation, still check
// that it's valid to avoid surprises when running the same code under the // that it's valid to avoid surprises when running the same code under the