]>
Commit | Line | Data |
---|---|---|
1 | ///////////////////////////////////////////////////////////////////////////// | |
2 | // Name: scroll.cpp | |
3 | // Purpose: wxScrolledWindow sample | |
4 | // Author: Robert Roebling | |
5 | // Modified by: | |
6 | // Created: | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (C) 1998 Robert Roebling, 2002 Ron Lee, 2003 Matt Gregory | |
9 | // Licence: wxWindows license | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | ||
12 | // For compilers that support precompilation, includes "wx/wx.h". | |
13 | #include "wx/wxprec.h" | |
14 | ||
15 | #ifdef __BORLANDC__ | |
16 | #pragma hdrstop | |
17 | #endif | |
18 | ||
19 | #ifndef WX_PRECOMP | |
20 | #include "wx/wx.h" | |
21 | #endif | |
22 | ||
23 | #include "wx/image.h" | |
24 | #include "wx/listctrl.h" | |
25 | #include "wx/sizer.h" | |
26 | #include "wx/log.h" | |
27 | ||
28 | const long ID_QUIT = wxID_EXIT; | |
29 | const long ID_ABOUT = wxID_ABOUT; | |
30 | const long ID_DELETE_ALL = 100; | |
31 | const long ID_INSERT_NEW = 101; | |
32 | ||
33 | // ---------------------------------------------------------------------- | |
34 | // a trivial example | |
35 | // ---------------------------------------------------------------------- | |
36 | ||
37 | class MySimpleFrame; | |
38 | class MySimpleCanvas; | |
39 | ||
40 | // MySimpleCanvas | |
41 | ||
42 | class MySimpleCanvas: public wxScrolledWindow | |
43 | { | |
44 | public: | |
45 | MySimpleCanvas() { } | |
46 | MySimpleCanvas( wxWindow *parent, wxWindowID, const wxPoint &pos, const wxSize &size ); | |
47 | ||
48 | void OnPaint( wxPaintEvent &event ); | |
49 | ||
50 | private: | |
51 | DECLARE_DYNAMIC_CLASS(MyCanvas) | |
52 | DECLARE_EVENT_TABLE() | |
53 | }; | |
54 | ||
55 | IMPLEMENT_DYNAMIC_CLASS(MySimpleCanvas, wxScrolledWindow) | |
56 | ||
57 | BEGIN_EVENT_TABLE(MySimpleCanvas, wxScrolledWindow) | |
58 | EVT_PAINT( MySimpleCanvas::OnPaint) | |
59 | END_EVENT_TABLE() | |
60 | ||
61 | MySimpleCanvas::MySimpleCanvas( wxWindow *parent, wxWindowID id, | |
62 | const wxPoint &pos, const wxSize &size ) | |
63 | : wxScrolledWindow( parent, id, pos, size, wxSUNKEN_BORDER, _T("test canvas") ) | |
64 | { | |
65 | SetScrollRate( 10, 10 ); | |
66 | SetVirtualSize( 92, 97 ); | |
67 | SetBackgroundColour( *wxWHITE ); | |
68 | } | |
69 | ||
70 | void MySimpleCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) ) | |
71 | { | |
72 | wxPaintDC dc(this); | |
73 | PrepareDC( dc ); | |
74 | ||
75 | dc.SetPen( *wxRED_PEN ); | |
76 | dc.SetBrush( *wxTRANSPARENT_BRUSH ); | |
77 | dc.DrawRectangle( 0,0,92,97 ); | |
78 | } | |
79 | ||
80 | // MySimpleFrame | |
81 | ||
82 | class MySimpleFrame: public wxFrame | |
83 | { | |
84 | public: | |
85 | MySimpleFrame(); | |
86 | ||
87 | void OnQuit( wxCommandEvent &event ); | |
88 | ||
89 | MySimpleCanvas *m_canvas; | |
90 | ||
91 | private: | |
92 | DECLARE_DYNAMIC_CLASS(MySimpleFrame) | |
93 | DECLARE_EVENT_TABLE() | |
94 | }; | |
95 | ||
96 | ||
97 | IMPLEMENT_DYNAMIC_CLASS( MySimpleFrame, wxFrame ) | |
98 | ||
99 | BEGIN_EVENT_TABLE(MySimpleFrame,wxFrame) | |
100 | EVT_MENU (ID_QUIT, MySimpleFrame::OnQuit) | |
101 | END_EVENT_TABLE() | |
102 | ||
103 | MySimpleFrame::MySimpleFrame() | |
104 | : wxFrame( (wxFrame *)NULL, wxID_ANY, _T("wxScrolledWindow sample"), | |
105 | wxPoint(120,120), wxSize(150,150) ) | |
106 | { | |
107 | wxMenu *file_menu = new wxMenu(); | |
108 | file_menu->Append( ID_QUIT, _T("E&xit\tAlt-X")); | |
109 | ||
110 | wxMenuBar *menu_bar = new wxMenuBar(); | |
111 | menu_bar->Append(file_menu, _T("&File")); | |
112 | ||
113 | SetMenuBar( menu_bar ); | |
114 | ||
115 | m_canvas = new MySimpleCanvas( this, wxID_ANY, wxPoint(0,0), wxSize(100,100) ); | |
116 | } | |
117 | ||
118 | void MySimpleFrame::OnQuit( wxCommandEvent &WXUNUSED(event) ) | |
119 | { | |
120 | Close( true ); | |
121 | } | |
122 | ||
123 | // ---------------------------------------------------------------------- | |
124 | // a complex example | |
125 | // ---------------------------------------------------------------------- | |
126 | ||
127 | // derived classes | |
128 | ||
129 | class MyFrame; | |
130 | class MyApp; | |
131 | ||
132 | // MyCanvas | |
133 | ||
134 | class MyCanvas: public wxScrolledWindow | |
135 | { | |
136 | public: | |
137 | MyCanvas() {} | |
138 | MyCanvas( wxWindow *parent, wxWindowID, const wxPoint &pos, const wxSize &size ); | |
139 | ~MyCanvas(){}; | |
140 | void OnPaint( wxPaintEvent &event ); | |
141 | void OnQueryPosition( wxCommandEvent &event ); | |
142 | void OnAddButton( wxCommandEvent &event ); | |
143 | void OnDeleteButton( wxCommandEvent &event ); | |
144 | void OnMoveButton( wxCommandEvent &event ); | |
145 | void OnScrollWin( wxCommandEvent &event ); | |
146 | void OnMouseRightDown( wxMouseEvent &event ); | |
147 | void OnMouseWheel( wxMouseEvent &event ); | |
148 | ||
149 | wxButton *m_button; | |
150 | ||
151 | DECLARE_DYNAMIC_CLASS(MyCanvas) | |
152 | DECLARE_EVENT_TABLE() | |
153 | }; | |
154 | ||
155 | ||
156 | // ---------------------------------------------------------------------------- | |
157 | // Autoscrolling example. | |
158 | // ---------------------------------------------------------------------------- | |
159 | ||
160 | // this class uses the 'virtual' size attribute along with an internal | |
161 | // sizer to automatically set up scrollbars as needed | |
162 | ||
163 | class MyAutoScrollWindow : public wxScrolledWindow | |
164 | { | |
165 | private: | |
166 | ||
167 | wxButton *m_button; | |
168 | ||
169 | public: | |
170 | ||
171 | MyAutoScrollWindow( wxWindow *parent ); | |
172 | ||
173 | void OnResizeClick( wxCommandEvent &WXUNUSED( event ) ); | |
174 | ||
175 | DECLARE_EVENT_TABLE() | |
176 | }; | |
177 | ||
178 | ||
179 | // ---------------------------------------------------------------------------- | |
180 | // MyScrolledWindow classes: examples of wxScrolledWindow usage | |
181 | // ---------------------------------------------------------------------------- | |
182 | ||
183 | // base class for both of them | |
184 | class MyScrolledWindowBase : public wxScrolledWindow | |
185 | { | |
186 | public: | |
187 | MyScrolledWindowBase(wxWindow *parent) | |
188 | : wxScrolledWindow(parent) | |
189 | , m_nLines( 100 ) | |
190 | { | |
191 | wxClientDC dc(this); | |
192 | dc.GetTextExtent(_T("Line 17"), NULL, &m_hLine); | |
193 | } | |
194 | ||
195 | protected: | |
196 | // the height of one line on screen | |
197 | wxCoord m_hLine; | |
198 | ||
199 | // the number of lines we draw | |
200 | size_t m_nLines; | |
201 | }; | |
202 | ||
203 | // this class does "stupid" redrawing - it redraws everything each time | |
204 | // and sets the scrollbar extent directly. | |
205 | ||
206 | class MyScrolledWindowDumb : public MyScrolledWindowBase | |
207 | { | |
208 | public: | |
209 | MyScrolledWindowDumb(wxWindow *parent) : MyScrolledWindowBase(parent) | |
210 | { | |
211 | // no horz scrolling | |
212 | SetScrollbars(0, m_hLine, 0, m_nLines + 1, 0, 0, true /* no refresh */); | |
213 | } | |
214 | ||
215 | virtual void OnDraw(wxDC& dc); | |
216 | }; | |
217 | ||
218 | // this class does "smart" redrawing - only redraws the lines which must be | |
219 | // redrawn and sets the scroll rate and virtual size to affect the | |
220 | // scrollbars. | |
221 | // | |
222 | // Note that this class should produce identical results to the one above. | |
223 | ||
224 | class MyScrolledWindowSmart : public MyScrolledWindowBase | |
225 | { | |
226 | public: | |
227 | MyScrolledWindowSmart(wxWindow *parent) : MyScrolledWindowBase(parent) | |
228 | { | |
229 | // no horz scrolling | |
230 | SetScrollRate( 0, m_hLine ); | |
231 | SetVirtualSize( wxDefaultCoord, ( m_nLines + 1 ) * m_hLine ); | |
232 | } | |
233 | ||
234 | virtual void OnDraw(wxDC& dc); | |
235 | }; | |
236 | ||
237 | // ---------------------------------------------------------------------------- | |
238 | // MyAutoTimedScrollingWindow: implements a text viewer with simple blocksize | |
239 | // selection to test auto-scrolling functionality | |
240 | // ---------------------------------------------------------------------------- | |
241 | ||
242 | class MyAutoTimedScrollingWindow : public wxScrolledWindow | |
243 | { | |
244 | protected: // member data | |
245 | // test data variables | |
246 | static const wxChar* sm_testData; | |
247 | static const int sm_lineCnt; // line count | |
248 | static const int sm_lineLen; // line length in characters | |
249 | // sizes for graphical data | |
250 | wxCoord m_fontH, m_fontW; | |
251 | // selection tracking | |
252 | wxPoint m_selStart; // beginning of blockwise selection | |
253 | wxPoint m_cursor; // end of blockwise selection (mouse position) | |
254 | ||
255 | protected: // gui stuff | |
256 | wxFont m_font; | |
257 | ||
258 | public: // interface | |
259 | MyAutoTimedScrollingWindow( wxWindow* parent ); | |
260 | wxRect DeviceCoordsToGraphicalChars(wxRect updRect) const; | |
261 | wxPoint DeviceCoordsToGraphicalChars(wxPoint pos) const; | |
262 | wxPoint GraphicalCharToDeviceCoords(wxPoint pos) const; | |
263 | wxRect LogicalCoordsToGraphicalChars(wxRect updRect) const; | |
264 | wxPoint LogicalCoordsToGraphicalChars(wxPoint pos) const; | |
265 | wxPoint GraphicalCharToLogicalCoords(wxPoint pos) const; | |
266 | void MyRefresh(); | |
267 | bool IsSelected(int chX, int chY) const; | |
268 | static bool IsInside(int k, int bound1, int bound2); | |
269 | static wxRect DCNormalize(wxCoord x, wxCoord y, wxCoord w, wxCoord h); | |
270 | ||
271 | protected: // event stuff | |
272 | void OnDraw(wxDC& dc); | |
273 | void OnMouseLeftDown(wxMouseEvent& event); | |
274 | void OnMouseLeftUp(wxMouseEvent& event); | |
275 | void OnMouseMove(wxMouseEvent& event); | |
276 | void OnMouseCaptureLost(wxMouseCaptureLostEvent& event); | |
277 | void OnScroll(wxScrollWinEvent& event); | |
278 | ||
279 | DECLARE_EVENT_TABLE() | |
280 | }; | |
281 | ||
282 | // ---------------------------------------------------------------------------- | |
283 | // MyFrame | |
284 | // ---------------------------------------------------------------------------- | |
285 | ||
286 | class MyFrame: public wxFrame | |
287 | { | |
288 | public: | |
289 | MyFrame(); | |
290 | ||
291 | void OnAbout( wxCommandEvent &event ); | |
292 | void OnQuit( wxCommandEvent &event ); | |
293 | void OnDeleteAll( wxCommandEvent &event ); | |
294 | void OnInsertNew( wxCommandEvent &event ); | |
295 | ||
296 | MyCanvas *m_canvas; | |
297 | wxTextCtrl *m_log; | |
298 | ||
299 | DECLARE_DYNAMIC_CLASS(MyFrame) | |
300 | DECLARE_EVENT_TABLE() | |
301 | }; | |
302 | ||
303 | // ---------------------------------------------------------------------------- | |
304 | // MyApp | |
305 | // ---------------------------------------------------------------------------- | |
306 | ||
307 | class MyApp: public wxApp | |
308 | { | |
309 | public: | |
310 | virtual bool OnInit(); | |
311 | }; | |
312 | ||
313 | ||
314 | // ---------------------------------------------------------------------------- | |
315 | // main program | |
316 | // ---------------------------------------------------------------------------- | |
317 | ||
318 | IMPLEMENT_APP(MyApp) | |
319 | ||
320 | // ids | |
321 | ||
322 | const long ID_ADDBUTTON = wxNewId(); | |
323 | const long ID_DELBUTTON = wxNewId(); | |
324 | const long ID_MOVEBUTTON = wxNewId(); | |
325 | const long ID_SCROLLWIN = wxNewId(); | |
326 | const long ID_QUERYPOS = wxNewId(); | |
327 | ||
328 | const long ID_NEWBUTTON = wxNewId(); | |
329 | ||
330 | // ---------------------------------------------------------------------------- | |
331 | // MyCanvas | |
332 | // ---------------------------------------------------------------------------- | |
333 | ||
334 | IMPLEMENT_DYNAMIC_CLASS(MyCanvas, wxScrolledWindow) | |
335 | ||
336 | BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow) | |
337 | EVT_PAINT( MyCanvas::OnPaint) | |
338 | EVT_RIGHT_DOWN( MyCanvas::OnMouseRightDown) | |
339 | EVT_MOUSEWHEEL( MyCanvas::OnMouseWheel) | |
340 | EVT_BUTTON( ID_QUERYPOS, MyCanvas::OnQueryPosition) | |
341 | EVT_BUTTON( ID_ADDBUTTON, MyCanvas::OnAddButton) | |
342 | EVT_BUTTON( ID_DELBUTTON, MyCanvas::OnDeleteButton) | |
343 | EVT_BUTTON( ID_MOVEBUTTON, MyCanvas::OnMoveButton) | |
344 | EVT_BUTTON( ID_SCROLLWIN, MyCanvas::OnScrollWin) | |
345 | END_EVENT_TABLE() | |
346 | ||
347 | MyCanvas::MyCanvas( wxWindow *parent, wxWindowID id, | |
348 | const wxPoint &pos, const wxSize &size ) | |
349 | : wxScrolledWindow( parent, id, pos, size, wxSUNKEN_BORDER | wxTAB_TRAVERSAL, _T("test canvas") ) | |
350 | { | |
351 | SetScrollRate( 10, 10 ); | |
352 | SetVirtualSize( 500, 1000 ); | |
353 | ||
354 | (void) new wxButton( this, ID_ADDBUTTON, _T("add button"), wxPoint(10,10) ); | |
355 | (void) new wxButton( this, ID_DELBUTTON, _T("del button"), wxPoint(10,40) ); | |
356 | (void) new wxButton( this, ID_MOVEBUTTON, _T("move button"), wxPoint(150,10) ); | |
357 | (void) new wxButton( this, ID_SCROLLWIN, _T("scroll win"), wxPoint(250,10) ); | |
358 | ||
359 | #if 0 | |
360 | ||
361 | wxString choices[] = | |
362 | { | |
363 | "This", | |
364 | "is one of my", | |
365 | "really", | |
366 | "wonderful", | |
367 | "examples." | |
368 | }; | |
369 | ||
370 | m_button = new wxButton( this, ID_QUERYPOS, "Query position", wxPoint(10,110) ); | |
371 | ||
372 | (void) new wxTextCtrl( this, wxID_ANY, "wxTextCtrl", wxPoint(10,150), wxSize(80,wxDefaultCoord) ); | |
373 | ||
374 | (void) new wxRadioButton( this, wxID_ANY, "Disable", wxPoint(10,190) ); | |
375 | ||
376 | (void) new wxComboBox( this, wxID_ANY, "This", wxPoint(10,230), wxDefaultSize, 5, choices ); | |
377 | ||
378 | (void) new wxRadioBox( this, wxID_ANY, "This", wxPoint(10,310), wxDefaultSize, 5, choices, 2, wxRA_SPECIFY_COLS ); | |
379 | ||
380 | (void) new wxRadioBox( this, wxID_ANY, "This", wxPoint(10,440), wxDefaultSize, 5, choices, 2, wxRA_SPECIFY_ROWS ); | |
381 | ||
382 | wxListCtrl *m_listCtrl = new wxListCtrl( | |
383 | this, wxID_ANY, wxPoint(200, 110), wxSize(180, 120), | |
384 | wxLC_REPORT | wxSIMPLE_BORDER | wxLC_SINGLE_SEL ); | |
385 | ||
386 | m_listCtrl->InsertColumn(0, "First", wxLIST_FORMAT_LEFT, 90); | |
387 | m_listCtrl->InsertColumn(1, "Last", wxLIST_FORMAT_LEFT, 90); | |
388 | ||
389 | for ( int i=0; i < 30; i++) | |
390 | { | |
391 | char buf[20]; | |
392 | sprintf(buf, "Item %d", i); | |
393 | m_listCtrl->InsertItem(i, buf); | |
394 | } | |
395 | m_listCtrl->SetItemState( 3, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); | |
396 | ||
397 | (void) new wxListBox( this, wxID_ANY, wxPoint(260,280), wxSize(120,120), 5, choices, wxLB_ALWAYS_SB ); | |
398 | ||
399 | #endif | |
400 | ||
401 | wxPanel *test = new wxPanel( this, wxID_ANY, wxPoint(10, 110), wxSize(130,50), wxSIMPLE_BORDER | wxTAB_TRAVERSAL ); | |
402 | test->SetBackgroundColour( wxT("WHEAT") ); | |
403 | ||
404 | #if 0 | |
405 | ||
406 | wxButton *test2 = new wxButton( test, wxID_ANY, "Hallo", wxPoint(10,10) ); | |
407 | ||
408 | test = new wxPanel( this, wxID_ANY, wxPoint(160, 530), wxSize(130,120), wxSUNKEN_BORDER | wxTAB_TRAVERSAL ); | |
409 | test->SetBackgroundColour( wxT("WHEAT") ); | |
410 | test->SetCursor( wxCursor( wxCURSOR_NO_ENTRY ) ); | |
411 | test2 = new wxButton( test, wxID_ANY, "Hallo", wxPoint(10,10) ); | |
412 | test2->SetCursor( wxCursor( wxCURSOR_PENCIL ) ); | |
413 | ||
414 | test = new wxPanel( this, wxID_ANY, wxPoint(310, 530), wxSize(130,120), wxRAISED_BORDER | wxTAB_TRAVERSAL ); | |
415 | test->SetBackgroundColour( wxT("WHEAT") ); | |
416 | test->SetCursor( wxCursor( wxCURSOR_PENCIL ) ); | |
417 | test2 = new wxButton( test, wxID_ANY, "Hallo", wxPoint(10,10) ); | |
418 | test2->SetCursor( wxCursor( wxCURSOR_NO_ENTRY ) ); | |
419 | ||
420 | #endif | |
421 | ||
422 | SetBackgroundColour( wxT("BLUE") ); | |
423 | ||
424 | SetCursor( wxCursor( wxCURSOR_IBEAM ) ); | |
425 | } | |
426 | ||
427 | void MyCanvas::OnMouseRightDown( wxMouseEvent &event ) | |
428 | { | |
429 | wxPoint pt( event.GetPosition() ); | |
430 | int x,y; | |
431 | CalcUnscrolledPosition( pt.x, pt.y, &x, &y ); | |
432 | wxLogMessage( wxT("Mouse down event at: %d %d, scrolled: %d %d"), pt.x, pt.y, x, y ); | |
433 | } | |
434 | ||
435 | void MyCanvas::OnMouseWheel( wxMouseEvent &event ) | |
436 | { | |
437 | wxPoint pt( event.GetPosition() ); | |
438 | int x,y; | |
439 | CalcUnscrolledPosition( pt.x, pt.y, &x, &y ); | |
440 | wxLogMessage( wxT("Mouse wheel event at: %d %d, scrolled: %d %d\n") | |
441 | wxT("Rotation: %d, delta = %d"), | |
442 | pt.x, pt.y, x, y, | |
443 | event.GetWheelRotation(), event.GetWheelDelta() ); | |
444 | ||
445 | event.Skip(); | |
446 | } | |
447 | ||
448 | void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) ) | |
449 | { | |
450 | wxPaintDC dc( this ); | |
451 | PrepareDC( dc ); | |
452 | ||
453 | dc.DrawText( _T("Press mouse button to test calculations!"), 160, 50 ); | |
454 | ||
455 | dc.DrawText( _T("Some text"), 140, 140 ); | |
456 | ||
457 | dc.DrawRectangle( 100, 160, 200, 200 ); | |
458 | } | |
459 | ||
460 | void MyCanvas::OnQueryPosition( wxCommandEvent &WXUNUSED(event) ) | |
461 | { | |
462 | wxPoint pt( m_button->GetPosition() ); | |
463 | wxLogMessage( wxT("Position of \"Query position\" is %d %d"), pt.x, pt.y ); | |
464 | pt = ClientToScreen( pt ); | |
465 | wxLogMessage( wxT("Position of \"Query position\" on screen is %d %d"), pt.x, pt.y ); | |
466 | } | |
467 | ||
468 | void MyCanvas::OnAddButton( wxCommandEvent &WXUNUSED(event) ) | |
469 | { | |
470 | wxLogMessage( wxT("Inserting button at position 10,70...") ); | |
471 | wxButton *button = new wxButton( this, ID_NEWBUTTON, wxT("new button"), wxPoint(10,70), wxSize(80,25) ); | |
472 | wxPoint pt( button->GetPosition() ); | |
473 | wxLogMessage( wxT("-> Position after inserting %d %d"), pt.x, pt.y ); | |
474 | } | |
475 | ||
476 | void MyCanvas::OnDeleteButton( wxCommandEvent &WXUNUSED(event) ) | |
477 | { | |
478 | wxLogMessage( wxT("Deleting button inserted with \"Add button\"...") ); | |
479 | wxWindow *win = FindWindow( ID_NEWBUTTON ); | |
480 | if (win) | |
481 | win->Destroy(); | |
482 | else | |
483 | wxLogMessage( wxT("-> No window with id = ID_NEWBUTTON found.") ); | |
484 | } | |
485 | ||
486 | void MyCanvas::OnMoveButton( wxCommandEvent &event ) | |
487 | { | |
488 | wxLogMessage( wxT("Moving button 10 pixels downward..") ); | |
489 | wxWindow *win = FindWindow( event.GetId() ); | |
490 | wxPoint pt( win->GetPosition() ); | |
491 | wxLogMessage( wxT("-> Position before move is %d %d"), pt.x, pt.y ); | |
492 | win->Move( wxDefaultCoord, pt.y + 10 ); | |
493 | pt = win->GetPosition(); | |
494 | wxLogMessage( wxT("-> Position after move is %d %d"), pt.x, pt.y ); | |
495 | } | |
496 | ||
497 | void MyCanvas::OnScrollWin( wxCommandEvent &WXUNUSED(event) ) | |
498 | { | |
499 | wxLogMessage( wxT("Scrolling 2 units up.\nThe white square and the controls should move equally!") ); | |
500 | int x,y; | |
501 | GetViewStart( &x, &y ); | |
502 | Scroll( wxDefaultCoord, y+2 ); | |
503 | } | |
504 | ||
505 | // ---------------------------------------------------------------------------- | |
506 | // MyAutoScrollWindow | |
507 | // ---------------------------------------------------------------------------- | |
508 | ||
509 | const long ID_RESIZEBUTTON = wxNewId(); | |
510 | const wxSize SMALL_BUTTON( 100, 50 ); | |
511 | const wxSize LARGE_BUTTON( 300, 100 ); | |
512 | ||
513 | BEGIN_EVENT_TABLE( MyAutoScrollWindow, wxScrolledWindow) | |
514 | EVT_BUTTON( ID_RESIZEBUTTON, MyAutoScrollWindow::OnResizeClick) | |
515 | END_EVENT_TABLE() | |
516 | ||
517 | MyAutoScrollWindow::MyAutoScrollWindow( wxWindow *parent ) | |
518 | : wxScrolledWindow( parent, -1, wxDefaultPosition, wxDefaultSize, | |
519 | wxSUNKEN_BORDER|wxScrolledWindowStyle ) | |
520 | { | |
521 | SetBackgroundColour( wxT("GREEN") ); | |
522 | ||
523 | // Set the rate we'd like for scrolling. | |
524 | ||
525 | SetScrollRate( 5, 5 ); | |
526 | ||
527 | // Populate a sizer with a 'resizing' button and some | |
528 | // other static decoration | |
529 | ||
530 | wxFlexGridSizer *innersizer = new wxFlexGridSizer( 2, 2 ); | |
531 | ||
532 | m_button = new wxButton( this, | |
533 | ID_RESIZEBUTTON, | |
534 | _T("Press me"), | |
535 | wxDefaultPosition, | |
536 | SMALL_BUTTON ); | |
537 | ||
538 | m_button->SetSizeHints( SMALL_BUTTON.GetWidth(), SMALL_BUTTON.GetHeight() ); | |
539 | ||
540 | innersizer->Add( m_button, | |
541 | 0, | |
542 | wxALIGN_CENTER | wxALL, | |
543 | 20 ); | |
544 | ||
545 | innersizer->Add( new wxStaticText( this, wxID_ANY, _T("This is just") ), | |
546 | 0, | |
547 | wxALIGN_CENTER ); | |
548 | ||
549 | innersizer->Add( new wxStaticText( this, wxID_ANY, _T("some decoration") ), | |
550 | 0, | |
551 | wxALIGN_CENTER ); | |
552 | ||
553 | innersizer->Add( new wxStaticText( this, wxID_ANY, _T("for you to scroll...") ), | |
554 | 0, | |
555 | wxALIGN_CENTER ); | |
556 | ||
557 | // Then use the sizer to set the scrolled region size. | |
558 | ||
559 | SetSizer( innersizer ); | |
560 | } | |
561 | ||
562 | void MyAutoScrollWindow::OnResizeClick( wxCommandEvent &WXUNUSED( event ) ) | |
563 | { | |
564 | // Arbitrarily resize the button to change the minimum size of | |
565 | // the (scrolled) sizer. | |
566 | ||
567 | if( m_button->GetSize() == SMALL_BUTTON ) | |
568 | m_button->SetSizeHints( LARGE_BUTTON.GetWidth(), LARGE_BUTTON.GetHeight() ); | |
569 | else | |
570 | m_button->SetSizeHints( SMALL_BUTTON.GetWidth(), SMALL_BUTTON.GetHeight() ); | |
571 | ||
572 | // Force update layout and scrollbars, since nothing we do here | |
573 | // necessarily generates a size event which would do it for us. | |
574 | ||
575 | FitInside(); | |
576 | } | |
577 | ||
578 | // ---------------------------------------------------------------------------- | |
579 | // MyFrame | |
580 | // ---------------------------------------------------------------------------- | |
581 | ||
582 | IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame ) | |
583 | ||
584 | BEGIN_EVENT_TABLE(MyFrame,wxFrame) | |
585 | EVT_MENU (ID_DELETE_ALL, MyFrame::OnDeleteAll) | |
586 | EVT_MENU (ID_INSERT_NEW, MyFrame::OnInsertNew) | |
587 | EVT_MENU (ID_ABOUT, MyFrame::OnAbout) | |
588 | EVT_MENU (ID_QUIT, MyFrame::OnQuit) | |
589 | END_EVENT_TABLE() | |
590 | ||
591 | MyFrame::MyFrame() | |
592 | : wxFrame( (wxFrame *)NULL, wxID_ANY, _T("wxScrolledWindow sample"), | |
593 | wxPoint(20,20), wxSize(800,500) ) | |
594 | { | |
595 | wxMenu *file_menu = new wxMenu(); | |
596 | file_menu->Append( ID_DELETE_ALL, _T("Delete all")); | |
597 | file_menu->Append( ID_INSERT_NEW, _T("Insert new")); | |
598 | file_menu->Append( ID_ABOUT, _T("&About..")); | |
599 | file_menu->Append( ID_QUIT, _T("E&xit\tAlt-X")); | |
600 | ||
601 | wxMenuBar *menu_bar = new wxMenuBar(); | |
602 | menu_bar->Append(file_menu, _T("&File")); | |
603 | ||
604 | SetMenuBar( menu_bar ); | |
605 | ||
606 | #if wxUSE_STATUSBAR | |
607 | CreateStatusBar(2); | |
608 | int widths[] = { -1, 100 }; | |
609 | SetStatusWidths( 2, widths ); | |
610 | #endif // wxUSE_STATUSBAR | |
611 | ||
612 | wxBoxSizer *topsizer = new wxBoxSizer( wxHORIZONTAL ); | |
613 | // subsizer splits topsizer down the middle | |
614 | wxBoxSizer *subsizer = new wxBoxSizer( wxVERTICAL ); | |
615 | ||
616 | // Setting an explicit size here is superfluous, it will be overridden | |
617 | // by the sizer in any case. | |
618 | m_canvas = new MyCanvas( this, wxID_ANY, wxPoint(0,0), wxSize(100,100) ); | |
619 | ||
620 | // This is done with ScrollRate/VirtualSize in MyCanvas ctor now, | |
621 | // both should produce identical results. | |
622 | //m_canvas->SetScrollbars( 10, 10, 50, 100 ); | |
623 | ||
624 | subsizer->Add( m_canvas, 1, wxEXPAND ); | |
625 | subsizer->Add( new MyAutoScrollWindow( this ), 1, wxEXPAND ); | |
626 | ||
627 | wxSizer *sizerBtm = new wxBoxSizer(wxHORIZONTAL); | |
628 | sizerBtm->Add( new MyScrolledWindowDumb(this), 1, wxEXPAND ); | |
629 | sizerBtm->Add( new MyScrolledWindowSmart(this), 1, wxEXPAND ); | |
630 | subsizer->Add( sizerBtm, 1, wxEXPAND ); | |
631 | ||
632 | topsizer->Add( subsizer, 1, wxEXPAND ); | |
633 | topsizer->Add( new MyAutoTimedScrollingWindow( this ), 1, wxEXPAND ); | |
634 | ||
635 | SetSizer( topsizer ); | |
636 | } | |
637 | ||
638 | void MyFrame::OnDeleteAll( wxCommandEvent &WXUNUSED(event) ) | |
639 | { | |
640 | m_canvas->DestroyChildren(); | |
641 | } | |
642 | ||
643 | void MyFrame::OnInsertNew( wxCommandEvent &WXUNUSED(event) ) | |
644 | { | |
645 | (void)new wxButton( m_canvas, wxID_ANY, _T("Hello"), wxPoint(100,100) ); | |
646 | } | |
647 | ||
648 | void MyFrame::OnQuit( wxCommandEvent &WXUNUSED(event) ) | |
649 | { | |
650 | Close( true ); | |
651 | } | |
652 | ||
653 | void MyFrame::OnAbout( wxCommandEvent &WXUNUSED(event) ) | |
654 | { | |
655 | (void)wxMessageBox( _T("wxScroll demo\n") | |
656 | _T("Robert Roebling (c) 1998\n") | |
657 | _T("Autoscrolling examples\n") | |
658 | _T("Ron Lee (c) 2002\n") | |
659 | _T("Auto-timed-scrolling example\n") | |
660 | _T("Matt Gregory (c) 2003\n"), | |
661 | _T("About wxScroll Demo"), | |
662 | wxICON_INFORMATION | wxOK ); | |
663 | } | |
664 | ||
665 | //----------------------------------------------------------------------------- | |
666 | // MyApp | |
667 | //----------------------------------------------------------------------------- | |
668 | ||
669 | bool MyApp::OnInit() | |
670 | { | |
671 | if ( !wxApp::OnInit() ) | |
672 | return false; | |
673 | ||
674 | wxFrame *frame = new MyFrame(); | |
675 | frame->Show( true ); | |
676 | ||
677 | frame = new MySimpleFrame(); | |
678 | frame->Show(); | |
679 | ||
680 | return true; | |
681 | } | |
682 | ||
683 | // ---------------------------------------------------------------------------- | |
684 | // MyScrolledWindowXXX | |
685 | // ---------------------------------------------------------------------------- | |
686 | ||
687 | void MyScrolledWindowDumb::OnDraw(wxDC& dc) | |
688 | { | |
689 | // this is useful to see which lines are redrawn | |
690 | static size_t s_redrawCount = 0; | |
691 | dc.SetTextForeground(s_redrawCount++ % 2 ? *wxRED : *wxBLUE); | |
692 | ||
693 | wxCoord y = 0; | |
694 | for ( size_t line = 0; line < m_nLines; line++ ) | |
695 | { | |
696 | wxCoord yPhys; | |
697 | CalcScrolledPosition(0, y, NULL, &yPhys); | |
698 | ||
699 | dc.DrawText(wxString::Format(_T("Line %u (logical %d, physical %d)"), | |
700 | unsigned(line), y, yPhys), 0, y); | |
701 | y += m_hLine; | |
702 | } | |
703 | } | |
704 | ||
705 | void MyScrolledWindowSmart::OnDraw(wxDC& dc) | |
706 | { | |
707 | // this is useful to see which lines are redrawn | |
708 | static size_t s_redrawCount = 0; | |
709 | dc.SetTextForeground(s_redrawCount++ % 2 ? *wxRED : *wxBLUE); | |
710 | ||
711 | // update region is always in device coords, translate to logical ones | |
712 | wxRect rectUpdate = GetUpdateRegion().GetBox(); | |
713 | CalcUnscrolledPosition(rectUpdate.x, rectUpdate.y, | |
714 | &rectUpdate.x, &rectUpdate.y); | |
715 | ||
716 | size_t lineFrom = rectUpdate.y / m_hLine, | |
717 | lineTo = rectUpdate.GetBottom() / m_hLine; | |
718 | ||
719 | if ( lineTo > m_nLines - 1) | |
720 | lineTo = m_nLines - 1; | |
721 | ||
722 | wxCoord y = lineFrom*m_hLine; | |
723 | for ( size_t line = lineFrom; line <= lineTo; line++ ) | |
724 | { | |
725 | wxCoord yPhys; | |
726 | CalcScrolledPosition(0, y, NULL, &yPhys); | |
727 | ||
728 | dc.DrawText(wxString::Format(_T("Line %u (logical %d, physical %d)"), | |
729 | unsigned(line), y, yPhys), 0, y); | |
730 | y += m_hLine; | |
731 | } | |
732 | } | |
733 | ||
734 | // ---------------------------------------------------------------------------- | |
735 | // MyAutoTimedScrollingWindow | |
736 | // ---------------------------------------------------------------------------- | |
737 | ||
738 | BEGIN_EVENT_TABLE(MyAutoTimedScrollingWindow, wxScrolledWindow) | |
739 | EVT_LEFT_DOWN(MyAutoTimedScrollingWindow::OnMouseLeftDown) | |
740 | EVT_LEFT_UP(MyAutoTimedScrollingWindow::OnMouseLeftUp) | |
741 | EVT_MOTION(MyAutoTimedScrollingWindow::OnMouseMove) | |
742 | EVT_MOUSE_CAPTURE_LOST(MyAutoTimedScrollingWindow::OnMouseCaptureLost) | |
743 | EVT_SCROLLWIN(MyAutoTimedScrollingWindow::OnScroll) | |
744 | END_EVENT_TABLE() | |
745 | ||
746 | MyAutoTimedScrollingWindow::MyAutoTimedScrollingWindow(wxWindow* parent) | |
747 | : wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize | |
748 | //, wxSUNKEN_BORDER) // can't seem to do it this way | |
749 | , wxVSCROLL | wxHSCROLL | wxSUNKEN_BORDER) | |
750 | , m_selStart(-1, -1), m_cursor(-1, -1) | |
751 | , m_font(9, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL | |
752 | , wxFONTWEIGHT_NORMAL) | |
753 | { | |
754 | wxClientDC dc(this); | |
755 | // query dc for text size | |
756 | dc.SetFont(m_font); | |
757 | dc.GetTextExtent(wxString(_T("A")), &m_fontW, &m_fontH); | |
758 | // set up the virtual window | |
759 | SetScrollbars(m_fontW, m_fontH, sm_lineLen, sm_lineCnt); | |
760 | } | |
761 | ||
762 | wxRect MyAutoTimedScrollingWindow::DeviceCoordsToGraphicalChars | |
763 | (wxRect updRect) const | |
764 | { | |
765 | wxPoint pos(updRect.GetPosition()); | |
766 | pos = DeviceCoordsToGraphicalChars(pos); | |
767 | updRect.x = pos.x; | |
768 | updRect.y = pos.y; | |
769 | updRect.width /= m_fontW; | |
770 | updRect.height /= m_fontH; | |
771 | // the *CoordsToGraphicalChars() funcs round down to upper-left corner, | |
772 | // so an off-by-one correction is needed | |
773 | ++updRect.width; // kludge | |
774 | ++updRect.height; // kludge | |
775 | return updRect; | |
776 | } | |
777 | ||
778 | wxPoint MyAutoTimedScrollingWindow::DeviceCoordsToGraphicalChars | |
779 | (wxPoint pos) const | |
780 | { | |
781 | pos.x /= m_fontW; | |
782 | pos.y /= m_fontH; | |
783 | int vX, vY; | |
784 | GetViewStart(&vX, &vY); | |
785 | pos.x += vX; | |
786 | pos.y += vY; | |
787 | return pos; | |
788 | } | |
789 | ||
790 | wxPoint MyAutoTimedScrollingWindow::GraphicalCharToDeviceCoords | |
791 | (wxPoint pos) const | |
792 | { | |
793 | int vX, vY; | |
794 | GetViewStart(&vX, &vY); | |
795 | pos.x -= vX; | |
796 | pos.y -= vY; | |
797 | pos.x *= m_fontW; | |
798 | pos.y *= m_fontH; | |
799 | return pos; | |
800 | } | |
801 | ||
802 | wxRect MyAutoTimedScrollingWindow::LogicalCoordsToGraphicalChars | |
803 | (wxRect updRect) const | |
804 | { | |
805 | wxPoint pos(updRect.GetPosition()); | |
806 | pos = LogicalCoordsToGraphicalChars(pos); | |
807 | updRect.x = pos.x; | |
808 | updRect.y = pos.y; | |
809 | updRect.width /= m_fontW; | |
810 | updRect.height /= m_fontH; | |
811 | // the *CoordsToGraphicalChars() funcs round down to upper-left corner, | |
812 | // so an off-by-one correction is needed | |
813 | ++updRect.width; // kludge | |
814 | ++updRect.height; // kludge | |
815 | return updRect; | |
816 | } | |
817 | ||
818 | wxPoint MyAutoTimedScrollingWindow::LogicalCoordsToGraphicalChars | |
819 | (wxPoint pos) const | |
820 | { | |
821 | pos.x /= m_fontW; | |
822 | pos.y /= m_fontH; | |
823 | return pos; | |
824 | } | |
825 | ||
826 | wxPoint MyAutoTimedScrollingWindow::GraphicalCharToLogicalCoords | |
827 | (wxPoint pos) const | |
828 | { | |
829 | pos.x *= m_fontW; | |
830 | pos.y *= m_fontH; | |
831 | return pos; | |
832 | } | |
833 | ||
834 | void MyAutoTimedScrollingWindow::MyRefresh() | |
835 | { | |
836 | static wxPoint lastSelStart(-1, -1), lastCursor(-1, -1); | |
837 | // refresh last selected area (to deselect previously selected text) | |
838 | wxRect lastUpdRect( | |
839 | GraphicalCharToDeviceCoords(lastSelStart), | |
840 | GraphicalCharToDeviceCoords(lastCursor) | |
841 | ); | |
842 | // off-by-one corrections, necessary because it's not possible to know | |
843 | // when to round up until rect is normalized by lastUpdRect constructor | |
844 | lastUpdRect.width += m_fontW; // kludge | |
845 | lastUpdRect.height += m_fontH; // kludge | |
846 | // refresh currently selected (to select previously unselected text) | |
847 | wxRect updRect( | |
848 | GraphicalCharToDeviceCoords(m_selStart), | |
849 | GraphicalCharToDeviceCoords(m_cursor) | |
850 | ); | |
851 | // off-by-one corrections | |
852 | updRect.width += m_fontW; // kludge | |
853 | updRect.height += m_fontH; // kludge | |
854 | // find necessary refresh areas | |
855 | wxCoord rx = lastUpdRect.x; | |
856 | wxCoord ry = lastUpdRect.y; | |
857 | wxCoord rw = updRect.x - lastUpdRect.x; | |
858 | wxCoord rh = lastUpdRect.height; | |
859 | if (rw && rh) { | |
860 | RefreshRect(DCNormalize(rx, ry, rw, rh)); | |
861 | } | |
862 | rx = updRect.x; | |
863 | ry = updRect.y + updRect.height; | |
864 | rw= updRect.width; | |
865 | rh = (lastUpdRect.y + lastUpdRect.height) - (updRect.y + updRect.height); | |
866 | if (rw && rh) { | |
867 | RefreshRect(DCNormalize(rx, ry, rw, rh)); | |
868 | } | |
869 | rx = updRect.x + updRect.width; | |
870 | ry = lastUpdRect.y; | |
871 | rw = (lastUpdRect.x + lastUpdRect.width) - (updRect.x + updRect.width); | |
872 | rh = lastUpdRect.height; | |
873 | if (rw && rh) { | |
874 | RefreshRect(DCNormalize(rx, ry, rw, rh)); | |
875 | } | |
876 | rx = updRect.x; | |
877 | ry = lastUpdRect.y; | |
878 | rw = updRect.width; | |
879 | rh = updRect.y - lastUpdRect.y; | |
880 | if (rw && rh) { | |
881 | RefreshRect(DCNormalize(rx, ry, rw, rh)); | |
882 | } | |
883 | // update last | |
884 | lastSelStart = m_selStart; | |
885 | lastCursor = m_cursor; | |
886 | } | |
887 | ||
888 | bool MyAutoTimedScrollingWindow::IsSelected(int chX, int chY) const | |
889 | { | |
890 | if (IsInside(chX, m_selStart.x, m_cursor.x) | |
891 | && IsInside(chY, m_selStart.y, m_cursor.y)) { | |
892 | return true; | |
893 | } | |
894 | return false; | |
895 | } | |
896 | ||
897 | bool MyAutoTimedScrollingWindow::IsInside(int k, int bound1, int bound2) | |
898 | { | |
899 | if ((k >= bound1 && k <= bound2) || (k >= bound2 && k <= bound1)) { | |
900 | return true; | |
901 | } | |
902 | return false; | |
903 | } | |
904 | ||
905 | wxRect MyAutoTimedScrollingWindow::DCNormalize(wxCoord x, wxCoord y | |
906 | , wxCoord w, wxCoord h) | |
907 | { | |
908 | // this is needed to get rid of the graphical remnants from the selection | |
909 | // I think it's because DrawRectangle() excludes a pixel in either direction | |
910 | const int kludge = 1; | |
911 | // make (x, y) the top-left corner | |
912 | if (w < 0) { | |
913 | w = -w + kludge; | |
914 | x -= w; | |
915 | } else { | |
916 | x -= kludge; | |
917 | w += kludge; | |
918 | } | |
919 | if (h < 0) { | |
920 | h = -h + kludge; | |
921 | y -= h; | |
922 | } else { | |
923 | y -= kludge; | |
924 | h += kludge; | |
925 | } | |
926 | return wxRect(x, y, w, h); | |
927 | } | |
928 | ||
929 | void MyAutoTimedScrollingWindow::OnDraw(wxDC& dc) | |
930 | { | |
931 | dc.SetFont(m_font); | |
932 | wxBrush normBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW) | |
933 | , wxSOLID); | |
934 | wxBrush selBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT) | |
935 | , wxSOLID); | |
936 | dc.SetPen(*wxTRANSPARENT_PEN); | |
937 | wxString str = sm_testData; | |
938 | ||
939 | // draw the characters | |
940 | // 1. for each update region | |
941 | for (wxRegionIterator upd(GetUpdateRegion()); upd; ++upd) { | |
942 | wxRect updRect = upd.GetRect(); | |
943 | wxRect updRectInGChars(DeviceCoordsToGraphicalChars(updRect)); | |
944 | // 2. for each row of chars in the update region | |
945 | for (int chY = updRectInGChars.y | |
946 | ; chY <= updRectInGChars.y + updRectInGChars.height; ++chY) { | |
947 | // 3. for each character in the row | |
948 | for (int chX = updRectInGChars.x | |
949 | ; chX <= updRectInGChars.x + updRectInGChars.width | |
950 | ; ++chX) { | |
951 | // 4. set up dc | |
952 | if (IsSelected(chX, chY)) { | |
953 | dc.SetBrush(selBrush); | |
954 | dc.SetTextForeground( wxSystemSettings::GetColour | |
955 | (wxSYS_COLOUR_HIGHLIGHTTEXT)); | |
956 | } else { | |
957 | dc.SetBrush(normBrush); | |
958 | dc.SetTextForeground( wxSystemSettings::GetColour | |
959 | (wxSYS_COLOUR_WINDOWTEXT)); | |
960 | } | |
961 | // 5. find position info | |
962 | wxPoint charPos = GraphicalCharToLogicalCoords(wxPoint | |
963 | (chX, chY)); | |
964 | // 6. draw! | |
965 | dc.DrawRectangle(charPos.x, charPos.y, m_fontW, m_fontH); | |
966 | size_t charIndex = chY * sm_lineLen + chX; | |
967 | if (chY < sm_lineCnt && | |
968 | chX < sm_lineLen && | |
969 | charIndex < str.Length()) | |
970 | { | |
971 | dc.DrawText(str.Mid(charIndex,1), | |
972 | charPos.x, charPos.y); | |
973 | } | |
974 | } | |
975 | } | |
976 | } | |
977 | } | |
978 | ||
979 | void MyAutoTimedScrollingWindow::OnMouseLeftDown(wxMouseEvent& event) | |
980 | { | |
981 | // initial press of mouse button sets the beginning of the selection | |
982 | m_selStart = DeviceCoordsToGraphicalChars(event.GetPosition()); | |
983 | // set the cursor to the same position | |
984 | m_cursor = m_selStart; | |
985 | // draw/erase selection | |
986 | MyRefresh(); | |
987 | } | |
988 | ||
989 | void MyAutoTimedScrollingWindow::OnMouseLeftUp(wxMouseEvent& WXUNUSED(event)) | |
990 | { | |
991 | // this test is necessary | |
992 | if (HasCapture()) { | |
993 | // uncapture mouse | |
994 | ReleaseMouse(); | |
995 | } | |
996 | } | |
997 | ||
998 | void MyAutoTimedScrollingWindow::OnMouseMove(wxMouseEvent& event) | |
999 | { | |
1000 | // if user is dragging | |
1001 | if (event.Dragging() && event.LeftIsDown()) { | |
1002 | // set the new cursor position | |
1003 | m_cursor = DeviceCoordsToGraphicalChars(event.GetPosition()); | |
1004 | // draw/erase selection | |
1005 | MyRefresh(); | |
1006 | // capture mouse to activate auto-scrolling | |
1007 | if (!HasCapture()) { | |
1008 | CaptureMouse(); | |
1009 | } | |
1010 | } | |
1011 | } | |
1012 | ||
1013 | void MyAutoTimedScrollingWindow::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event)) | |
1014 | { | |
1015 | // we only capture mouse for timed scrolling, so nothing is needed here | |
1016 | // other than making sure to not call event.Skip() | |
1017 | } | |
1018 | ||
1019 | void MyAutoTimedScrollingWindow::OnScroll(wxScrollWinEvent& event) | |
1020 | { | |
1021 | // need to move the cursor when autoscrolling | |
1022 | // FIXME: the cursor also moves when the scrollbar arrows are clicked | |
1023 | if (HasCapture()) { | |
1024 | if (event.GetOrientation() == wxHORIZONTAL) { | |
1025 | if (event.GetEventType() == wxEVT_SCROLLWIN_LINEUP) { | |
1026 | --m_cursor.x; | |
1027 | } else if (event.GetEventType() == wxEVT_SCROLLWIN_LINEDOWN) { | |
1028 | ++m_cursor.x; | |
1029 | } | |
1030 | } else if (event.GetOrientation() == wxVERTICAL) { | |
1031 | if (event.GetEventType() == wxEVT_SCROLLWIN_LINEUP) { | |
1032 | --m_cursor.y; | |
1033 | } else if (event.GetEventType() == wxEVT_SCROLLWIN_LINEDOWN) { | |
1034 | ++m_cursor.y; | |
1035 | } | |
1036 | } | |
1037 | } | |
1038 | MyRefresh(); | |
1039 | event.Skip(); | |
1040 | } | |
1041 | ||
1042 | const int MyAutoTimedScrollingWindow::sm_lineCnt = 125; | |
1043 | const int MyAutoTimedScrollingWindow::sm_lineLen = 79; | |
1044 | const wxChar* MyAutoTimedScrollingWindow::sm_testData = | |
1045 | _T("162 Cult of the genius out of vanity. Because we think well of ourselves, but ") | |
1046 | _T("nonetheless never suppose ourselves capable of producing a painting like one of ") | |
1047 | _T("Raphael's or a dramatic scene like one of Shakespeare's, we convince ourselves ") | |
1048 | _T("that the capacity to do so is quite extraordinarily marvelous, a wholly ") | |
1049 | _T("uncommon accident, or, if we are still religiously inclined, a mercy from on ") | |
1050 | _T("high. Thus our vanity, our self-love, promotes the cult of the genius: for only ") | |
1051 | _T("if we think of him as being very remote from us, as a miraculum, does he not ") | |
1052 | _T("aggrieve us (even Goethe, who was without envy, called Shakespeare his star of ") | |
1053 | _T("the most distant heights [\"William! Stern der schonsten Ferne\": from Goethe's, ") | |
1054 | _T("\"Between Two Worlds\"]; in regard to which one might recall the lines: \"the ") | |
1055 | _T("stars, these we do not desire\" [from Goethe's, \"Comfort in Tears\"]). But, aside ") | |
1056 | _T("from these suggestions of our vanity, the activity of the genius seems in no ") | |
1057 | _T("way fundamentally different from the activity of the inventor of machines, the ") | |
1058 | _T("scholar of astronomy or history, the master of tactics. All these activities ") | |
1059 | _T("are explicable if one pictures to oneself people whose thinking is active in ") | |
1060 | _T("one direction, who employ everything as material, who always zealously observe ") | |
1061 | _T("their own inner life and that of others, who perceive everywhere models and ") | |
1062 | _T("incentives, who never tire of combining together the means available to them. ") | |
1063 | _T("Genius too does nothing except learn first how to lay bricks then how to build, ") | |
1064 | _T("except continually seek for material and continually form itself around it. ") | |
1065 | _T("Every activity of man is amazingly complicated, not only that of the genius: ") | |
1066 | _T("but none is a \"miracle.\" Whence, then, the belief that genius exists only in ") | |
1067 | _T("the artist, orator and philosopher? that only they have \"intuition\"? (Whereby ") | |
1068 | _T("they are supposed to possess a kind of miraculous eyeglass with which they can ") | |
1069 | _T("see directly into \"the essence of the thing\"!) It is clear that people speak of ") | |
1070 | _T("genius only where the effects of the great intellect are most pleasant to them ") | |
1071 | _T("and where they have no desire to feel envious. To call someone \"divine\" means: ") | |
1072 | _T("\"here there is no need for us to compete.\" Then, everything finished and ") | |
1073 | _T("complete is regarded with admiration, everything still becoming is undervalued. ") | |
1074 | _T("But no one can see in the work of the artist how it has become; that is its ") | |
1075 | _T("advantage, for wherever one can see the act of becoming one grows somewhat ") | |
1076 | _T("cool. The finished and perfect art of representation repulses all thinking as ") | |
1077 | _T("to how it has become; it tyrannizes as present completeness and perfection. ") | |
1078 | _T("That is why the masters of the art of representation count above all as gifted ") | |
1079 | _T("with genius and why men of science do not. In reality, this evaluation of the ") | |
1080 | _T("former and undervaluation of the latter is only a piece of childishness in the ") | |
1081 | _T("realm of reason. ") | |
1082 | _T("\n\n") | |
1083 | _T("163 The serious workman. Do not talk about giftedness, inborn talents! One can ") | |
1084 | _T("name great men of all kinds who were very little gifted. The acquired ") | |
1085 | _T("greatness, became \"geniuses\" (as we put it), through qualities the lack of ") | |
1086 | _T("which no one who knew what they were would boast of: they all possessed that ") | |
1087 | _T("seriousness of the efficient workman which first learns to construct the parts ") | |
1088 | _T("properly before it ventures to fashion a great whole; they allowed themselves ") | |
1089 | _T("time for it, because they took more pleasure in making the little, secondary ") | |
1090 | _T("things well than in the effect of a dazzling whole. the recipe for becoming a ") | |
1091 | _T("good novelist, for example, is easy to give, but to carry it out presupposes ") | |
1092 | _T("qualities one is accustomed to overlook when one says \"I do not have enough ") | |
1093 | _T("talent.\" One has only to make a hundred or so sketches for novels, none longer ") | |
1094 | _T("than two pages but of such distinctness that every word in them is necessary; ") | |
1095 | _T("one should write down anecdotes each day until one has learned how to give them ") | |
1096 | _T("the most pregnant and effective form; one should be tireless in collecting and ") | |
1097 | _T("describing human types and characters; one should above all relate things to ") | |
1098 | _T("others and listen to others relate, keeping one's eyes and ears open for the ") | |
1099 | _T("effect produced on those present, one should travel like a landscape painter or ") | |
1100 | _T("costume designer; one should excerpt for oneself out of the individual sciences ") | |
1101 | _T("everything that will produce an artistic effect when it is well described, one ") | |
1102 | _T("should, finally, reflect on the motives of human actions, disdain no signpost ") | |
1103 | _T("to instruction about them and be a collector of these things by day and night. ") | |
1104 | _T("One should continue in this many-sided exercise some ten years: what is then ") | |
1105 | _T("created in the workshop, however, will be fit to go out into the world. What, ") | |
1106 | _T("however, do most people do? They begin, not with the parts, but with the whole. ") | |
1107 | _T("Perhaps they chance to strike a right note, excite attention and from then on ") | |
1108 | _T("strike worse and worse notes, for good, natural reasons. Sometimes, when the ") | |
1109 | _T("character and intellect needed to formulate such a life-plan are lacking, fate ") | |
1110 | _T("and need take their place and lead the future master step by step through all ") | |
1111 | _T("the stipulations of his trade. ") | |
1112 | _T("\n\n") | |
1113 | _T("164 Peril and profit in the cult of the genius. The belief in great, superior, ") | |
1114 | _T("fruitful spirits is not necessarily, yet nonetheless is very frequently ") | |
1115 | _T("associated with that religious or semi-religious superstition that these ") | |
1116 | _T("spirits are of supra-human origin and possess certain miraculous abilities by ") | |
1117 | _T("virtue of which they acquire their knowledge by quite other means than the rest ") | |
1118 | _T("of mankind. One ascribes to them, it seems, a direct view of the nature of the ") | |
1119 | _T("world, as it were a hole in the cloak of appearance, and believes that, by ") | |
1120 | _T("virtue of this miraculous seer's vision, they are able to communicate something ") | |
1121 | _T("conclusive and decisive about man and the world without the toil and ") | |
1122 | _T("rigorousness required by science. As long as there continue to be those who ") | |
1123 | _T("believe in the miraculous in the domain of knowledge one can perhaps concede ") | |
1124 | _T("that these people themselves derive some benefit from their belief, inasmuch as ") | |
1125 | _T("through their unconditional subjection to the great spirits they create for ") | |
1126 | _T("their own spirit during its time of development the finest form of discipline ") | |
1127 | _T("and schooling. On the other hand, it is at least questionable whether the ") | |
1128 | _T("superstitious belief in genius, in its privileges and special abilities, is of ") | |
1129 | _T("benefit to the genius himself if it takes root in him. It is in any event a ") | |
1130 | _T("dangerous sign when a man is assailed by awe of himself, whether it be the ") | |
1131 | _T("celebrated Caesar's awe of Caesar or the awe of one's own genius now under ") | |
1132 | _T("consideration; when the sacrificial incense which is properly rendered only to ") | |
1133 | _T("a god penetrates the brain of the genius, so that his head begins to swim and ") | |
1134 | _T("he comes to regard himself as something supra-human. The consequences that ") | |
1135 | _T("slowly result are: the feeling of irresponsibility, of exceptional rights, the ") | |
1136 | _T("belief that he confers a favor by his mere presence, insane rage when anyone ") | |
1137 | _T("attempts even to compare him with others, let alone to rate him beneath them, ") | |
1138 | _T("or to draw attention to lapses in his work. Because he ceases to practice ") | |
1139 | _T("criticism of himself, at last one pinion after the other falls out of his ") | |
1140 | _T("plumage: that superstitious eats at the roots of his powers and perhaps even ") | |
1141 | _T("turns him into a hypocrite after his powers have fled from him. For the great ") | |
1142 | _T("spirits themselves it is therefore probably more beneficial if they acquire an ") | |
1143 | _T("insight into the nature and origin of their powers, if they grasp, that is to ") | |
1144 | _T("say, what purely human qualities have come together in them and what fortunate ") | |
1145 | _T("circumstances attended them: in the first place undiminished energy, resolute ") | |
1146 | _T("application to individual goals, great personal courage, then the good fortune ") | |
1147 | _T("to receive an upbringing which offered in the early years the finest teachers, ") | |
1148 | _T("models and methods. To be sure, when their goal is the production of the ") | |
1149 | _T("greatest possible effect, unclarity with regard to oneself and that ") | |
1150 | _T("semi-insanity superadded to it has always achieved much; for what has been ") | |
1151 | _T("admired and envied at all times has been that power in them by virtue of which ") | |
1152 | _T("they render men will-less and sweep them away into the delusion that the ") | |
1153 | _T("leaders they are following are supra-natural. Indeed, it elevates and inspires ") | |
1154 | _T("men to believe that someone is in possession of supra-natural powers: to this ") | |
1155 | _T("extent Plato was right to say [Plato: Phaedrus, 244a] that madness has brought ") | |
1156 | _T("the greatest of blessings upon mankind. In rare individual cases this portion ") | |
1157 | _T("of madness may, indeed, actually have been the means by which such a nature, ") | |
1158 | _T("excessive in all directions, was held firmly together: in the life of ") | |
1159 | _T("individuals, too, illusions that are in themselves poisons often play the role ") | |
1160 | _T("of healers; yet, in the end, in the case of every \"genius\" who believes in his ") | |
1161 | _T("own divinity the poison shows itself to the same degree as his \"genius\" grows ") | |
1162 | _T("old: one may recall, for example, the case of Napoleon, whose nature certainly ") | |
1163 | _T("grew into the mighty unity that sets him apart from all men of modern times ") | |
1164 | _T("precisely through his belief in himself and his star and through the contempt ") | |
1165 | _T("for men that flowed from it; until in the end, however, this same belief went ") | |
1166 | _T("over into an almost insane fatalism, robbed him of his acuteness and swiftness ") | |
1167 | _T("of perception, and became the cause of his destruction."); |