Warning fixes found under hardest mode of OpenWatcom. Seems clean in Borland, MinGW...
[wxWidgets.git] / samples / scroll / scroll.cpp
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, wxID_ANY, "wxTextCtrl", wxPoint(10,150), wxSize(80,wxDefaultCoord) );
221
222 (void) new wxRadioButton( this, wxID_ANY, "Disable", wxPoint(10,190) );
223
224 (void) new wxComboBox( this, wxID_ANY, "This", wxPoint(10,230), wxDefaultSize, 5, choices );
225
226 (void) new wxRadioBox( this, wxID_ANY, "This", wxPoint(10,310), wxDefaultSize, 5, choices, 2, wxRA_SPECIFY_COLS );
227
228 (void) new wxRadioBox( this, wxID_ANY, "This", wxPoint(10,440), wxDefaultSize, 5, choices, 2, wxRA_SPECIFY_ROWS );
229
230 wxListCtrl *m_listCtrl = new wxListCtrl(
231 this, wxID_ANY, 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, wxID_ANY, wxPoint(260,280), wxSize(120,120), 5, choices, wxLB_ALWAYS_SB );
246
247 #endif
248
249 wxPanel *test = new wxPanel( this, wxID_ANY, 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, wxID_ANY, "Hallo", wxPoint(10,10) );
255
256 test = new wxPanel( this, wxID_ANY, 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, wxID_ANY, "Hallo", wxPoint(10,10) );
260 test2->SetCursor( wxCursor( wxCURSOR_PENCIL ) );
261
262 test = new wxPanel( this, wxID_ANY, 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, wxID_ANY, "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 void MyCanvas::OnMouseDown( wxMouseEvent &event )
276 {
277 if (event.LeftDown())
278 {
279 wxPoint pt( event.GetPosition() );
280 int x,y;
281 CalcUnscrolledPosition( pt.x, pt.y, &x, &y );
282 wxLogMessage( wxT("Mouse down event at: %d %d, scrolled: %d %d"), pt.x, pt.y, x, y );
283
284 if ( !event.LeftIsDown() )
285 wxLogMessage( wxT("Error: LeftIsDown() should be true if for LeftDown()") );
286 }
287 }
288
289 void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) )
290 {
291 wxPaintDC dc( this );
292 PrepareDC( dc );
293
294 dc.DrawText( _T("Press mouse button to test calculations!"), 160, 50 );
295
296 dc.DrawText( _T("Some text"), 140, 140 );
297
298 dc.DrawRectangle( 100, 160, 200, 200 );
299 }
300
301 void MyCanvas::OnQueryPosition( wxCommandEvent &WXUNUSED(event) )
302 {
303 wxPoint pt( m_button->GetPosition() );
304 wxLogMessage( wxT("Position of \"Query position\" is %d %d"), pt.x, pt.y );
305 pt = ClientToScreen( pt );
306 wxLogMessage( wxT("Position of \"Query position\" on screen is %d %d"), pt.x, pt.y );
307 }
308
309 void MyCanvas::OnAddButton( wxCommandEvent &WXUNUSED(event) )
310 {
311 wxLogMessage( wxT("Inserting button at position 10,70...") );
312 wxButton *button = new wxButton( this, ID_NEWBUTTON, wxT("new button"), wxPoint(10,70), wxSize(80,25) );
313 wxPoint pt( button->GetPosition() );
314 wxLogMessage( wxT("-> Position after inserting %d %d"), pt.x, pt.y );
315 }
316
317 void MyCanvas::OnDeleteButton( wxCommandEvent &WXUNUSED(event) )
318 {
319 wxLogMessage( wxT("Deleting button inserted with \"Add button\"...") );
320 wxWindow *win = FindWindow( ID_NEWBUTTON );
321 if (win)
322 win->Destroy();
323 else
324 wxLogMessage( wxT("-> No window with id = ID_NEWBUTTON found.") );
325 }
326
327 void MyCanvas::OnMoveButton( wxCommandEvent &event )
328 {
329 wxLogMessage( wxT("Moving button 10 pixels downward..") );
330 wxWindow *win = FindWindow( event.GetId() );
331 wxPoint pt( win->GetPosition() );
332 wxLogMessage( wxT("-> Position before move is %d %d"), pt.x, pt.y );
333 win->Move( wxDefaultCoord, pt.y + 10 );
334 pt = win->GetPosition();
335 wxLogMessage( wxT("-> Position after move is %d %d"), pt.x, pt.y );
336 }
337
338 void MyCanvas::OnScrollWin( wxCommandEvent &WXUNUSED(event) )
339 {
340 wxLogMessage( wxT("Scrolling 2 units up.\nThe white square and the controls should move equally!") );
341 int x,y;
342 GetViewStart( &x, &y );
343 Scroll( -1, y+2 );
344 }
345
346 // MyAutoScrollWindow
347
348 const long ID_RESIZEBUTTON = wxNewId();
349 const wxSize SMALL_BUTTON( 100, 50 );
350 const wxSize LARGE_BUTTON( 300, 100 );
351
352 BEGIN_EVENT_TABLE( MyAutoScrollWindow, wxScrolledWindow)
353 EVT_BUTTON( ID_RESIZEBUTTON, MyAutoScrollWindow::OnResizeClick)
354 END_EVENT_TABLE()
355
356 MyAutoScrollWindow::MyAutoScrollWindow( wxWindow *parent )
357 : wxScrolledWindow( parent )
358 {
359 SetBackgroundColour( wxT("GREEN") );
360
361 // Set the rate we'd like for scrolling.
362
363 SetScrollRate( 5, 5 );
364
365 // Populate a sizer with a 'resizing' button and some
366 // other static decoration
367
368 wxFlexGridSizer *innersizer = new wxFlexGridSizer( 2, 2 );
369
370 m_button = new wxButton( this,
371 ID_RESIZEBUTTON,
372 _T("Press me"),
373 wxDefaultPosition,
374 SMALL_BUTTON );
375
376 // We need to do this here, because wxADJUST_MINSIZE below
377 // will cause the initial size to be ignored for Best/Min size.
378 // It would be nice to fix the sizers to handle this a little
379 // more cleanly.
380
381 m_button->SetSizeHints( SMALL_BUTTON.GetWidth(), SMALL_BUTTON.GetHeight() );
382
383 innersizer->Add( m_button,
384 0,
385 wxALIGN_CENTER | wxALL | wxADJUST_MINSIZE,
386 20 );
387
388 innersizer->Add( new wxStaticText( this, wxID_ANY, _T("This is just") ),
389 0,
390 wxALIGN_CENTER );
391
392 innersizer->Add( new wxStaticText( this, wxID_ANY, _T("some decoration") ),
393 0,
394 wxALIGN_CENTER );
395
396 innersizer->Add( new wxStaticText( this, wxID_ANY, _T("for you to scroll...") ),
397 0,
398 wxALIGN_CENTER );
399
400 // Then use the sizer to set the scrolled region size.
401
402 SetSizer( innersizer );
403 }
404
405 void MyAutoScrollWindow::OnResizeClick( wxCommandEvent &WXUNUSED( event ) )
406 {
407 // Arbitrarily resize the button to change the minimum size of
408 // the (scrolled) sizer.
409
410 if( m_button->GetSize() == SMALL_BUTTON )
411 m_button->SetSizeHints( LARGE_BUTTON.GetWidth(), LARGE_BUTTON.GetHeight() );
412 else
413 m_button->SetSizeHints( SMALL_BUTTON.GetWidth(), SMALL_BUTTON.GetHeight() );
414
415 // Force update layout and scrollbars, since nothing we do here
416 // necessarily generates a size event which would do it for us.
417
418 FitInside();
419 }
420
421 // MyFrame
422
423 const long ID_QUIT = wxNewId();
424 const long ID_ABOUT = wxNewId();
425 const long ID_DELETE_ALL = wxNewId();
426 const long ID_INSERT_NEW = wxNewId();
427
428 IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
429
430 BEGIN_EVENT_TABLE(MyFrame,wxFrame)
431 EVT_MENU (ID_DELETE_ALL, MyFrame::OnDeleteAll)
432 EVT_MENU (ID_INSERT_NEW, MyFrame::OnInsertNew)
433 EVT_MENU (ID_ABOUT, MyFrame::OnAbout)
434 EVT_MENU (ID_QUIT, MyFrame::OnQuit)
435 END_EVENT_TABLE()
436
437 MyFrame::MyFrame()
438 : wxFrame( (wxFrame *)NULL, wxID_ANY, _T("wxScrolledWindow sample"),
439 wxPoint(20,20), wxSize(470,500) )
440 {
441 wxMenu *file_menu = new wxMenu();
442 file_menu->Append( ID_DELETE_ALL, _T("Delete all"));
443 file_menu->Append( ID_INSERT_NEW, _T("Insert new"));
444 file_menu->Append( ID_ABOUT, _T("&About.."));
445 file_menu->Append( ID_QUIT, _T("E&xit\tAlt-X"));
446
447 wxMenuBar *menu_bar = new wxMenuBar();
448 menu_bar->Append(file_menu, _T("&File"));
449
450 SetMenuBar( menu_bar );
451
452 #if wxUSE_STATUSBAR
453 CreateStatusBar(2);
454 int widths[] = { -1, 100 };
455 SetStatusWidths( 2, widths );
456 #endif // wxUSE_STATUSBAR
457
458 wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
459
460 // Setting an explicit size here is superfluous, it will be overridden
461 // by the sizer in any case.
462 m_canvas = new MyCanvas( this, wxID_ANY, wxPoint(0,0), wxSize(100,100) );
463
464 // This is done with ScrollRate/VirtualSize in MyCanvas ctor now,
465 // both should produce identical results.
466 //m_canvas->SetScrollbars( 10, 10, 50, 100 );
467
468 topsizer->Add( m_canvas, 1, wxEXPAND );
469 topsizer->Add( new MyAutoScrollWindow( this ), 1, wxEXPAND );
470
471 wxSizer *sizerBtm = new wxBoxSizer(wxHORIZONTAL);
472 sizerBtm->Add( new MyScrolledWindowDumb(this), 1, wxEXPAND );
473 sizerBtm->Add( new MyScrolledWindowSmart(this), 1, wxEXPAND );
474 topsizer->Add( sizerBtm, 1, wxEXPAND );
475
476 SetSizer( topsizer );
477 }
478
479 void MyFrame::OnDeleteAll( wxCommandEvent &WXUNUSED(event) )
480 {
481 m_canvas->DestroyChildren();
482 }
483
484 void MyFrame::OnInsertNew( wxCommandEvent &WXUNUSED(event) )
485 {
486 (void)new wxButton( m_canvas, wxID_ANY, _T("Hello"), wxPoint(100,100) );
487 }
488
489 void MyFrame::OnQuit( wxCommandEvent &WXUNUSED(event) )
490 {
491 Close( true );
492 }
493
494 void MyFrame::OnAbout( wxCommandEvent &WXUNUSED(event) )
495 {
496 (void)wxMessageBox( _T("wxScroll demo\n")
497 _T("Robert Roebling (c) 1998\n")
498 _T("Autoscrolling examples\n")
499 _T("Ron Lee (c) 2002"),
500 _T("About wxScroll Demo"),
501 wxICON_INFORMATION | wxOK );
502 }
503
504 //-----------------------------------------------------------------------------
505 // MyApp
506 //-----------------------------------------------------------------------------
507
508 bool MyApp::OnInit()
509 {
510 wxFrame *frame = new MyFrame();
511 frame->Show( true );
512
513 return true;
514 }
515
516 // ----------------------------------------------------------------------------
517 // MyScrolledWindowXXX
518 // ----------------------------------------------------------------------------
519
520 void MyScrolledWindowDumb::OnDraw(wxDC& dc)
521 {
522 // this is useful to see which lines are redrawn
523 static size_t s_redrawCount = 0;
524 dc.SetTextForeground(s_redrawCount++ % 2 ? *wxRED : *wxBLUE);
525
526 wxCoord y = 0;
527 for ( size_t line = 0; line < m_nLines; line++ )
528 {
529 wxCoord yPhys;
530 CalcScrolledPosition(0, y, NULL, &yPhys);
531
532 dc.DrawText(wxString::Format(_T("Line %u (logical %d, physical %d)"),
533 line, y, yPhys), 0, y);
534 y += m_hLine;
535 }
536 }
537
538 void MyScrolledWindowSmart::OnDraw(wxDC& dc)
539 {
540 // this is useful to see which lines are redrawn
541 static size_t s_redrawCount = 0;
542 dc.SetTextForeground(s_redrawCount++ % 2 ? *wxRED : *wxBLUE);
543
544 // update region is always in device coords, translate to logical ones
545 wxRect rectUpdate = GetUpdateRegion().GetBox();
546 CalcUnscrolledPosition(rectUpdate.x, rectUpdate.y,
547 &rectUpdate.x, &rectUpdate.y);
548
549 size_t lineFrom = rectUpdate.y / m_hLine,
550 lineTo = rectUpdate.GetBottom() / m_hLine;
551
552 if ( lineTo > m_nLines - 1)
553 lineTo = m_nLines - 1;
554
555 wxCoord y = lineFrom*m_hLine;
556 for ( size_t line = lineFrom; line <= lineTo; line++ )
557 {
558 wxCoord yPhys;
559 CalcScrolledPosition(0, y, NULL, &yPhys);
560
561 dc.DrawText(wxString::Format(_T("Line %u (logical %d, physical %d)"),
562 line, y, yPhys), 0, y);
563 y += m_hLine;
564 }
565 }