+ void OnResizeClick(wxCommandEvent& event);
+};
+
+class MySizerFrame : public wxFrame
+{
+public:
+ MySizerFrame(wxWindow *parent)
+ : wxFrame(parent, wxID_ANY, "MySizerScrolledWindow")
+ {
+ new MySizerScrolledWindow(this);
+
+ // ensure that the scrollbars appear when the button becomes large
+ SetClientSize(LARGE_BUTTON/2);
+ Show();
+ }
+};
+
+// ----------------------------------------------------------------------------
+// example showing scrolling only part of the window
+// ----------------------------------------------------------------------------
+
+// this window consists of an empty space in its corner, column labels window
+// along its top, row labels window along its left hand side and a canvas in
+// the remaining space
+
+class MySubColLabels : public wxWindow
+{
+public:
+ MySubColLabels(wxScrolledWindow *parent)
+ : wxWindow(parent, wxID_ANY)
+ {
+ m_owner = parent;
+
+ Connect(wxEVT_PAINT, wxPaintEventHandler(MySubColLabels::OnPaint));
+ }
+
+private:
+ void OnPaint(wxPaintEvent& WXUNUSED(event))
+ {
+ wxPaintDC dc(this);
+
+ // This is wrong.. it will translate both x and y if the
+ // window is scrolled, the label windows are active in one
+ // direction only. Do the action below instead -- RL.
+ //m_owner->PrepareDC( dc );
+
+ int xScrollUnits, xOrigin;
+
+ m_owner->GetViewStart( &xOrigin, 0 );
+ m_owner->GetScrollPixelsPerUnit( &xScrollUnits, 0 );
+ dc.SetDeviceOrigin( -xOrigin * xScrollUnits, 0 );
+
+ dc.DrawText("Column 1", 5, 5);
+ dc.DrawText("Column 2", 105, 5);
+ dc.DrawText("Column 3", 205, 5);
+ }
+
+ wxScrolledWindow *m_owner;
+};
+
+class MySubRowLabels : public wxWindow
+{
+public:
+ MySubRowLabels(wxScrolledWindow *parent)
+ : wxWindow(parent, wxID_ANY)
+ {
+ m_owner = parent;
+
+ Connect(wxEVT_PAINT, wxPaintEventHandler(MySubRowLabels::OnPaint));
+ }
+
+private:
+ void OnPaint(wxPaintEvent& WXUNUSED(event))
+ {
+ wxPaintDC dc(this);
+
+ // This is wrong.. it will translate both x and y if the
+ // window is scrolled, the label windows are active in one
+ // direction only. Do the action below instead -- RL.
+ //m_owner->PrepareDC( dc );
+
+ int yScrollUnits, yOrigin;
+
+ m_owner->GetViewStart( 0, &yOrigin );
+ m_owner->GetScrollPixelsPerUnit( 0, &yScrollUnits );
+ dc.SetDeviceOrigin( 0, -yOrigin * yScrollUnits );
+
+ dc.DrawText("Row 1", 5, 5);
+ dc.DrawText("Row 2", 5, 30);
+ dc.DrawText("Row 3", 5, 55);
+ dc.DrawText("Row 4", 5, 80);
+ dc.DrawText("Row 5", 5, 105);
+ dc.DrawText("Row 6", 5, 130);
+ }
+
+ wxScrolledWindow *m_owner;
+};
+
+class MySubCanvas : public wxPanel
+{
+public:
+ MySubCanvas(wxScrolledWindow *parent, wxWindow *cols, wxWindow *rows)
+ : wxPanel(parent, wxID_ANY)
+ {
+ m_owner = parent;
+ m_colLabels = cols;
+ m_rowLabels = rows;
+
+ (void)new wxButton(this, wxID_ANY, "Hallo I",
+ wxPoint(0,50), wxSize(100,25) );
+ (void)new wxButton(this, wxID_ANY, "Hallo II",
+ wxPoint(200,50), wxSize(100,25) );
+
+ (void)new wxTextCtrl(this, wxID_ANY, "Text I",
+ wxPoint(0,100), wxSize(100,25) );
+ (void)new wxTextCtrl(this, wxID_ANY, "Text II",
+ wxPoint(200,100), wxSize(100,25) );
+
+ (void)new wxComboBox(this, wxID_ANY, "ComboBox I",
+ wxPoint(0,150), wxSize(100,25));
+ (void)new wxComboBox(this, wxID_ANY, "ComboBox II",
+ wxPoint(200,150), wxSize(100,25));
+
+ SetBackgroundColour("WHEAT");
+
+ Connect(wxEVT_PAINT, wxPaintEventHandler(MySubCanvas::OnPaint));
+ }
+
+ // override the base class function so that when this window is scrolled,
+ // the labels are scrolled in sync
+ virtual void ScrollWindow(int dx, int dy, const wxRect *rect)
+ {
+ wxPanel::ScrollWindow( dx, dy, rect );
+ m_colLabels->ScrollWindow( dx, 0, rect );
+ m_rowLabels->ScrollWindow( 0, dy, rect );
+ }
+
+private:
+ void OnPaint(wxPaintEvent& WXUNUSED(event))
+ {
+ wxPaintDC dc( this );
+ m_owner->PrepareDC( dc );
+
+ dc.SetPen( *wxBLACK_PEN );
+
+ // OK, let's assume we are a grid control and we have two
+ // grid cells. Here in OnPaint we want to know which cell
+ // to redraw so that we prevent redrawing cells that don't
+ // need to get redrawn. We have one cell at (0,0) and one
+ // more at (200,0), both having a size of (100,25).
+
+ // We can query how much the window has been scrolled
+ // by calling CalcUnscrolledPosition()
+
+ int scroll_x = 0;
+ int scroll_y = 0;
+ m_owner->CalcUnscrolledPosition( scroll_x, scroll_y, &scroll_x, &scroll_y );
+
+ // We also need to know the size of the window to see which
+ // cells are completely hidden and not get redrawn
+
+ int size_x = 0;
+ int size_y = 0;
+ GetClientSize( &size_x, &size_y );
+
+ // First cell: (0,0)(100,25)
+ // It it on screen?
+ if ((0+100-scroll_x > 0) && (0+25-scroll_y > 0) &&
+ (0-scroll_x < size_x) && (0-scroll_y < size_y))
+ {
+ // Has the region on screen been exposed?
+ if (IsExposed(0,0,100,25))
+ {
+ dc.DrawRectangle( 0, 0, 100, 25 );
+ dc.DrawText("First Cell", 5, 5);
+ }
+ }
+
+
+ // Second cell: (0,200)(100,25)
+ // It it on screen?
+ if ((200+100-scroll_x > 0) && (0+25-scroll_y > 0) &&
+ (200-scroll_x < size_x) && (0-scroll_y < size_y))
+ {
+ // Has the region on screen been exposed?
+ if (IsExposed(200,0,100,25))
+ {
+ dc.DrawRectangle( 200, 0, 100, 25 );
+ dc.DrawText("Second Cell", 205, 5);
+ }
+ }
+ }
+
+ wxScrolledWindow *m_owner;
+ wxWindow *m_colLabels,
+ *m_rowLabels;
+};
+
+class MySubScrolledWindow : public wxScrolledWindow
+{
+public:
+ enum
+ {
+ CORNER_WIDTH = 60,
+ CORNER_HEIGHT = 25
+ };
+
+ MySubScrolledWindow(wxWindow *parent)
+ : wxScrolledWindow(parent, wxID_ANY)
+ {
+ // create the children
+ MySubColLabels *cols = new MySubColLabels(this);
+ MySubRowLabels *rows = new MySubRowLabels(this);
+
+ m_canvas = new MySubCanvas(this, cols, rows);
+
+ // lay them out
+ wxFlexGridSizer *sizer = new wxFlexGridSizer(2, 2, 10, 10);
+ sizer->Add(CORNER_WIDTH, CORNER_HEIGHT); // just a spacer
+ sizer->Add(cols, wxSizerFlags().Expand());
+ sizer->Add(rows, wxSizerFlags().Expand());
+ sizer->Add(m_canvas, wxSizerFlags().Expand());
+ sizer->AddGrowableRow(1);
+ sizer->AddGrowableCol(1);
+ SetSizer(sizer);
+
+ // this is the key call: it means that only m_canvas will be scrolled
+ // and not this window itself
+ SetTargetWindow(m_canvas);
+
+ SetScrollbars(10, 10, 50, 50);
+
+ Connect(wxEVT_SIZE, wxSizeEventHandler(MySubScrolledWindow::OnSize));
+ }
+
+protected:
+ // scrolled windows which use scroll target different from the window
+ // itself must override this virtual method
+ virtual wxSize GetSizeAvailableForScrollTarget(const wxSize& size)
+ {
+ // decrease the total size by the size of the non-scrollable parts
+ // above/to the left of the canvas
+ wxSize sizeCanvas(size);
+ sizeCanvas.x -= 60;
+ sizeCanvas.y -= 25;
+ return sizeCanvas;
+ }
+
+private:
+ void OnSize(wxSizeEvent& WXUNUSED(event))
+ {
+ // We need to override OnSize so that our scrolled
+ // window a) does call Layout() to use sizers for
+ // positioning the controls but b) does not query
+ // the sizer for their size and use that for setting
+ // the scrollable area as set that ourselves by
+ // calling SetScrollbar() further down.
+
+ Layout();
+
+ AdjustScrollbars();
+ }
+
+ MySubCanvas *m_canvas;
+};
+
+class MySubFrame : public wxFrame
+{
+public:
+ MySubFrame(wxWindow *parent)
+ : wxFrame(parent, wxID_ANY, "MySubScrolledWindow")
+ {
+ new MySubScrolledWindow(this);
+
+ Show();
+ }
+};
+
+// ----------------------------------------------------------------------------
+// more simple examples of wxScrolledWindow usage
+// ----------------------------------------------------------------------------
+
+// base class for both of them
+class MyScrolledWindowBase : public wxScrolledWindow
+{
+public:
+ MyScrolledWindowBase(wxWindow *parent)
+ : wxScrolledWindow(parent, wxID_ANY,
+ wxDefaultPosition, wxDefaultSize,
+ wxBORDER_SUNKEN)
+ {
+ m_nLines = 50;
+ m_winSync = NULL;
+ m_inDoSync = false;
+
+ wxClientDC dc(this);
+ dc.GetTextExtent("Line 17", NULL, &m_hLine);
+ }
+
+ // this scrolled window can be synchronized with another one: if this
+ // function is called with a non-NULL pointer, the given window will be
+ // scrolled to the same position as this one
+ void SyncWith(MyScrolledWindowBase *win)
+ {
+ m_winSync = win;
+
+ DoSyncIfNecessary();
+ }
+
+ virtual void ScrollWindow(int dx, int dy, const wxRect *rect = NULL)
+ {
+ wxScrolledWindow::ScrollWindow(dx, dy, rect);
+
+ DoSyncIfNecessary();
+ }
+
+protected:
+ // the height of one line on screen
+ int m_hLine;
+
+ // the number of lines we draw
+ size_t m_nLines;
+
+private:
+ bool WasScrolledFirst() const { return m_inDoSync; }
+
+ void DoSyncIfNecessary()
+ {
+ if ( m_winSync && !m_winSync->WasScrolledFirst() )
+ {
+ m_inDoSync = true;
+
+ m_winSync->Scroll(GetViewStart());
+
+ m_inDoSync = false;
+ }
+ }
+
+ // the window to synchronize with this one or NULL
+ MyScrolledWindowBase *m_winSync;
+
+ // the flag preventing infinite recursion which would otherwise happen if
+ // one window synchronized the other one which in turn synchronized this
+ // one and so on
+ bool m_inDoSync;
+};
+
+// this class does "stupid" redrawing - it redraws everything each time
+// and sets the scrollbar extent directly.
+
+class MyScrolledWindowDumb : public MyScrolledWindowBase
+{
+public:
+ MyScrolledWindowDumb(wxWindow *parent) : MyScrolledWindowBase(parent)
+ {
+ // no horz scrolling
+ SetScrollbars(0, m_hLine, 0, m_nLines + 1, 0, 0, true /* no refresh */);
+ }
+
+ virtual void OnDraw(wxDC& dc);
+};
+
+// this class does "smart" redrawing - only redraws the lines which must be
+// redrawn and sets the scroll rate and virtual size to affect the
+// scrollbars.
+//
+// Note that this class should produce identical results to the one above.
+
+class MyScrolledWindowSmart : public MyScrolledWindowBase
+{
+public:
+ MyScrolledWindowSmart(wxWindow *parent) : MyScrolledWindowBase(parent)
+ {
+ // no horz scrolling
+ SetScrollRate( 0, m_hLine );
+ SetVirtualSize( wxDefaultCoord, ( m_nLines + 1 ) * m_hLine );
+ }
+
+ virtual void OnDraw(wxDC& dc);
+};
+
+// ----------------------------------------------------------------------------
+// implements a text viewer with simple block selection to test auto-scrolling
+// functionality
+// ----------------------------------------------------------------------------
+
+class MyAutoScrollingWindow : public wxScrolledWindow
+{
+public:
+ MyAutoScrollingWindow( wxWindow* parent );
+ wxRect DeviceCoordsToGraphicalChars(wxRect updRect) const;
+ wxPoint DeviceCoordsToGraphicalChars(wxPoint pos) const;
+ wxPoint GraphicalCharToDeviceCoords(wxPoint pos) const;
+ wxRect LogicalCoordsToGraphicalChars(wxRect updRect) const;
+ wxPoint LogicalCoordsToGraphicalChars(wxPoint pos) const;
+ wxPoint GraphicalCharToLogicalCoords(wxPoint pos) const;
+ void MyRefresh();
+ bool IsSelected(int chX, int chY) const;
+ static bool IsInside(int k, int bound1, int bound2);
+ static wxRect DCNormalize(int x, int y, int w, int h);
+
+private:
+ // event handlers
+ void OnDraw(wxDC& dc);
+ void OnMouseLeftDown(wxMouseEvent& event);
+ void OnMouseLeftUp(wxMouseEvent& event);
+ void OnMouseMove(wxMouseEvent& event);
+ void OnMouseCaptureLost(wxMouseCaptureLostEvent& event);
+ void OnScroll(wxScrollWinEvent& event);
+
+ // test data variables
+ static const char* sm_testData;
+ static const int sm_lineCnt; // line count
+ static const int sm_lineLen; // line length in characters
+ // sizes for graphical data
+ int m_fontH, m_fontW;
+ // selection tracking
+ wxPoint m_selStart; // beginning of blockwise selection
+ wxPoint m_cursor; // end of blockwise selection (mouse position)
+
+ // gui stuff
+ wxFont m_font;
+
+