From 82edfbe7d99a970b00ca37e5017ce74c3c9a37e0 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 26 Apr 2009 17:02:53 +0000 Subject: [PATCH] add a possibility to disable individual grid rows/columns resizing git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@60408 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + docs/doxygen/overviews/grid.h | 17 +++-- include/wx/generic/grid.h | 50 +++++++++++- include/wx/generic/private/grid.h | 13 +--- interface/wx/grid.h | 68 ++++++++++++++--- samples/grid/griddemo.cpp | 8 ++ src/generic/grid.cpp | 123 +++++++++++++++--------------- 7 files changed, 189 insertions(+), 91 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index ad4c3ef8e9..7d0825aa3b 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -329,6 +329,7 @@ All: All (GUI): +- wxGrid: add possibility to prevent resizing of individual rows/columns. - wxHTML: add support for table borders width (Laurent Humbertclaude). i18n: diff --git a/docs/doxygen/overviews/grid.h b/docs/doxygen/overviews/grid.h index d5ea310988..91de20825a 100644 --- a/docs/doxygen/overviews/grid.h +++ b/docs/doxygen/overviews/grid.h @@ -143,12 +143,15 @@ to fit its contents with wxGrid::AutoSizeRow() or do it for all rows at once with wxGrid::AutoSizeRows(). Additionally, by default the user can also drag the row separator lines to -resize the rows interactively. This can be forbidden by calling -wxGrid::DisableDragRowSize(). If you do allow the user to resize the grid rows, -it may be a good idea to save their heights and restore it when the grid is -recreated the next time (possibly during a next program execution): the -functions wxGrid::GetRowSizes() and wxGrid::SetRowSizes() can help with this, -you will just need to serialize wxGridSizesInfo structure returned by the -former in some way and deserialize it back before calling the latter. +resize the rows interactively. This can be forbidden completely by calling +wxGrid::DisableDragRowSize() or just for the individual rows using +wxGrid::DisableRowResize(). + +If you do allow the user to resize the grid rows, it may be a good idea to save +their heights and restore it when the grid is recreated the next time (possibly +during a next program execution): the functions wxGrid::GetRowSizes() and +wxGrid::SetRowSizes() can help with this, you will just need to serialize +wxGridSizesInfo structure returned by the former in some way and deserialize it +back before calling the latter. */ diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index 9c16160f28..0e8c1b9ff3 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -16,6 +16,8 @@ #if wxUSE_GRID +#include "wx/hashmap.h" + #include "wx/scrolwin.h" // ---------------------------------------------------------------------------- @@ -85,6 +87,8 @@ class WXDLLIMPEXP_FWD_CORE wxTextCtrl; class WXDLLIMPEXP_FWD_CORE wxSpinCtrl; #endif +class wxGridFixedIndicesSet; + class wxGridOperations; class wxGridRowOperations; class wxGridColumnOperations; @@ -771,7 +775,7 @@ private: // their non default size for those which don't have the default size. // ---------------------------------------------------------------------------- -// Hashmap to store postions as the keys and sizes as the values +// hash map to store positions as the keys and sizes as the values WX_DECLARE_HASH_MAP_WITH_DECL( unsigned, int, wxIntegerHash, wxIntegerEqual, wxUnsignedToIntHashMap, class WXDLLIMPEXP_ADV ); @@ -1101,19 +1105,42 @@ public: void SetCellHighlightPenWidth(int width); void SetCellHighlightROPenWidth(int width); + + // interactive grid mouse operations control + // ----------------------------------------- + + // functions globally enabling row/column interactive resizing (enabled by + // default) void EnableDragRowSize( bool enable = true ); void DisableDragRowSize() { EnableDragRowSize( false ); } - bool CanDragRowSize() const { return m_canDragRowSize; } + void EnableDragColSize( bool enable = true ); void DisableDragColSize() { EnableDragColSize( false ); } - bool CanDragColSize() const { return m_canDragColSize; } + + // if interactive resizing is enabled, some rows/columns can still have + // fixed size + void DisableRowResize(int row) { DoDisableLineResize(row, m_setFixedRows); } + void DisableColResize(int col) { DoDisableLineResize(col, m_setFixedCols); } + + // these functions return whether the given row/column can be + // effectively resized: for this interactive resizing must be enabled + // and this index must not have been passed to DisableRow/ColResize() + bool CanDragRowSize(int row) const + { return m_canDragRowSize && DoCanResizeLine(row, m_setFixedRows); } + bool CanDragColSize(int col) const + { return m_canDragColSize && DoCanResizeLine(col, m_setFixedCols); } + + // interactive column reordering (disabled by default) void EnableDragColMove( bool enable = true ); void DisableDragColMove() { EnableDragColMove( false ); } bool CanDragColMove() const { return m_canDragColMove; } + + // interactive resizing of grid cells (enabled by default) void EnableDragGridSize(bool enable = true); void DisableDragGridSize() { EnableDragGridSize(false); } bool CanDragGridSize() const { return m_canDragGridSize; } + // interactive dragging of cells (disabled by default) void EnableDragCell( bool enable = true ); void DisableDragCell() { EnableDragCell( false ); } bool CanDragCell() const { return m_canDragCell; } @@ -1659,6 +1686,9 @@ public: wxGRID_CHECKBOX, wxGRID_CHOICE, wxGRID_COMBOBOX }; + + wxDEPRECATED_INLINE(bool CanDragRowSize() const, return m_canDragRowSize; ) + wxDEPRECATED_INLINE(bool CanDragColSize() const, return m_canDragColSize; ) #endif // WXWIN_COMPATIBILITY_2_8 @@ -2083,10 +2113,22 @@ private: bool DoAppendLines(bool (wxGridTableBase::*funcAppend)(size_t), int num, bool updateLabels); - // Common part of Set{Col,Row}Sizes + // common part of Set{Col,Row}Sizes void DoSetSizes(const wxGridSizesInfo& sizeInfo, const wxGridOperations& oper); + // common part of Disable{Row,Col}Resize and CanDrag{Row,Col}Size + void DoDisableLineResize(int line, wxGridFixedIndicesSet *& setFixed); + bool DoCanResizeLine(int line, const wxGridFixedIndicesSet *setFixed) const; + + + + // these sets contain the indices of fixed, i.e. non-resizable + // interactively, grid rows or columns and are NULL if there are no fixed + // elements (which is the default) + wxGridFixedIndicesSet *m_setFixedRows, + *m_setFixedCols; + DECLARE_DYNAMIC_CLASS( wxGrid ) DECLARE_EVENT_TABLE() wxDECLARE_NO_COPY_CLASS(wxGrid); diff --git a/include/wx/generic/private/grid.h b/include/wx/generic/private/grid.h index 0b29eca1ff..e8fc6ec037 100644 --- a/include/wx/generic/private/grid.h +++ b/include/wx/generic/private/grid.h @@ -107,7 +107,7 @@ public: // we can't know in advance whether we can sort by this column or not // with wxGrid API so suppose we can by default int flags = wxCOL_SORTABLE; - if ( m_grid->CanDragColSize() ) + if ( m_grid->CanDragColSize(m_col) ) flags |= wxCOL_RESIZABLE; if ( m_grid->CanDragColMove() ) flags |= wxCOL_REORDERABLE; @@ -500,9 +500,6 @@ public: // Set the row default height or column default width virtual void SetDefaultLineSize(wxGrid *grid, int size, bool resizeExisting) const = 0; - // True if rows/columns can be resized by user - virtual bool CanResizeLines(const wxGrid *grid) const = 0; - // Return the index of the line at the given position // @@ -572,10 +569,8 @@ public: { return grid->GetRowMinimalHeight(line); } virtual void SetLineSize(wxGrid *grid, int line, int size) const { grid->SetRowSize(line, size); } - virtual bool CanResizeLines(const wxGrid *grid) const - { return grid->CanDragRowSize(); } virtual void SetDefaultLineSize(wxGrid *grid, int size, bool resizeExisting) const - { grid->SetDefaultRowSize(size, resizeExisting); } + { grid->SetDefaultRowSize(size, resizeExisting); } virtual int GetLineAt(const wxGrid * WXUNUSED(grid), int line) const { return line; } // TODO: implement row reordering @@ -635,10 +630,8 @@ public: { return grid->GetColMinimalWidth(line); } virtual void SetLineSize(wxGrid *grid, int line, int size) const { grid->SetColSize(line, size); } - virtual bool CanResizeLines(const wxGrid *grid) const - { return grid->CanDragColSize(); } virtual void SetDefaultLineSize(wxGrid *grid, int size, bool resizeExisting) const - { grid->SetDefaultColSize(size, resizeExisting); } + { grid->SetDefaultColSize(size, resizeExisting); } virtual int GetLineAt(const wxGrid *grid, int line) const { return grid->GetColAt(line); } diff --git a/interface/wx/grid.h b/interface/wx/grid.h index 22f1ff4f59..d65e97a00a 100644 --- a/interface/wx/grid.h +++ b/interface/wx/grid.h @@ -2037,6 +2037,8 @@ public: /** @name Column and Row Sizes + + @see overview_grid_resizing */ //@{ @@ -2322,6 +2324,17 @@ public: /** @name User-Resizing and Dragging + + Functions controlling various interactive mouse operations. + + By default, columns and rows can be resized by dragging the edges of + their labels (this can be disabled using DisableDragColSize() and + DisableDragRowSize() methods). And if grid line dragging is enabled with + EnableDragGridSize() they can also be resized by dragging the right or + bottom edge of the grid cells. + + Columns can also be moved to interactively change their order but this + needs to be explicitly enabled with EnableDragColMove(). */ //@{ @@ -2338,13 +2351,15 @@ public: bool CanDragColMove() const; /** - Returns @true if columns can be resized by dragging with the mouse. + Returns @true if the given column can be resized by dragging with the + mouse. - Columns can be resized by dragging the edges of their labels. If grid - line dragging is enabled they can also be resized by dragging the right - edge of the column in the grid cell area (see EnableDragGridSize()). + This function returns @true if resizing the columns interactively is + globally enabled, i.e. if DisableDragColSize() hadn't been called, and + if this column wasn't explicitly marked as non-resizable with + DisableColResize(). */ - bool CanDragColSize() const; + bool CanDragColSize(int col) const; /** Return @true if the dragging of grid lines to resize rows and columns @@ -2353,13 +2368,42 @@ public: bool CanDragGridSize() const; /** - Returns @true if rows can be resized by dragging with the mouse. + Returns @true if the given row can be resized by dragging with the + mouse. - Rows can be resized by dragging the edges of their labels. If grid line - dragging is enabled they can also be resized by dragging the lower edge - of the row in the grid cell area (see EnableDragGridSize()). + This is the same as CanDragColSize() but for rows. */ - bool CanDragRowSize() const; + bool CanDragRowSize(int row) const; + + /** + Disable interactive resizing of the specified column. + + This method allows to disable resizing of an individual column in a + grid where the columns are otherwise resizable (which is the case by + default). + + Notice that currently there is no way to make some columns resizable in + a grid where columns can't be resized by default as there doesn't seem + to be any need for this in practice. There is also no way to make the + column marked as fixed using this method resizeable again because it is + supposed that fixed columns are used for static parts of the grid and + so should remain fixed during the entire grid lifetime. + + Also notice that disabling interactive column resizing will not prevent + the program from changing the column size. + + @see EnableDragColSize() + */ + void DisableColResize(int col); + + /** + Disable interactive resizing of the specified row. + + This is the same as DisableColResize() but for rows. + + @see EnableDragRowSize() + */ + void DisableRowResize(int row); /** Disables column moving by dragging with the mouse. @@ -2401,6 +2445,8 @@ public: /** Enables or disables column sizing by dragging with the mouse. + + @see DisableColResize() */ void EnableDragColSize(bool enable = true); @@ -2412,6 +2458,8 @@ public: /** Enables or disables row sizing by dragging with the mouse. + + @see DisableRowResize() */ void EnableDragRowSize(bool enable = true); diff --git a/samples/grid/griddemo.cpp b/samples/grid/griddemo.cpp index c485fdfe4d..dc42486acb 100644 --- a/samples/grid/griddemo.cpp +++ b/samples/grid/griddemo.cpp @@ -377,6 +377,14 @@ GridFrame::GridFrame() grid->SetCellAlignment(7, 1, wxALIGN_CENTRE, wxALIGN_CENTRE); grid->SetCellValue(7, 1, _T("Big box!")); + // create a separator-like row: it's grey and it's non-resizeable + grid->DisableRowResize(10); + grid->SetRowSize(10, 30); + attr = new wxGridCellAttr; + attr->SetBackgroundColour(*wxLIGHT_GREY); + grid->SetRowAttr(10, attr); + grid->SetCellValue(10, 0, "You can't resize this row interactively -- try it"); + // this does exactly nothing except testing that SetAttr() handles NULL // attributes and does reference counting correctly grid->SetAttr(11, 11, NULL); diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 80c7a07be7..231630ea02 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -48,6 +48,7 @@ #include "wx/tokenzr.h" #include "wx/renderer.h" #include "wx/headerctrl.h" +#include "wx/hashset.h" #include "wx/generic/gridsel.h" #include "wx/generic/gridctrl.h" @@ -71,6 +72,9 @@ const char wxGridNameStr[] = "grid"; // Required for wxIs... functions #include +WX_DECLARE_HASH_SET_WITH_DECL(int, wxIntegerHash, wxIntegerEqual, + wxGridFixedIndicesSet, class WXDLLIMPEXP_ADV); + // ---------------------------------------------------------------------------- // globals @@ -1822,6 +1826,9 @@ wxGrid::~wxGrid() delete m_typeRegistry; delete m_selection; + + delete m_setFixedRows; + delete m_setFixedCols; } // @@ -2047,6 +2054,9 @@ void wxGrid::Init() m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH; m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT; + m_setFixedRows = + m_setFixedCols = NULL; + // init attr cache m_attrCache.row = -1; m_attrCache.col = -1; @@ -2916,11 +2926,12 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) // else if ( event.LeftDown() ) { - // don't send a label click event for a hit on the - // edge of the row label - this is probably the user - // wanting to resize the row - // - if ( YToEdgeOfRow(y) < 0 ) + row = YToEdgeOfRow(y); + if ( row != wxNOT_FOUND && CanDragRowSize(row) ) + { + ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin); + } + else // not a request to start resizing { row = YToRow(y); if ( row >= 0 && @@ -2948,12 +2959,6 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin); } } - else - { - // starting to drag-resize a row - if ( CanDragRowSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin); - } } // ------------ Left double click @@ -2961,7 +2966,15 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) else if (event.LeftDClick() ) { row = YToEdgeOfRow(y); - if ( row < 0 ) + if ( row != wxNOT_FOUND && CanDragRowSize(row) ) + { + // adjust row height depending on label text + AutoSizeRowLabelSize( row ); + + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow()); + m_dragLastPos = -1; + } + else // not on row separator or it's not resizeable { row = YToRow(y); if ( row >=0 && @@ -2970,14 +2983,6 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) // no default action at the moment } } - else - { - // adjust row height depending on label text - AutoSizeRowLabelSize( row ); - - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow()); - m_dragLastPos = -1; - } } // ------------ Left button released @@ -3027,12 +3032,11 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) else if ( event.Moving() ) { m_dragRowOrCol = YToEdgeOfRow( y ); - if ( m_dragRowOrCol >= 0 ) + if ( m_dragRowOrCol != wxNOT_FOUND ) { if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { - // don't capture the mouse yet - if ( CanDragRowSize() ) + if ( CanDragRowSize(m_dragRowOrCol) ) ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, false); } } @@ -3248,12 +3252,14 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) // else if ( event.LeftDown() ) { - // don't send a label click event for a hit on the - // edge of the col label - this is probably the user - // wanting to resize the col - // - if ( XToEdgeOfCol(x) < 0 ) + int col = XToEdgeOfCol(x); + if ( col != wxNOT_FOUND && CanDragColSize(col) ) { + ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, GetColLabelWindow()); + } + else // not a request to start resizing + { + col = XToCol(x); if ( col >= 0 && !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) ) { @@ -3294,13 +3300,6 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) } } } - else - { - // starting to drag-resize a col - // - if ( CanDragColSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, GetColLabelWindow()); - } } // ------------ Left double click @@ -3394,8 +3393,7 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) { if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { - // don't capture the cursor yet - if ( CanDragColSize() ) + if ( CanDragColSize(m_dragRowOrCol) ) ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, GetColLabelWindow(), false); } } @@ -3796,27 +3794,24 @@ wxGrid::DoGridMouseMoveEvent(wxMouseEvent& WXUNUSED(event), return; } - if ( dragRow >= 0 ) + if ( dragRow >= 0 && CanDragGridSize() && CanDragRowSize(dragRow) ) { - m_dragRowOrCol = dragRow; - if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { - if ( CanDragRowSize() && CanDragGridSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, NULL, false); + m_dragRowOrCol = dragRow; + ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, NULL, false); } } // When using the native header window we can only resize the columns by // dragging the dividers in it because we can't make it enter into the // column resizing mode programmatically - else if ( dragCol >= 0 && !m_useNativeHeader ) + else if ( dragCol >= 0 && !m_useNativeHeader && + CanDragGridSize() && CanDragColSize(dragCol) ) { - m_dragRowOrCol = dragCol; - if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { - if ( CanDragColSize() && CanDragGridSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, NULL, false); + m_dragRowOrCol = dragCol; + ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, NULL, false); } } else // Neither on a row or col edge @@ -6124,23 +6119,15 @@ int wxGrid::XToPos(int x) const return PosToLinePos(x, true /* clip */, wxGridColumnOperations()); } -// return the row number that that the y coord is near the edge of, or -1 if +// return the row number such that the y coord is near the edge of, or -1 if // not near an edge. // -// coords can only possibly be near an edge if -// (a) the row/column is large enough to still allow for an "inner" area -// that is _not_ near the edge (i.e., if the height/width is smaller -// than WXGRID_LABEL_EDGE_ZONE, coords are _never_ considered to be -// near the edge). -// and -// (b) resizing rows/columns (the thing for which edge detection is -// relevant at all) is enabled. -// +// notice that position can only possibly be near an edge if the row/column is +// large enough to still allow for an "inner" area that is _not_ near the edge +// (i.e., if the height/width is smaller than WXGRID_LABEL_EDGE_ZONE, pos will +// _never_ be considered to be near the edge). int wxGrid::PosToEdgeOfLine(int pos, const wxGridOperations& oper) const { - if ( !oper.CanResizeLines(this) ) - return -1; - const int line = oper.PosToLine(this, pos, true); if ( oper.GetLineSize(this, line) > WXGRID_LABEL_EDGE_ZONE ) @@ -7481,6 +7468,22 @@ wxGridCellRenderer * wxGrid::GetDefaultRendererForType(const wxString& typeName) // row/col size // ---------------------------------------------------------------------------- +void wxGrid::DoDisableLineResize(int line, wxGridFixedIndicesSet *& setFixed) +{ + if ( !setFixed ) + { + setFixed = new wxGridFixedIndicesSet; + } + + setFixed->insert(line); +} + +bool +wxGrid::DoCanResizeLine(int line, const wxGridFixedIndicesSet *setFixed) const +{ + return !setFixed || !setFixed->count(line); +} + void wxGrid::EnableDragRowSize( bool enable ) { m_canDragRowSize = enable;