]> git.saurik.com Git - wxWidgets.git/blob - samples/scroll/scroll.cpp
Documented tbar95.cpp backports
[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, -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 &WXUNUSED(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 }