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