Improve grid editors placing

Remove the code in wxGrid::ShowCellEditControl() which moves grid
editors unnecessarily and also remove workarounds that were required
because of it in the editors SetSize() functions.

This helps to ensure that the editor is placed at the same position the
renderer draws the cell value, so that it doesn't jump around annoyingly
when editing starts (which was especially noticeable for boolean-valued
cells).
This commit is contained in:
Ilya Sinitsyn
2019-11-01 04:02:26 +07:00
committed by Vadim Zeitlin
parent 6a21d6f2e4
commit 3ca9491c5f
4 changed files with 84 additions and 133 deletions

View File

@@ -1007,5 +1007,12 @@ private:
wxGridDataTypeInfoArray m_typeinfo; wxGridDataTypeInfoArray m_typeinfo;
}; };
// Returns the rect of the check box in a cell with the given alignmens
// and the size.
// The function is used by wxGridCellBoolEditor and wxGridCellBoolRenderer.
wxRect wxGetGridCheckBoxRect(const wxSize& checkBoxSize,
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

@@ -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_X = 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,44 @@ wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index)
return editor; return editor;
} }
wxRect wxGetGridCheckBoxRect(const wxSize& checkBoxSize,
const wxRect& cellRect,
int hAlign, int WXUNUSED(vAlign))
{
// TODO: support vAlign
wxRect checkBoxRect;
checkBoxRect.SetY(cellRect.y + cellRect.height / 2 - checkBoxSize.y / 2);
wxCoord minSize = wxMin(cellRect.width, cellRect.height);
if ( checkBoxRect.GetWidth() >= minSize || checkBoxRect.GetHeight() >= minSize )
{
// let the checkbox mark be even smaller than the min size
// to leave some space between cell edges and the checkbox
const int newSize = wxMax(1, minSize - 2);
checkBoxRect.SetWidth(newSize);
checkBoxRect.SetHeight(newSize);
}
else
{
checkBoxRect.SetSize(checkBoxSize);
}
if ( hAlign & wxALIGN_CENTER_HORIZONTAL )
{
checkBoxRect.SetX(cellRect.x + cellRect.width / 2 - checkBoxSize.x / 2);
}
else if ( hAlign & wxALIGN_RIGHT )
{
checkBoxRect.SetX(cellRect.x + cellRect.width
- checkBoxSize.x - GRID_CELL_CHECKBOX_MARGIN_X);
}
else // ( hAlign == wxALIGN_LEFT ) and invalid alignment value
{
checkBoxRect.SetX(cellRect.x + GRID_CELL_CHECKBOX_MARGIN_X);
}
return checkBoxRect;
}
#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,16 @@ 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)
wxSize size = GetBestSize(grid, attr, dc, row, col);
// don't draw outside the cell
wxCoord minSize = wxMin(rect.width, rect.height);
if ( size.x >= minSize || size.y >= minSize )
{
// and even leave (at least) 1 pixel margin
size.x = size.y = minSize;
}
// draw a border around checkmark
int vAlign, hAlign; int vAlign, hAlign;
attr.GetAlignment(&hAlign, &vAlign); attr.GetAlignment(&hAlign, &vAlign);
wxRect rectBorder; const wxRect
if (hAlign == wxALIGN_CENTRE) checkBoxRect = wxGetGridCheckBoxRect
{ (
rectBorder.x = rect.x + rect.width / 2 - size.x / 2; GetBestSize(grid, attr, dc, row, col),
rectBorder.y = rect.y + rect.height / 2 - size.y / 2; rect,
rectBorder.width = size.x; hAlign, vAlign
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 +975,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

@@ -440,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;
@@ -1239,73 +1218,28 @@ void wxGridCellBoolEditor::Create(wxWindow* parent,
void wxGridCellBoolEditor::SetSize(const wxRect& r) void wxGridCellBoolEditor::SetSize(const wxRect& r)
{ {
bool resize = false;
wxSize size = m_control->GetSize();
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 hAlign = wxALIGN_CENTRE;
int vAlign = wxALIGN_CENTRE; int vAlign = wxALIGN_CENTRE;
if (GetCellAttr()) if (GetCellAttr())
GetCellAttr()->GetAlignment(& hAlign, & vAlign); GetCellAttr()->GetAlignment(& hAlign, & vAlign);
int x = 0, y = 0; const wxRect
if (hAlign == wxALIGN_LEFT) checkBoxRect = wxGetGridCheckBoxRect
{ (
x = r.x + 2; wxRendererNative::Get().
GetCheckBoxSize(GetWindow(), wxCONTROL_CELL),
r,
hAlign, vAlign
);
#ifdef __WXMSW__ // resize the control if required
x += 2; if ( m_control->GetSize() != checkBoxRect.GetSize() )
#endif
y = r.y + r.height / 2 - size.y / 2;
}
else if (hAlign == wxALIGN_RIGHT)
{ {
x = r.x + r.width - size.x - 2; m_control->SetSize(checkBoxRect.GetSize());
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); // and move it
m_control->Move(checkBoxRect.GetPosition());
} }
void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr) void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr)