From f85afd4e46af8d5432aefa584bb3e54a8eac5522 Mon Sep 17 00:00:00 2001 From: Michael Bedward Date: Wed, 6 Oct 1999 05:13:20 +0000 Subject: [PATCH] Added new wxGrid classes. This is a work in progress ! Define wxUSE_NEW_GRID as 1 in setup.h to compile the new wxGrid otherwise the old wxGrid class will be compiled. Treat with caution and expect bugs and missing bits at this stage. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@3841 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- Makefile.in | 81 +- configure.in | 12 + distrib/msw/tmake/filelist.txt | 4 +- distrib/msw/tmake/unx.t | 8 +- include/wx/generic/grid.h | 1084 ++++++++ include/wx/grid.h | 6 +- include/wx/msw/setup0.h | 5 + setup.h.in | 5 + src/generic/grid.cpp | 4253 ++++++++++++++++++++++++++++++++ src/msw/makefile.b32 | 6 +- src/msw/makefile.bcc | 6 +- src/msw/makefile.dos | 6 +- src/msw/makefile.g295 | 32 +- src/msw/makefile.g95 | 4 +- src/msw/makefile.sc | 4 +- src/msw/makefile.vc | 4 +- src/msw/makefile.wat | 6 +- 17 files changed, 5427 insertions(+), 99 deletions(-) create mode 100644 include/wx/generic/grid.h create mode 100644 src/generic/grid.cpp diff --git a/Makefile.in b/Makefile.in index 886fc4de86..52f12c9578 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,5 +1,5 @@ # -# This file was automatically generated by tmake at 15:20, 1999/10/04 +# This file was automatically generated by tmake at 13:22, 1999/10/06 # DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE UNX.T! # @@ -526,7 +526,7 @@ GENERIC_HEADERS = \ generic/dirdlgg.h \ generic/filedlgg.h \ generic/fontdlgg.h \ - generic/gridg.h \ + generic/grid.h \ generic/helpext.h \ generic/helphtml.h \ generic/helpwxht.h \ @@ -577,7 +577,7 @@ GTK_GENERICOBJS = \ dcpsg.o \ dirdlgg.o \ filedlgg.o \ - gridg.o \ + grid.o \ helphtml.o \ helpwxht.o \ imaglist.o \ @@ -610,7 +610,7 @@ GTK_GENERICDEPS = \ dcpsg.d \ dirdlgg.d \ filedlgg.d \ - gridg.d \ + grid.d \ helphtml.d \ helpwxht.d \ imaglist.d \ @@ -935,7 +935,7 @@ MOTIF_GENERICOBJS = \ dcpsg.o \ dirdlgg.o \ fontdlgg.o \ - gridg.o \ + grid.o \ helphtml.o \ helpwxht.o \ helpxlp.o \ @@ -972,7 +972,7 @@ MOTIF_GENERICDEPS = \ dcpsg.d \ dirdlgg.d \ fontdlgg.d \ - gridg.d \ + grid.d \ helphtml.d \ helpwxht.d \ helpxlp.d \ @@ -1297,7 +1297,7 @@ MSW_GENERICOBJS = \ busyinfo.o \ choicdgg.o \ dirdlgg.o \ - gridg.o \ + grid.o \ laywin.o \ logg.o \ numdlgg.o \ @@ -1319,7 +1319,7 @@ MSW_GENERICDEPS = \ busyinfo.d \ choicdgg.d \ dirdlgg.d \ - gridg.d \ + grid.d \ laywin.d \ logg.d \ numdlgg.d \ @@ -1821,55 +1821,16 @@ JPEGOBJS = \ jquant2.o \ jdmerge.o -BASE_OBJS = \ - dynarray.o \ - event.o \ - hash.o \ - intl.o \ - init.o \ - file.o \ - filefn.o \ - list.o \ - log.o \ - object.o \ - string.o \ - utilscmn.o \ - utilsunx.o - -BASE_DEPS = \ - dynarray.d \ - event.d \ - hash.d \ - intl.d \ - init.d \ - file.d \ - filefn.d \ - list.d \ - log.d \ - object.d \ - string.d \ - utilscmn.d \ - utilsunx.d - -BASE_HEADERS = - -GUIOBJS = @GUIOBJS@ -GUIDEPS = @GUIDEPS@ -GUIHEADERS = @GUIHEADERS@ -COMMONOBJS = @COMMONOBJS@ -COMMONDEPS = @COMMONDEPS@ -GENERICOBJS = @GENERICOBJS@ -GENERICDEPS = @GENERICDEPS@ -UNIXOBJS = @UNIXOBJS@ -UNIXDEPS = @UNIXDEPS@ - -OBJECTS = @ALL_OBJECTS@ - -DEPFILES = @ALL_DEPFILES@ - -HEADERS = @ALL_HEADERS@ - -all: @WX_CREATE_LINKS@ + +OBJECTS = $(@GUIOBJS@) $(@COMMONOBJS@) $(@GENERICOBJS@) $(@UNIXOBJS@) $(HTMLOBJS) \ + $(JPEGOBJS) $(PNGOBJS) $(ZLIBOBJS) + +DEPFILES = $(@GUIDEPS@) $(@COMMONDEPS@) $(@GENERICDEPS@) $(UNIXDEPS) $(HTMLDEPS) + +HEADERS = $(@GUIHEADERS@) $(HTML_HEADERS) $(UNIX_HEADERS) $(PROTOCOL_HEADERS) \ + $(GENERIC_HEADERS) $(WX_HEADERS) + +all: $(OBJECTS) @WX_TARGET_LIBRARY@ @WX_CREATE_LINKS@ @WX_LIBRARY_NAME_STATIC@: $(OBJECTS) @$(INSTALL) -d ./lib @@ -1880,7 +1841,7 @@ all: @WX_CREATE_LINKS@ @$(INSTALL) -d ./lib $(SHARED_LD) ./lib/$@ $(OBJECTS) $(EXTRALIBS) -CREATE_LINKS: @WX_TARGET_LIBRARY@ +CREATE_LINKS@: @WX_TARGET_LIBRARY@ @$(RM) ./lib/@WX_LIBRARY_LINK1@ @$(RM) ./lib/@WX_LIBRARY_LINK2@ @$(RM) ./lib/@WX_LIBRARY_LINK3@ @@ -2237,6 +2198,10 @@ SAMPLES_DIST: cp $(SAMPDIR)/minimal/Makefile.in $(DISTDIR)/samples/minimal cp $(SAMPDIR)/minimal/*.cpp $(DISTDIR)/samples/minimal cp $(SAMPDIR)/minimal/*.xpm $(DISTDIR)/samples/minimal + mkdir $(DISTDIR)/samples/newgrid + cp $(SAMPDIR)/newgrid/Makefile.in $(DISTDIR)/samples/newgrid + cp $(SAMPDIR)/newgrid/*.cpp $(DISTDIR)/samples/newgrid + cp $(SAMPDIR)/newgrid/*.h $(DISTDIR)/samples/newgrid mkdir $(DISTDIR)/samples/notebook cp $(SAMPDIR)/notebook/Makefile.in $(DISTDIR)/samples/notebook cp $(SAMPDIR)/notebook/*.cpp $(DISTDIR)/samples/notebook diff --git a/configure.in b/configure.in index aaa380472d..960d2c06b0 100644 --- a/configure.in +++ b/configure.in @@ -723,6 +723,7 @@ if test $DEBUG_CONFIGURE = 1; then DEFAULT_wxUSE_COMBOBOX=no DEFAULT_wxUSE_GAUGE=no DEFAULT_wxUSE_GRID=no + DEFAULT_wxUSE_NEW_GRID=no DEFAULT_wxUSE_IMAGLIST=no DEFAULT_wxUSE_LISTBOX=no DEFAULT_wxUSE_LISTCTRL=no @@ -834,6 +835,7 @@ else DEFAULT_wxUSE_COMBOBOX=yes DEFAULT_wxUSE_GAUGE=yes DEFAULT_wxUSE_GRID=yes + DEFAULT_wxUSE_NEW_GRID=yes DEFAULT_wxUSE_IMAGLIST=yes DEFAULT_wxUSE_LISTBOX=yes DEFAULT_wxUSE_LISTCTRL=yes @@ -936,6 +938,7 @@ if test "$wxUSE_GUI" = "no"; then DEFAULT_wxUSE_COMBOBOX=no DEFAULT_wxUSE_GAUGE=no DEFAULT_wxUSE_GRID=no + DEFAULT_wxUSE_NEW_GRID=no DEFAULT_wxUSE_IMAGLIST=no DEFAULT_wxUSE_LISTBOX=no DEFAULT_wxUSE_LISTCTRL=no @@ -1099,6 +1102,7 @@ if test "$wxUSE_CONTROLS" = "yes"; then DEFAULT_wxUSE_CHOICE=yes DEFAULT_wxUSE_GAUGE=yes DEFAULT_wxUSE_GRID=yes + DEFAULT_wxUSE_NEW_GRID=yes DEFAULT_wxUSE_IMAGLIST=yes DEFAULT_wxUSE_LISTBOX=yes DEFAULT_wxUSE_LISTCTRL=yes @@ -1128,6 +1132,7 @@ elif test "$wxUSE_CONTROLS" = "no"; then DEFAULT_wxUSE_CHOICE=no DEFAULT_wxUSE_GAUGE=no DEFAULT_wxUSE_GRID=no + DEFAULT_wxUSE_NEW_GRID=no DEFAULT_wxUSE_IMAGLIST=no DEFAULT_wxUSE_LISTBOX=no DEFAULT_wxUSE_LISTCTRL=no @@ -1158,6 +1163,7 @@ WX_ARG_ENABLE(choice, [ --enable-choice use wxChoice class], wxUSE WX_ARG_ENABLE(combobox, [ --enable-combobox use wxComboBox classes], wxUSE_COMBOBOX) WX_ARG_ENABLE(gauge, [ --enable-gauge use wxGauge class], wxUSE_GAUGE) WX_ARG_ENABLE(grid, [ --enable-grid use wxGrid class], wxUSE_GRID) +WX_ARG_ENABLE(newgrid, [ --enable-newgrid use new wxGrid class], wxUSE_NEW_GRID) WX_ARG_ENABLE(imaglist, [ --enable-imaglist use wxImageList class], wxUSE_IMAGLIST) WX_ARG_ENABLE(listbox, [ --enable-listbox use wxListBox class], wxUSE_LISTBOX) WX_ARG_ENABLE(listctrl, [ --enable-listctrl use wxListCtrl class], wxUSE_LISTCTRL) @@ -2592,6 +2598,11 @@ if test "$wxUSE_GRID" = "yes"; then SAMPLES_SUBDIRS="$SAMPLES_SUBDIRS grid" fi +if test "$wxUSE_NEW_GRID" = "yes"; then + AC_DEFINE(wxUSE_NEW_GRID) + SAMPLES_SUBDIRS="$SAMPLES_SUBDIRS newgrid" +fi + if test "$wxUSE_IMAGLIST" = "yes"; then AC_DEFINE(wxUSE_IMAGLIST) fi @@ -2924,6 +2935,7 @@ AC_OUTPUT([ samples/mdi/Makefile samples/minifram/Makefile samples/minimal/Makefile + samples/newgrid/Makefile samples/notebook/Makefile samples/printing/Makefile samples/proplist/Makefile diff --git a/distrib/msw/tmake/filelist.txt b/distrib/msw/tmake/filelist.txt index 7cece77f45..662511b16b 100644 --- a/distrib/msw/tmake/filelist.txt +++ b/distrib/msw/tmake/filelist.txt @@ -61,7 +61,7 @@ dcpsg.cpp G U dirdlgg.cpp G 16 fontdlgg.cpp G G,R filedlgg.cpp G U,X -gridg.cpp G +grid.cpp G helphtml.cpp G G helpwxht.cpp G G helpxlp.cpp G G,R @@ -849,7 +849,7 @@ dcpsg.h N dirdlgg.h N fontdlgg.h N filedlgg.h N -gridg.h N +grid.h N helpext.h N helpwxht.h N helphtml.h N diff --git a/distrib/msw/tmake/unx.t b/distrib/msw/tmake/unx.t index 6e09796a45..7504ce6280 100644 --- a/distrib/msw/tmake/unx.t +++ b/distrib/msw/tmake/unx.t @@ -484,7 +484,7 @@ DEPFILES = $(@GUIDEPS@) $(@COMMONDEPS@) $(@GENERICDEPS@) $(UNIXDEPS) $(HTMLDEPS) HEADERS = $(@GUIHEADERS@) $(HTML_HEADERS) $(UNIX_HEADERS) $(PROTOCOL_HEADERS) \ $(GENERIC_HEADERS) $(WX_HEADERS) -all: @WX_CREATE_LINKS@ +all: $(OBJECTS) @WX_TARGET_LIBRARY@ @WX_CREATE_LINKS@ @WX_LIBRARY_NAME_STATIC@: $(OBJECTS) @$(INSTALL) -d ./lib @@ -495,7 +495,7 @@ all: @WX_CREATE_LINKS@ @$(INSTALL) -d ./lib $(SHARED_LD) ./lib/$@ $(OBJECTS) $(EXTRALIBS) -CREATE_LINKS: @WX_TARGET_LIBRARY@ +CREATE_LINKS@: @WX_TARGET_LIBRARY@ @$(RM) ./lib/@WX_LIBRARY_LINK1@ @$(RM) ./lib/@WX_LIBRARY_LINK2@ @$(RM) ./lib/@WX_LIBRARY_LINK3@ @@ -852,6 +852,10 @@ SAMPLES_DIST: cp $(SAMPDIR)/minimal/Makefile.in $(DISTDIR)/samples/minimal cp $(SAMPDIR)/minimal/*.cpp $(DISTDIR)/samples/minimal cp $(SAMPDIR)/minimal/*.xpm $(DISTDIR)/samples/minimal + mkdir $(DISTDIR)/samples/newgrid + cp $(SAMPDIR)/newgrid/Makefile.in $(DISTDIR)/samples/newgrid + cp $(SAMPDIR)/newgrid/*.cpp $(DISTDIR)/samples/newgrid + cp $(SAMPDIR)/newgrid/*.h $(DISTDIR)/samples/newgrid mkdir $(DISTDIR)/samples/notebook cp $(SAMPDIR)/notebook/Makefile.in $(DISTDIR)/samples/notebook cp $(SAMPDIR)/notebook/*.cpp $(DISTDIR)/samples/notebook diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h new file mode 100644 index 0000000000..f36a93b26a --- /dev/null +++ b/include/wx/generic/grid.h @@ -0,0 +1,1084 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: grid.h +// Purpose: wxGrid and related classes +// Author: Michael Bedward (based on code by Julian Smart, Robin Dunn) +// Modified by: +// Created: 1/08/1999 +// RCS-ID: $Id$ +// Copyright: (c) Michael Bedward +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + + +#include "wx/defs.h" + +#if !defined(wxUSE_NEW_GRID) || !(wxUSE_NEW_GRID) +#include "gridg.h" +#else + +#ifndef __WXGRID_H__ +#define __WXGRID_H__ + +#ifdef __GNUG__ +#pragma interface "grid.h" +#endif + +#include "wx/panel.h" +#include "wx/string.h" +#include "wx/scrolbar.h" +#include "wx/event.h" +#include "wx/textctrl.h" +#include "wx/combobox.h" +#include "wx/dynarray.h" + + +// Default parameters for wxGrid +// +#define WXGRID_DEFAULT_NUMBER_ROWS 10 +#define WXGRID_DEFAULT_NUMBER_COLS 10 +#ifdef __WXMSW__ +#define WXGRID_DEFAULT_ROW_HEIGHT 25 +#else +#define WXGRID_DEFAULT_ROW_HEIGHT 30 +#endif // __WXMSW__ +#define WXGRID_DEFAULT_COL_WIDTH 80 +#define WXGRID_DEFAULT_COL_LABEL_HEIGHT 32 +#define WXGRID_DEFAULT_ROW_LABEL_WIDTH 82 +#define WXGRID_LABEL_EDGE_ZONE 5 +#define WXGRID_MIN_ROW_HEIGHT 15 +#define WXGRID_MIN_COL_WIDTH 15 +#define WXGRID_DEFAULT_SCROLLBAR_WIDTH 16 +#define WXGRID_DEFAULT_TOPEDIT_WIDTH 300 +#define WXGRID_DEFAULT_TOPEDIT_HEIGHT 60 + + +class wxGrid; + + +////////////////////////////////////////////////////////////////////// +// +// Grid table classes +// +////////////////////////////////////////////////////////////////////// + + +class wxGridTableBase : public wxObject +{ + wxGrid * m_view; + + public: + wxGridTableBase(); + virtual ~wxGridTableBase(); + + // You must override these functions in a derived table class + // + virtual long GetNumberRows() = 0; + virtual long GetNumberCols() = 0; + virtual wxString GetValue( int row, int col ) = 0; + virtual void SetValue( int row, int col, const wxString& s ) = 0; + virtual bool IsEmptyCell( int row, int col ) = 0; + + // Overriding these is optional + // + virtual void SetView( wxGrid *grid ) { m_view = grid; } + virtual wxGrid * GetView() const { return m_view; } + + virtual void Clear() {} + virtual bool InsertRows( size_t pos = 0, size_t numRows = 1 ); + virtual bool AppendRows( size_t numRows = 1 ); + virtual bool DeleteRows( size_t pos = 0, size_t numRows = 1 ); + virtual bool InsertCols( size_t pos = 0, size_t numCols = 1 ); + virtual bool AppendCols( size_t numCols = 1 ); + virtual bool DeleteCols( size_t pos = 0, size_t numCols = 1 ); + + virtual wxString GetRowLabelValue( int row ); + virtual wxString GetColLabelValue( int col ); + virtual void SetRowLabelValue( int row, const wxString& ) {} + virtual void SetColLabelValue( int col, const wxString& ) {} + + DECLARE_ABSTRACT_CLASS( wxGridTableBase ); +}; + + + +// IDs for messages sent from grid table to view +// +enum wxGridTableRequest { + wxGRIDTABLE_REQUEST_VIEW_GET_VALUES = 2000, + wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES, + wxGRIDTABLE_NOTIFY_ROWS_INSERTED, + wxGRIDTABLE_NOTIFY_ROWS_APPENDED, + wxGRIDTABLE_NOTIFY_ROWS_DELETED, + wxGRIDTABLE_NOTIFY_COLS_INSERTED, + wxGRIDTABLE_NOTIFY_COLS_APPENDED, + wxGRIDTABLE_NOTIFY_COLS_DELETED +}; + +class wxGridTableMessage +{ + wxGridTableBase *m_table; + int m_id; + int m_comInt1; + int m_comInt2; + + public: + wxGridTableMessage(); + wxGridTableMessage( wxGridTableBase *table, int id, + int comInt1 = -1, + int comInt2 = -1 ); + + void SetTableObject( wxGridTableBase *table ) { m_table = table; } + wxGridTableBase * GetTableObject() const { return m_table; } + void SetId( int id ) { m_id = id; } + int GetId() { return m_id; } + void SetCommandInt( int comInt1 ) { m_comInt1 = comInt1; } + int GetCommandInt() { return m_comInt1; } + void SetCommandInt2( int comInt2 ) { m_comInt2 = comInt2; } + int GetCommandInt2() { return m_comInt2; } +}; + + + +// ------ wxGridStringArray +// A 2-dimensional array of strings for data values +// + +WX_DECLARE_OBJARRAY(wxArrayString, wxGridStringArray); + + +// ------ wxGridStringTable +// +// Simplest type of data table for a grid for small tables of strings +// that are stored in memory +// + +class wxGridStringTable : public wxGridTableBase +{ + wxGridStringArray m_data; + + // These only get used if you set your own labels, otherwise the + // GetRow/ColLabelValue functions return wxGridTableBase defaults + // + wxArrayString m_rowLabels; + wxArrayString m_colLabels; + + public: + wxGridStringTable(); + wxGridStringTable( int numRows, int numCols ); + ~wxGridStringTable(); + + // these are pure virtual in wxGridTableBase + // + long GetNumberRows(); + long GetNumberCols(); + wxString GetValue( int row, int col ); + void SetValue( int row, int col, const wxString& s ); + bool IsEmptyCell( int row, int col ); + + // overridden functions from wxGridTableBase + // + void Clear(); + bool InsertRows( size_t pos = 0, size_t numRows = 1 ); + bool AppendRows( size_t numRows = 1 ); + bool DeleteRows( size_t pos = 0, size_t numRows = 1 ); + bool InsertCols( size_t pos = 0, size_t numCols = 1 ); + bool AppendCols( size_t numCols = 1 ); + bool DeleteCols( size_t pos = 0, size_t numCols = 1 ); + + void SetRowLabelValue( int row, const wxString& ); + void SetColLabelValue( int col, const wxString& ); + wxString GetRowLabelValue( int row ); + wxString GetColLabelValue( int col ); + + DECLARE_DYNAMIC_CLASS( wxGridStringTable ) +}; + + + +#if 0 + +// ------ sketchy experimental code to create a grid table for a given type +// +// This doesn't work at the moment !! +// + +#define _WX_DECLARE_GRIDTABLE( T, name ) \ + \ + \ +WX_DECLARE_ARRAY( T, T##Row ) \ +WX_DECLARE_OBJARRAY( T##Row, T##Array ) \ + \ +class WXDLLEXPORT name : public wxGridTableBase \ +{ \ + T##Array m_data; \ + int m_numRows; \ + int m_numCols; \ + \ + public: \ + name() { } \ + name( int numRows, int numCols ); \ + ~name(); \ + \ + wxString GetValue( int row, int col ); \ + wxString SetValue( int row, int col, const wxString& s ); \ + \ + DECLARE_DYNAMIC_CLASS( name ) \ +} + + +#define WX_DECLARE_GRIDTABLE(T, name) \ + typedef T name##var; \ + _WX_DECLARE_GRIDTABLE(name##var, name) + + +#endif // if 0 + + + +////////////////////////////////////////////////////////////////////// +// +// Grid view classes +// +////////////////////////////////////////////////////////////////////// + +class wxGridCellCoords +{ + long m_row; + long m_col; + + public: + wxGridCellCoords() { m_row = m_col = -1; } + wxGridCellCoords( int r, int c ) { m_row = r; m_col = c; } + + // default copy ctor is ok + + long GetRow() const { return m_row; } + void SetRow( long n ) { m_row = n; } + long GetCol() const { return m_col; } + void SetCol( long n ) { m_col = n; } + void Set( long row, long col ) { m_row = row; m_col = col; } + + wxGridCellCoords& operator=( const wxGridCellCoords& other ) + { + if ( &other != this ) + { + m_row=other.m_row; + m_col=other.m_col; + } + return *this; + } + + bool operator==( const wxGridCellCoords& other ) + { + return (m_row == other.m_row && m_col == other.m_col); + } + + bool operator!=( const wxGridCellCoords& other ) + { + return (m_row != other.m_row || m_col != other.m_col); + } + + bool operator!() + { + return (m_row == -1 && m_col == -1 ); + } +}; + + +// For comparisons... +// +extern wxGridCellCoords wxGridNoCellCoords; +extern wxRect wxGridNoCellRect; + + +// This set of classes is to provide for the use of different types of +// cell edit controls in the grid while avoiding the wx class info +// system in deference to wxPython + +class wxGridTextCtrl : public wxTextCtrl +{ + // TRUE for controls placed over cells, + // FALSE for a control on a grid control panel + bool m_isCellControl; + + wxString startValue; + + void OnKeyDown( wxKeyEvent& ); + + public: + wxGridTextCtrl() {} + wxGridTextCtrl( wxWindow *, + bool isCellControl, + wxWindowID id, + const wxString& value = wxEmptyString, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0 ); + + void SetStartValue( const wxString& ); + wxString GetStartValue() { return startValue; } + + DECLARE_DYNAMIC_CLASS( wxGridTextCtrl ) + DECLARE_EVENT_TABLE() +}; + + +class wxGrid : public wxPanel +{ + DECLARE_DYNAMIC_CLASS( wxGrid ) + + private: + bool m_created; + + wxGridTableBase *m_table; + + int m_left; + int m_top; + int m_right; + int m_bottom; + + int m_numRows; + int m_numCols; + + wxGridCellCoords m_currentCellCoords; + bool m_currentCellHighlighted; + + wxGridCellCoords m_selectedTopLeft; + wxGridCellCoords m_selectedBottomRight; + + int m_defaultRowHeight; + wxArrayInt m_rowHeights; + wxArrayInt m_rowBottoms; + + int m_defaultColWidth; + wxArrayInt m_colWidths; + wxArrayInt m_colRights; + + int m_rowLabelWidth; + int m_colLabelHeight; + + wxColour m_labelBackgroundColour; + wxColour m_labelTextColour; + wxFont m_labelFont; + + int m_rowLabelHorizAlign; + int m_rowLabelVertAlign; + int m_colLabelHorizAlign; + int m_colLabelVertAlign; + + bool m_defaultRowLabelValues; + bool m_defaultColLabelValues; + + wxColour m_gridLineColour; + bool m_gridLinesEnabled; + + wxFont m_defaultCellFont; + + wxScrollBar * m_horizScrollBar; + wxScrollBar * m_vertScrollBar; + int m_scrollBarWidth; + int m_scrollPosX; + int m_scrollPosY; + int m_wholeColsVisible; + int m_wholeRowsVisible; + + bool m_inOnKeyDown; + bool m_inOnText; + bool m_firstPaint; + int m_batchCount; + + int m_cursorMode; + enum { WXGRID_CURSOR_DEFAULT, + WXGRID_CURSOR_SELECT_CELL, + WXGRID_CURSOR_RESIZE_ROW, + WXGRID_CURSOR_RESIZE_COL, + WXGRID_CURSOR_SELECT_ROW, + WXGRID_CURSOR_SELECT_COL + }; + + int m_dragLastPos; + int m_dragRowOrCol; + bool m_isDragging; + + wxGridCellCoords m_selectionStart; + + wxCursor m_rowResizeCursor; + wxCursor m_colResizeCursor; + + bool m_editable; // applies to whole grid + int m_editCtrlType; // for current cell + wxWindow* m_cellEditCtrl; + bool m_cellEditCtrlEnabled; + wxWindow* m_topEditCtrl; + bool m_topEditCtrlEnabled; + + + // ------ internal init and update functions + // + void Create(); + void Init(); + void CalcDimensions(); + bool IsOnScreen(); + bool Redimension( wxGridTableMessage& ); + + // ------ event processing + // + bool SendEvent( const wxEventType, + int row, int col, + wxMouseEvent& ); + + bool SendEvent( const wxEventType, + int row, int col ); + + void OnPaint( wxPaintEvent& ); + void OnSize( wxSizeEvent& ); + void OnMouse( wxMouseEvent& ); + void OnKeyDown( wxKeyEvent& ); + void OnText( wxKeyEvent& ); + void OnGridScroll( wxScrollEvent& ); + + void SelectCell( const wxGridCellCoords& coords ); + void SelectCell( int row, int col ) + { SelectCell( wxGridCellCoords(row, col) ); } + + + // ------ edit controls + // + void ShowCellEditControl(); + void HideCellEditControl(); + void SaveEditControlValue(); + + + // ------ grid location functions + // + int XYToArea( int x, int y ); // returns one of the following... + enum { WXGRID_NOAREA, + WXGRID_ROWLABEL, + WXGRID_ROWLABEL_EDGE, + WXGRID_COLLABEL, + WXGRID_COLLABEL_EDGE, + WXGRID_CORNERLABEL, + WXGRID_CELL }; + + void XYToCell( int x, int y, wxGridCellCoords& ); + int YToRow( int y ); + int XToCol( int x ); + + int YToEdgeOfRow( int y ); + int XToEdgeOfCol( int x ); + + wxRect CellToRect( int row, int col ); + wxRect CellToRect( const wxGridCellCoords& coords ) + { return CellToRect( coords.GetRow(), coords.GetCol() ); } + + bool MoveCursorUp(); + bool MoveCursorDown(); + bool MoveCursorLeft(); + bool MoveCursorRight(); + bool MoveCursorUpBlock(); + bool MoveCursorDownBlock(); + bool MoveCursorLeftBlock(); + bool MoveCursorRightBlock(); + + + // ------ label drawing functions + // + void DrawLabelAreas( wxDC& dc ); + void DrawColLabelBorders( wxDC& dc ); + void DrawColLabels( wxDC& dc ); + void DrawColLabel( wxDC& dc, const wxRect&, int col ); + void DrawRowLabelBorders( wxDC& dc ); + void DrawRowLabels( wxDC& dc ); + void DrawRowLabel( wxDC& dc, const wxRect&, int col ); + + + // ------ cell drawing functions + // + void DrawCellArea( wxDC& dc ); + void DrawGridLines( wxDC& dc ); + void DrawCells( wxDC& dc ); + void DrawCellBackground( wxDC& dc, const wxRect&, int row, int col ); + void DrawCellValue( wxDC& dc, const wxRect&, int row, int col ); + + // this one is useful when you just need to draw one or a few + // cells + void DrawCell( int row, int col ); + void DrawCell( const wxGridCellCoords& coords ) + { DrawCell( coords.GetRow(), coords.GetCol() ); } + + void DrawCellHighlight( wxDC& dc, int row, int col ); + void DrawCellHighlight( wxDC& dc, wxGridCellCoords& coords ) + { DrawCellHighlight( dc, coords.GetRow(), coords.GetCol() ); } + void ShowCurrentCellHighlight( wxDC& dc ); + void HideCurrentCellHighlight( wxDC& dc ); + + + // ------ generic drawing functions + // + void DrawTextRectangle( wxDC& dc, const wxString&, const wxRect&, + int horizontalAlignment = wxLEFT, + int verticalAlignment = wxTOP ); + + // Split a string containing newline chararcters into an array of + // strings and return the number of lines + // + void StringToLines( const wxString& value, wxArrayString& lines ); + + void GetTextBoxSize( wxDC& dc, + wxArrayString& lines, + long *width, long *height ); + + + // ------ functions to get/send data (see also public functions) + // + bool GetModelValues(); + bool SetModelValues(); + + + ////////////////////// Public section //////////////////// + + public: + wxGrid() + { Create(); } + + wxGrid( wxWindow *parent, + wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxPanelNameStr ) + : wxPanel( parent, id, pos, size, style, name ) + { + Create(); + } + + ~wxGrid(); + + bool CreateGrid( int numRows = WXGRID_DEFAULT_NUMBER_ROWS, + int numCols = WXGRID_DEFAULT_NUMBER_COLS ); + + wxGridTableBase * GetTable() const { return m_table; } + void SetTable( wxGridTableBase *table ) { m_table = table; } + + void ClearGrid(); + bool InsertRows( int pos = 0, int numRows = 1, bool updateLabels=TRUE ); + bool AppendRows( int numRows = 1, bool updateLabels=TRUE ); + bool DeleteRows( int pos = 0, int numRows = 1, bool updateLabels=TRUE ); + bool InsertCols( int pos = 0, int numCols = 1, bool updateLabels=TRUE ); + bool AppendCols( int numCols = 1, bool updateLabels=TRUE ); + bool DeleteCols( int pos = 0, int numCols = 1, bool updateLabels=TRUE ); + + // ------ editing and edit controls + // + bool IsEditable() { return m_editable; } + void EnableEditing( bool edit ); + + void EnableTopEditControl( bool enable ); + bool IsTopEditControlEnabled() + { return (m_topEditCtrl && m_topEditCtrlEnabled); } + void EnableCellEditControl( bool enable ); + bool IsCellEditControlEnabled() + { return (m_cellEditCtrl && m_cellEditCtrlEnabled); } + void SetEditControlValue( const wxString& s = wxEmptyString ); + + + // ------ grid dimensions + // + int GetNumberRows() { return m_numRows; } + int GetNumberCols() { return m_numCols; } + int GetNumberVisibleRows() { return m_wholeRowsVisible; } + int GetNumberVisibleCols() { return m_wholeColsVisible; } + + + // ------ + // Code that does a lot of grid modification can be enclosed + // between BeginBatch() and EndBatch() calls to avoid screen + // flicker + // + void BeginBatch() { m_batchCount++; } + void EndBatch() { if ( m_batchCount > 0 ) m_batchCount--; } + int GetBatchCount() { return m_batchCount; } + + + // ------ label and gridline formatting + // + int GetDefaultRowLabelSize() { return WXGRID_DEFAULT_ROW_LABEL_WIDTH; } + int GetRowLabelSize() { return m_rowLabelWidth; } + int GetDefaultColLabelSize() { return WXGRID_DEFAULT_COL_LABEL_HEIGHT; } + int GetColLabelSize() { return m_colLabelHeight; } + wxColour GetLabelBackgroundColour() { return m_labelBackgroundColour; } + wxColour GetLabelTextColour() { return m_labelTextColour; } + wxFont GetLabelFont() { return m_labelFont; } + void GetRowLabelAlignment( int *horiz, int *vert ); + void GetColLabelAlignment( int *horiz, int *vert ); + wxString GetRowLabelValue( int row ); + wxString GetColLabelValue( int col ); + wxColour GetGridLineColour() { return m_gridLineColour; } + + void SetRowLabelSize( int width ); + void SetColLabelSize( int height ); + void SetLabelBackgroundColour( const wxColour& ); + void SetLabelTextColour( const wxColour& ); + void SetLabelFont( const wxFont& ); + void SetRowLabelAlignment( int horiz, int vert ); + void SetColLabelAlignment( int horiz, int vert ); + void SetRowLabelValue( int row, const wxString& ); + void SetColLabelValue( int col, const wxString& ); + void SetGridLineColour( const wxColour& ); + + void EnableGridLines( bool enable = TRUE ); + bool GridLinesEnabled() { return m_gridLinesEnabled; } + + + // ------ row and col formatting + // + int GetDefaultRowSize(); + int GetRowSize( int row ); + int GetDefaultColSize(); + int GetColSize( int col ); + wxColour GetDefaultCellBackgroundColour(); + wxColour GetCellBackgroundColour( int row, int col ); + wxColour GetDefaultCellTextColour(); + wxColour GetCellTextColour( int row, int col ); + wxColour GetCellHighlightColour(); + wxFont GetDefaultCellFont(); + wxFont GetCellFont( int row, int col ); + void GetDefaultCellAlignment( int *horiz, int *vert ); + void GetCellAlignment( int row, int col, int *horiz, int *vert ); + + void SetDefaultRowSize( int height, bool resizeExistingRows = FALSE ); + void SetRowSize( int row, int height ); + void SetDefaultColSize( int width, bool resizeExistingCols = FALSE ); + void SetColSize( int col, int width ); + void SetDefaultCellBackgroundColour( const wxColour& ); + void SetCellBackgroundColour( int row, int col, const wxColour& ); + void SetDefaultCellTextColour( const wxColour& ); + void SetCellTextColour( int row, int col, const wxColour& ); + void SetCellHighlightColour( const wxColour& ); + void SetDefaultCellFont( const wxFont& ); + void SetCellFont( int row, int col, const wxFont& ); + void SetDefaultCellAlignment( int horiz, int vert ); + void SetCellAlignment( int row, int col, int horiz, int vert ); + + + // ------ cell value accessors + // + wxString GetCellValue( int row, int col ) + { + if ( m_table ) + { + return m_table->GetValue( row, col ); + } + else + { + return wxEmptyString; + } + } + + wxString GetCellValue( const wxGridCellCoords& coords ) + { return GetCellValue( coords.GetRow(), coords.GetCol() ); } + + void SetCellValue( int row, int col, const wxString& s ); + void SetCellValue( const wxGridCellCoords& coords, const wxString& s ) + { SetCellValue( coords.GetRow(), coords.GetCol(), s ); } + + + // ------ interaction with data model + // + bool ProcessTableMessage( wxGridTableMessage& ); + + + + // ------ grid location functions + // + + int GetGridCursorRow() { return m_currentCellCoords.GetRow(); } + int GetGridCursorCol() { return m_currentCellCoords.GetCol(); } + int GetHorizontalScrollPos() { return m_scrollPosX; } + int GetVerticalScrollPos() { return m_scrollPosY; } + + bool IsVisible( const wxGridCellCoords& ); + void MakeCellVisible( int row, int col ); + void MakeCellVisible( const wxGridCellCoords& coords ) + { MakeCellVisible( coords.GetRow(), coords.GetCol() ); } + + void SetGridCursor( int row, int col ) + { SelectCell( wxGridCellCoords(row, col) ); } + + void SetHorizontalScrollPos( int leftMostCol ); + void SetVerticalScrollPos( int topMostRow ); + + + // ------ selections of blocks of cells + // + void SelectRow( int row, bool addToSelected = FALSE ); + void SelectCol( int col, bool addToSelected = FALSE ); + + void SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol ); + + void SelectBlock( const wxGridCellCoords& topLeft, + const wxGridCellCoords& bottomRight ) + { SelectBlock( topLeft.GetRow(), topLeft.GetCol(), + bottomRight.GetRow(), bottomRight.GetCol() ); } + + void SelectAll(); + + bool IsSelection() + { return ( m_selectedTopLeft != wxGridNoCellCoords && + m_selectedBottomRight != wxGridNoCellCoords ); + } + + void ClearSelection(); + + bool IsInSelection( int row, int col ) + { return ( IsSelection() && + row >= m_selectedTopLeft.GetRow() && + col >= m_selectedTopLeft.GetCol() && + row <= m_selectedBottomRight.GetRow() && + col <= m_selectedBottomRight.GetCol() ); + } + + bool IsInSelection( const wxGridCellCoords& coords ) + { return IsInSelection( coords.GetRow(), coords.GetCol() ); } + + void GetSelection( int* topRow, int* leftCol, int* bottomRow, int* rightCol ) + { + // these will all be -1 if there is no selected block + // + *topRow = m_selectedTopLeft.GetRow(); + *leftCol = m_selectedTopLeft.GetCol(); + *bottomRow = m_selectedBottomRight.GetRow(); + *rightCol = m_selectedBottomRight.GetCol(); + } + + // get coordinates of selected block edges for repainting etc. + // + wxRect SelectionToRect(); + + + // ------ For compatibility with previous wxGrid only... + // + // ************************************************ + // ** Don't use these in new code because they ** + // ** are liable to disappear in a future ** + // ** revision ** + // ************************************************ + // + + wxGrid( wxWindow *parent, + int x = -1, int y = -1, int w = -1, int h = -1, + long style = 0, + const wxString& name = wxPanelNameStr ) + : wxPanel( parent, -1, wxPoint(x,y), wxSize(w,h), style, name ) + { + Create(); + } + + void SetCellValue( const wxString& val, int row, int col ) + { SetCellValue( row, col, val ); } + + void AdjustScrollbars() + { CalcDimensions(); } + + void UpdateDimensions() + { CalcDimensions(); } + + int GetRows() { return GetNumberRows(); } + int GetCols() { return GetNumberCols(); } + int GetCursorRow() { return GetGridCursorRow(); } + int GetCursorColumn() { return GetGridCursorCol(); } + int GetScrollPosX() { return GetHorizontalScrollPos(); } + int GetScrollPosY() { return GetVerticalScrollPos(); } + + void SetScrollX( int x ) { SetHorizontalScrollPos( x ); } + void SetScrollY( int y ) { SetVerticalScrollPos( y ); } + + void SetColumnWidth( int col, int width ) + { SetColSize( col, width ); } + + int GetColumnWidth( int col ) + { return GetColSize( col ); } + + void SetRowHeight( int row, int height ) + { SetRowSize( row, height ); } + + int GetRowHeight( int row ) + { return GetRowSize( row ); } + + int GetViewHeight() + { return m_wholeRowsVisible; } + + int GetViewWidth() + { return m_wholeColsVisible; } + + void SetLabelSize( int orientation, int sz ) + { + if ( orientation == wxHORIZONTAL ) + SetColLabelSize( sz ); + else + SetRowLabelSize( sz ); + } + + int GetLabelSize( int orientation ) + { + if ( orientation == wxHORIZONTAL ) + return GetColLabelSize(); + else + return GetRowLabelSize(); + } + + void SetLabelAlignment( int orientation, int align ) + { + if ( orientation == wxHORIZONTAL ) + SetColLabelAlignment( align, -1 ); + else + SetRowLabelAlignment( align, -1 ); + } + + int GetLabelAlignment( int orientation, int align ) + { + int h, v; + if ( orientation == wxHORIZONTAL ) + { + GetColLabelAlignment( &h, &v ); + return h; + } + else + { + GetRowLabelAlignment( &h, &v ); + return h; + } + } + + void SetLabelValue( int orientation, const wxString& val, int pos ) + { + if ( orientation == wxHORIZONTAL ) + SetColLabelValue( pos, val ); + else + SetRowLabelValue( pos, val ); + } + + wxString GetLabelValue( int orientation, int pos) + { + if ( orientation == wxHORIZONTAL ) + return GetColLabelValue( pos ); + else + return GetRowLabelValue( pos ); + } + + wxFont GetCellTextFont() const + { return m_defaultCellFont; } + + wxFont GetCellTextFont(int row, int col) const + { return m_defaultCellFont; } + + void SetCellTextFont(const wxFont& fnt) + { SetDefaultCellFont( fnt ); } + + void SetCellTextFont(const wxFont& fnt, int row, int col) + { SetCellFont( row, col, fnt ); } + + void SetCellTextColour(const wxColour& val, int row, int col) + { SetCellTextColour( row, col, val ); } + + void SetCellTextColour(const wxColour& col) + { SetDefaultCellTextColour( col ); } + + void SetCellBackgroundColour(const wxColour& col) + { SetDefaultCellBackgroundColour( col ); } + + void SetCellBackgroundColour(const wxColour& colour, int row, int col) + { SetCellBackgroundColour( row, col, colour ); } + + bool GetEditable() { return IsEditable(); } + void SetEditable( bool edit = TRUE ) { EnableEditing( edit ); } + bool GetEditInPlace() { return IsCellEditControlEnabled(); } + void SetEditInPlace(bool edit = TRUE) { EnableCellEditControl( edit ); } + + + // ******** End of compatibility functions ********** + + + // ------ control IDs + enum { wxGRID_HORIZSCROLL = 2000, + wxGRID_VERTSCROLL, + wxGRID_CELLCTRL, + wxGRID_TOPCTRL }; + + // ------ control types + enum { wxGRID_TEXTCTRL = 100, + wxGRID_CHECKBOX, + wxGRID_CHOICE, + wxGRID_COMBOBOX }; + + + DECLARE_EVENT_TABLE() +}; + + + + + +// +// ------ Grid event class and event types +// + +class WXDLLEXPORT wxGridEvent : public wxNotifyEvent +{ + DECLARE_DYNAMIC_CLASS(wxGridEvent) + + private: + int m_row; + int m_col; + int m_x; + int m_y; + bool m_control; + bool m_meta; + bool m_shift; + bool m_alt; + + public: + wxGridEvent() + : wxNotifyEvent(), m_row(-1), m_col(-1), m_x(-1), m_y(-1), + m_control(0), m_meta(0), m_shift(0), m_alt(0) + { + } + + wxGridEvent(int id, wxEventType type, wxObject* obj, + int row=-1, int col=-1, int x=-1, int y=-1, + bool control=FALSE, bool shift=FALSE, bool alt=FALSE, bool meta=FALSE); + + virtual int GetRow() { return m_row; } + virtual int GetCol() { return m_col; } + wxPoint GetPosition() { return wxPoint( m_x, m_y ); } + bool ControlDown() { return m_control; } + bool MetaDown() { return m_meta; } + bool ShiftDown() { return m_shift; } + bool AltDown() { return m_alt; } +}; + + +class WXDLLEXPORT wxGridSizeEvent : public wxNotifyEvent +{ + DECLARE_DYNAMIC_CLASS(wxGridSizeEvent) + + private: + int m_rowOrCol; + int m_x; + int m_y; + bool m_control; + bool m_meta; + bool m_shift; + bool m_alt; + + public: + wxGridSizeEvent() + : wxNotifyEvent(), m_rowOrCol(-1), m_x(-1), m_y(-1), + m_control(0), m_meta(0), m_shift(0), m_alt(0) + { + } + + wxGridSizeEvent(int id, wxEventType type, wxObject* obj, + int rowOrCol=-1, int x=-1, int y=-1, + bool control=FALSE, bool shift=FALSE, bool alt=FALSE, bool meta=FALSE); + + int GetRowOrCol() { return m_rowOrCol; } + wxPoint GetPosition() { return wxPoint( m_x, m_y ); } + bool ControlDown() { return m_control; } + bool MetaDown() { return m_meta; } + bool ShiftDown() { return m_shift; } + bool AltDown() { return m_alt; } +}; + + +class WXDLLEXPORT wxGridRangeSelectEvent : public wxNotifyEvent +{ + DECLARE_DYNAMIC_CLASS(wxGridRangeSelectEvent) + + private: + wxGridCellCoords m_topLeft; + wxGridCellCoords m_bottomRight; + bool m_control; + bool m_meta; + bool m_shift; + bool m_alt; + + public: + wxGridRangeSelectEvent() + : wxNotifyEvent() + { + m_topLeft = wxGridNoCellCoords; + m_bottomRight = wxGridNoCellCoords; + m_control = FALSE; + m_meta = FALSE; + m_shift = FALSE; + m_alt = FALSE; + } + + wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj, + const wxGridCellCoords& topLeft, + const wxGridCellCoords& bottomRight, + bool control=FALSE, bool shift=FALSE, + bool alt=FALSE, bool meta=FALSE); + + wxGridCellCoords GetTopLeftCoords() { return m_topLeft; } + wxGridCellCoords GetBottomRightCoords() { return m_bottomRight; } + int GetTopRow() { return m_topLeft.GetRow(); } + int GetBottomRow() { return m_bottomRight.GetRow(); } + int GetLeftCol() { return m_topLeft.GetCol(); } + int GetRightCol() { return m_bottomRight.GetCol(); } + bool ControlDown() { return m_control; } + bool MetaDown() { return m_meta; } + bool ShiftDown() { return m_shift; } + bool AltDown() { return m_alt; } +}; + + +const wxEventType EVT_WXGRID_CELL_LEFT_CLICK = wxEVT_FIRST + 1580; +const wxEventType EVT_WXGRID_CELL_RIGHT_CLICK = wxEVT_FIRST + 1581; +const wxEventType EVT_WXGRID_CELL_LEFT_DCLICK = wxEVT_FIRST + 1582; +const wxEventType EVT_WXGRID_CELL_RIGHT_DCLICK = wxEVT_FIRST + 1583; +const wxEventType EVT_WXGRID_LABEL_LEFT_CLICK = wxEVT_FIRST + 1584; +const wxEventType EVT_WXGRID_LABEL_RIGHT_CLICK = wxEVT_FIRST + 1585; +const wxEventType EVT_WXGRID_LABEL_LEFT_DCLICK = wxEVT_FIRST + 1586; +const wxEventType EVT_WXGRID_LABEL_RIGHT_DCLICK = wxEVT_FIRST + 1587; +const wxEventType EVT_WXGRID_ROW_SIZE = wxEVT_FIRST + 1588; +const wxEventType EVT_WXGRID_COL_SIZE = wxEVT_FIRST + 1589; +const wxEventType EVT_WXGRID_RANGE_SELECT = wxEVT_FIRST + 1590; +const wxEventType EVT_WXGRID_CELL_CHANGE = wxEVT_FIRST + 1591; + +typedef void (wxEvtHandler::*wxGridEventFunction)(wxGridEvent&); +typedef void (wxEvtHandler::*wxGridSizeEventFunction)(wxGridSizeEvent&); +typedef void (wxEvtHandler::*wxGridRangeSelectEventFunction)(wxGridRangeSelectEvent&); + +#define EVT_WXGRID_CELL_LEFT_CLICK(fn) { EVT_WXGRID_CELL_LEFT_CLICK, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &fn, NULL }, +#define EVT_WXGRID_CELL_RIGHT_CLICK(fn) { EVT_WXGRID_CELL_RIGHT_CLICK, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &fn, NULL }, +#define EVT_WXGRID_CELL_LEFT_DCLICK(fn) { EVT_WXGRID_CELL_LEFT_DCLICK, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &fn, NULL }, +#define EVT_WXGRID_CELL_RIGHT_DCLICK(fn) { EVT_WXGRID_CELL_RIGHT_DCLICK, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &fn, NULL }, +#define EVT_WXGRID_LABEL_LEFT_CLICK(fn) { EVT_WXGRID_LABEL_LEFT_CLICK, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &fn, NULL }, +#define EVT_WXGRID_LABEL_RIGHT_CLICK(fn) { EVT_WXGRID_LABEL_RIGHT_CLICK, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &fn, NULL }, +#define EVT_WXGRID_LABEL_LEFT_DCLICK(fn) { EVT_WXGRID_LABEL_LEFT_DCLICK, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &fn, NULL }, +#define EVT_WXGRID_LABEL_RIGHT_DCLICK(fn) { EVT_WXGRID_LABEL_RIGHT_DCLICK, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &fn, NULL }, +#define EVT_WXGRID_ROW_SIZE(fn) { EVT_WXGRID_ROW_SIZE, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridSizeEventFunction) &fn, NULL }, +#define EVT_WXGRID_COL_SIZE(fn) { EVT_WXGRID_COL_SIZE, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridSizeEventFunction) &fn, NULL }, +#define EVT_WXGRID_RANGE_SELECT(fn) { EVT_WXGRID_RANGE_SELECT, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridRangeSelectEventFunction) &fn, NULL }, +#define EVT_WXGRID_CELL_CHANGE(fn) { EVT_WXGRID_CELL_CHANGE, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &fn, NULL }, + + +#if 0 // TODO: implement these ? others ? + +const wxEventType EVT_WXGRID_SELECT_CELL = wxEVT_FIRST + 1575; +const wxEventType EVT_WXGRID_CREATE_CELL = wxEVT_FIRST + 1576; +const wxEventType EVT_WXGRID_CHANGE_LABELS = wxEVT_FIRST + 1577; +const wxEventType EVT_WXGRID_CHANGE_SEL_LABEL = wxEVT_FIRST + 1578; + +#define EVT_WXGRID_SELECT_CELL(fn) { EVT_WXGRID_SELECT_CELL, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &fn, NULL }, +#define EVT_WXGRID_CREATE_CELL(fn) { EVT_WXGRID_CREATE_CELL, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &fn, NULL }, +#define EVT_WXGRID_CHANGE_LABELS(fn) { EVT_WXGRID_CHANGE_LABELS, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &fn, NULL }, +#define EVT_WXGRID_CHANGE_SEL_LABEL(fn) { EVT_WXGRID_CHANGE_SEL_LABEL, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &fn, NULL }, + +#endif + +#endif // #ifndef __WXGRID_H__ + +#endif // ifndef wxUSE_NEW_GRID diff --git a/include/wx/grid.h b/include/wx/grid.h index 668f69a3e3..c6f4fc5dc8 100644 --- a/include/wx/grid.h +++ b/include/wx/grid.h @@ -1,11 +1,7 @@ #ifndef _WX_GRID_H_BASE_ #define _WX_GRID_H_BASE_ -#include "wx/generic/gridg.h" - -#ifndef wxGrid -#define wxGrid wxGenericGrid -#endif +#include "wx/generic/grid.h" #endif // _WX_GRID_H_BASE_ diff --git a/include/wx/msw/setup0.h b/include/wx/msw/setup0.h index 4acb6ca886..fa3435b1af 100644 --- a/include/wx/msw/setup0.h +++ b/include/wx/msw/setup0.h @@ -103,6 +103,11 @@ #define wxUSE_CARET 1 // Define 1 to use wxCaret class + +#define wxUSE_NEW_GRID 1 + // Define 1 to use the new wxGrid class + // (still under development, define 0 to + // use existing wxGrid class) #define wxUSE_XPM_IN_MSW 1 // Define 1 to support the XPM package in wxBitmap. #define wxUSE_IMAGE_LOADING_IN_MSW 1 diff --git a/setup.h.in b/setup.h.in index 6251dc39eb..6b51e00caa 100644 --- a/setup.h.in +++ b/setup.h.in @@ -212,6 +212,11 @@ /* * Use this control */ +#define wxUSE_NEW_GRID 0 +/* + * Use the new prototype wxGrid classes + * (wxUSE_GRID must also be defined) + */ #define wxUSE_IMAGLIST 0 /* * Use this control diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp new file mode 100644 index 0000000000..6f9512c5af --- /dev/null +++ b/src/generic/grid.cpp @@ -0,0 +1,4253 @@ +//////////////////////////////////////////////////////////////////////////// +// Name: grid.cpp +// Purpose: wxGrid and related classes +// Author: Michael Bedward (based on code by Julian Smart, Robin Dunn) +// Modified by: +// Created: 1/08/1999 +// RCS-ID: $Id$ +// Copyright: (c) Michael Bedward (mbedward@ozemail.com.au) +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + + +#include "wx/defs.h" + +#if !defined(wxUSE_NEW_GRID) || !(wxUSE_NEW_GRID) +#include "gridg.cpp" +#else + +#ifdef __GNUG__ + #pragma implementation "grid.h" +#endif + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/dcclient.h" + #include "wx/settings.h" + #include "wx/log.h" +#endif + +#include "wx/generic/grid.h" + + +////////////////////////////////////////////////////////////////////// + +wxGridCellCoords wxGridNoCellCoords( -1, -1 ); +wxRect wxGridNoCellRect( -1, -1, -1, -1 ); + + + +////////////////////////////////////////////////////////////////////// +// +// Abstract base class for grid data (the model) +// +IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject ) + + +wxGridTableBase::wxGridTableBase() + : wxObject() +{ + m_view = (wxGrid *) NULL; +} + +wxGridTableBase::~wxGridTableBase() +{ +} + + +bool wxGridTableBase::InsertRows( size_t pos, size_t numRows ) +{ + wxLogWarning( "Called grid table class function InsertRows(pos=%d, N=%d)\n" + "but your derived table class does not override this function", + pos, numRows ); + + return FALSE; +} + +bool wxGridTableBase::AppendRows( size_t numRows ) +{ + wxLogWarning( "Called grid table class function AppendRows(N=%d)\n" + "but your derived table class does not override this function", + numRows ); + + return FALSE; +} + +bool wxGridTableBase::DeleteRows( size_t pos, size_t numRows ) +{ + wxLogWarning( "Called grid table class function DeleteRows(pos=%d, N=%d)\n" + "but your derived table class does not override this function", + pos, numRows ); + + return FALSE; +} + +bool wxGridTableBase::InsertCols( size_t pos, size_t numCols ) +{ + wxLogWarning( "Called grid table class function InsertCols(pos=%d, N=%d)\n" + "but your derived table class does not override this function", + pos, numCols ); + + return FALSE; +} + +bool wxGridTableBase::AppendCols( size_t numCols ) +{ + wxLogWarning( "Called grid table class function AppendCols(N=%d)\n" + "but your derived table class does not override this function", + numCols ); + + return FALSE; +} + +bool wxGridTableBase::DeleteCols( size_t pos, size_t numCols ) +{ + wxLogWarning( "Called grid table class function DeleteCols(pos=%d, N=%d)\n" + "but your derived table class does not override this function", + pos, numCols ); + + return FALSE; +} + + +wxString wxGridTableBase::GetRowLabelValue( int row ) +{ + wxString s; + s << row; + return s; +} + +wxString wxGridTableBase::GetColLabelValue( int col ) +{ + // default col labels are: + // cols 0 to 25 : A-Z + // cols 26 to 675 : AA-ZZ + // etc. + + wxString s; + unsigned int i, n; + for ( n = 1; ; n++ ) + { + s += ('A' + (char)( col%26 )); + col = col/26 - 1; + if ( col < 0 ) break; + } + + // reverse the string... + wxString s2; + for ( i = 0; i < n; i++ ) + { + s2 += s[n-i-1]; + } + + return s2; +} + + + +////////////////////////////////////////////////////////////////////// +// +// Message class for the grid table to send requests and notifications +// to the grid view +// + +wxGridTableMessage::wxGridTableMessage() +{ + m_table = (wxGridTableBase *) NULL; + m_id = -1; + m_comInt1 = -1; + m_comInt2 = -1; +} + +wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id, + int commandInt1, int commandInt2 ) +{ + m_table = table; + m_id = id; + m_comInt1 = commandInt1; + m_comInt2 = commandInt2; +} + + + +////////////////////////////////////////////////////////////////////// +// +// A basic grid table for string data. An object of this class will +// created by wxGrid if you don't specify an alternative table class. +// + + +// this is a magic incantation which must be done! +#include + +WX_DEFINE_OBJARRAY(wxGridStringArray); + +IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase ) + +wxGridStringTable::wxGridStringTable() + : wxGridTableBase() +{ +} + +wxGridStringTable::wxGridStringTable( int numRows, int numCols ) + : wxGridTableBase() +{ + int row, col; + + m_data.Alloc( numRows ); + + wxArrayString sa; + sa.Alloc( numCols ); + for ( col = 0; col < numCols; col++ ) + { + sa.Add( wxEmptyString ); + } + + for ( row = 0; row < numRows; row++ ) + { + m_data.Add( sa ); + } +} + +wxGridStringTable::~wxGridStringTable() +{ +} + +long wxGridStringTable::GetNumberRows() +{ + return m_data.GetCount(); +} + +long wxGridStringTable::GetNumberCols() +{ + if ( m_data.GetCount() > 0 ) + return m_data[0].GetCount(); + else + return 0; +} + +wxString wxGridStringTable::GetValue( int row, int col ) +{ + // TODO: bounds checking + // + return m_data[row][col]; +} + +void wxGridStringTable::SetValue( int row, int col, const wxString& s ) +{ + // TODO: bounds checking + // + m_data[row][col] = s; +} + +bool wxGridStringTable::IsEmptyCell( int row, int col ) +{ + // TODO: bounds checking + // + return (m_data[row][col] == wxEmptyString); +} + + +void wxGridStringTable::Clear() +{ + int row, col; + int numRows, numCols; + + numRows = m_data.GetCount(); + if ( numRows > 0 ) + { + numCols = m_data[0].GetCount(); + + for ( row = 0; row < numRows; row++ ) + { + for ( col = 0; col < numCols; col++ ) + { + m_data[row][col] = wxEmptyString; + } + } + } +} + + +bool wxGridStringTable::InsertRows( size_t pos, size_t numRows ) +{ + size_t row, col; + + size_t curNumRows = m_data.GetCount(); + size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 ); + + if ( pos >= curNumRows ) + { + return AppendRows( numRows ); + } + + wxArrayString sa; + sa.Alloc( curNumCols ); + for ( col = 0; col < curNumCols; col++ ) + { + sa.Add( wxEmptyString ); + } + + for ( row = pos; row < pos + numRows; row++ ) + { + m_data.Insert( sa, row ); + } + + if ( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_INSERTED, + pos, + numRows ); + + GetView()->ProcessTableMessage( msg ); + } + + return TRUE; +} + +bool wxGridStringTable::AppendRows( size_t numRows ) +{ + size_t row, col; + + size_t curNumRows = m_data.GetCount(); + size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 ); + + wxArrayString sa; + if ( curNumCols > 0 ) + { + sa.Alloc( curNumCols ); + for ( col = 0; col < curNumCols; col++ ) + { + sa.Add( wxEmptyString ); + } + } + + for ( row = 0; row < numRows; row++ ) + { + m_data.Add( sa ); + } + + if ( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_APPENDED, + numRows ); + + GetView()->ProcessTableMessage( msg ); + } + + return TRUE; +} + +bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows ) +{ + size_t n; + + size_t curNumRows = m_data.GetCount(); + + if ( pos >= curNumRows ) + { + wxLogError( "Called wxGridStringTable::DeleteRows(pos=%d, N=%d)...\n" + "Pos value is invalid for present table with %d rows", + pos, numRows, curNumRows ); + return FALSE; + } + + if ( numRows > curNumRows - pos ) + { + numRows = curNumRows - pos; + } + + if ( numRows >= curNumRows ) + { + m_data.Empty(); // don't release memory just yet + } + else + { + for ( n = 0; n < numRows; n++ ) + { + m_data.Remove( pos ); + } + } + + if ( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_DELETED, + pos, + numRows ); + + GetView()->ProcessTableMessage( msg ); + } + + return TRUE; +} + +bool wxGridStringTable::InsertCols( size_t pos, size_t numCols ) +{ + size_t row, col; + + size_t curNumRows = m_data.GetCount(); + size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 ); + + if ( pos >= curNumCols ) + { + return AppendCols( numCols ); + } + + for ( row = 0; row < curNumRows; row++ ) + { + for ( col = pos; col < pos + numCols; col++ ) + { + m_data[row].Insert( wxEmptyString, col ); + } + } + + if ( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_COLS_INSERTED, + pos, + numCols ); + + GetView()->ProcessTableMessage( msg ); + } + + return TRUE; +} + +bool wxGridStringTable::AppendCols( size_t numCols ) +{ + size_t row, n; + + size_t curNumRows = m_data.GetCount(); + if ( !curNumRows ) + { + // TODO: something better than this ? + // + wxLogError( "Unable to append cols to a grid table with no rows.\n" + "Call AppendRows() first" ); + return FALSE; + } + + for ( row = 0; row < curNumRows; row++ ) + { + for ( n = 0; n < numCols; n++ ) + { + m_data[row].Add( wxEmptyString ); + } + } + + if ( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_COLS_APPENDED, + numCols ); + + GetView()->ProcessTableMessage( msg ); + } + + return TRUE; +} + +bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols ) +{ + size_t row, n; + + size_t curNumRows = m_data.GetCount(); + size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 ); + + if ( pos >= curNumCols ) + { + wxLogError( "Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\n" + "Pos value is invalid for present table with %d cols", + pos, numCols, curNumCols ); + return FALSE; + } + + if ( numCols > curNumCols - pos ) + { + numCols = curNumCols - pos; + } + + for ( row = 0; row < curNumRows; row++ ) + { + if ( numCols >= curNumCols ) + { + m_data[row].Clear(); + } + else + { + for ( n = 0; n < numCols; n++ ) + { + m_data[row].Remove( pos ); + } + } + } + + if ( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_COLS_DELETED, + pos, + numCols ); + + GetView()->ProcessTableMessage( msg ); + } + + return TRUE; +} + +wxString wxGridStringTable::GetRowLabelValue( int row ) +{ + if ( row > (int)(m_rowLabels.GetCount()) - 1 ) + { + // using default label + // + return wxGridTableBase::GetRowLabelValue( row ); + } + else + { + return m_rowLabels[ row ]; + } +} + +wxString wxGridStringTable::GetColLabelValue( int col ) +{ + if ( col > (int)(m_colLabels.GetCount()) - 1 ) + { + // using default label + // + return wxGridTableBase::GetColLabelValue( col ); + } + else + { + return m_colLabels[ col ]; + } +} + +void wxGridStringTable::SetRowLabelValue( int row, const wxString& value ) +{ + if ( row > (int)(m_rowLabels.GetCount()) - 1 ) + { + int n = m_rowLabels.GetCount(); + int i; + for ( i = n; i <= row; i++ ) + { + m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) ); + } + } + + m_rowLabels[row] = value; +} + +void wxGridStringTable::SetColLabelValue( int col, const wxString& value ) +{ + if ( col > (int)(m_colLabels.GetCount()) - 1 ) + { + int n = m_colLabels.GetCount(); + int i; + for ( i = n; i <= col; i++ ) + { + m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) ); + } + } + + m_colLabels[col] = value; +} + + + + +////////////////////////////////////////////////////////////////////// + +IMPLEMENT_DYNAMIC_CLASS( wxGridTextCtrl, wxTextCtrl ) + +BEGIN_EVENT_TABLE( wxGridTextCtrl, wxTextCtrl ) + EVT_KEY_DOWN( wxGridTextCtrl::OnKeyDown ) +END_EVENT_TABLE() + + +wxGridTextCtrl::wxGridTextCtrl( wxWindow *par, + bool isCellControl, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + long style ) + : wxTextCtrl( par, id, value, pos, size, style ) +{ + m_isCellControl = isCellControl; +} + + +void wxGridTextCtrl::OnKeyDown( wxKeyEvent& ev ) +{ + switch ( ev.KeyCode() ) + { + case WXK_ESCAPE: + ((wxGrid *)GetParent())->SetEditControlValue( startValue ); + SetInsertionPointEnd(); + break; + + case WXK_UP: + case WXK_DOWN: + case WXK_LEFT: + case WXK_RIGHT: + case WXK_RETURN: + if ( m_isCellControl ) + { + // send the event to the parent grid, skipping the + // event if nothing happens + // + ev.Skip( !GetParent()->ProcessEvent( ev ) ); + } + else + { + // default text control response within the top edit + // control + // + ev.Skip(); + } + break; + + case WXK_HOME: + case WXK_END: + if ( m_isCellControl ) + { + // send the event to the parent grid, skipping the + // event if nothing happens + // + ev.Skip( !GetParent()->ProcessEvent( ev ) ); + } + else + { + // default text control response within the top edit + // control + // + ev.Skip(); + } + break; + + default: + ev.Skip(); + } +} + +void wxGridTextCtrl::SetStartValue( const wxString& s ) +{ + startValue = s; + wxTextCtrl::SetValue( s.c_str() ); +} + + +////////////////////////////////////////////////////////////////////// + +IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxPanel ) + + +BEGIN_EVENT_TABLE( wxGrid, wxPanel ) + EVT_PAINT( wxGrid::OnPaint ) + EVT_SIZE( wxGrid::OnSize ) + EVT_MOUSE_EVENTS( wxGrid::OnMouse ) + EVT_KEY_DOWN( wxGrid::OnKeyDown ) + EVT_TEXT( wxGRID_CELLCTRL, wxGrid::OnText ) + EVT_TEXT( wxGRID_TOPCTRL, wxGrid::OnText ) + EVT_COMMAND_SCROLL( wxGRID_HORIZSCROLL, wxGrid::OnGridScroll) + EVT_COMMAND_SCROLL( wxGRID_VERTSCROLL, wxGrid::OnGridScroll) +END_EVENT_TABLE() + + +wxGrid::~wxGrid() +{ + delete m_table; +} + + +// +// ----- internal init and update functions +// + +void wxGrid::Create() +{ + m_table = (wxGridTableBase *) NULL; + m_topEditCtrl = (wxWindow *) NULL; + m_cellEditCtrl = (wxWindow *) NULL; + m_horizScrollBar = (wxScrollBar *) NULL; + m_vertScrollBar = (wxScrollBar *) NULL; + + m_numRows = 0; + m_numCols = 0; + m_created = FALSE; +} + +void wxGrid::Init() +{ + int i; + + m_left = 0; + m_top = 0; + + // TODO: perhaps have a style flag for control panel + // + m_topEditCtrlEnabled = FALSE; + m_topEditCtrl = new wxGridTextCtrl( this, + FALSE, + wxGRID_TOPCTRL, + "", + wxPoint(10, 10), + wxSize(WXGRID_DEFAULT_TOPEDIT_WIDTH, + WXGRID_DEFAULT_TOPEDIT_HEIGHT), + wxTE_MULTILINE ); + m_topEditCtrl->Show( FALSE ); + + if ( m_numRows <= 0 ) + m_numRows = WXGRID_DEFAULT_NUMBER_ROWS; + + if ( m_numCols <= 0 ) + m_numCols = WXGRID_DEFAULT_NUMBER_COLS; + + m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH; + m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT; + + // default labels are pale grey with black text + // + m_labelBackgroundColour = wxColour( 192, 192, 192 ); + m_labelTextColour = wxColour( 0, 0, 0 ); + + // TODO: something better than this ? + // + m_labelFont = this->GetFont(); + m_labelFont.SetWeight( m_labelFont.GetWeight() + 2 ); + + m_rowLabelHorizAlign = wxLEFT; + m_rowLabelVertAlign = wxCENTRE; + + m_colLabelHorizAlign = wxCENTRE; + m_colLabelVertAlign = wxTOP; + + m_defaultRowHeight = WXGRID_DEFAULT_ROW_HEIGHT; + m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH; + + m_rowHeights.Alloc( m_numRows ); + m_rowBottoms.Alloc( m_numRows ); + for ( i = 0; i < m_numRows; i++ ) + { + m_rowHeights.Add( m_defaultRowHeight ); + m_rowBottoms.Add( 0 ); // set by CalcDimensions() + } + + m_colWidths.Alloc( m_numCols ); + m_colRights.Alloc( m_numRows ); + for ( i = 0; i < m_numCols; i++ ) + { + m_colWidths.Add( m_defaultColWidth ); + m_colRights.Add( 0 ); // set by CalcDimensions() + } + + // TODO: improve this ? + // + m_defaultCellFont = this->GetFont(); + + m_gridLineColour = wxColour( 0, 0, 255 ); + m_gridLinesEnabled = TRUE; + + m_scrollBarWidth = WXGRID_DEFAULT_SCROLLBAR_WIDTH; + + m_horizScrollBar = new wxScrollBar( this, + wxGRID_HORIZSCROLL, + wxPoint(0, 0), + wxSize(10, 10), + wxHORIZONTAL); + + m_vertScrollBar = new wxScrollBar( this, + wxGRID_VERTSCROLL, + wxPoint(0, 0), + wxSize(10, 10), + wxVERTICAL); + m_scrollPosX = 0; + m_scrollPosY = 0; + m_wholeColsVisible = 0; + m_wholeRowsVisible = 0; + + m_firstPaint = TRUE; + m_inOnKeyDown = FALSE; + m_batchCount = 0; + + m_cursorMode = WXGRID_CURSOR_DEFAULT; + m_dragLastPos = -1; + m_dragRowOrCol = -1; + m_isDragging = FALSE; + + m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS ); + m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE ); + + m_currentCellCoords = wxGridNoCellCoords; + m_currentCellHighlighted = FALSE; + + m_selectedTopLeft = wxGridNoCellCoords; + m_selectedBottomRight = wxGridNoCellCoords; + + m_editable = TRUE; // default for whole grid + + // TODO: extend this to other types of controls + // + m_cellEditCtrl = new wxGridTextCtrl( this, + TRUE, + wxGRID_CELLCTRL, + "", + wxPoint(1,1), + wxSize(1,1), + wxNO_BORDER +#ifdef __WXMSW__ + | wxTE_MULTILINE | wxTE_NO_VSCROLL +#endif + ); + + m_cellEditCtrl->Show( FALSE ); + m_cellEditCtrlEnabled = TRUE; + m_editCtrlType = wxGRID_TEXTCTRL; + + // Not really needed here, it gets called by OnSize() + // + // CalcDimensions(); +} + + +void wxGrid::CalcDimensions() +{ + int i; + + if ( IsTopEditControlEnabled() ) + { + int ctrlW, ctrlH; + m_topEditCtrl->GetSize( &ctrlW, &ctrlH ); + + m_top = ctrlH + 20; + } + else + { + m_top = 0; + } + + int bottom = m_top + m_colLabelHeight; + for ( i = m_scrollPosY; i < m_numRows; i++ ) + { + bottom += m_rowHeights[i]; + m_rowBottoms[i] = bottom; + } + + int right = m_left + m_rowLabelWidth; + for ( i = m_scrollPosX; i < m_numCols; i++ ) + { + right += m_colWidths[i]; + m_colRights[i] = right; + } + + // adjust the scroll bars + // + + int cw, ch; + GetClientSize(&cw, &ch); + + // begin by assuming that we don't need either scroll bar + // + int vertScrollBarWidth = 0; + int horizScrollBarHeight = 0; + + // Each scroll bar needs to eventually know if the other one is + // required in deciding whether or not it is also required - hence + // this loop. A bit inelegant but simple and it works. + // + int check; + for ( check = 0; check < 2; check++ ) + { + if ( m_numRows > 0 && + m_rowBottoms[m_numRows-1] + horizScrollBarHeight > ch ) + { + vertScrollBarWidth = m_scrollBarWidth; + + m_wholeRowsVisible = 0; + for ( i = m_scrollPosY; i < m_numRows; i++ ) + { + // A partial row doesn't count, we still have to scroll to + // see the rest of it + if ( m_rowBottoms[i] + horizScrollBarHeight > ch ) break; + + m_wholeRowsVisible++ ; + } + } + else + { + m_wholeRowsVisible = m_numRows - m_scrollPosY; + if ( m_scrollPosY ) + { + vertScrollBarWidth = m_scrollBarWidth; + } + } + + + if ( m_numCols && + m_colRights[m_numCols-1] + vertScrollBarWidth > cw) + { + horizScrollBarHeight = m_scrollBarWidth; + + m_wholeColsVisible = 0; + for ( i = m_scrollPosX; i < m_numCols; i++ ) + { + // A partial col doesn't count, we still have to scroll to + // see the rest of it + if ( m_colRights[i] + vertScrollBarWidth > cw ) break; + + m_wholeColsVisible++ ; + } + } + else + { + // we can see the right-most column + // + m_wholeColsVisible = m_numCols - m_scrollPosX; + if ( m_scrollPosX ) + { + horizScrollBarHeight = m_scrollBarWidth; + } + } + } + + + if ( m_vertScrollBar ) + { + if ( !vertScrollBarWidth ) + { + m_vertScrollBar->Show(FALSE); + } + else + { + m_vertScrollBar->Show(TRUE); + m_vertScrollBar->SetScrollbar( + m_scrollPosY, + wxMax(m_wholeRowsVisible, 1), + (m_wholeRowsVisible == 0 ? 1 : m_numRows), + wxMax(m_wholeRowsVisible, 1) ); + + m_vertScrollBar->SetSize( cw - m_scrollBarWidth, + m_top, + m_scrollBarWidth, + ch - m_top - horizScrollBarHeight); + } + } + + if ( m_horizScrollBar ) + { + if ( !horizScrollBarHeight ) + { + m_horizScrollBar->Show(FALSE); + } + else + { + m_horizScrollBar->Show(TRUE); + + m_horizScrollBar->SetScrollbar( + m_scrollPosX, + wxMax(m_wholeColsVisible, 1), + (m_wholeColsVisible == 0) ? 1 : m_numCols, + wxMax(m_wholeColsVisible, 1) ); + + m_horizScrollBar->SetSize( m_left, + ch - m_scrollBarWidth, + cw - m_left - vertScrollBarWidth, + m_scrollBarWidth ); + } + } + + m_bottom = m_right = 0; + if ( m_numRows > 0 ) + { + m_bottom = wxMin( m_rowBottoms[m_numRows-1], + ch - horizScrollBarHeight ); + } + if ( m_numCols > 0 ) + { + m_right = wxMin( m_colRights[m_numCols-1], + cw - vertScrollBarWidth ); + } +} + + +bool wxGrid::IsOnScreen() +{ + int cw, ch; + GetClientSize( &cw, &ch ); + return ( cw > 10 ); +} + + +// this is called when the grid table sends a message to say that it +// has been redimensioned +// +bool wxGrid::Redimension( wxGridTableMessage& msg ) +{ + int i; + + switch ( msg.GetId() ) + { + case wxGRIDTABLE_NOTIFY_ROWS_INSERTED: + { + size_t pos = msg.GetCommandInt(); + int numRows = msg.GetCommandInt2(); + for ( i = 0; i < numRows; i++ ) + { + m_rowHeights.Insert( m_defaultRowHeight, pos ); + m_rowBottoms.Insert( 0, pos ); + } + m_numRows += numRows; + CalcDimensions(); + } + return TRUE; + + case wxGRIDTABLE_NOTIFY_ROWS_APPENDED: + { + int numRows = msg.GetCommandInt(); + for ( i = 0; i < numRows; i++ ) + { + m_rowHeights.Add( m_defaultRowHeight ); + m_rowBottoms.Add( 0 ); + } + m_numRows += numRows; + CalcDimensions(); + } + return TRUE; + + case wxGRIDTABLE_NOTIFY_ROWS_DELETED: + { + size_t pos = msg.GetCommandInt(); + int numRows = msg.GetCommandInt2(); + for ( i = 0; i < numRows; i++ ) + { + m_rowHeights.Remove( pos ); + m_rowBottoms.Remove( pos ); + } + m_numRows -= numRows; + + // TODO: improve these adjustments... + // + if ( m_scrollPosY >= m_numRows ) + m_scrollPosY = 0; + + if ( !m_numRows ) + { + m_numCols = 0; + m_colWidths.Clear(); + m_colRights.Clear(); + m_currentCellCoords = wxGridNoCellCoords; + } + else if ( m_currentCellCoords.GetRow() >= m_numRows ) + { + m_currentCellCoords.Set( 0, 0 ); + } + CalcDimensions(); + } + return TRUE; + + case wxGRIDTABLE_NOTIFY_COLS_INSERTED: + { + size_t pos = msg.GetCommandInt(); + int numCols = msg.GetCommandInt2(); + for ( i = 0; i < numCols; i++ ) + { + m_colWidths.Insert( m_defaultColWidth, pos ); + m_colRights.Insert( 0, pos ); + } + m_numCols += numCols; + CalcDimensions(); + } + return TRUE; + + case wxGRIDTABLE_NOTIFY_COLS_APPENDED: + { + int numCols = msg.GetCommandInt(); + for ( i = 0; i < numCols; i++ ) + { + m_colWidths.Add( m_defaultColWidth ); + m_colRights.Add( 0 ); + } + m_numCols += numCols; + CalcDimensions(); + } + return TRUE; + + case wxGRIDTABLE_NOTIFY_COLS_DELETED: + { + size_t pos = msg.GetCommandInt(); + int numCols = msg.GetCommandInt2(); + for ( i = 0; i < numCols; i++ ) + { + m_colWidths.Remove( pos ); + m_colRights.Remove( pos ); + } + m_numCols -= numCols; + // + // TODO: improve these adjustments... + // + if ( m_scrollPosX >= m_numCols ) + m_scrollPosX = 0; + + if ( !m_numCols ) + { +#if 0 // leave the row alone here so that AppendCols will work subsequently + m_numRows = 0; + m_rowHeights.Clear(); + m_rowBottoms.Clear(); +#endif + m_currentCellCoords = wxGridNoCellCoords; + } + else if ( m_currentCellCoords.GetCol() >= m_numCols ) + { + m_currentCellCoords.Set( 0, 0 ); + } + CalcDimensions(); + } + return TRUE; + } + + return FALSE; +} + + +// +// ----- event handlers +// + +// Generate a grid event based on a mouse event and +// return the result of ProcessEvent() +// +bool wxGrid::SendEvent( const wxEventType type, + int row, int col, + wxMouseEvent& mouseEv ) +{ + if ( type == EVT_WXGRID_ROW_SIZE || + type == EVT_WXGRID_COL_SIZE ) + { + int rowOrCol = (row == -1 ? col : row); + + wxGridSizeEvent gridEvt( GetId(), + type, + this, + rowOrCol, + mouseEv.GetX(), mouseEv.GetY(), + mouseEv.ControlDown(), + mouseEv.ShiftDown(), + mouseEv.AltDown(), + mouseEv.MetaDown() ); + + return GetEventHandler()->ProcessEvent(gridEvt); + } + else if ( type == EVT_WXGRID_RANGE_SELECT ) + { + wxGridRangeSelectEvent gridEvt( GetId(), + type, + this, + m_selectedTopLeft, + m_selectedBottomRight, + mouseEv.ControlDown(), + mouseEv.ShiftDown(), + mouseEv.AltDown(), + mouseEv.MetaDown() ); + + return GetEventHandler()->ProcessEvent(gridEvt); + } + else + { + wxGridEvent gridEvt( GetId(), + type, + this, + row, col, + mouseEv.GetX(), mouseEv.GetY(), + mouseEv.ControlDown(), + mouseEv.ShiftDown(), + mouseEv.AltDown(), + mouseEv.MetaDown() ); + + return GetEventHandler()->ProcessEvent(gridEvt); + } +} + + +// Generate a grid event of specified type and return the result +// of ProcessEvent(). +// +bool wxGrid::SendEvent( const wxEventType type, + int row, int col ) +{ + if ( type == EVT_WXGRID_ROW_SIZE || + type == EVT_WXGRID_COL_SIZE ) + { + int rowOrCol = (row == -1 ? col : row); + + wxGridSizeEvent gridEvt( GetId(), + type, + this, + rowOrCol ); + + return GetEventHandler()->ProcessEvent(gridEvt); + } + else + { + wxGridEvent gridEvt( GetId(), + type, + this, + row, col ); + + return GetEventHandler()->ProcessEvent(gridEvt); + } +} + + +void wxGrid::OnPaint( wxPaintEvent& ev ) +{ + wxPaintDC dc( this ); + + if ( !m_batchCount ) + { + // define a clipping region to avoid painting over the scroll bars + // + int vs = 0; + if ( m_vertScrollBar && m_vertScrollBar->IsShown() ) + vs = m_scrollBarWidth; + + int hs = 0; + if ( m_horizScrollBar && m_horizScrollBar->IsShown() ) + hs = m_scrollBarWidth; + + int cw, ch; + GetClientSize( &cw, &ch ); + dc.SetClippingRegion( 0, 0, cw - vs, ch - hs ); + + HideCurrentCellHighlight( dc ); + + DrawLabelAreas( dc ); + DrawColLabels( dc ); + DrawRowLabels( dc ); + DrawCellArea( dc ); + DrawGridLines( dc ); + DrawCells( dc ); + + // TODO: something more elegant than this... + // + if ( m_firstPaint ) + { + if ( m_currentCellCoords == wxGridNoCellCoords ) + m_currentCellCoords.Set(0, 0); + + SetEditControlValue(); + ShowCellEditControl(); + m_firstPaint = FALSE; + } + + ShowCurrentCellHighlight( dc ); + + dc.DestroyClippingRegion(); + } +} + + +void wxGrid::OnSize( wxSizeEvent& ev ) +{ + CalcDimensions(); +} + + +void wxGrid::OnMouse( wxMouseEvent& ev ) +{ + int x = ev.GetX(); + int y = ev.GetY(); + int row, col; + + // ------------------------------------------------------------ + // + // Mouse dragging + // + if ( ev.Dragging() ) + { + m_isDragging = TRUE; + + if ( ev.LeftIsDown() ) + { + switch( m_cursorMode ) + { + case WXGRID_CURSOR_SELECT_CELL: + { + wxGridCellCoords cellCoords; + XYToCell( x, y, cellCoords ); + if ( cellCoords != wxGridNoCellCoords ) + { + if ( !IsSelection() ) + { + SelectBlock( cellCoords, cellCoords ); + } + else if ( !IsInSelection( cellCoords ) ) + { + SelectBlock( m_currentCellCoords, cellCoords ); + } + } + } + break; + + case WXGRID_CURSOR_RESIZE_ROW: + { + wxClientDC dc(this); + dc.SetLogicalFunction(wxXOR); + if ( m_dragLastPos >= 0 ) + { + dc.DrawLine( m_left, m_dragLastPos, + m_right, m_dragLastPos ); + } + dc.DrawLine( m_left, ev.GetY(), + m_right, ev.GetY()); + + m_dragLastPos = ev.GetY(); + } + break; + + case WXGRID_CURSOR_RESIZE_COL: + { + wxClientDC dc(this); + dc.SetLogicalFunction(wxINVERT); + if ( m_dragLastPos >= 0 ) + { + dc.DrawLine( m_dragLastPos, m_top, + m_dragLastPos, m_bottom ); + } + dc.DrawLine( ev.GetX(), m_top, + ev.GetX(), m_bottom ); + + m_dragLastPos = ev.GetX(); + } + break; + + case WXGRID_CURSOR_SELECT_ROW: + { + if ( (row = YToRow( y )) >= 0 && + !IsInSelection( row, 0 ) ) + { + SelectRow( row, TRUE ); + } + } + break; + + case WXGRID_CURSOR_SELECT_COL: + { + if ( (col = XToCol( x )) >= 0 && + !IsInSelection( 0, col ) ) + { + SelectCol( col, TRUE ); + } + } + break; + } + } + return; + } + + m_isDragging = FALSE; + + // ------------------------------------------------------------ + // + // Left mouse button down + // + if ( ev.LeftDown() ) + { + row = -1; + col = -1; + wxGridCellCoords cellCoords; + + switch( XYToArea( x, y ) ) + { + case WXGRID_ROWLABEL: + { + // 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 = YToRow(y); + if ( !SendEvent( EVT_WXGRID_LABEL_LEFT_CLICK, row, col, ev ) ) + { + SelectRow( row, ev.ShiftDown() ); + m_cursorMode = WXGRID_CURSOR_SELECT_ROW; + } + } + } + break; + + case WXGRID_COLLABEL: + { + // 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 ) + { + col = XToCol(x); + if ( !SendEvent( EVT_WXGRID_LABEL_LEFT_CLICK, row, col, ev ) ) + { + SelectCol( col, ev.ShiftDown() ); + m_cursorMode = WXGRID_CURSOR_SELECT_COL; + } + } + } + break; + + case WXGRID_CORNERLABEL: + { + // leave both row and col as -1 + // + if ( !SendEvent( EVT_WXGRID_LABEL_LEFT_CLICK, row, col, ev ) ) + { + SelectAll(); + } + } + break; + + case WXGRID_CELL: + { + XYToCell( x, y, cellCoords ); + if ( !SendEvent( EVT_WXGRID_CELL_LEFT_CLICK, + cellCoords.GetRow(), + cellCoords.GetCol(), + ev ) ) + { + MakeCellVisible( cellCoords ); + SelectCell( cellCoords ); + } + } + break; + + default: +#if 0 + wxLogMessage( "outside grid area" ); +#endif + break; + } + } + // ------------------------------------------------------------ + // + // Left mouse button double click + // + else if ( ev.LeftDClick() ) + { + row = -1; + col = -1; + wxGridCellCoords cellCoords; + + switch( XYToArea( x, y ) ) + { + case WXGRID_ROWLABEL: + { + // 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 = YToRow(y); + SendEvent( EVT_WXGRID_LABEL_LEFT_DCLICK, row, col, ev ); + } + } + break; + + case WXGRID_COLLABEL: + { + // 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 ) + { + col = XToCol(x); + SendEvent( EVT_WXGRID_LABEL_LEFT_DCLICK, row, col, ev ); + } + } + break; + + case WXGRID_CORNERLABEL: + { + // leave both row and col as -1 + // + SendEvent( EVT_WXGRID_LABEL_LEFT_DCLICK, row, col, ev ); + } + break; + + case WXGRID_CELL: + { + XYToCell( x, y, cellCoords ); + SendEvent( EVT_WXGRID_CELL_LEFT_DCLICK, + cellCoords.GetRow(), + cellCoords.GetCol(), + ev ); + } + break; + + default: +#if 0 + wxLogMessage( "outside grid area" ); +#endif + break; + } + } + // ------------------------------------------------------------ + // + // Left mouse button released + // + else if ( ev.LeftUp() ) + { + switch ( m_cursorMode ) + { + case WXGRID_CURSOR_RESIZE_ROW: + { + if ( m_dragLastPos >= 0 ) + { + // erase the last line and resize the row + // + wxClientDC dc( this ); + dc.SetLogicalFunction( wxINVERT ); + dc.DrawLine( m_left, m_dragLastPos, + m_right, m_dragLastPos ); + HideCellEditControl(); + int top = m_top + m_colLabelHeight; + if ( m_dragRowOrCol > 0 ) + top = m_rowBottoms[m_dragRowOrCol-1]; + m_rowHeights[m_dragRowOrCol] = wxMax( ev.GetY() - top, + WXGRID_MIN_ROW_HEIGHT ); + CalcDimensions(); + ShowCellEditControl(); + Refresh(); + + // Note: we are ending the event *after* doing + // default processing in this case + // + SendEvent( EVT_WXGRID_ROW_SIZE, m_dragRowOrCol, -1, ev ); + } + } + break; + + case WXGRID_CURSOR_RESIZE_COL: + { + if ( m_dragLastPos >= 0 ) + { + // erase the last line and resize the col + // + wxClientDC dc( this ); + dc.SetLogicalFunction( wxINVERT ); + dc.DrawLine( m_left, m_dragLastPos, + m_right, m_dragLastPos ); + HideCellEditControl(); + int left = m_left + m_rowLabelWidth; + if ( m_dragRowOrCol > 0 ) + left = m_colRights[m_dragRowOrCol-1]; + m_colWidths[m_dragRowOrCol] = wxMax( ev.GetX() - left, + WXGRID_MIN_COL_WIDTH ); + CalcDimensions(); + ShowCellEditControl(); + Refresh(); + + // Note: we are ending the event *after* doing + // default processing in this case + // + SendEvent( EVT_WXGRID_COL_SIZE, -1, m_dragRowOrCol, ev ); + } + } + break; + + case WXGRID_CURSOR_SELECT_CELL: + { + if ( IsSelection() ) + { + // Note: we are ending the event *after* doing + // default processing in this case + // + SendEvent( EVT_WXGRID_RANGE_SELECT, -1, -1, ev ); + } + } + break; + } + + m_dragLastPos = -1; + } + // ------------------------------------------------------------ + // + // Right mouse button down + // + else if ( ev.RightDown() ) + { + row = -1; + col = -1; + wxGridCellCoords cellCoords; + + switch( XYToArea( x, y ) ) + { + + case WXGRID_ROWLABEL: + { + row = YToRow(y); + if ( !SendEvent( EVT_WXGRID_LABEL_RIGHT_CLICK, row, col, ev ) ) + { + // TODO: default processing ? + } + } + break; + + case WXGRID_COLLABEL: + { + col = XToCol(x); + if ( !SendEvent( EVT_WXGRID_LABEL_RIGHT_CLICK, row, col, ev ) ) + { + // TODO: default processing ? + } + } + break; + + case WXGRID_CORNERLABEL: + { + // leave both row and col as -1 + // + if ( !SendEvent( EVT_WXGRID_LABEL_RIGHT_CLICK, row, col, ev ) ) + { + // TODO: default processing ? + } + } + break; + + case WXGRID_CELL: + { + XYToCell( x, y, cellCoords ); + if ( !SendEvent( EVT_WXGRID_CELL_RIGHT_CLICK, + cellCoords.GetRow(), + cellCoords.GetCol(), + ev ) ) + { + // TODO: default processing ? + } + } + break; + + default: +#if 0 + wxLogMessage( "outside grid area" ); +#endif + break; + } + } + // ------------------------------------------------------------ + // + // Right mouse button double click + // + else if ( ev.RightDClick() ) + { + row = -1; + col = -1; + wxGridCellCoords cellCoords; + + switch( XYToArea( x, y ) ) + { + + case WXGRID_ROWLABEL: + { + row = YToRow(y); + SendEvent( EVT_WXGRID_LABEL_RIGHT_DCLICK, row, col, ev ); + } + break; + + case WXGRID_COLLABEL: + { + col = XToCol(x); + SendEvent( EVT_WXGRID_LABEL_RIGHT_DCLICK, row, col, ev ); + } + break; + + case WXGRID_CORNERLABEL: + { + // leave both row and col as -1 + // + SendEvent( EVT_WXGRID_LABEL_RIGHT_DCLICK, row, col, ev ); + } + break; + + case WXGRID_CELL: + { + XYToCell( x, y, cellCoords ); + SendEvent( EVT_WXGRID_CELL_RIGHT_DCLICK, + cellCoords.GetRow(), + cellCoords.GetCol(), + ev ); + } + break; + + default: +#if 0 + wxLogMessage( "outside grid area" ); +#endif + break; + } + } + // ------------------------------------------------------------ + // + // No buttons down and mouse moving + // + else if ( ev.Moving() ) + { + switch( XYToArea( x, y ) ) + { + case WXGRID_ROWLABEL: + { + m_dragRowOrCol = YToEdgeOfRow( y ); + if ( m_dragRowOrCol >= 0 ) + { + if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) + { + m_cursorMode = WXGRID_CURSOR_RESIZE_ROW; + SetCursor( m_rowResizeCursor ); + } + } + else + { + if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL ) + { + m_cursorMode = WXGRID_CURSOR_SELECT_CELL; + SetCursor( *wxSTANDARD_CURSOR ); + } + } + } + break; + + case WXGRID_COLLABEL: + { + m_dragRowOrCol = XToEdgeOfCol( x ); + if ( m_dragRowOrCol >= 0 ) + { + if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) + { + m_cursorMode = WXGRID_CURSOR_RESIZE_COL; + SetCursor( m_colResizeCursor ); + } + } + else + { + if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL ) + { + m_cursorMode = WXGRID_CURSOR_SELECT_CELL; + SetCursor( *wxSTANDARD_CURSOR ); + } + } + } + break; + + default: + { + if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL ) + { + m_cursorMode = WXGRID_CURSOR_SELECT_CELL; + SetCursor( *wxSTANDARD_CURSOR ); + } + } + break; + } + } +} + + +void wxGrid::OnKeyDown( wxKeyEvent& ev ) +{ + if ( m_inOnKeyDown ) + { + // shouldn't be here - we are going round in circles... + // + wxLogFatalError( "wxGrid::OnKeyDown called while alread active" ); + } + + m_inOnKeyDown = TRUE; + + // propagate the event up and see if it gets processed + // + wxWindow *parent = GetParent(); + wxKeyEvent keyEvt( ev ); + keyEvt.SetEventObject( parent ); + + if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) ) + { + // try local handlers + // + switch ( ev.KeyCode() ) + { + case WXK_UP: + if ( ev.ControlDown() ) + { + MoveCursorUpBlock(); + } + else + { + MoveCursorUp(); + } + break; + + case WXK_DOWN: + if ( ev.ControlDown() ) + { + MoveCursorDownBlock(); + } + else + { + MoveCursorDown(); + } + break; + + case WXK_LEFT: + if ( ev.ControlDown() ) + { + MoveCursorLeftBlock(); + } + else + { + MoveCursorLeft(); + } + break; + + case WXK_RIGHT: + if ( ev.ControlDown() ) + { + MoveCursorRightBlock(); + } + else + { + MoveCursorRight(); + } + break; + + case WXK_RETURN: + MoveCursorDown(); + break; + + case WXK_HOME: + if ( ev.ControlDown() ) + { + MakeCellVisible( 0, 0 ); + SelectCell( 0, 0 ); + } + else + { + ev.Skip(); + } + break; + + case WXK_END: + if ( ev.ControlDown() ) + { + MakeCellVisible( m_numRows-1, m_numCols-1 ); + SelectCell( m_numRows-1, m_numCols-1 ); + } + else + { + ev.Skip(); + } + break; + + default: + // now try the cell edit control + // + if ( IsCellEditControlEnabled() ) + { + ev.SetEventObject( m_cellEditCtrl ); + m_cellEditCtrl->GetEventHandler()->ProcessEvent( ev ); + } + break; + } + } + + m_inOnKeyDown = FALSE; +} + + +// Text updated in an edit control - either a text control or a +// combo box +// +void wxGrid::OnText( wxKeyEvent& ev ) +{ + if ( !m_inOnText ) + { + m_inOnText = TRUE; + wxWindow *ctrl = (wxWindow *)ev.GetEventObject(); + + if ( ctrl == m_cellEditCtrl && + IsTopEditControlEnabled() ) + { + // set the value of the top edit control + // + switch ( m_editCtrlType ) + { + case wxGRID_TEXTCTRL: + ((wxTextCtrl *)m_topEditCtrl)-> + SetValue(((wxTextCtrl *)ctrl)->GetValue()); + break; + + case wxGRID_COMBOBOX: + ((wxComboBox *)m_topEditCtrl)-> + SetValue(((wxComboBox *)ctrl)->GetValue()); + break; + } + } + else if ( ctrl == m_topEditCtrl && + IsCellEditControlEnabled() ) + { + switch ( m_editCtrlType ) + { + case wxGRID_TEXTCTRL: + ((wxTextCtrl *)m_cellEditCtrl)-> + SetValue(((wxTextCtrl *)ctrl)->GetValue()); + break; + + case wxGRID_COMBOBOX: + ((wxComboBox *)m_cellEditCtrl)-> + SetValue(((wxComboBox *)ctrl)->GetValue()); + break; + } + } + } + + m_inOnText = FALSE; +} + +void wxGrid::OnGridScroll( wxScrollEvent& ev ) +{ + // propagate the event up and see if it gets processed + // + wxWindow *parent = GetParent(); + wxScrollEvent scrollEvt( ev ); + if (parent->GetEventHandler()->ProcessEvent( scrollEvt )) return; + + HideCellEditControl(); + + if ( ev.GetEventObject() == m_horizScrollBar ) + { + if ( ev.GetPosition() != m_scrollPosX ) + { + SetHorizontalScrollPos( ev.GetPosition() ); + } + } + else + { + if ( ev.GetPosition() != m_scrollPosY ) + { + SetVerticalScrollPos( ev.GetPosition() ); + } + } + + ShowCellEditControl(); +} + + +void wxGrid::SelectCell( const wxGridCellCoords& coords ) +{ + wxClientDC dc( this ); + + if ( m_currentCellCoords != wxGridNoCellCoords ) + { + HideCurrentCellHighlight( dc ); + HideCellEditControl(); + SaveEditControlValue(); + } + + m_currentCellCoords = coords; + + SetEditControlValue(); + if ( IsOnScreen() ) + { + ShowCellEditControl(); + ShowCurrentCellHighlight( dc ); + } + + if ( IsSelection() ) + { + ClearSelection(); + if ( !GetBatchCount() ) Refresh(); + } +} + + +void wxGrid::ShowCellEditControl() +{ + wxRect rect; + + if ( IsCellEditControlEnabled() ) + { + if ( !IsVisible( m_currentCellCoords ) ) + { + return; + } + else + { + rect = CellToRect( m_currentCellCoords ); + + m_cellEditCtrl->SetSize( rect ); + m_cellEditCtrl->Show( TRUE ); + + switch ( m_editCtrlType ) + { + case wxGRID_TEXTCTRL: + ((wxTextCtrl *) m_cellEditCtrl)->SetInsertionPointEnd(); + break; + + case wxGRID_CHECKBOX: + // TODO: anything ??? + // + break; + + case wxGRID_CHOICE: + // TODO: anything ??? + // + break; + + case wxGRID_COMBOBOX: + // TODO: anything ??? + // + break; + } + + // m_cellEditCtrl->SetFocus(); + } + } +} + + +void wxGrid::HideCellEditControl() +{ + if ( IsCellEditControlEnabled() ) + { + m_cellEditCtrl->Show( FALSE ); + } +} + +void wxGrid::SetEditControlValue( const wxString& value ) +{ + if ( m_table ) + { + wxString s; + s = ( value == wxEmptyString ? GetCellValue(m_currentCellCoords) : value ); + + if ( IsTopEditControlEnabled() ) + { + switch ( m_editCtrlType ) + { + case wxGRID_TEXTCTRL: + ((wxGridTextCtrl *)m_topEditCtrl)->SetStartValue(s); + break; + + case wxGRID_CHECKBOX: + // TODO: implement this + // + break; + + case wxGRID_CHOICE: + // TODO: implement this + // + break; + + case wxGRID_COMBOBOX: + // TODO: implement this + // + break; + } + } + + if ( IsCellEditControlEnabled() ) + { + switch ( m_editCtrlType ) + { + case wxGRID_TEXTCTRL: + ((wxGridTextCtrl *)m_cellEditCtrl)->SetStartValue(s); + break; + + case wxGRID_CHECKBOX: + // TODO: implement this + // + break; + + case wxGRID_CHOICE: + // TODO: implement this + // + break; + + case wxGRID_COMBOBOX: + // TODO: implement this + // + break; + } + } + } +} + +void wxGrid::SaveEditControlValue() +{ + if ( m_table ) + { + wxWindow *ctrl = (wxWindow *)NULL; + + if ( IsCellEditControlEnabled() ) + { + ctrl = m_cellEditCtrl; + } + else if ( IsTopEditControlEnabled() ) + { + ctrl = m_topEditCtrl; + } + else + { + return; + } + + bool valueChanged = FALSE; + + switch ( m_editCtrlType ) + { + case wxGRID_TEXTCTRL: + valueChanged = (((wxGridTextCtrl *)ctrl)->GetValue() != + ((wxGridTextCtrl *)ctrl)->GetStartValue()); + SetCellValue( m_currentCellCoords, + ((wxTextCtrl *) ctrl)->GetValue() ); + break; + + case wxGRID_CHECKBOX: + // TODO: implement this + // + break; + + case wxGRID_CHOICE: + // TODO: implement this + // + break; + + case wxGRID_COMBOBOX: + // TODO: implement this + // + break; + } + + if ( valueChanged ) + { + SendEvent( EVT_WXGRID_CELL_CHANGE, + m_currentCellCoords.GetRow(), + m_currentCellCoords.GetCol() ); + } + } +} + + +int wxGrid::XYToArea( int x, int y ) +{ + if ( x > m_left && x < m_right && + y > m_top && y < m_bottom ) + { + if ( y < m_top + m_colLabelHeight ) + { + if ( x > m_left + m_rowLabelWidth ) + { + return WXGRID_COLLABEL; + } + else + { + return WXGRID_CORNERLABEL; + } + } + else if ( x <= m_left + m_rowLabelWidth ) + { + return WXGRID_ROWLABEL; + } + else + { + return WXGRID_CELL; + } + } + + return WXGRID_NOAREA; +} + + +void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords ) +{ + coords.SetRow( YToRow(y) ); + coords.SetCol( XToCol(x) ); +} + + +int wxGrid::YToRow( int y ) +{ + int i; + + if ( y > m_top + m_colLabelHeight ) + { + for ( i = m_scrollPosY; i < m_numRows; i++ ) + { + if ( y < m_rowBottoms[i] ) + { + return i; + } + } + } + + return -1; +} + + +int wxGrid::XToCol( int x ) +{ + int i; + + if ( x > m_left + m_rowLabelWidth ) + { + for ( i = m_scrollPosX; i < m_numCols; i++ ) + { + if ( x < m_colRights[i] ) + { + return i; + } + } + } + + return -1; +} + + +// return the row number that that the y coord is near the edge of, or +// -1 if not near an edge +// +int wxGrid::YToEdgeOfRow( int y ) +{ + int i, d; + + if ( y > m_top + m_colLabelHeight ) + { + for ( i = m_scrollPosY; i < m_numRows; i++ ) + { + if ( m_rowHeights[i] > WXGRID_LABEL_EDGE_ZONE ) + { + d = abs( y - m_rowBottoms[i] ); + { + if ( d < WXGRID_LABEL_EDGE_ZONE ) return i; + } + } + } + } + + return -1; + +} + + +// return the col number that that the x coord is near the edge of, or +// -1 if not near an edge +// +int wxGrid::XToEdgeOfCol( int x ) +{ + int i, d; + + if ( x > m_left + m_rowLabelWidth ) + { + for ( i = m_scrollPosX; i < m_numCols; i++ ) + { + if ( m_colWidths[i] > WXGRID_LABEL_EDGE_ZONE ) + { + d = abs( x - m_colRights[i] ); + { + if ( d < WXGRID_LABEL_EDGE_ZONE ) return i; + } + } + } + } + + return -1; + +} + + +wxRect wxGrid::CellToRect( int row, int col ) +{ + wxRect rect( -1, -1, -1, -1 ); + + if ( row >= m_scrollPosY && col >= m_scrollPosX ) + { + rect.x = m_colRights[col] - m_colWidths[col]; + rect.y = m_rowBottoms[row] - m_rowHeights[row]; + rect.width = m_colWidths[col]; + rect.height = m_rowHeights[ row ]; + } + + return rect; +} + + +bool wxGrid::MoveCursorUp() +{ + if ( m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetRow() > 0 ) + { + SelectCell( m_currentCellCoords.GetRow() - 1, + m_currentCellCoords.GetCol() ); + + if ( !IsVisible( m_currentCellCoords ) ) + MakeCellVisible( m_currentCellCoords ); + + return TRUE; + } + + return FALSE; +} + +bool wxGrid::MoveCursorDown() +{ + // TODO: allow for scrolling + // + if ( m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetRow() < m_numRows-1 ) + { + SelectCell( m_currentCellCoords.GetRow() + 1, + m_currentCellCoords.GetCol() ); + + if ( !IsVisible( m_currentCellCoords ) ) + MakeCellVisible( m_currentCellCoords ); + + return TRUE; + } + + return FALSE; +} + +bool wxGrid::MoveCursorLeft() +{ + if ( m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetCol() > 0 ) + { + SelectCell( m_currentCellCoords.GetRow(), + m_currentCellCoords.GetCol() - 1 ); + + if ( !IsVisible( m_currentCellCoords ) ) + MakeCellVisible( m_currentCellCoords ); + + return TRUE; + } + + return FALSE; +} + +bool wxGrid::MoveCursorRight() +{ + if ( m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetCol() < m_numCols - 1 ) + { + SelectCell( m_currentCellCoords.GetRow(), + m_currentCellCoords.GetCol() + 1 ); + + if ( !IsVisible( m_currentCellCoords ) ) + MakeCellVisible( m_currentCellCoords ); + + return TRUE; + } + + return FALSE; +} + +bool wxGrid::MoveCursorUpBlock() +{ + if ( m_table && + m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetRow() > 0 ) + { + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + + if ( m_table->IsEmptyCell(row, col) ) + { + // starting in an empty cell: find the next block of + // non-empty cells + // + while ( row > 0 ) + { + row-- ; + if ( !(m_table->IsEmptyCell(row, col)) ) break; + } + } + else if ( m_table->IsEmptyCell(row-1, col) ) + { + // starting at the top of a block: find the next block + // + row--; + while ( row > 0 ) + { + row-- ; + if ( !(m_table->IsEmptyCell(row, col)) ) break; + } + } + else + { + // starting within a block: find the top of the block + // + while ( row > 0 ) + { + row-- ; + if ( m_table->IsEmptyCell(row, col) ) + { + row++ ; + break; + } + } + } + + SelectCell( row, col ); + + if ( !IsVisible( m_currentCellCoords ) ) + MakeCellVisible( m_currentCellCoords ); + + return TRUE; + } + + return FALSE; +} + +bool wxGrid::MoveCursorDownBlock() +{ + if ( m_table && + m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetRow() < m_numRows-1 ) + { + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + + if ( m_table->IsEmptyCell(row, col) ) + { + // starting in an empty cell: find the next block of + // non-empty cells + // + while ( row < m_numRows-1 ) + { + row++ ; + if ( !(m_table->IsEmptyCell(row, col)) ) break; + } + } + else if ( m_table->IsEmptyCell(row+1, col) ) + { + // starting at the bottom of a block: find the next block + // + row++; + while ( row < m_numRows-1 ) + { + row++ ; + if ( !(m_table->IsEmptyCell(row, col)) ) break; + } + } + else + { + // starting within a block: find the bottom of the block + // + while ( row < m_numRows-1 ) + { + row++ ; + if ( m_table->IsEmptyCell(row, col) ) + { + row-- ; + break; + } + } + } + + SelectCell( row, col ); + + if ( !IsVisible( m_currentCellCoords ) ) + MakeCellVisible( m_currentCellCoords ); + + return TRUE; + } + + return FALSE; +} + +bool wxGrid::MoveCursorLeftBlock() +{ + if ( m_table && + m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetCol() > 0 ) + { + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + + if ( m_table->IsEmptyCell(row, col) ) + { + // starting in an empty cell: find the next block of + // non-empty cells + // + while ( col > 0 ) + { + col-- ; + if ( !(m_table->IsEmptyCell(row, col)) ) break; + } + } + else if ( m_table->IsEmptyCell(row, col-1) ) + { + // starting at the left of a block: find the next block + // + col--; + while ( col > 0 ) + { + col-- ; + if ( !(m_table->IsEmptyCell(row, col)) ) break; + } + } + else + { + // starting within a block: find the left of the block + // + while ( col > 0 ) + { + col-- ; + if ( m_table->IsEmptyCell(row, col) ) + { + col++ ; + break; + } + } + } + + SelectCell( row, col ); + + if ( !IsVisible( m_currentCellCoords ) ) + MakeCellVisible( m_currentCellCoords ); + + return TRUE; + } + + return FALSE; +} + +bool wxGrid::MoveCursorRightBlock() +{ + if ( m_table && + m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetCol() < m_numCols-1 ) + { + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + + if ( m_table->IsEmptyCell(row, col) ) + { + // starting in an empty cell: find the next block of + // non-empty cells + // + while ( col < m_numCols-1 ) + { + col++ ; + if ( !(m_table->IsEmptyCell(row, col)) ) break; + } + } + else if ( m_table->IsEmptyCell(row, col+1) ) + { + // starting at the right of a block: find the next block + // + col++; + while ( col < m_numCols-1 ) + { + col++ ; + if ( !(m_table->IsEmptyCell(row, col)) ) break; + } + } + else + { + // starting within a block: find the right of the block + // + while ( col < m_numCols-1 ) + { + col++ ; + if ( m_table->IsEmptyCell(row, col) ) + { + col-- ; + break; + } + } + } + + SelectCell( row, col ); + + if ( !IsVisible( m_currentCellCoords ) ) + MakeCellVisible( m_currentCellCoords ); + + return TRUE; + } + + return FALSE; +} + + + +// +// ----- grid drawing functions +// + +void wxGrid::DrawLabelAreas( wxDC& dc ) +{ + int cw, ch; + GetClientSize(&cw, &ch); + + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush( wxBrush(GetLabelBackgroundColour(), wxSOLID) ); + + dc.DrawRectangle( m_left, m_top, + cw - m_left, m_colLabelHeight ); + + dc.DrawRectangle( m_left, m_top, + m_rowLabelWidth, ch - m_top ); +} + + +void wxGrid::DrawColLabels( wxDC& dc ) +{ + int cw, ch; + GetClientSize(&cw, &ch); + + if (m_colLabelHeight == 0) return; + + DrawColLabelBorders( dc ); + + wxRect rect; + rect.y = m_top + 1; + rect.height = m_colLabelHeight - 1; + + int labelLeft = m_left + m_rowLabelWidth; + int i; + + for ( i = m_scrollPosX; i < m_numCols; i++ ) + { + if ( labelLeft > cw) break; + + rect.x = 1 + labelLeft; + rect.width = m_colWidths[i]; + DrawColLabel( dc, rect, i ); + + labelLeft += m_colWidths[i]; + } +} + + +void wxGrid::DrawColLabelBorders( wxDC& dc ) +{ + if ( m_colLabelHeight <= 0 ) return; + + int i; + int cw, ch; + GetClientSize( &cw, &ch ); + + dc.SetPen( *wxBLACK_PEN ); + + // horizontal lines + // + dc.DrawLine( m_left, m_top, cw, m_top ); + + dc.DrawLine( m_left, m_top + m_colLabelHeight, + cw, m_top + m_colLabelHeight ); + + // vertical lines + // + int colLeft = m_left + m_rowLabelWidth; + for ( i = m_scrollPosX; i <= m_numCols; i++ ) + { + if (colLeft > cw) break; + + dc.DrawLine( colLeft, m_top, + colLeft, m_top + m_colLabelHeight); + + if ( i < m_numCols ) colLeft += m_colWidths[i]; + } + + // Draw white highlights for a 3d effect + // + dc.SetPen( *wxWHITE_PEN ); + + colLeft = m_left + m_rowLabelWidth; + for ( i = m_scrollPosX; i < m_numCols; i++ ) + { + if (colLeft > cw) break; + + dc.DrawLine(colLeft + 1, m_top + 1, + colLeft + m_colWidths[i], m_top + 1); + + dc.DrawLine(colLeft + 1, m_top + 1, + colLeft + 1, m_top + m_colLabelHeight); + + colLeft += m_colWidths[i]; + } +} + + +void wxGrid::DrawColLabel( wxDC& dc, const wxRect& rect, int col ) +{ + wxRect rect2; + rect2 = rect; + rect2.x += 3; + rect2.y += 2; + rect2.width -= 5; + rect2.height -= 4; + + dc.SetBackgroundMode( wxTRANSPARENT ); + dc.SetTextBackground( GetLabelBackgroundColour() ); + dc.SetTextForeground( GetLabelTextColour() ); + dc.SetFont( GetLabelFont() ); + + int hAlign, vAlign; + GetColLabelAlignment( &hAlign, &vAlign ); + DrawTextRectangle( dc, GetColLabelValue( col ), rect2, hAlign, vAlign ); +} + + +void wxGrid::DrawRowLabels( wxDC& dc ) +{ + int cw, ch; + GetClientSize(&cw, &ch); + + if (m_rowLabelWidth == 0) return; + + DrawRowLabelBorders( dc ); + + wxRect rect; + rect.x = m_left + 1; + rect.width = m_rowLabelWidth - 1; + + int labelTop = m_top + m_colLabelHeight; + int i; + + for ( i = m_scrollPosY; i < m_numRows; i++ ) + { + if ( labelTop > ch ) break; + + rect.y = 1 + labelTop; + rect.height = m_rowHeights[i]; + DrawRowLabel( dc, rect, i ); + + labelTop += m_rowHeights[i]; + } +} + + +void wxGrid::DrawRowLabelBorders( wxDC& dc ) +{ + if ( m_rowLabelWidth <= 0 ) return; + + int i; + int cw, ch; + GetClientSize( &cw, &ch ); + + dc.SetPen( *wxBLACK_PEN ); + + // vertical lines + // + dc.DrawLine( m_left, m_top, m_left, ch ); + + dc.DrawLine( m_left + m_rowLabelWidth, m_top, + m_left + m_rowLabelWidth, ch ); + + // horizontal lines + // + int rowTop = m_top + m_colLabelHeight; + for ( i = m_scrollPosY; i <= m_numRows; i++ ) + { + if ( rowTop > ch ) break; + + dc.DrawLine( m_left, rowTop, + m_left + m_rowLabelWidth, rowTop ); + + if ( i < m_numRows ) rowTop += m_rowHeights[i]; + } + + // Draw white highlights for a 3d effect + // + dc.SetPen( *wxWHITE_PEN ); + + rowTop = m_top + m_colLabelHeight; + for ( i = m_scrollPosY; i < m_numRows; i++ ) + { + if ( rowTop > ch ) break; + + dc.DrawLine( m_left + 1, rowTop + 1, + m_left + m_rowLabelWidth, rowTop + 1 ); + + dc.DrawLine( m_left + 1, rowTop + 1, + m_left + 1, rowTop + m_rowHeights[i] ); + + rowTop += m_rowHeights[i]; + } +} + + +void wxGrid::DrawRowLabel( wxDC& dc, const wxRect& rect, int row ) +{ + wxRect rect2; + rect2 = rect; + rect2.x += 3; + rect2.y += 2; + rect2.width -= 5; + rect2.height -= 4; + + dc.SetBackgroundMode( wxTRANSPARENT ); + dc.SetTextBackground( GetLabelBackgroundColour() ); + dc.SetTextForeground( GetLabelTextColour() ); + dc.SetFont( GetLabelFont() ); + + int hAlign, vAlign; + GetRowLabelAlignment( &hAlign, &vAlign ); + DrawTextRectangle( dc, GetRowLabelValue( row ), rect2, hAlign, vAlign ); +} + + +void wxGrid::DrawCellArea( wxDC& dc ) +{ + int cw, ch; + GetClientSize(&cw, &ch); + + dc.SetPen( *wxTRANSPARENT_PEN ); + dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) ); + + int left = m_left + m_rowLabelWidth + 1; + int top = m_top + m_colLabelHeight + 1; + + dc.DrawRectangle( left, top, cw - left, ch - top ); +} + + +void wxGrid::DrawGridLines( wxDC& dc ) +{ + if ( !m_gridLinesEnabled || !m_numRows || !m_numCols ) return; + + int i; + int cw, ch; + GetClientSize(&cw, &ch); + + dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) ); + + // horizontal grid lines + // + int rowTop = m_top + m_colLabelHeight + m_rowHeights[m_scrollPosY]; + for ( i = m_scrollPosY + 1; i <= m_numRows; i++ ) + { + if ( rowTop > ch ) break; + + dc.DrawLine( m_left + m_rowLabelWidth + 1, rowTop, + m_right, rowTop); + + if ( i < m_numRows ) rowTop += m_rowHeights[i]; + } + + + // vertical grid lines + // + int colLeft = m_left + m_rowLabelWidth + m_colWidths[m_scrollPosX]; + for ( i = m_scrollPosX + 1; i <= m_numCols; i++ ) + { + if ( colLeft > cw ) break; + + dc.DrawLine( colLeft, m_top + m_colLabelHeight + 1, + colLeft, m_bottom ); + + if ( i < m_numCols ) colLeft += m_colWidths[i]; + } +} + + +void wxGrid::DrawCells( wxDC& dc ) +{ + if ( !m_numRows || !m_numCols ) return; + + int row, col; + + int cw, ch; + GetClientSize( &cw, &ch ); + + wxRect rect; + + if ( m_table ) + { + rect.y = m_top + m_colLabelHeight; + for ( row = m_scrollPosY; row < m_numRows; row++ ) + { + if ( rect.y > ch ) break; + + rect.height = m_rowHeights[ row ]; + rect.x = m_left + m_rowLabelWidth; + + for ( col = m_scrollPosX; col < m_numCols; col++ ) + { + if ( rect.x > cw ) break; + + rect.width = m_colWidths[col]; + DrawCellBackground( dc, rect, row, col ); + DrawCellValue( dc, rect, row, col ); + rect.x += rect.width; + } + rect.y += rect.height; + } + } +} + + +void wxGrid::DrawCellBackground( wxDC& dc, const wxRect& rect, int row, int col ) +{ + wxRect rect2; + rect2 = rect; + rect2.x += 1; + rect2.y += 1; + rect2.width -= 2; + rect2.height -= 2; + + dc.SetBackgroundMode( wxSOLID ); + + if ( IsInSelection( row, col ) ) + { + // TODO: improve this + // + dc.SetBrush( *wxBLACK_BRUSH ); + } + else + { + dc.SetBrush( wxBrush(GetCellBackgroundColour(row, col), wxSOLID) ); + } + dc.SetPen( *wxTRANSPARENT_PEN ); + dc.DrawRectangle( rect2 ); +} + + +void wxGrid::DrawCellValue( wxDC& dc, const wxRect& rect, int row, int col ) +{ + wxRect rect2; + rect2 = rect; + rect2.x += 3; + rect2.y += 2; + rect2.width -= 5; + rect2.height -= 4; + + dc.SetBackgroundMode( wxTRANSPARENT ); + + if ( IsInSelection( row, col ) ) + { + // TODO: improve this + // + dc.SetTextBackground( wxColour(0, 0, 0) ); + dc.SetTextForeground( wxColour(255, 255, 255) ); + } + else + { + dc.SetTextBackground( GetCellBackgroundColour(row, col) ); + dc.SetTextForeground( GetCellTextColour(row, col) ); + } + dc.SetFont( GetCellFont(row, col) ); + + int hAlign, vAlign; + GetCellAlignment( row, col, &hAlign, &vAlign ); + DrawTextRectangle( dc, GetCellValue( row, col ), rect2, hAlign, vAlign ); +} + + +void wxGrid::DrawCellHighlight( wxDC& dc, int row, int col ) +{ + // TODO: bounds checking on row, col ? + // + + if ( row >= m_scrollPosY && col >= m_scrollPosX ) + { + long x, y; + + int cw, ch; + GetClientSize( &cw, &ch ); + + x = m_colRights[col] - m_colWidths[col]; + if ( x >= cw ) return; + + y = m_rowBottoms[row] - m_rowHeights[row]; + if ( y >= ch ) return; + + dc.SetLogicalFunction( wxXOR ); + dc.SetPen( wxPen(GetCellHighlightColour(), 2, wxSOLID) ); + dc.SetBrush( *wxTRANSPARENT_BRUSH ); + + dc.DrawRectangle( x, y, + m_colWidths[col] + 2, + m_rowHeights[row] + 2 ); + + dc.SetLogicalFunction( wxCOPY ); + } +} + + +// This function is handy when you just want to update one or a few +// cells. For example, it is used by SetCellValue() +// +void wxGrid::DrawCell( int row, int col ) +{ + if ( !GetBatchCount() ) + { + if ( !IsVisible( wxGridCellCoords(row, col) ) ) return; + + int cw, ch; + GetClientSize( &cw, &ch ); + + wxRect rect( CellToRect( row, col ) ); + + if ( m_table ) + { + wxClientDC dc( this ); + DrawCellBackground( dc, rect, row, col ); + DrawCellValue( dc, rect, row, col ); + } + } +} + + +// this is just to make other code more obvious +// +void wxGrid::HideCurrentCellHighlight( wxDC& dc ) +{ + if ( m_currentCellHighlighted && + m_currentCellCoords != wxGridNoCellCoords ) + { + DrawCellHighlight( dc, m_currentCellCoords ); + m_currentCellHighlighted = FALSE; + } +} + + +// this is just to make other code more obvious +// +void wxGrid::ShowCurrentCellHighlight( wxDC& dc ) +{ + if ( !m_currentCellHighlighted && + m_currentCellCoords != wxGridNoCellCoords ) + { + DrawCellHighlight( dc, m_currentCellCoords ); + m_currentCellHighlighted = TRUE; + } +} + + +void wxGrid::DrawTextRectangle( wxDC& dc, + const wxString& value, + const wxRect& rect, + int horizAlign, + int vertAlign ) +{ + int i; + long textWidth, textHeight; + long lineWidth, lineHeight; + wxArrayString lines; + + // see if we are already clipping + // + wxRect clipRect; + dc.GetClippingBox( clipRect ); + + bool alreadyClipping = TRUE; + wxRect intersectRect; + + if ( clipRect.x == 0 && clipRect.y == 0 && + clipRect.width == 0 && clipRect.height == 0) + { + alreadyClipping = FALSE; + intersectRect = rect; + } + else + { + // Find the intersection of the clipping rectangle and our + // rectangle + // + wxRegion region( rect ); + region.Intersect( clipRect ); + if ( region.IsEmpty() ) + { + // nothing to do + // + return; + } + intersectRect = region.GetBox(); + } + + if ( alreadyClipping ) dc.DestroyClippingRegion(); + + dc.SetClippingRegion( intersectRect ); + + StringToLines( value, lines ); + if ( lines.GetCount() ) + { + GetTextBoxSize( dc, lines, &textWidth, &textHeight ); + dc.GetTextExtent( lines[0], &lineWidth, &lineHeight ); + + float x, y; + switch ( horizAlign ) + { + case wxRIGHT: + x = rect.x + (rect.width - textWidth - 1.0); + break; + + case wxCENTRE: + x = rect.x + ((rect.width - textWidth)/2.0); + break; + + case wxLEFT: + default: + x = rect.x + 1.0; + break; + } + + switch ( vertAlign ) + { + case wxBOTTOM: + y = rect.y + (rect.height - textHeight - 1); + break; + + case wxCENTRE: + y = rect.y + ((rect.height - textHeight)/2.0); + break; + + case wxTOP: + default: + y = rect.y + 1.0; + break; + } + + for ( i = 0; i < lines.GetCount(); i++ ) + { + dc.DrawText( lines[i], (long)x, (long)y ); + y += lineHeight; + } + } + + dc.DestroyClippingRegion(); + if (alreadyClipping) dc.SetClippingRegion( clipRect ); +} + + +// Split multi line text up into an array of strings. Any existing +// contents of the string array are preserved. +// +void wxGrid::StringToLines( const wxString& value, wxArrayString& lines ) +{ + // TODO: this won't work for WXMAC ? (lines end with '\r') + // + int startPos = 0; + int pos; + while ( startPos < value.Length() ) + { + pos = value.Mid(startPos).Find( '\n' ); + if ( pos < 0 ) + { + break; + } + else if ( pos == 0 ) + { + lines.Add( wxEmptyString ); + } + else + { + if ( value[startPos+pos-1] == '\r' ) + { + lines.Add( value.Mid(startPos, pos-1) ); + } + else + { + lines.Add( value.Mid(startPos, pos) ); + } + } + startPos += pos+1; + } + if ( startPos < value.Length() ) + { + lines.Add( value.Mid( startPos ) ); + } +} + + +void wxGrid::GetTextBoxSize( wxDC& dc, + wxArrayString& lines, + long *width, long *height ) +{ + long w = 0; + long h = 0; + long lineW, lineH; + + int i; + for ( i = 0; i < lines.GetCount(); i++ ) + { + dc.GetTextExtent( lines[i], &lineW, &lineH ); + w = wxMax( w, lineW ); + h += lineH; + } + + *width = w; + *height = h; +} + + +// +// ------ functions to get/send data (see also public functions) +// + +bool wxGrid::GetModelValues() +{ + if ( m_table ) + { + // all we need to do is repaint the grid + // + Refresh(); + return TRUE; + } + + return FALSE; +} + + +bool wxGrid::SetModelValues() +{ + int row, col; + + if ( m_table ) + { + for ( row = m_scrollPosY; row < m_numRows; row++ ) + { + for ( col = m_scrollPosX; col < m_numCols; col++ ) + { + m_table->SetValue( row, col, GetCellValue(row, col) ); + } + } + + return TRUE; + } + + return FALSE; +} + + +// +// ------ public functions +// + +bool wxGrid::CreateGrid( int numRows, int numCols ) +{ + if ( m_created ) + { + wxLogError( "wxGrid::CreateGrid(numRows, numCols) called more than once" ); + return FALSE; + } + else + { + m_numRows = numRows; + m_numCols = numCols; + + m_table = new wxGridStringTable( m_numRows, m_numCols ); + m_table->SetView( this ); + Init(); + m_created = TRUE; + } + + return m_created; +} + + +// The behaviour of this function depends on the grid table class +// Clear() function. For the default wxGridStringTable class the +// behavious is to replace all cell contents with wxEmptyString but +// not to change the number of rows or cols. +// +void wxGrid::ClearGrid() +{ + if ( m_table ) + { + m_table->Clear(); + SetEditControlValue(); + if ( !GetBatchCount() ) Refresh(); + } +} + + +bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) ) +{ + // TODO: something with updateLabels flag + + if ( !m_created ) + { + wxLogError( "Called wxGrid::InsertRows() before calling CreateGrid()" ); + return FALSE; + } + + if ( m_table ) + { + bool ok = m_table->InsertRows( pos, numRows ); + + // the table will have sent the results of the insert row + // operation to this view object as a grid table message + // + if ( ok ) + { + if ( !GetBatchCount() ) Refresh(); + } + SetEditControlValue(); + return ok; + } + else + { + return FALSE; + } +} + +bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) ) +{ + // TODO: something with updateLabels flag + + if ( !m_created ) + { + wxLogError( "Called wxGrid::AppendRows() before calling CreateGrid()" ); + return FALSE; + } + + if ( m_table && m_table->AppendRows( numRows ) ) + { + // the table will have sent the results of the append row + // operation to this view object as a grid table message + // + if ( !GetBatchCount() ) Refresh(); + return TRUE; + } + else + { + return FALSE; + } +} + +bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) ) +{ + // TODO: something with updateLabels flag + + if ( !m_created ) + { + wxLogError( "Called wxGrid::DeleteRows() before calling CreateGrid()" ); + return FALSE; + } + + if ( m_table && m_table->DeleteRows( pos, numRows ) ) + { + // the table will have sent the results of the delete row + // operation to this view object as a grid table message + // + if ( m_numRows > 0 ) + SetEditControlValue(); + else + HideCellEditControl(); + + if ( !GetBatchCount() ) Refresh(); + return TRUE; + } + else + { + return FALSE; + } +} + +bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) ) +{ + // TODO: something with updateLabels flag + + if ( !m_created ) + { + wxLogError( "Called wxGrid::InsertCols() before calling CreateGrid()" ); + return FALSE; + } + + if ( m_table ) + { + HideCellEditControl(); + bool ok = m_table->InsertCols( pos, numCols ); + if ( ok ) + { + // the table will have sent the results of the insert col + // operation to this view object as a grid table message + // + if ( !GetBatchCount() ) Refresh(); + } + SetEditControlValue(); + return ok; + } + else + { + return FALSE; + } +} + +bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) ) +{ + // TODO: something with updateLabels flag + + if ( !m_created ) + { + wxLogError( "Called wxGrid::AppendCols() before calling CreateGrid()" ); + return FALSE; + } + + if ( m_table && m_table->AppendCols( numCols ) ) + { + // the table will have sent the results of the append col + // operation to this view object as a grid table message + // + if ( !GetBatchCount() ) Refresh(); + return TRUE; + } + else + { + return FALSE; + } +} + +bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) ) +{ + // TODO: something with updateLabels flag + + if ( !m_created ) + { + wxLogError( "Called wxGrid::DeleteCols() before calling CreateGrid()" ); + return FALSE; + } + + if ( m_table && m_table->DeleteCols( pos, numCols ) ) + { + // the table will have sent the results of the delete col + // operation to this view object as a grid table message + // + if ( m_numCols > 0 ) + SetEditControlValue(); + else + HideCellEditControl(); + + if ( !GetBatchCount() ) Refresh(); + return TRUE; + } + else + { + return FALSE; + } +} + + + + +// ------ control panel and cell edit control +// + +void wxGrid::EnableEditing( bool edit ) +{ + // TODO: improve this ? + // + if ( edit != m_editable ) + { + m_editable = edit; + if ( !m_editable ) HideCellEditControl(); + m_topEditCtrlEnabled = m_editable; + m_cellEditCtrlEnabled = m_editable; + if ( !m_editable ) ShowCellEditControl(); + } +} + + +void wxGrid::EnableTopEditControl( bool enable ) +{ + if ( enable != m_topEditCtrlEnabled ) + { + HideCellEditControl(); + m_topEditCtrlEnabled = enable; + CalcDimensions(); + m_topEditCtrl->Show( enable ); + + if ( m_currentCellCoords != wxGridNoCellCoords ) + SetEditControlValue(); + + ShowCellEditControl(); + if ( !GetBatchCount() ) Refresh(); + } +} + +void wxGrid::EnableCellEditControl( bool enable ) +{ + if ( m_cellEditCtrl && + enable != m_cellEditCtrlEnabled ) + { + HideCellEditControl(); + SaveEditControlValue(); + + m_cellEditCtrlEnabled = enable; + + SetEditControlValue(); + ShowCellEditControl(); + } +} + + +// +// ------ grid formatting functions +// + +void wxGrid::GetRowLabelAlignment( int *horiz, int *vert ) +{ + *horiz = m_rowLabelHorizAlign; + *vert = m_rowLabelVertAlign; +} + +void wxGrid::GetColLabelAlignment( int *horiz, int *vert ) +{ + *horiz = m_colLabelHorizAlign; + *vert = m_colLabelVertAlign; +} + +wxString wxGrid::GetRowLabelValue( int row ) +{ + if ( m_table ) + { + return m_table->GetRowLabelValue( row ); + } + else + { + wxString s; + s << row; + return s; + } +} + +wxString wxGrid::GetColLabelValue( int col ) +{ + if ( m_table ) + { + return m_table->GetColLabelValue( col ); + } + else + { + wxString s; + s << col; + return s; + } +} + +void wxGrid::SetRowLabelSize( int width ) +{ + m_rowLabelWidth = wxMax( 0, width ); + CalcDimensions(); + ShowCellEditControl(); + if ( !GetBatchCount() ) Refresh(); +} + +void wxGrid::SetColLabelSize( int height ) +{ + m_colLabelHeight = wxMax( 0, height ); + CalcDimensions(); + ShowCellEditControl(); + if ( !GetBatchCount() ) Refresh(); +} + +void wxGrid::SetLabelBackgroundColour( const wxColour& colour ) +{ + m_labelBackgroundColour = colour; + if ( !GetBatchCount() ) Refresh(); +} + +void wxGrid::SetLabelTextColour( const wxColour& colour ) +{ + m_labelTextColour = colour; + if ( !GetBatchCount() ) Refresh(); +} + +void wxGrid::SetLabelFont( const wxFont& font ) +{ + m_labelFont = font; + if ( !GetBatchCount() ) Refresh(); +} + +void wxGrid::SetRowLabelAlignment( int horiz, int vert ) +{ + if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT ) + { + m_rowLabelHorizAlign = horiz; + } + + if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM ) + { + m_rowLabelVertAlign = vert; + } + + if ( !GetBatchCount() ) Refresh(); +} + +void wxGrid::SetColLabelAlignment( int horiz, int vert ) +{ + if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT ) + { + m_colLabelHorizAlign = horiz; + } + + if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM ) + { + m_colLabelVertAlign = vert; + } + + if ( !GetBatchCount() ) Refresh(); +} + +void wxGrid::SetRowLabelValue( int row, const wxString& s ) +{ + if ( m_table ) + { + m_table->SetRowLabelValue( row, s ); + if ( !GetBatchCount() ) Refresh(); + } +} + +void wxGrid::SetColLabelValue( int col, const wxString& s ) +{ + if ( m_table ) + { + m_table->SetColLabelValue( col, s ); + if ( !GetBatchCount() ) Refresh(); + } +} + +void wxGrid::SetGridLineColour( const wxColour& colour ) +{ + m_gridLineColour = colour; + + wxClientDC dc( this ); + DrawGridLines( dc ); +} + +void wxGrid::EnableGridLines( bool enable ) +{ + if ( enable != m_gridLinesEnabled ) + { + m_gridLinesEnabled = enable; + if ( !GetBatchCount() ) Refresh(); + } +} + + +int wxGrid::GetDefaultRowSize() +{ + return m_defaultRowHeight; +} + +int wxGrid::GetRowSize( int row ) +{ + if ( row >= 0 && row < m_numRows ) + return m_rowHeights[row]; + else + return 0; // TODO: log an error here +} + +int wxGrid::GetDefaultColSize() +{ + return m_defaultColWidth; +} + +int wxGrid::GetColSize( int col ) +{ + if ( col >= 0 && col < m_numCols ) + return m_colWidths[col]; + else + return 0; // TODO: log an error here +} + +wxColour wxGrid::GetDefaultCellBackgroundColour() +{ + // TODO: replace this temp test code + // + return wxColour( 255, 255, 255 ); +} + +wxColour wxGrid::GetCellBackgroundColour( int row, int col ) +{ + // TODO: replace this temp test code + // + return wxColour( 255, 255, 255 ); +} + +wxColour wxGrid::GetDefaultCellTextColour() +{ + // TODO: replace this temp test code + // + return wxColour( 0, 0, 0 ); +} + +wxColour wxGrid::GetCellTextColour( int row, int col ) +{ + // TODO: replace this temp test code + // + return wxColour( 0, 0, 0 ); +} + + +wxColour wxGrid::GetCellHighlightColour() +{ + // TODO: replace this temp test code + // + return wxColour( 0, 0, 0 ); +} + + +wxFont wxGrid::GetDefaultCellFont() +{ + return m_defaultCellFont; +} + +wxFont wxGrid::GetCellFont( int row, int col ) +{ + // TODO: replace this temp test code + // + return m_defaultCellFont; +} + +void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert ) +{ + // TODO: replace this temp test code + // + *horiz = wxLEFT; + *vert = wxTOP; +} + +void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert ) +{ + // TODO: replace this temp test code + // + *horiz = wxLEFT; + *vert = wxTOP; +} + +void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows ) +{ + m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT ); + + if ( resizeExistingRows ) + { + // TODO: what do we do about events here ? + // Generate an event for each resize ? + // + int row; + for ( row = 0; row < m_numRows; row++ ) + { + m_rowHeights[row] = m_defaultRowHeight; + } + CalcDimensions(); + if ( !GetBatchCount() ) Refresh(); + } +} + +void wxGrid::SetRowSize( int row, int height ) +{ + if ( row >= 0 && row < m_numRows ) + { + m_rowHeights[row] = wxMax( 0, height ); + CalcDimensions(); + if ( !GetBatchCount() ) Refresh(); + + // Note: we are ending the event *after* doing + // default processing in this case + // + SendEvent( EVT_WXGRID_ROW_SIZE, + row, -1 ); + } + else + { + // TODO: log an error here + } +} + +void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols ) +{ + m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH ); + + if ( resizeExistingCols ) + { + // TODO: what do we do about events here ? + // Generate an event for each resize ? + // + int col; + for ( col = 0; col < m_numCols; col++ ) + { + m_colWidths[col] = m_defaultColWidth; + } + CalcDimensions(); + if ( !GetBatchCount() ) Refresh(); + } +} + +void wxGrid::SetColSize( int col, int width ) +{ + if ( col >= 0 && col < m_numCols ) + { + m_colWidths[col] = wxMax( 0, width ); + CalcDimensions(); + if ( !GetBatchCount() ) Refresh(); + + // Note: we are ending the event *after* doing + // default processing in this case + // + SendEvent( EVT_WXGRID_COL_SIZE, + -1, col ); + } + else + { + // TODO: log an error here + } +} + +void wxGrid::SetDefaultCellBackgroundColour( const wxColour& ) +{ + // TODO: everything !!! + // +} + +void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& ) +{ + // TODO: everything !!! + // +} + +void wxGrid::SetDefaultCellTextColour( const wxColour& ) +{ + // TODO: everything !!! + // +} + +void wxGrid::SetCellTextColour( int row, int col, const wxColour& ) +{ + // TODO: everything !!! + // +} + +void wxGrid::SetCellHighlightColour( const wxColour& ) +{ + // TODO: everything !!! + // +} + +void wxGrid::SetDefaultCellFont( const wxFont& ) +{ + // TODO: everything !!! + // +} + +void wxGrid::SetCellFont( int row, int col, const wxFont& ) +{ + // TODO: everything !!! + // +} + +void wxGrid::SetDefaultCellAlignment( int horiz, int vert ) +{ + // TODO: everything !!! + // +} + +void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert ) +{ + // TODO: everything !!! + // +} + + +// +// ------ cell value accessor functions +// + +void wxGrid::SetCellValue( int row, int col, const wxString& s ) +{ + if ( m_table ) + { + m_table->SetValue( row, col, s.c_str() ); + DrawCell( row, col ); + if ( m_currentCellCoords.GetRow() == row && + m_currentCellCoords.GetCol() == col ) + { + SetEditControlValue( s ); + } + } +} + + + +// +// ------ interaction with data model +// +bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg ) +{ + switch ( msg.GetId() ) + { + case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES: + return GetModelValues(); + + case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES: + return SetModelValues(); + + case wxGRIDTABLE_NOTIFY_ROWS_INSERTED: + case wxGRIDTABLE_NOTIFY_ROWS_APPENDED: + case wxGRIDTABLE_NOTIFY_ROWS_DELETED: + case wxGRIDTABLE_NOTIFY_COLS_INSERTED: + case wxGRIDTABLE_NOTIFY_COLS_APPENDED: + case wxGRIDTABLE_NOTIFY_COLS_DELETED: + return Redimension( msg ); + + default: + return FALSE; + } +} + + +// +// ------ Grid location functions +// +// (see also inline functions in grid.h) + + +// check to see if a cell location is wholly visible +// +bool wxGrid::IsVisible( const wxGridCellCoords& coords ) +{ + return ( coords.GetRow() >= m_scrollPosY && + coords.GetRow() < m_scrollPosY + m_wholeRowsVisible && + coords.GetCol() >= m_scrollPosX && + coords.GetCol() < m_scrollPosX + m_wholeColsVisible ); +} + + +// make the specified cell location visible by doing a minimal amount +// of scrolling +// +void wxGrid::MakeCellVisible( int row, int col ) +{ + int lastX = m_scrollPosX; + int lastY = m_scrollPosY; + + if ( row >= 0 && row < m_numRows && + col >= 0 && col < m_numCols ) + { + if ( row < m_scrollPosY ) + { + SetVerticalScrollPos( row ); + } + else if ( row >= m_scrollPosY + m_wholeRowsVisible ) + { + int i; + int h = m_rowBottoms[row]; + for ( i = m_scrollPosY; i < m_numRows && h > m_bottom; i++ ) + { + h -= m_rowHeights[i]; + } + SetVerticalScrollPos( i ); + } + + if ( col < m_scrollPosX ) + { + SetHorizontalScrollPos( col ); + } + else if ( col >= m_scrollPosX + m_wholeColsVisible ) + { + int i; + int w = m_colRights[col]; + for ( i = m_scrollPosX; i < m_numCols && w > m_right; i++ ) + { + w -= m_colWidths[i]; + } + SetHorizontalScrollPos( i ); + } + + if ( m_scrollPosX != lastX || m_scrollPosY != lastY ) + { + // The cell was not visible before but not it is + // + ShowCellEditControl(); + } + } + else + { + // TODO: log an error + } +} + + +void wxGrid::SetVerticalScrollPos( int topMostRow ) +{ + if ( m_vertScrollBar && topMostRow != m_scrollPosY ) + { + m_scrollPosY = topMostRow; + + CalcDimensions(); + Refresh(); + } +} + + +void wxGrid::SetHorizontalScrollPos( int leftMostCol ) +{ + if ( m_horizScrollBar && leftMostCol != m_scrollPosX ) + { + m_scrollPosX = leftMostCol; + + CalcDimensions(); + Refresh(); + } +} + + +// +// ------ block, row and col selection +// + +void wxGrid::SelectRow( int row, bool addToSelected ) +{ + if ( IsSelection() && addToSelected ) + { + if ( m_selectedTopLeft.GetRow() > row ) + m_selectedTopLeft.SetRow( row ); + + m_selectedTopLeft.SetCol( 0 ); + + if ( m_selectedBottomRight.GetRow() < row ) + m_selectedBottomRight.SetRow( row ); + + m_selectedBottomRight.SetCol( m_numCols - 1 ); + } + else + { + ClearSelection(); + m_selectedTopLeft.Set( row, 0 ); + m_selectedBottomRight.Set( row, m_numCols-1 ); + } + + if ( !GetBatchCount() ) + { + wxRect rect( SelectionToRect() ); + if ( rect != wxGridNoCellRect ) Refresh( TRUE, &rect ); + } + + wxGridRangeSelectEvent gridEvt( GetId(), + EVT_WXGRID_RANGE_SELECT, + this, + m_selectedTopLeft, + m_selectedBottomRight ); + + GetEventHandler()->ProcessEvent(gridEvt); +} + + +void wxGrid::SelectCol( int col, bool addToSelected ) +{ + if ( addToSelected && m_selectedTopLeft != wxGridNoCellCoords ) + { + if ( m_selectedTopLeft.GetCol() > col ) + m_selectedTopLeft.SetCol( col ); + + m_selectedTopLeft.SetRow( 0 ); + + if ( m_selectedBottomRight.GetCol() < col ) + m_selectedBottomRight.SetCol( col ); + + m_selectedBottomRight.SetRow( m_numRows - 1 ); + } + else + { + ClearSelection(); + m_selectedTopLeft.Set( 0, col ); + m_selectedBottomRight.Set( m_numRows-1, col ); + } + + if ( !GetBatchCount() ) + { + wxRect rect( SelectionToRect() ); + if ( rect != wxGridNoCellRect ) Refresh( TRUE, &rect ); + } + + wxGridRangeSelectEvent gridEvt( GetId(), + EVT_WXGRID_RANGE_SELECT, + this, + m_selectedTopLeft, + m_selectedBottomRight ); + + GetEventHandler()->ProcessEvent(gridEvt); +} + + +void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol ) +{ + int temp; + + if ( topRow > bottomRow ) + { + temp = topRow; + topRow = bottomRow; + bottomRow = temp; + } + + if ( leftCol > rightCol ) + { + temp = leftCol; + leftCol = rightCol; + rightCol = temp; + } + + m_selectedTopLeft.Set( topRow, leftCol ); + m_selectedBottomRight.Set( bottomRow, rightCol ); + + if ( !GetBatchCount() ) + { + wxRect rect( SelectionToRect() ); + if ( rect != wxGridNoCellRect ) Refresh( TRUE, &rect ); + } + + // only generate an event if the block is not being selected by + // dragging the mouse (in which case the event will be generated in + // OnMouse) } + if ( !m_isDragging ) + { + wxGridRangeSelectEvent gridEvt( GetId(), + EVT_WXGRID_RANGE_SELECT, + this, + m_selectedTopLeft, + m_selectedBottomRight ); + + GetEventHandler()->ProcessEvent(gridEvt); + } +} + +void wxGrid::SelectAll() +{ + m_selectedTopLeft.Set( 0, 0 ); + m_selectedBottomRight.Set( m_numRows-1, m_numCols-1 ); + + if ( !GetBatchCount() ) Refresh(); +} + + +void wxGrid::ClearSelection() +{ + if ( IsSelection() ) + { + wxRect rect( SelectionToRect() ); + if ( rect != wxGridNoCellRect ) + { + Refresh( TRUE, &rect ); + } + + m_selectedTopLeft = wxGridNoCellCoords; + m_selectedBottomRight = wxGridNoCellCoords; + } +} + + +wxRect wxGrid::SelectionToRect() +{ + wxRect rect; + wxRect cellRect; + + if ( IsSelection() ) + { + cellRect = CellToRect( m_selectedTopLeft ); + if ( cellRect != wxGridNoCellRect ) + { + rect = cellRect; + } + else + { + rect = wxRect( m_left, m_top, 0, 0 ); + } + + cellRect = CellToRect( m_selectedBottomRight ); + if ( cellRect != wxGridNoCellRect ) + { + rect += cellRect; + } + else + { + return wxGridNoCellRect; + } + } + + return rect; +} + + + + +// +// ------ Grid event classes +// + +IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent ) + +wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj, + int row, int col, int x, int y, + bool control, bool shift, bool alt, bool meta ) + : wxNotifyEvent( type, id ) +{ + m_row = row; + m_col = col; + m_x = x; + m_y = y; + m_control = control; + m_shift = shift; + m_alt = alt; + m_meta = meta; + + SetEventObject(obj); +} + + +IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent ) + +wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj, + int rowOrCol, int x, int y, + bool control, bool shift, bool alt, bool meta ) + : wxNotifyEvent( type, id ) +{ + m_rowOrCol = rowOrCol; + m_x = x; + m_y = y; + m_control = control; + m_shift = shift; + m_alt = alt; + m_meta = meta; + + SetEventObject(obj); +} + + +IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent ) + +wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj, + const wxGridCellCoords& topLeft, + const wxGridCellCoords& bottomRight, + bool control, bool shift, bool alt, bool meta ) + : wxNotifyEvent( type, id ) +{ + m_topLeft = topLeft; + m_bottomRight = bottomRight; + m_control = control; + m_shift = shift; + m_alt = alt; + m_meta = meta; + + SetEventObject(obj); +} + + +#endif // ifndef wxUSE_NEW_GRID + diff --git a/src/msw/makefile.b32 b/src/msw/makefile.b32 index 0428ee6578..50b8200cd7 100644 --- a/src/msw/makefile.b32 +++ b/src/msw/makefile.b32 @@ -1,6 +1,6 @@ -# This file was automatically generated by tmake at 20:06, 1999/10/02 +# This file was automatically generated by tmake at 13:22, 1999/10/06 # DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE B32.T! # @@ -78,7 +78,7 @@ DOCDIR = $(WXDIR)\docs GENERICOBJS= $(MSWDIR)\busyinfo.obj \ $(MSWDIR)\choicdgg.obj \ - $(MSWDIR)\gridg.obj \ + $(MSWDIR)\grid.obj \ $(MSWDIR)\laywin.obj \ $(MSWDIR)\logg.obj \ $(MSWDIR)\numdlgg.obj \ @@ -706,7 +706,7 @@ $(MSWDIR)\busyinfo.obj: $(GENDIR)\busyinfo.$(SRCSUFF) $(MSWDIR)\choicdgg.obj: $(GENDIR)\choicdgg.$(SRCSUFF) -$(MSWDIR)\gridg.obj: $(GENDIR)\gridg.$(SRCSUFF) +$(MSWDIR)\grid.obj: $(GENDIR)\grid.$(SRCSUFF) $(MSWDIR)\laywin.obj: $(GENDIR)\laywin.$(SRCSUFF) diff --git a/src/msw/makefile.bcc b/src/msw/makefile.bcc index d8a2b497bd..2d42139759 100644 --- a/src/msw/makefile.bcc +++ b/src/msw/makefile.bcc @@ -1,6 +1,6 @@ -# This file was automatically generated by tmake at 20:06, 1999/10/02 +# This file was automatically generated by tmake at 13:22, 1999/10/06 # DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE BCC.T! # @@ -76,7 +76,7 @@ DOCDIR = $(WXDIR)\docs GENERICOBJS= $(MSWDIR)\busyinfo.obj \ $(MSWDIR)\choicdgg.obj \ $(MSWDIR)\dirdlgg.obj \ - $(MSWDIR)\gridg.obj \ + $(MSWDIR)\grid.obj \ $(MSWDIR)\imaglist.obj \ $(MSWDIR)\laywin.obj \ $(MSWDIR)\listctrl.obj \ @@ -586,7 +586,7 @@ $(MSWDIR)\choicdgg.obj: $(GENDIR)\choicdgg.$(SRCSUFF) $(MSWDIR)\dirdlgg.obj: $(GENDIR)\dirdlgg.$(SRCSUFF) -$(MSWDIR)\gridg.obj: $(GENDIR)\gridg.$(SRCSUFF) +$(MSWDIR)\grid.obj: $(GENDIR)\grid.$(SRCSUFF) $(MSWDIR)\imaglist.obj: $(GENDIR)\imaglist.$(SRCSUFF) diff --git a/src/msw/makefile.dos b/src/msw/makefile.dos index 76899b1063..8beda177d4 100644 --- a/src/msw/makefile.dos +++ b/src/msw/makefile.dos @@ -1,6 +1,6 @@ -# This file was automatically generated by tmake at 20:06, 1999/10/02 +# This file was automatically generated by tmake at 13:22, 1999/10/06 # DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE DOS.T! # @@ -62,7 +62,7 @@ MSWDIR=. GENERICOBJS= $(GENDIR)\busyinfo.obj \ $(GENDIR)\choicdgg.obj \ $(GENDIR)\dirdlgg.obj \ - $(GENDIR)\gridg.obj \ + $(GENDIR)\grid.obj \ $(GENDIR)\imaglist.obj \ $(GENDIR)\laywin.obj \ $(GENDIR)\listctrl.obj \ @@ -1046,7 +1046,7 @@ $(GENDIR)/dirdlgg.obj: $*.$(SRCSUFF) $(CPPFLAGS) /Fo$@ /c /Tp $*.$(SRCSUFF) << -$(GENDIR)/gridg.obj: $*.$(SRCSUFF) +$(GENDIR)/grid.obj: $*.$(SRCSUFF) cl @<< $(CPPFLAGS) /Fo$@ /c /Tp $*.$(SRCSUFF) << diff --git a/src/msw/makefile.g295 b/src/msw/makefile.g295 index 263461ec0e..5f34dbaded 100644 --- a/src/msw/makefile.g295 +++ b/src/msw/makefile.g295 @@ -1,5 +1,5 @@ -# This file was automatically generated by tmake at 13:53, 1999/09/14 +# This file was automatically generated by tmake at 13:22, 1999/10/06 # DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE G295.T! # @@ -39,8 +39,9 @@ DOCDIR = $(WXDIR)\docs GENERICOBJS = \ $(GENDIR)/busyinfo.$(OBJSUFF) \ $(GENDIR)/choicdgg.$(OBJSUFF) \ - $(GENDIR)/gridg.$(OBJSUFF) \ + $(GENDIR)/grid.$(OBJSUFF) \ $(GENDIR)/laywin.$(OBJSUFF) \ + $(GENDIR)/logg.$(OBJSUFF) \ $(GENDIR)/numdlgg.$(OBJSUFF) \ $(GENDIR)/panelg.$(OBJSUFF) \ $(GENDIR)/progdlgg.$(OBJSUFF) \ @@ -79,6 +80,7 @@ COMMONOBJS = \ $(COMMDIR)/fileconf.$(OBJSUFF) \ $(COMMDIR)/filefn.$(OBJSUFF) \ $(COMMDIR)/filesys.$(OBJSUFF) \ + $(COMMDIR)/fontcmn.$(OBJSUFF) \ $(COMMDIR)/framecmn.$(OBJSUFF) \ $(COMMDIR)/fs_inet.$(OBJSUFF) \ $(COMMDIR)/fs_zip.$(OBJSUFF) \ @@ -88,6 +90,7 @@ COMMONOBJS = \ $(COMMDIR)/hash.$(OBJSUFF) \ $(COMMDIR)/helpbase.$(OBJSUFF) \ $(COMMDIR)/http.$(OBJSUFF) \ + $(COMMDIR)/imagall.$(OBJSUFF) \ $(COMMDIR)/imagbmp.$(OBJSUFF) \ $(COMMDIR)/image.$(OBJSUFF) \ $(COMMDIR)/imaggif.$(OBJSUFF) \ @@ -116,6 +119,7 @@ COMMONOBJS = \ $(COMMDIR)/sckfile.$(OBJSUFF) \ $(COMMDIR)/sckipc.$(OBJSUFF) \ $(COMMDIR)/sckstrm.$(OBJSUFF) \ + $(COMMDIR)/serbase.$(OBJSUFF) \ $(COMMDIR)/sizer.$(OBJSUFF) \ $(COMMDIR)/socket.$(OBJSUFF) \ $(COMMDIR)/strconv.$(OBJSUFF) \ @@ -148,20 +152,20 @@ HTMLOBJS = \ $(HTMLDIR)/helpdata.$(OBJSUFF) \ $(HTMLDIR)/helpfrm.$(OBJSUFF) \ $(HTMLDIR)/htmlcell.$(OBJSUFF) \ - $(HTMLDIR)/htmlfilter.$(OBJSUFF) \ - $(HTMLDIR)/htmlparser.$(OBJSUFF) \ + $(HTMLDIR)/htmlfilt.$(OBJSUFF) \ + $(HTMLDIR)/htmlpars.$(OBJSUFF) \ $(HTMLDIR)/htmltag.$(OBJSUFF) \ $(HTMLDIR)/htmlwin.$(OBJSUFF) \ - $(HTMLDIR)/htmlwinparser.$(OBJSUFF) \ - $(HTMLDIR)/mod_fonts.$(OBJSUFF) \ - $(HTMLDIR)/mod_hline.$(OBJSUFF) \ - $(HTMLDIR)/mod_image.$(OBJSUFF) \ - $(HTMLDIR)/mod_layout.$(OBJSUFF) \ - $(HTMLDIR)/mod_links.$(OBJSUFF) \ - $(HTMLDIR)/mod_list.$(OBJSUFF) \ - $(HTMLDIR)/mod_pre.$(OBJSUFF) \ - $(HTMLDIR)/mod_tables.$(OBJSUFF) \ - $(HTMLDIR)/search.$(OBJSUFF) + $(HTMLDIR)/m_fonts.$(OBJSUFF) \ + $(HTMLDIR)/m_hline.$(OBJSUFF) \ + $(HTMLDIR)/m_image.$(OBJSUFF) \ + $(HTMLDIR)/m_layout.$(OBJSUFF) \ + $(HTMLDIR)/m_links.$(OBJSUFF) \ + $(HTMLDIR)/m_list.$(OBJSUFF) \ + $(HTMLDIR)/m_pre.$(OBJSUFF) \ + $(HTMLDIR)/m_tables.$(OBJSUFF) \ + $(HTMLDIR)/search.$(OBJSUFF) \ + $(HTMLDIR)/winpars.$(OBJSUFF) MSWOBJS = \ $(MSWDIR)/accel.$(OBJSUFF) \ diff --git a/src/msw/makefile.g95 b/src/msw/makefile.g95 index 39aa3176d8..78ec2ee9ba 100644 --- a/src/msw/makefile.g95 +++ b/src/msw/makefile.g95 @@ -1,5 +1,5 @@ -# This file was automatically generated by tmake at 20:06, 1999/10/02 +# This file was automatically generated by tmake at 13:22, 1999/10/06 # DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE G95.T! # @@ -40,7 +40,7 @@ GENERICOBJS = \ $(GENDIR)/busyinfo.$(OBJSUFF) \ $(GENDIR)/choicdgg.$(OBJSUFF) \ $(GENDIR)/dirdlgg.$(OBJSUFF) \ - $(GENDIR)/gridg.$(OBJSUFF) \ + $(GENDIR)/grid.$(OBJSUFF) \ $(GENDIR)/laywin.$(OBJSUFF) \ $(GENDIR)/logg.$(OBJSUFF) \ $(GENDIR)/numdlgg.$(OBJSUFF) \ diff --git a/src/msw/makefile.sc b/src/msw/makefile.sc index 0c3c083c72..22c1daf1e1 100644 --- a/src/msw/makefile.sc +++ b/src/msw/makefile.sc @@ -1,6 +1,6 @@ -# This file was automatically generated by tmake at 20:06, 1999/10/02 +# This file was automatically generated by tmake at 13:22, 1999/10/06 # DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE SC.T! # Symantec C++ makefile for the msw objects @@ -28,7 +28,7 @@ MSWDIR=$(WXDIR)\src\msw GENERICOBJS= $(GENDIR)\busyinfo.obj \ $(GENDIR)\choicdgg.obj \ - $(GENDIR)\gridg.obj \ + $(GENDIR)\grid.obj \ $(GENDIR)\laywin.obj \ $(GENDIR)\logg.obj \ $(GENDIR)\numdlgg.obj \ diff --git a/src/msw/makefile.vc b/src/msw/makefile.vc index c39e3d16cd..3d370a60c5 100644 --- a/src/msw/makefile.vc +++ b/src/msw/makefile.vc @@ -1,4 +1,4 @@ -# This file was automatically generated by tmake at 18:29, 1999/10/03 +# This file was automatically generated by tmake at 13:22, 1999/10/06 # DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE VC.T! # File: makefile.vc @@ -85,7 +85,7 @@ $(CPPFLAGS) /Fo$@ /c /Tp $< GENERICOBJS= ..\generic\$D\busyinfo.obj \ ..\generic\$D\choicdgg.obj \ - ..\generic\$D\gridg.obj \ + ..\generic\$D\grid.obj \ ..\generic\$D\laywin.obj \ ..\generic\$D\logg.obj \ ..\generic\$D\numdlgg.obj \ diff --git a/src/msw/makefile.wat b/src/msw/makefile.wat index c08b07b927..565501040d 100644 --- a/src/msw/makefile.wat +++ b/src/msw/makefile.wat @@ -1,6 +1,6 @@ -# This file was automatically generated by tmake at 20:06, 1999/10/02 +# This file was automatically generated by tmake at 13:22, 1999/10/06 # DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE WAT.T! #!/binb/wmake.exe @@ -34,7 +34,7 @@ DOCDIR = $(WXDIR)\docs GENERICOBJS= busyinfo.obj & choicdgg.obj & - gridg.obj & + grid.obj & laywin.obj & logg.obj & numdlgg.obj & @@ -833,7 +833,7 @@ busyinfo.obj: $(GENDIR)\busyinfo.cpp choicdgg.obj: $(GENDIR)\choicdgg.cpp *$(CCC) $(CPPFLAGS) $(IFLAGS) $< -gridg.obj: $(GENDIR)\gridg.cpp +grid.obj: $(GENDIR)\grid.cpp *$(CCC) $(CPPFLAGS) $(IFLAGS) $< laywin.obj: $(GENDIR)\laywin.cpp -- 2.45.2