home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / samples / scroll / scroll.cpp < prev    next >
C/C++ Source or Header  |  2002-11-10  |  17KB  |  568 lines

  1. /*
  2.  * Program: scroll
  3.  *
  4.  * Author: Robert Roebling
  5.  *
  6.  * Copyright: (C) 1998, Robert Roebling
  7.  *                2002, Ron Lee
  8.  *
  9.  */
  10.  
  11. // For compilers that support precompilation, includes "wx/wx.h".
  12. #include "wx/wxprec.h"
  13.  
  14. #ifdef __BORLANDC__
  15. #pragma hdrstop
  16. #endif
  17.  
  18. #ifndef WX_PRECOMP
  19. #include "wx/wx.h"
  20. #endif
  21.  
  22. #include "wx/image.h"
  23. #include "wx/listctrl.h"
  24. #include "wx/sizer.h"
  25. #include "wx/log.h"
  26.  
  27.  
  28. // derived classes
  29.  
  30. class MyFrame;
  31. class MyApp;
  32.  
  33. // MyCanvas
  34.  
  35. class MyCanvas: public wxScrolledWindow
  36. {
  37. public:
  38.     MyCanvas() {}
  39.     MyCanvas( wxWindow *parent, wxWindowID, const wxPoint &pos, const wxSize &size );
  40.     ~MyCanvas();
  41.     void OnPaint( wxPaintEvent &event );
  42.     void OnQueryPosition( wxCommandEvent &event );
  43.     void OnAddButton( wxCommandEvent &event );
  44.     void OnDeleteButton( wxCommandEvent &event );
  45.     void OnMoveButton( wxCommandEvent &event );
  46.     void OnScrollWin( wxCommandEvent &event );
  47.     void OnMouseDown( wxMouseEvent &event );
  48.  
  49.     wxButton *m_button;
  50.  
  51.     DECLARE_DYNAMIC_CLASS(MyCanvas)
  52.     DECLARE_EVENT_TABLE()
  53. };
  54.  
  55.  
  56. // ----------------------------------------------------------------------------
  57. // Autoscrolling example.
  58. // ----------------------------------------------------------------------------
  59.  
  60. // this class uses the 'virtual' size attribute along with an internal
  61. // sizer to automatically set up scrollbars as needed
  62.  
  63. class MyAutoScrollWindow : public wxScrolledWindow
  64. {
  65. private:
  66.  
  67.     wxButton    *m_button;
  68.  
  69. public:
  70.  
  71.     MyAutoScrollWindow( wxWindow *parent );
  72.  
  73.     void OnResizeClick( wxCommandEvent &WXUNUSED( event ) );
  74.  
  75.     DECLARE_EVENT_TABLE()
  76. };
  77.  
  78.  
  79. // ----------------------------------------------------------------------------
  80. // MyScrolledWindow classes: examples of wxScrolledWindow usage
  81. // ----------------------------------------------------------------------------
  82.  
  83. // base class for both of them
  84. class MyScrolledWindowBase : public wxScrolledWindow
  85. {
  86. public:
  87.     MyScrolledWindowBase(wxWindow *parent)
  88.         : wxScrolledWindow(parent)
  89.         , m_nLines( 100 )
  90.     {
  91.         wxClientDC dc(this);
  92.         dc.GetTextExtent(_T("Line 17"), NULL, &m_hLine);
  93.     }
  94.  
  95. protected:
  96.     // the height of one line on screen
  97.     wxCoord m_hLine;
  98.  
  99.     // the number of lines we draw
  100.     size_t m_nLines;
  101. };
  102.  
  103. // this class does "stupid" redrawing - it redraws everything each time
  104. // and sets the scrollbar extent directly.
  105.  
  106. class MyScrolledWindowDumb : public MyScrolledWindowBase
  107. {
  108. public:
  109.     MyScrolledWindowDumb(wxWindow *parent) : MyScrolledWindowBase(parent)
  110.     {
  111.         // no horz scrolling
  112.         SetScrollbars(0, m_hLine, 0, m_nLines + 1, 0, 0, TRUE /* no refresh */);
  113.     }
  114.  
  115.     virtual void OnDraw(wxDC& dc);
  116. };
  117.  
  118. // this class does "smart" redrawing - only redraws the lines which must be
  119. // redrawn and sets the scroll rate and virtual size to affect the
  120. // scrollbars.
  121. //
  122. // Note that this class should produce identical results to the one above.
  123.  
  124. class MyScrolledWindowSmart : public MyScrolledWindowBase
  125. {
  126. public:
  127.     MyScrolledWindowSmart(wxWindow *parent) : MyScrolledWindowBase(parent)
  128.     {
  129.         // no horz scrolling
  130.         SetScrollRate( 0, m_hLine );
  131.         SetVirtualSize( -1, ( m_nLines + 1 ) * m_hLine );
  132.     }
  133.  
  134.     virtual void OnDraw(wxDC& dc);
  135. };
  136.  
  137.  
  138. // ----------------------------------------------------------------------------
  139. // MyFrame
  140. // ----------------------------------------------------------------------------
  141.  
  142. class MyFrame: public wxFrame
  143. {
  144. public:
  145.     MyFrame();
  146.  
  147.     void OnAbout( wxCommandEvent &event );
  148.     void OnQuit( wxCommandEvent &event );
  149.     void OnDeleteAll( wxCommandEvent &event );
  150.     void OnInsertNew( wxCommandEvent &event );
  151.  
  152.     MyCanvas         *m_canvas;
  153.     wxTextCtrl       *m_log;
  154.  
  155.     DECLARE_DYNAMIC_CLASS(MyFrame)
  156.     DECLARE_EVENT_TABLE()
  157. };
  158.  
  159. // MyApp
  160.  
  161. class MyApp: public wxApp
  162. {
  163. public:
  164.     virtual bool OnInit();
  165. };
  166.  
  167. // main program
  168.  
  169. IMPLEMENT_APP(MyApp)
  170.  
  171. // ids
  172.  
  173. const long   ID_ADDBUTTON   = wxNewId();
  174. const long   ID_DELBUTTON   = wxNewId();
  175. const long   ID_MOVEBUTTON  = wxNewId();
  176. const long   ID_SCROLLWIN   = wxNewId();
  177. const long   ID_QUERYPOS    = wxNewId();
  178.  
  179. const long   ID_NEWBUTTON   = wxNewId();
  180.  
  181. // MyCanvas
  182.  
  183. IMPLEMENT_DYNAMIC_CLASS(MyCanvas, wxScrolledWindow)
  184.  
  185. BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
  186.   EVT_PAINT(                  MyCanvas::OnPaint)
  187.   EVT_MOUSE_EVENTS(           MyCanvas::OnMouseDown)
  188.   EVT_BUTTON( ID_QUERYPOS,    MyCanvas::OnQueryPosition)
  189.   EVT_BUTTON( ID_ADDBUTTON,   MyCanvas::OnAddButton)
  190.   EVT_BUTTON( ID_DELBUTTON,   MyCanvas::OnDeleteButton)
  191.   EVT_BUTTON( ID_MOVEBUTTON,  MyCanvas::OnMoveButton)
  192.   EVT_BUTTON( ID_SCROLLWIN,   MyCanvas::OnScrollWin)
  193. END_EVENT_TABLE()
  194.  
  195. MyCanvas::MyCanvas( wxWindow *parent, wxWindowID id,
  196.                     const wxPoint &pos, const wxSize &size )
  197.     : wxScrolledWindow( parent, id, pos, size, wxSUNKEN_BORDER | wxTAB_TRAVERSAL, _T("test canvas") )
  198. {
  199.     SetScrollRate( 10, 10 );
  200.     SetVirtualSize( 500, 1000 );
  201.  
  202.     (void) new wxButton( this, ID_ADDBUTTON,  _T("add button"), wxPoint(10,10) );
  203.     (void) new wxButton( this, ID_DELBUTTON,  _T("del button"), wxPoint(10,40) );
  204.     (void) new wxButton( this, ID_MOVEBUTTON, _T("move button"), wxPoint(150,10) );
  205.     (void) new wxButton( this, ID_SCROLLWIN,  _T("scroll win"), wxPoint(250,10) );
  206.  
  207. #if 0
  208.  
  209.     wxString choices[] =
  210.     {
  211.         "This",
  212.         "is one of my",
  213.         "really",
  214.         "wonderful",
  215.         "examples."
  216.     };
  217.  
  218.     m_button = new wxButton( this, ID_QUERYPOS, "Query position", wxPoint(10,110) );
  219.  
  220.     (void) new wxTextCtrl( this, -1, "wxTextCtrl", wxPoint(10,150), wxSize(80,-1) );
  221.  
  222.     (void) new wxRadioButton( this, -1, "Disable", wxPoint(10,190) );
  223.  
  224.     (void) new wxComboBox( this, -1, "This", wxPoint(10,230), wxDefaultSize, 5, choices );
  225.  
  226.     (void) new wxRadioBox( this, -1, "This", wxPoint(10,310), wxDefaultSize, 5, choices, 2, wxRA_SPECIFY_COLS );
  227.  
  228.     (void) new wxRadioBox( this, -1, "This", wxPoint(10,440), wxDefaultSize, 5, choices, 2, wxRA_SPECIFY_ROWS );
  229.  
  230.     wxListCtrl *m_listCtrl = new wxListCtrl(
  231.             this, -1, wxPoint(200, 110), wxSize(180, 120),
  232.             wxLC_REPORT | wxSIMPLE_BORDER | wxLC_SINGLE_SEL );
  233.  
  234.     m_listCtrl->InsertColumn(0, "First", wxLIST_FORMAT_LEFT, 90);
  235.     m_listCtrl->InsertColumn(1, "Last", wxLIST_FORMAT_LEFT, 90);
  236.  
  237.     for ( int i=0; i < 30; i++)
  238.     {
  239.         char buf[20];
  240.         sprintf(buf, "Item %d", i);
  241.         m_listCtrl->InsertItem(i, buf);
  242.     }
  243.     m_listCtrl->SetItemState( 3, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
  244.  
  245.     (void) new wxListBox( this, -1, wxPoint(260,280), wxSize(120,120), 5, choices, wxLB_ALWAYS_SB );
  246.  
  247. #endif
  248.  
  249.     wxPanel *test = new wxPanel( this, -1, wxPoint(10, 110), wxSize(130,50), wxSIMPLE_BORDER | wxTAB_TRAVERSAL );
  250.     test->SetBackgroundColour( wxT("WHEAT") );
  251.  
  252. #if 0
  253.  
  254.     wxButton *test2 = new wxButton( test, -1, "Hallo", wxPoint(10,10) );
  255.  
  256.     test = new wxPanel( this, -1, wxPoint(160, 530), wxSize(130,120), wxSUNKEN_BORDER | wxTAB_TRAVERSAL );
  257.     test->SetBackgroundColour( wxT("WHEAT") );
  258.     test->SetCursor( wxCursor( wxCURSOR_NO_ENTRY ) );
  259.     test2 = new wxButton( test, -1, "Hallo", wxPoint(10,10) );
  260.     test2->SetCursor( wxCursor( wxCURSOR_PENCIL ) );
  261.  
  262.     test = new wxPanel( this, -1, wxPoint(310, 530), wxSize(130,120), wxRAISED_BORDER | wxTAB_TRAVERSAL );
  263.     test->SetBackgroundColour( wxT("WHEAT") );
  264.     test->SetCursor( wxCursor( wxCURSOR_PENCIL ) );
  265.     test2 = new wxButton( test, -1, "Hallo", wxPoint(10,10) );
  266.     test2->SetCursor( wxCursor( wxCURSOR_NO_ENTRY ) );
  267.  
  268. #endif
  269.  
  270.     SetBackgroundColour( wxT("BLUE") );
  271.  
  272.     SetCursor( wxCursor( wxCURSOR_IBEAM ) );
  273. }
  274.  
  275. MyCanvas::~MyCanvas()
  276. {
  277. }
  278.  
  279. void MyCanvas::OnMouseDown( wxMouseEvent &event )
  280. {
  281.     if (event.LeftDown())
  282.     {
  283.         wxPoint pt( event.GetPosition() );
  284.         int x,y;
  285.         CalcUnscrolledPosition( pt.x, pt.y, &x, &y );
  286.         wxLogMessage( wxT("Mouse down event at: %d %d, scrolled: %d %d"), pt.x, pt.y, x, y );
  287.  
  288.         if ( !event.LeftIsDown() )
  289.             wxLogMessage( wxT("Error: LeftIsDown() should be TRUE if for LeftDown()") );
  290.     }
  291. }
  292.  
  293. void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) )
  294. {
  295.     wxPaintDC dc( this );
  296.     PrepareDC( dc );
  297.  
  298.     dc.DrawText( _T("Press mouse button to test calculations!"), 160, 50 );
  299.  
  300.     dc.DrawText( _T("Some text"), 140, 140 );
  301.  
  302.     dc.DrawRectangle( 100, 160, 200, 200 );
  303. }
  304.  
  305. void MyCanvas::OnQueryPosition( wxCommandEvent &WXUNUSED(event) )
  306. {
  307.     wxPoint pt( m_button->GetPosition() );
  308.     wxLogMessage( wxT("Position of \"Query position\" is %d %d"), pt.x, pt.y );
  309.     pt = ClientToScreen( pt );
  310.     wxLogMessage( wxT("Position of \"Query position\" on screen is %d %d"), pt.x, pt.y );
  311. }
  312.  
  313. void MyCanvas::OnAddButton( wxCommandEvent &WXUNUSED(event) )
  314. {
  315.     wxLogMessage( wxT("Inserting button at position 10,70...") );
  316.     wxButton *button = new wxButton( this, ID_NEWBUTTON, wxT("new button"), wxPoint(10,70), wxSize(80,25) );
  317.     wxPoint pt( button->GetPosition() );
  318.     wxLogMessage( wxT("-> Position after inserting %d %d"), pt.x, pt.y );
  319. }
  320.  
  321. void MyCanvas::OnDeleteButton( wxCommandEvent &event )
  322. {
  323.     wxLogMessage( wxT("Deleting button inserted with \"Add button\"...") );
  324.     wxWindow *win = FindWindow( ID_NEWBUTTON );
  325.     if (win)
  326.        win->Destroy();
  327.     else
  328.        wxLogMessage( wxT("-> No window with id = ID_NEWBUTTON found.") );
  329. }
  330.  
  331. void MyCanvas::OnMoveButton( wxCommandEvent &event )
  332. {
  333.     wxLogMessage( wxT("Moving button 10 pixels downward..") );
  334.     wxWindow *win = FindWindow( event.GetId() );
  335.     wxPoint pt( win->GetPosition() );
  336.     wxLogMessage( wxT("-> Position before move is %d %d"), pt.x, pt.y );
  337.     win->Move( -1, pt.y + 10 );
  338.     pt = win->GetPosition();
  339.     wxLogMessage( wxT("-> Position after move is %d %d"), pt.x, pt.y );
  340. }
  341.  
  342. void MyCanvas::OnScrollWin( wxCommandEvent &WXUNUSED(event) )
  343. {
  344.     wxLogMessage( wxT("Scrolling 2 units up.\nThe white square and the controls should move equally!") );
  345.     int x,y;
  346.     GetViewStart( &x, &y );
  347.     Scroll( -1, y+2 );
  348. }
  349.  
  350. // MyAutoScrollWindow
  351.  
  352. const long   ID_RESIZEBUTTON = wxNewId();
  353. const wxSize SMALL_BUTTON( 100, 50 );
  354. const wxSize LARGE_BUTTON( 300, 100 );
  355.  
  356. BEGIN_EVENT_TABLE( MyAutoScrollWindow, wxScrolledWindow)
  357.   EVT_BUTTON( ID_RESIZEBUTTON,    MyAutoScrollWindow::OnResizeClick)
  358. END_EVENT_TABLE()
  359.  
  360. MyAutoScrollWindow::MyAutoScrollWindow( wxWindow *parent )
  361.     : wxScrolledWindow( parent )
  362. {
  363.     SetBackgroundColour( wxT("GREEN") );
  364.  
  365.     // Set the rate we'd like for scrolling.
  366.  
  367.     SetScrollRate( 5, 5 );
  368.  
  369.     // Populate a sizer with a 'resizing' button and some
  370.     // other static decoration
  371.  
  372.     wxFlexGridSizer  *innersizer = new wxFlexGridSizer( 2, 2 );
  373.  
  374.     m_button = new wxButton( this,
  375.                              ID_RESIZEBUTTON,
  376.                              _T("Press me"),
  377.                              wxDefaultPosition,
  378.                              SMALL_BUTTON );
  379.  
  380.     // We need to do this here, because wxADJUST_MINSIZE below
  381.     // will cause the initial size to be ignored for Best/Min size.
  382.     // It would be nice to fix the sizers to handle this a little
  383.     // more cleanly.
  384.  
  385.     m_button->SetSizeHints( SMALL_BUTTON.GetWidth(), SMALL_BUTTON.GetHeight() );
  386.  
  387.     innersizer->Add( m_button,
  388.                      0,
  389.                      wxALIGN_CENTER | wxALL | wxADJUST_MINSIZE,
  390.                      20 );
  391.  
  392.     innersizer->Add( new wxStaticText( this, -1, _T("This is just") ),
  393.                     0,
  394.                     wxALIGN_CENTER );
  395.  
  396.     innersizer->Add( new wxStaticText( this, -1, _T("some decoration") ),
  397.                     0,
  398.                     wxALIGN_CENTER );
  399.  
  400.     innersizer->Add( new wxStaticText( this, -1, _T("for you to scroll...") ),
  401.                     0,
  402.                     wxALIGN_CENTER );
  403.  
  404.     // Then use the sizer to set the scrolled region size.
  405.  
  406.     SetSizer( innersizer );
  407. }
  408.  
  409. void MyAutoScrollWindow::OnResizeClick( wxCommandEvent &WXUNUSED( event ) )
  410. {
  411.     // Arbitrarily resize the button to change the minimum size of
  412.     // the (scrolled) sizer.
  413.  
  414.     if( m_button->GetSize() == SMALL_BUTTON )
  415.         m_button->SetSizeHints( LARGE_BUTTON.GetWidth(), LARGE_BUTTON.GetHeight() );
  416.     else
  417.         m_button->SetSizeHints( SMALL_BUTTON.GetWidth(), SMALL_BUTTON.GetHeight() );
  418.  
  419.     // Force update layout and scrollbars, since nothing we do here
  420.     // necessarily generates a size event which would do it for us.
  421.  
  422.     FitInside();
  423. }
  424.  
  425. // MyFrame
  426.  
  427. const long ID_QUIT       = wxNewId();
  428. const long ID_ABOUT      = wxNewId();
  429. const long ID_DELETE_ALL = wxNewId();
  430. const long ID_INSERT_NEW = wxNewId();
  431.  
  432. IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
  433.  
  434. BEGIN_EVENT_TABLE(MyFrame,wxFrame)
  435.   EVT_MENU    (ID_DELETE_ALL, MyFrame::OnDeleteAll)
  436.   EVT_MENU    (ID_INSERT_NEW,  MyFrame::OnInsertNew)
  437.   EVT_MENU    (ID_ABOUT, MyFrame::OnAbout)
  438.   EVT_MENU    (ID_QUIT,  MyFrame::OnQuit)
  439. END_EVENT_TABLE()
  440.  
  441. MyFrame::MyFrame()
  442.        : wxFrame( (wxFrame *)NULL, -1, _T("wxScrolledWindow sample"),
  443.                   wxPoint(20,20), wxSize(470,500) )
  444. {
  445.     wxMenu *file_menu = new wxMenu();
  446.     file_menu->Append( ID_DELETE_ALL, _T("Delete all"));
  447.     file_menu->Append( ID_INSERT_NEW, _T("Insert new"));
  448.     file_menu->Append( ID_ABOUT,      _T("&About.."));
  449.     file_menu->Append( ID_QUIT,       _T("E&xit\tAlt-X"));
  450.  
  451.     wxMenuBar *menu_bar = new wxMenuBar();
  452.     menu_bar->Append(file_menu, _T("&File"));
  453.  
  454.     SetMenuBar( menu_bar );
  455.  
  456.     CreateStatusBar(2);
  457.     int widths[] = { -1, 100 };
  458.     SetStatusWidths( 2, widths );
  459.  
  460.     wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
  461.  
  462.     // Setting an explicit size here is superfluous, it will be overridden
  463.     // by the sizer in any case.
  464.     m_canvas = new MyCanvas( this, -1, wxPoint(0,0), wxSize(100,100) );
  465.  
  466.     // This is done with ScrollRate/VirtualSize in MyCanvas ctor now,
  467.     // both should produce identical results.
  468.     //m_canvas->SetScrollbars( 10, 10, 50, 100 );
  469.  
  470.     topsizer->Add( m_canvas, 1, wxEXPAND );
  471.     topsizer->Add( new MyAutoScrollWindow( this ), 1, wxEXPAND );
  472.  
  473.     wxSizer *sizerBtm = new wxBoxSizer(wxHORIZONTAL);
  474.     sizerBtm->Add( new MyScrolledWindowDumb(this), 1, wxEXPAND );
  475.     sizerBtm->Add( new MyScrolledWindowSmart(this), 1, wxEXPAND );
  476.     topsizer->Add( sizerBtm, 1, wxEXPAND );
  477.  
  478.     SetSizer( topsizer );
  479. }
  480.  
  481. void MyFrame::OnDeleteAll( wxCommandEvent &WXUNUSED(event) )
  482. {
  483.     m_canvas->DestroyChildren();
  484. }
  485.  
  486. void MyFrame::OnInsertNew( wxCommandEvent &WXUNUSED(event) )
  487. {
  488.     (void)new wxButton( m_canvas, -1, _T("Hello"), wxPoint(100,100) );
  489. }
  490.  
  491. void MyFrame::OnQuit( wxCommandEvent &WXUNUSED(event) )
  492. {
  493.   Close( TRUE );
  494. }
  495.  
  496. void MyFrame::OnAbout( wxCommandEvent &WXUNUSED(event) )
  497. {
  498.   (void)wxMessageBox( _T("wxScroll demo\n"
  499.                          "Robert Roebling (c) 1998\n"
  500.                          "Autoscrolling examples\n"
  501.                          "Ron Lee (c) 2002"),
  502.                       _T("About wxScroll Demo"),
  503.                       wxICON_INFORMATION | wxOK );
  504. }
  505.  
  506. //-----------------------------------------------------------------------------
  507. // MyApp
  508. //-----------------------------------------------------------------------------
  509.  
  510. bool MyApp::OnInit()
  511. {
  512.   wxFrame *frame = new MyFrame();
  513.   frame->Show( TRUE );
  514.  
  515.   return TRUE;
  516. }
  517.  
  518. // ----------------------------------------------------------------------------
  519. // MyScrolledWindowXXX
  520. // ----------------------------------------------------------------------------
  521.  
  522. void MyScrolledWindowDumb::OnDraw(wxDC& dc)
  523. {
  524.     // this is useful to see which lines are redrawn
  525.     static size_t s_redrawCount = 0;
  526.     dc.SetTextForeground(s_redrawCount++ % 2 ? *wxRED : *wxBLUE);
  527.  
  528.     wxCoord y = 0;
  529.     for ( size_t line = 0; line < m_nLines; line++ )
  530.     {
  531.         wxCoord yPhys;
  532.         CalcScrolledPosition(0, y, NULL, &yPhys);
  533.  
  534.         dc.DrawText(wxString::Format(_T("Line %u (logical %d, physical %d)"),
  535.                                      line, y, yPhys), 0, y);
  536.         y += m_hLine;
  537.     }
  538. }
  539.  
  540. void MyScrolledWindowSmart::OnDraw(wxDC& dc)
  541. {
  542.     // this is useful to see which lines are redrawn
  543.     static size_t s_redrawCount = 0;
  544.     dc.SetTextForeground(s_redrawCount++ % 2 ? *wxRED : *wxBLUE);
  545.  
  546.     // update region is always in device coords, translate to logical ones
  547.     wxRect rectUpdate = GetUpdateRegion().GetBox();
  548.     CalcUnscrolledPosition(rectUpdate.x, rectUpdate.y,
  549.                            &rectUpdate.x, &rectUpdate.y);
  550.  
  551.     size_t lineFrom = rectUpdate.y / m_hLine,
  552.            lineTo = rectUpdate.GetBottom() / m_hLine;
  553.  
  554.     if ( lineTo > m_nLines - 1)
  555.         lineTo = m_nLines - 1;
  556.  
  557.     wxCoord y = lineFrom*m_hLine;
  558.     for ( size_t line = lineFrom; line <= lineTo; line++ )
  559.     {
  560.         wxCoord yPhys;
  561.         CalcScrolledPosition(0, y, NULL, &yPhys);
  562.  
  563.         dc.DrawText(wxString::Format(_T("Line %u (logical %d, physical %d)"),
  564.                                      line, y, yPhys), 0, y);
  565.         y += m_hLine;
  566.     }
  567. }
  568.