]>
Commit | Line | Data |
---|---|---|
4e04f777 WS |
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 | ///////////////////////////////////////////////////////////////////////////// | |
fdd3ed7a RR |
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" | |
053f9cc1 | 24 | #include "wx/listctrl.h" |
ed673c6a RR |
25 | #include "wx/sizer.h" |
26 | #include "wx/log.h" | |
27 | ||
db4ad642 RR |
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 &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 | // ---------------------------------------------------------------------- | |
fdd3ed7a RR |
126 | |
127 | // derived classes | |
128 | ||
129 | class MyFrame; | |
130 | class MyApp; | |
131 | ||
132 | // MyCanvas | |
133 | ||
134 | class MyCanvas: public wxScrolledWindow | |
135 | { | |
136 | public: | |
8a73bf3d | 137 | MyCanvas() {} |
fdd3ed7a | 138 | MyCanvas( wxWindow *parent, wxWindowID, const wxPoint &pos, const wxSize &size ); |
925e9792 | 139 | ~MyCanvas(){}; |
fdd3ed7a | 140 | void OnPaint( wxPaintEvent &event ); |
307f16e8 | 141 | void OnQueryPosition( wxCommandEvent &event ); |
ed673c6a RR |
142 | void OnAddButton( wxCommandEvent &event ); |
143 | void OnDeleteButton( wxCommandEvent &event ); | |
144 | void OnMoveButton( wxCommandEvent &event ); | |
145 | void OnScrollWin( wxCommandEvent &event ); | |
4686e0f6 VZ |
146 | void OnMouseRightDown( wxMouseEvent &event ); |
147 | void OnMouseWheel( wxMouseEvent &event ); | |
ed673c6a RR |
148 | |
149 | wxButton *m_button; | |
fdd3ed7a RR |
150 | |
151 | DECLARE_DYNAMIC_CLASS(MyCanvas) | |
152 | DECLARE_EVENT_TABLE() | |
153 | }; | |
154 | ||
2b5f62a0 VZ |
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 | ||
8a73bf3d VZ |
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: | |
2b5f62a0 VZ |
187 | MyScrolledWindowBase(wxWindow *parent) |
188 | : wxScrolledWindow(parent) | |
189 | , m_nLines( 100 ) | |
8a73bf3d | 190 | { |
2b5f62a0 VZ |
191 | wxClientDC dc(this); |
192 | dc.GetTextExtent(_T("Line 17"), NULL, &m_hLine); | |
8a73bf3d VZ |
193 | } |
194 | ||
195 | protected: | |
8a73bf3d VZ |
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 | |
2b5f62a0 VZ |
204 | // and sets the scrollbar extent directly. |
205 | ||
8a73bf3d VZ |
206 | class MyScrolledWindowDumb : public MyScrolledWindowBase |
207 | { | |
208 | public: | |
2b5f62a0 VZ |
209 | MyScrolledWindowDumb(wxWindow *parent) : MyScrolledWindowBase(parent) |
210 | { | |
211 | // no horz scrolling | |
b62ca03d | 212 | SetScrollbars(0, m_hLine, 0, m_nLines + 1, 0, 0, true /* no refresh */); |
2b5f62a0 | 213 | } |
8a73bf3d VZ |
214 | |
215 | virtual void OnDraw(wxDC& dc); | |
216 | }; | |
217 | ||
218 | // this class does "smart" redrawing - only redraws the lines which must be | |
2b5f62a0 VZ |
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 | ||
8a73bf3d VZ |
224 | class MyScrolledWindowSmart : public MyScrolledWindowBase |
225 | { | |
226 | public: | |
2b5f62a0 VZ |
227 | MyScrolledWindowSmart(wxWindow *parent) : MyScrolledWindowBase(parent) |
228 | { | |
229 | // no horz scrolling | |
230 | SetScrollRate( 0, m_hLine ); | |
4e04f777 | 231 | SetVirtualSize( wxDefaultCoord, ( m_nLines + 1 ) * m_hLine ); |
2b5f62a0 | 232 | } |
8a73bf3d VZ |
233 | |
234 | virtual void OnDraw(wxDC& dc); | |
235 | }; | |
236 | ||
57ac1a56 RN |
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 | |
57ac1a56 RN |
272 | void OnDraw(wxDC& dc); |
273 | void OnMouseLeftDown(wxMouseEvent& event); | |
274 | void OnMouseLeftUp(wxMouseEvent& event); | |
275 | void OnMouseMove(wxMouseEvent& event); | |
276 | void OnScroll(wxScrollWinEvent& event); | |
4686e0f6 VZ |
277 | |
278 | DECLARE_EVENT_TABLE() | |
57ac1a56 | 279 | }; |
2b5f62a0 | 280 | |
8a73bf3d | 281 | // ---------------------------------------------------------------------------- |
fdd3ed7a | 282 | // MyFrame |
8a73bf3d | 283 | // ---------------------------------------------------------------------------- |
fdd3ed7a RR |
284 | |
285 | class MyFrame: public wxFrame | |
286 | { | |
287 | public: | |
288 | MyFrame(); | |
289 | ||
290 | void OnAbout( wxCommandEvent &event ); | |
291 | void OnQuit( wxCommandEvent &event ); | |
8e217128 RR |
292 | void OnDeleteAll( wxCommandEvent &event ); |
293 | void OnInsertNew( wxCommandEvent &event ); | |
fdd3ed7a RR |
294 | |
295 | MyCanvas *m_canvas; | |
ed673c6a | 296 | wxTextCtrl *m_log; |
fdd3ed7a RR |
297 | |
298 | DECLARE_DYNAMIC_CLASS(MyFrame) | |
299 | DECLARE_EVENT_TABLE() | |
300 | }; | |
301 | ||
57ac1a56 | 302 | // ---------------------------------------------------------------------------- |
fdd3ed7a | 303 | // MyApp |
57ac1a56 | 304 | // ---------------------------------------------------------------------------- |
fdd3ed7a RR |
305 | |
306 | class MyApp: public wxApp | |
307 | { | |
308 | public: | |
309 | virtual bool OnInit(); | |
310 | }; | |
311 | ||
57ac1a56 RN |
312 | |
313 | // ---------------------------------------------------------------------------- | |
fdd3ed7a | 314 | // main program |
57ac1a56 | 315 | // ---------------------------------------------------------------------------- |
fdd3ed7a RR |
316 | |
317 | IMPLEMENT_APP(MyApp) | |
318 | ||
ed673c6a RR |
319 | // ids |
320 | ||
2b5f62a0 VZ |
321 | const long ID_ADDBUTTON = wxNewId(); |
322 | const long ID_DELBUTTON = wxNewId(); | |
323 | const long ID_MOVEBUTTON = wxNewId(); | |
324 | const long ID_SCROLLWIN = wxNewId(); | |
325 | const long ID_QUERYPOS = wxNewId(); | |
ed673c6a | 326 | |
2b5f62a0 | 327 | const long ID_NEWBUTTON = wxNewId(); |
ed673c6a | 328 | |
57ac1a56 | 329 | // ---------------------------------------------------------------------------- |
fdd3ed7a | 330 | // MyCanvas |
57ac1a56 | 331 | // ---------------------------------------------------------------------------- |
fdd3ed7a RR |
332 | |
333 | IMPLEMENT_DYNAMIC_CLASS(MyCanvas, wxScrolledWindow) | |
334 | ||
335 | BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow) | |
307f16e8 | 336 | EVT_PAINT( MyCanvas::OnPaint) |
4686e0f6 VZ |
337 | EVT_RIGHT_DOWN( MyCanvas::OnMouseRightDown) |
338 | EVT_MOUSEWHEEL( MyCanvas::OnMouseWheel) | |
307f16e8 | 339 | EVT_BUTTON( ID_QUERYPOS, MyCanvas::OnQueryPosition) |
ed673c6a RR |
340 | EVT_BUTTON( ID_ADDBUTTON, MyCanvas::OnAddButton) |
341 | EVT_BUTTON( ID_DELBUTTON, MyCanvas::OnDeleteButton) | |
342 | EVT_BUTTON( ID_MOVEBUTTON, MyCanvas::OnMoveButton) | |
343 | EVT_BUTTON( ID_SCROLLWIN, MyCanvas::OnScrollWin) | |
fdd3ed7a RR |
344 | END_EVENT_TABLE() |
345 | ||
346 | MyCanvas::MyCanvas( wxWindow *parent, wxWindowID id, | |
347 | const wxPoint &pos, const wxSize &size ) | |
2b5f62a0 | 348 | : wxScrolledWindow( parent, id, pos, size, wxSUNKEN_BORDER | wxTAB_TRAVERSAL, _T("test canvas") ) |
fdd3ed7a | 349 | { |
2b5f62a0 VZ |
350 | SetScrollRate( 10, 10 ); |
351 | SetVirtualSize( 500, 1000 ); | |
352 | ||
353 | (void) new wxButton( this, ID_ADDBUTTON, _T("add button"), wxPoint(10,10) ); | |
354 | (void) new wxButton( this, ID_DELBUTTON, _T("del button"), wxPoint(10,40) ); | |
355 | (void) new wxButton( this, ID_MOVEBUTTON, _T("move button"), wxPoint(150,10) ); | |
356 | (void) new wxButton( this, ID_SCROLLWIN, _T("scroll win"), wxPoint(250,10) ); | |
ed673c6a | 357 | |
aa06a8fd DW |
358 | #if 0 |
359 | ||
fdd3ed7a RR |
360 | wxString choices[] = |
361 | { | |
362 | "This", | |
363 | "is one of my", | |
364 | "really", | |
365 | "wonderful", | |
366 | "examples." | |
367 | }; | |
aa06a8fd | 368 | |
307f16e8 | 369 | m_button = new wxButton( this, ID_QUERYPOS, "Query position", wxPoint(10,110) ); |
aa06a8fd | 370 | |
422d0ff0 | 371 | (void) new wxTextCtrl( this, wxID_ANY, "wxTextCtrl", wxPoint(10,150), wxSize(80,wxDefaultCoord) ); |
aa06a8fd | 372 | |
b62ca03d | 373 | (void) new wxRadioButton( this, wxID_ANY, "Disable", wxPoint(10,190) ); |
aa06a8fd | 374 | |
b62ca03d | 375 | (void) new wxComboBox( this, wxID_ANY, "This", wxPoint(10,230), wxDefaultSize, 5, choices ); |
aa06a8fd | 376 | |
b62ca03d | 377 | (void) new wxRadioBox( this, wxID_ANY, "This", wxPoint(10,310), wxDefaultSize, 5, choices, 2, wxRA_SPECIFY_COLS ); |
053f9cc1 | 378 | |
b62ca03d | 379 | (void) new wxRadioBox( this, wxID_ANY, "This", wxPoint(10,440), wxDefaultSize, 5, choices, 2, wxRA_SPECIFY_ROWS ); |
e9158f7d | 380 | |
ed673c6a | 381 | wxListCtrl *m_listCtrl = new wxListCtrl( |
b62ca03d | 382 | this, wxID_ANY, wxPoint(200, 110), wxSize(180, 120), |
8a73bf3d | 383 | wxLC_REPORT | wxSIMPLE_BORDER | wxLC_SINGLE_SEL ); |
053f9cc1 | 384 | |
ed673c6a RR |
385 | m_listCtrl->InsertColumn(0, "First", wxLIST_FORMAT_LEFT, 90); |
386 | m_listCtrl->InsertColumn(1, "Last", wxLIST_FORMAT_LEFT, 90); | |
053f9cc1 | 387 | |
ed673c6a RR |
388 | for ( int i=0; i < 30; i++) |
389 | { | |
390 | char buf[20]; | |
391 | sprintf(buf, "Item %d", i); | |
392 | m_listCtrl->InsertItem(i, buf); | |
393 | } | |
394 | m_listCtrl->SetItemState( 3, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); | |
053f9cc1 | 395 | |
b62ca03d | 396 | (void) new wxListBox( this, wxID_ANY, wxPoint(260,280), wxSize(120,120), 5, choices, wxLB_ALWAYS_SB ); |
5e014a0c | 397 | |
aa06a8fd DW |
398 | #endif |
399 | ||
b62ca03d | 400 | wxPanel *test = new wxPanel( this, wxID_ANY, wxPoint(10, 110), wxSize(130,50), wxSIMPLE_BORDER | wxTAB_TRAVERSAL ); |
a60b1f5d | 401 | test->SetBackgroundColour( wxT("WHEAT") ); |
aa06a8fd DW |
402 | |
403 | #if 0 | |
404 | ||
b62ca03d | 405 | wxButton *test2 = new wxButton( test, wxID_ANY, "Hallo", wxPoint(10,10) ); |
aa06a8fd | 406 | |
b62ca03d | 407 | test = new wxPanel( this, wxID_ANY, wxPoint(160, 530), wxSize(130,120), wxSUNKEN_BORDER | wxTAB_TRAVERSAL ); |
a60b1f5d | 408 | test->SetBackgroundColour( wxT("WHEAT") ); |
ed673c6a | 409 | test->SetCursor( wxCursor( wxCURSOR_NO_ENTRY ) ); |
b62ca03d | 410 | test2 = new wxButton( test, wxID_ANY, "Hallo", wxPoint(10,10) ); |
ed673c6a | 411 | test2->SetCursor( wxCursor( wxCURSOR_PENCIL ) ); |
aa06a8fd | 412 | |
b62ca03d | 413 | test = new wxPanel( this, wxID_ANY, wxPoint(310, 530), wxSize(130,120), wxRAISED_BORDER | wxTAB_TRAVERSAL ); |
a60b1f5d | 414 | test->SetBackgroundColour( wxT("WHEAT") ); |
ed673c6a | 415 | test->SetCursor( wxCursor( wxCURSOR_PENCIL ) ); |
b62ca03d | 416 | test2 = new wxButton( test, wxID_ANY, "Hallo", wxPoint(10,10) ); |
ed673c6a | 417 | test2->SetCursor( wxCursor( wxCURSOR_NO_ENTRY ) ); |
5e014a0c | 418 | |
aa06a8fd DW |
419 | #endif |
420 | ||
a60b1f5d | 421 | SetBackgroundColour( wxT("BLUE") ); |
aa06a8fd | 422 | |
ed673c6a | 423 | SetCursor( wxCursor( wxCURSOR_IBEAM ) ); |
fdd3ed7a RR |
424 | } |
425 | ||
4686e0f6 | 426 | void MyCanvas::OnMouseRightDown( wxMouseEvent &event ) |
bf0c00c6 | 427 | { |
4686e0f6 VZ |
428 | wxPoint pt( event.GetPosition() ); |
429 | int x,y; | |
430 | CalcUnscrolledPosition( pt.x, pt.y, &x, &y ); | |
431 | wxLogMessage( wxT("Mouse down event at: %d %d, scrolled: %d %d"), pt.x, pt.y, x, y ); | |
432 | } | |
f6bcfd97 | 433 | |
4686e0f6 VZ |
434 | void MyCanvas::OnMouseWheel( wxMouseEvent &event ) |
435 | { | |
436 | wxPoint pt( event.GetPosition() ); | |
437 | int x,y; | |
438 | CalcUnscrolledPosition( pt.x, pt.y, &x, &y ); | |
439 | wxLogMessage( wxT("Mouse wheel event at: %d %d, scrolled: %d %d\n") | |
440 | wxT("Rotation: %d, delta = %d"), | |
441 | pt.x, pt.y, x, y, | |
442 | event.GetWheelRotation(), event.GetWheelDelta() ); | |
443 | ||
444 | event.Skip(); | |
bf0c00c6 RR |
445 | } |
446 | ||
447 | void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) ) | |
448 | { | |
449 | wxPaintDC dc( this ); | |
450 | PrepareDC( dc ); | |
451 | ||
2b5f62a0 | 452 | dc.DrawText( _T("Press mouse button to test calculations!"), 160, 50 ); |
bf0c00c6 | 453 | |
2b5f62a0 | 454 | dc.DrawText( _T("Some text"), 140, 140 ); |
aa06a8fd | 455 | |
bf0c00c6 RR |
456 | dc.DrawRectangle( 100, 160, 200, 200 ); |
457 | } | |
458 | ||
307f16e8 RR |
459 | void MyCanvas::OnQueryPosition( wxCommandEvent &WXUNUSED(event) ) |
460 | { | |
461 | wxPoint pt( m_button->GetPosition() ); | |
4693b20c | 462 | wxLogMessage( wxT("Position of \"Query position\" is %d %d"), pt.x, pt.y ); |
bf0c00c6 | 463 | pt = ClientToScreen( pt ); |
4693b20c | 464 | wxLogMessage( wxT("Position of \"Query position\" on screen is %d %d"), pt.x, pt.y ); |
307f16e8 RR |
465 | } |
466 | ||
ed673c6a RR |
467 | void MyCanvas::OnAddButton( wxCommandEvent &WXUNUSED(event) ) |
468 | { | |
4693b20c | 469 | wxLogMessage( wxT("Inserting button at position 10,70...") ); |
2b5f62a0 | 470 | wxButton *button = new wxButton( this, ID_NEWBUTTON, wxT("new button"), wxPoint(10,70), wxSize(80,25) ); |
bf0c00c6 | 471 | wxPoint pt( button->GetPosition() ); |
4693b20c | 472 | wxLogMessage( wxT("-> Position after inserting %d %d"), pt.x, pt.y ); |
ed673c6a RR |
473 | } |
474 | ||
256b8649 | 475 | void MyCanvas::OnDeleteButton( wxCommandEvent &WXUNUSED(event) ) |
ed673c6a | 476 | { |
4693b20c | 477 | wxLogMessage( wxT("Deleting button inserted with \"Add button\"...") ); |
ed673c6a RR |
478 | wxWindow *win = FindWindow( ID_NEWBUTTON ); |
479 | if (win) | |
480 | win->Destroy(); | |
481 | else | |
4693b20c | 482 | wxLogMessage( wxT("-> No window with id = ID_NEWBUTTON found.") ); |
ed673c6a RR |
483 | } |
484 | ||
485 | void MyCanvas::OnMoveButton( wxCommandEvent &event ) | |
486 | { | |
4693b20c | 487 | wxLogMessage( wxT("Moving button 10 pixels downward..") ); |
ed673c6a | 488 | wxWindow *win = FindWindow( event.GetId() ); |
bf0c00c6 | 489 | wxPoint pt( win->GetPosition() ); |
4693b20c | 490 | wxLogMessage( wxT("-> Position before move is %d %d"), pt.x, pt.y ); |
422d0ff0 | 491 | win->Move( wxDefaultCoord, pt.y + 10 ); |
bf0c00c6 | 492 | pt = win->GetPosition(); |
4693b20c | 493 | wxLogMessage( wxT("-> Position after move is %d %d"), pt.x, pt.y ); |
ed673c6a RR |
494 | } |
495 | ||
496 | void MyCanvas::OnScrollWin( wxCommandEvent &WXUNUSED(event) ) | |
497 | { | |
4693b20c | 498 | wxLogMessage( wxT("Scrolling 2 units up.\nThe white square and the controls should move equally!") ); |
ed673c6a | 499 | int x,y; |
8073eb40 | 500 | GetViewStart( &x, &y ); |
4e04f777 | 501 | Scroll( wxDefaultCoord, y+2 ); |
ed673c6a RR |
502 | } |
503 | ||
57ac1a56 | 504 | // ---------------------------------------------------------------------------- |
2b5f62a0 | 505 | // MyAutoScrollWindow |
57ac1a56 | 506 | // ---------------------------------------------------------------------------- |
2b5f62a0 VZ |
507 | |
508 | const long ID_RESIZEBUTTON = wxNewId(); | |
509 | const wxSize SMALL_BUTTON( 100, 50 ); | |
510 | const wxSize LARGE_BUTTON( 300, 100 ); | |
511 | ||
512 | BEGIN_EVENT_TABLE( MyAutoScrollWindow, wxScrolledWindow) | |
513 | EVT_BUTTON( ID_RESIZEBUTTON, MyAutoScrollWindow::OnResizeClick) | |
514 | END_EVENT_TABLE() | |
515 | ||
516 | MyAutoScrollWindow::MyAutoScrollWindow( wxWindow *parent ) | |
3fa5153e RR |
517 | : wxScrolledWindow( parent, -1, wxDefaultPosition, wxDefaultSize, |
518 | wxSUNKEN_BORDER|wxScrolledWindowStyle ) | |
2b5f62a0 VZ |
519 | { |
520 | SetBackgroundColour( wxT("GREEN") ); | |
521 | ||
522 | // Set the rate we'd like for scrolling. | |
523 | ||
524 | SetScrollRate( 5, 5 ); | |
525 | ||
526 | // Populate a sizer with a 'resizing' button and some | |
527 | // other static decoration | |
528 | ||
529 | wxFlexGridSizer *innersizer = new wxFlexGridSizer( 2, 2 ); | |
530 | ||
531 | m_button = new wxButton( this, | |
532 | ID_RESIZEBUTTON, | |
533 | _T("Press me"), | |
534 | wxDefaultPosition, | |
535 | SMALL_BUTTON ); | |
536 | ||
537 | // We need to do this here, because wxADJUST_MINSIZE below | |
538 | // will cause the initial size to be ignored for Best/Min size. | |
539 | // It would be nice to fix the sizers to handle this a little | |
540 | // more cleanly. | |
541 | ||
542 | m_button->SetSizeHints( SMALL_BUTTON.GetWidth(), SMALL_BUTTON.GetHeight() ); | |
543 | ||
544 | innersizer->Add( m_button, | |
545 | 0, | |
546 | wxALIGN_CENTER | wxALL | wxADJUST_MINSIZE, | |
547 | 20 ); | |
548 | ||
b62ca03d | 549 | innersizer->Add( new wxStaticText( this, wxID_ANY, _T("This is just") ), |
2b5f62a0 VZ |
550 | 0, |
551 | wxALIGN_CENTER ); | |
552 | ||
b62ca03d | 553 | innersizer->Add( new wxStaticText( this, wxID_ANY, _T("some decoration") ), |
2b5f62a0 VZ |
554 | 0, |
555 | wxALIGN_CENTER ); | |
556 | ||
b62ca03d | 557 | innersizer->Add( new wxStaticText( this, wxID_ANY, _T("for you to scroll...") ), |
2b5f62a0 VZ |
558 | 0, |
559 | wxALIGN_CENTER ); | |
560 | ||
561 | // Then use the sizer to set the scrolled region size. | |
562 | ||
563 | SetSizer( innersizer ); | |
564 | } | |
565 | ||
566 | void MyAutoScrollWindow::OnResizeClick( wxCommandEvent &WXUNUSED( event ) ) | |
567 | { | |
568 | // Arbitrarily resize the button to change the minimum size of | |
569 | // the (scrolled) sizer. | |
570 | ||
571 | if( m_button->GetSize() == SMALL_BUTTON ) | |
572 | m_button->SetSizeHints( LARGE_BUTTON.GetWidth(), LARGE_BUTTON.GetHeight() ); | |
573 | else | |
574 | m_button->SetSizeHints( SMALL_BUTTON.GetWidth(), SMALL_BUTTON.GetHeight() ); | |
575 | ||
576 | // Force update layout and scrollbars, since nothing we do here | |
577 | // necessarily generates a size event which would do it for us. | |
578 | ||
579 | FitInside(); | |
580 | } | |
581 | ||
57ac1a56 | 582 | // ---------------------------------------------------------------------------- |
fdd3ed7a | 583 | // MyFrame |
57ac1a56 | 584 | // ---------------------------------------------------------------------------- |
fdd3ed7a | 585 | |
fdd3ed7a RR |
586 | IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame ) |
587 | ||
588 | BEGIN_EVENT_TABLE(MyFrame,wxFrame) | |
8e217128 RR |
589 | EVT_MENU (ID_DELETE_ALL, MyFrame::OnDeleteAll) |
590 | EVT_MENU (ID_INSERT_NEW, MyFrame::OnInsertNew) | |
fdd3ed7a RR |
591 | EVT_MENU (ID_ABOUT, MyFrame::OnAbout) |
592 | EVT_MENU (ID_QUIT, MyFrame::OnQuit) | |
593 | END_EVENT_TABLE() | |
594 | ||
595 | MyFrame::MyFrame() | |
b62ca03d | 596 | : wxFrame( (wxFrame *)NULL, wxID_ANY, _T("wxScrolledWindow sample"), |
57ac1a56 | 597 | wxPoint(20,20), wxSize(800,500) ) |
fdd3ed7a | 598 | { |
ed673c6a | 599 | wxMenu *file_menu = new wxMenu(); |
2b5f62a0 VZ |
600 | file_menu->Append( ID_DELETE_ALL, _T("Delete all")); |
601 | file_menu->Append( ID_INSERT_NEW, _T("Insert new")); | |
602 | file_menu->Append( ID_ABOUT, _T("&About..")); | |
603 | file_menu->Append( ID_QUIT, _T("E&xit\tAlt-X")); | |
fdd3ed7a | 604 | |
ed673c6a | 605 | wxMenuBar *menu_bar = new wxMenuBar(); |
2b5f62a0 | 606 | menu_bar->Append(file_menu, _T("&File")); |
fdd3ed7a | 607 | |
ed673c6a | 608 | SetMenuBar( menu_bar ); |
fdd3ed7a | 609 | |
8520f137 | 610 | #if wxUSE_STATUSBAR |
ed673c6a RR |
611 | CreateStatusBar(2); |
612 | int widths[] = { -1, 100 }; | |
613 | SetStatusWidths( 2, widths ); | |
8520f137 | 614 | #endif // wxUSE_STATUSBAR |
fdd3ed7a | 615 | |
57ac1a56 RN |
616 | wxBoxSizer *topsizer = new wxBoxSizer( wxHORIZONTAL ); |
617 | // subsizer splits topsizer down the middle | |
618 | wxBoxSizer *subsizer = new wxBoxSizer( wxVERTICAL ); | |
2b5f62a0 VZ |
619 | |
620 | // Setting an explicit size here is superfluous, it will be overridden | |
621 | // by the sizer in any case. | |
b62ca03d | 622 | m_canvas = new MyCanvas( this, wxID_ANY, wxPoint(0,0), wxSize(100,100) ); |
8a73bf3d | 623 | |
2b5f62a0 VZ |
624 | // This is done with ScrollRate/VirtualSize in MyCanvas ctor now, |
625 | // both should produce identical results. | |
626 | //m_canvas->SetScrollbars( 10, 10, 50, 100 ); | |
4e04f777 | 627 | |
57ac1a56 RN |
628 | subsizer->Add( m_canvas, 1, wxEXPAND ); |
629 | subsizer->Add( new MyAutoScrollWindow( this ), 1, wxEXPAND ); | |
8a73bf3d VZ |
630 | |
631 | wxSizer *sizerBtm = new wxBoxSizer(wxHORIZONTAL); | |
632 | sizerBtm->Add( new MyScrolledWindowDumb(this), 1, wxEXPAND ); | |
633 | sizerBtm->Add( new MyScrolledWindowSmart(this), 1, wxEXPAND ); | |
57ac1a56 RN |
634 | subsizer->Add( sizerBtm, 1, wxEXPAND ); |
635 | ||
636 | topsizer->Add( subsizer, 1, wxEXPAND ); | |
637 | topsizer->Add( new MyAutoTimedScrollingWindow( this ), 1, wxEXPAND ); | |
ed673c6a | 638 | |
ed673c6a | 639 | SetSizer( topsizer ); |
fdd3ed7a RR |
640 | } |
641 | ||
8e217128 RR |
642 | void MyFrame::OnDeleteAll( wxCommandEvent &WXUNUSED(event) ) |
643 | { | |
644 | m_canvas->DestroyChildren(); | |
645 | } | |
646 | ||
647 | void MyFrame::OnInsertNew( wxCommandEvent &WXUNUSED(event) ) | |
648 | { | |
b62ca03d | 649 | (void)new wxButton( m_canvas, wxID_ANY, _T("Hello"), wxPoint(100,100) ); |
8e217128 RR |
650 | } |
651 | ||
fdd3ed7a RR |
652 | void MyFrame::OnQuit( wxCommandEvent &WXUNUSED(event) ) |
653 | { | |
b62ca03d | 654 | Close( true ); |
fdd3ed7a RR |
655 | } |
656 | ||
657 | void MyFrame::OnAbout( wxCommandEvent &WXUNUSED(event) ) | |
658 | { | |
57ac1a56 RN |
659 | (void)wxMessageBox( _T("wxScroll demo\n") |
660 | _T("Robert Roebling (c) 1998\n") | |
661 | _T("Autoscrolling examples\n") | |
662 | _T("Ron Lee (c) 2002\n") | |
663 | _T("Auto-timed-scrolling example\n") | |
664 | _T("Matt Gregory (c) 2003\n"), | |
665 | _T("About wxScroll Demo"), | |
666 | wxICON_INFORMATION | wxOK ); | |
fdd3ed7a RR |
667 | } |
668 | ||
669 | //----------------------------------------------------------------------------- | |
670 | // MyApp | |
671 | //----------------------------------------------------------------------------- | |
672 | ||
673 | bool MyApp::OnInit() | |
674 | { | |
db4ad642 RR |
675 | wxFrame *frame = new MyFrame(); |
676 | frame->Show( true ); | |
677 | ||
678 | frame = new MySimpleFrame(); | |
679 | frame->Show(); | |
fdd3ed7a | 680 | |
db4ad642 | 681 | return true; |
fdd3ed7a RR |
682 | } |
683 | ||
8a73bf3d VZ |
684 | // ---------------------------------------------------------------------------- |
685 | // MyScrolledWindowXXX | |
686 | // ---------------------------------------------------------------------------- | |
687 | ||
8a73bf3d VZ |
688 | void MyScrolledWindowDumb::OnDraw(wxDC& dc) |
689 | { | |
690 | // this is useful to see which lines are redrawn | |
691 | static size_t s_redrawCount = 0; | |
692 | dc.SetTextForeground(s_redrawCount++ % 2 ? *wxRED : *wxBLUE); | |
693 | ||
694 | wxCoord y = 0; | |
695 | for ( size_t line = 0; line < m_nLines; line++ ) | |
696 | { | |
697 | wxCoord yPhys; | |
698 | CalcScrolledPosition(0, y, NULL, &yPhys); | |
699 | ||
700 | dc.DrawText(wxString::Format(_T("Line %u (logical %d, physical %d)"), | |
701 | line, y, yPhys), 0, y); | |
702 | y += m_hLine; | |
703 | } | |
704 | } | |
705 | ||
706 | void MyScrolledWindowSmart::OnDraw(wxDC& dc) | |
707 | { | |
708 | // this is useful to see which lines are redrawn | |
709 | static size_t s_redrawCount = 0; | |
710 | dc.SetTextForeground(s_redrawCount++ % 2 ? *wxRED : *wxBLUE); | |
711 | ||
712 | // update region is always in device coords, translate to logical ones | |
713 | wxRect rectUpdate = GetUpdateRegion().GetBox(); | |
714 | CalcUnscrolledPosition(rectUpdate.x, rectUpdate.y, | |
715 | &rectUpdate.x, &rectUpdate.y); | |
716 | ||
717 | size_t lineFrom = rectUpdate.y / m_hLine, | |
718 | lineTo = rectUpdate.GetBottom() / m_hLine; | |
719 | ||
720 | if ( lineTo > m_nLines - 1) | |
721 | lineTo = m_nLines - 1; | |
722 | ||
723 | wxCoord y = lineFrom*m_hLine; | |
724 | for ( size_t line = lineFrom; line <= lineTo; line++ ) | |
725 | { | |
726 | wxCoord yPhys; | |
727 | CalcScrolledPosition(0, y, NULL, &yPhys); | |
728 | ||
729 | dc.DrawText(wxString::Format(_T("Line %u (logical %d, physical %d)"), | |
730 | line, y, yPhys), 0, y); | |
731 | y += m_hLine; | |
732 | } | |
733 | } | |
57ac1a56 RN |
734 | |
735 | // ---------------------------------------------------------------------------- | |
736 | // MyAutoTimedScrollingWindow | |
737 | // ---------------------------------------------------------------------------- | |
738 | ||
739 | BEGIN_EVENT_TABLE(MyAutoTimedScrollingWindow, wxScrolledWindow) | |
4ba64bde RR |
740 | EVT_LEFT_DOWN(MyAutoTimedScrollingWindow::OnMouseLeftDown) |
741 | EVT_LEFT_UP(MyAutoTimedScrollingWindow::OnMouseLeftUp) | |
742 | EVT_MOTION(MyAutoTimedScrollingWindow::OnMouseMove) | |
743 | EVT_SCROLLWIN(MyAutoTimedScrollingWindow::OnScroll) | |
57ac1a56 RN |
744 | END_EVENT_TABLE() |
745 | ||
746 | MyAutoTimedScrollingWindow::MyAutoTimedScrollingWindow(wxWindow* parent) | |
4e04f777 | 747 | : wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize |
57ac1a56 RN |
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)) { | |
4e04f777 | 892 | return true; |
57ac1a56 | 893 | } |
4e04f777 | 894 | return false; |
57ac1a56 RN |
895 | } |
896 | ||
897 | bool MyAutoTimedScrollingWindow::IsInside(int k, int bound1, int bound2) | |
898 | { | |
899 | if ((k >= bound1 && k <= bound2) || (k >= bound2 && k <= bound1)) { | |
4e04f777 | 900 | return true; |
57ac1a56 | 901 | } |
4e04f777 | 902 | return false; |
57ac1a56 RN |
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); | |
4e04f777 WS |
937 | wxString str = sm_testData; |
938 | ||
57ac1a56 RN |
939 | // draw the characters |
940 | // 1. for each update region | |
941 | for (wxRegionIterator upd(GetUpdateRegion()); upd; ++upd) { | |
57ac1a56 RN |
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); | |
4e04f777 WS |
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); | |
57ac1a56 RN |
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::OnScroll(wxScrollWinEvent& event) | |
1014 | { | |
1015 | // need to move the cursor when autoscrolling | |
1016 | // FIXME: the cursor also moves when the scrollbar arrows are clicked | |
1017 | if (HasCapture()) { | |
1018 | if (event.GetOrientation() == wxHORIZONTAL) { | |
687706f5 | 1019 | if (event.GetEventType() == wxEVT_SCROLLWIN_LINEUP) { |
57ac1a56 | 1020 | --m_cursor.x; |
687706f5 | 1021 | } else if (event.GetEventType() == wxEVT_SCROLLWIN_LINEDOWN) { |
57ac1a56 RN |
1022 | ++m_cursor.x; |
1023 | } | |
1024 | } else if (event.GetOrientation() == wxVERTICAL) { | |
687706f5 | 1025 | if (event.GetEventType() == wxEVT_SCROLLWIN_LINEUP) { |
57ac1a56 | 1026 | --m_cursor.y; |
687706f5 | 1027 | } else if (event.GetEventType() == wxEVT_SCROLLWIN_LINEDOWN) { |
57ac1a56 RN |
1028 | ++m_cursor.y; |
1029 | } | |
1030 | } | |
1031 | } | |
1032 | MyRefresh(); | |
1033 | event.Skip(); | |
1034 | } | |
1035 | ||
1036 | const int MyAutoTimedScrollingWindow::sm_lineCnt = 125; | |
1037 | const int MyAutoTimedScrollingWindow::sm_lineLen = 79; | |
4e04f777 | 1038 | const wxChar* MyAutoTimedScrollingWindow::sm_testData = |
49e7b7a2 | 1039 | _T("162 Cult of the genius out of vanity. Because we think well of ourselves, but ") |
4e04f777 WS |
1040 | _T("nonetheless never suppose ourselves capable of producing a painting like one of ") |
1041 | _T("Raphael's or a dramatic scene like one of Shakespeare's, we convince ourselves ") | |
1042 | _T("that the capacity to do so is quite extraordinarily marvelous, a wholly ") | |
1043 | _T("uncommon accident, or, if we are still religiously inclined, a mercy from on ") | |
1044 | _T("high. Thus our vanity, our self-love, promotes the cult of the genius: for only ") | |
1045 | _T("if we think of him as being very remote from us, as a miraculum, does he not ") | |
1046 | _T("aggrieve us (even Goethe, who was without envy, called Shakespeare his star of ") | |
49e7b7a2 | 1047 | _T("the most distant heights [\"William! Stern der schonsten Ferne\": from Goethe's, ") |
4e04f777 WS |
1048 | _T("\"Between Two Worlds\"]; in regard to which one might recall the lines: \"the ") |
1049 | _T("stars, these we do not desire\" [from Goethe's, \"Comfort in Tears\"]). But, aside ") | |
1050 | _T("from these suggestions of our vanity, the activity of the genius seems in no ") | |
1051 | _T("way fundamentally different from the activity of the inventor of machines, the ") | |
1052 | _T("scholar of astronomy or history, the master of tactics. All these activities ") | |
1053 | _T("are explicable if one pictures to oneself people whose thinking is active in ") | |
1054 | _T("one direction, who employ everything as material, who always zealously observe ") | |
1055 | _T("their own inner life and that of others, who perceive everywhere models and ") | |
1056 | _T("incentives, who never tire of combining together the means available to them. ") | |
1057 | _T("Genius too does nothing except learn first how to lay bricks then how to build, ") | |
1058 | _T("except continually seek for material and continually form itself around it. ") | |
1059 | _T("Every activity of man is amazingly complicated, not only that of the genius: ") | |
49e7b7a2 | 1060 | _T("but none is a \"miracle.\" Whence, then, the belief that genius exists only in ") |
4e04f777 WS |
1061 | _T("the artist, orator and philosopher? that only they have \"intuition\"? (Whereby ") |
1062 | _T("they are supposed to possess a kind of miraculous eyeglass with which they can ") | |
1063 | _T("see directly into \"the essence of the thing\"!) It is clear that people speak of ") | |
1064 | _T("genius only where the effects of the great intellect are most pleasant to them ") | |
1065 | _T("and where they have no desire to feel envious. To call someone \"divine\" means: ") | |
1066 | _T("\"here there is no need for us to compete.\" Then, everything finished and ") | |
1067 | _T("complete is regarded with admiration, everything still becoming is undervalued. ") | |
1068 | _T("But no one can see in the work of the artist how it has become; that is its ") | |
1069 | _T("advantage, for wherever one can see the act of becoming one grows somewhat ") | |
1070 | _T("cool. The finished and perfect art of representation repulses all thinking as ") | |
1071 | _T("to how it has become; it tyrannizes as present completeness and perfection. ") | |
1072 | _T("That is why the masters of the art of representation count above all as gifted ") | |
1073 | _T("with genius and why men of science do not. In reality, this evaluation of the ") | |
1074 | _T("former and undervaluation of the latter is only a piece of childishness in the ") | |
1075 | _T("realm of reason. ") | |
1076 | _T("\n\n") | |
49e7b7a2 | 1077 | _T("163 The serious workman. Do not talk about giftedness, inborn talents! One can ") |
4e04f777 WS |
1078 | _T("name great men of all kinds who were very little gifted. The acquired ") |
1079 | _T("greatness, became \"geniuses\" (as we put it), through qualities the lack of ") | |
1080 | _T("which no one who knew what they were would boast of: they all possessed that ") | |
1081 | _T("seriousness of the efficient workman which first learns to construct the parts ") | |
1082 | _T("properly before it ventures to fashion a great whole; they allowed themselves ") | |
1083 | _T("time for it, because they took more pleasure in making the little, secondary ") | |
1084 | _T("things well than in the effect of a dazzling whole. the recipe for becoming a ") | |
1085 | _T("good novelist, for example, is easy to give, but to carry it out presupposes ") | |
1086 | _T("qualities one is accustomed to overlook when one says \"I do not have enough ") | |
1087 | _T("talent.\" One has only to make a hundred or so sketches for novels, none longer ") | |
1088 | _T("than two pages but of such distinctness that every word in them is necessary; ") | |
1089 | _T("one should write down anecdotes each day until one has learned how to give them ") | |
1090 | _T("the most pregnant and effective form; one should be tireless in collecting and ") | |
1091 | _T("describing human types and characters; one should above all relate things to ") | |
1092 | _T("others and listen to others relate, keeping one's eyes and ears open for the ") | |
1093 | _T("effect produced on those present, one should travel like a landscape painter or ") | |
1094 | _T("costume designer; one should excerpt for oneself out of the individual sciences ") | |
1095 | _T("everything that will produce an artistic effect when it is well described, one ") | |
1096 | _T("should, finally, reflect on the motives of human actions, disdain no signpost ") | |
1097 | _T("to instruction about them and be a collector of these things by day and night. ") | |
1098 | _T("One should continue in this many-sided exercise some ten years: what is then ") | |
49e7b7a2 | 1099 | _T("created in the workshop, however, will be fit to go out into the world. What, ") |
4e04f777 WS |
1100 | _T("however, do most people do? They begin, not with the parts, but with the whole. ") |
1101 | _T("Perhaps they chance to strike a right note, excite attention and from then on ") | |
49e7b7a2 | 1102 | _T("strike worse and worse notes, for good, natural reasons. Sometimes, when the ") |
4e04f777 WS |
1103 | _T("character and intellect needed to formulate such a life-plan are lacking, fate ") |
1104 | _T("and need take their place and lead the future master step by step through all ") | |
1105 | _T("the stipulations of his trade. ") | |
1106 | _T("\n\n") | |
49e7b7a2 | 1107 | _T("164 Peril and profit in the cult of the genius. The belief in great, superior, ") |
4e04f777 WS |
1108 | _T("fruitful spirits is not necessarily, yet nonetheless is very frequently ") |
1109 | _T("associated with that religious or semi-religious superstition that these ") | |
1110 | _T("spirits are of supra-human origin and possess certain miraculous abilities by ") | |
1111 | _T("virtue of which they acquire their knowledge by quite other means than the rest ") | |
1112 | _T("of mankind. One ascribes to them, it seems, a direct view of the nature of the ") | |
1113 | _T("world, as it were a hole in the cloak of appearance, and believes that, by ") | |
1114 | _T("virtue of this miraculous seer's vision, they are able to communicate something ") | |
1115 | _T("conclusive and decisive about man and the world without the toil and ") | |
1116 | _T("rigorousness required by science. As long as there continue to be those who ") | |
1117 | _T("believe in the miraculous in the domain of knowledge one can perhaps concede ") | |
1118 | _T("that these people themselves derive some benefit from their belief, inasmuch as ") | |
1119 | _T("through their unconditional subjection to the great spirits they create for ") | |
1120 | _T("their own spirit during its time of development the finest form of discipline ") | |
1121 | _T("and schooling. On the other hand, it is at least questionable whether the ") | |
1122 | _T("superstitious belief in genius, in its privileges and special abilities, is of ") | |
1123 | _T("benefit to the genius himself if it takes root in him. It is in any event a ") | |
1124 | _T("dangerous sign when a man is assailed by awe of himself, whether it be the ") | |
1125 | _T("celebrated Caesar's awe of Caesar or the awe of one's own genius now under ") | |
1126 | _T("consideration; when the sacrificial incense which is properly rendered only to ") | |
1127 | _T("a god penetrates the brain of the genius, so that his head begins to swim and ") | |
1128 | _T("he comes to regard himself as something supra-human. The consequences that ") | |
1129 | _T("slowly result are: the feeling of irresponsibility, of exceptional rights, the ") | |
1130 | _T("belief that he confers a favor by his mere presence, insane rage when anyone ") | |
1131 | _T("attempts even to compare him with others, let alone to rate him beneath them, ") | |
1132 | _T("or to draw attention to lapses in his work. Because he ceases to practice ") | |
1133 | _T("criticism of himself, at last one pinion after the other falls out of his ") | |
1134 | _T("plumage: that superstitious eats at the roots of his powers and perhaps even ") | |
1135 | _T("turns him into a hypocrite after his powers have fled from him. For the great ") | |
1136 | _T("spirits themselves it is therefore probably more beneficial if they acquire an ") | |
1137 | _T("insight into the nature and origin of their powers, if they grasp, that is to ") | |
1138 | _T("say, what purely human qualities have come together in them and what fortunate ") | |
1139 | _T("circumstances attended them: in the first place undiminished energy, resolute ") | |
1140 | _T("application to individual goals, great personal courage, then the good fortune ") | |
1141 | _T("to receive an upbringing which offered in the early years the finest teachers, ") | |
1142 | _T("models and methods. To be sure, when their goal is the production of the ") | |
1143 | _T("greatest possible effect, unclarity with regard to oneself and that ") | |
1144 | _T("semi-insanity superadded to it has always achieved much; for what has been ") | |
1145 | _T("admired and envied at all times has been that power in them by virtue of which ") | |
1146 | _T("they render men will-less and sweep them away into the delusion that the ") | |
1147 | _T("leaders they are following are supra-natural. Indeed, it elevates and inspires ") | |
1148 | _T("men to believe that someone is in possession of supra-natural powers: to this ") | |
1149 | _T("extent Plato was right to say [Plato: Phaedrus, 244a] that madness has brought ") | |
49e7b7a2 | 1150 | _T("the greatest of blessings upon mankind. In rare individual cases this portion ") |
4e04f777 WS |
1151 | _T("of madness may, indeed, actually have been the means by which such a nature, ") |
1152 | _T("excessive in all directions, was held firmly together: in the life of ") | |
1153 | _T("individuals, too, illusions that are in themselves poisons often play the role ") | |
1154 | _T("of healers; yet, in the end, in the case of every \"genius\" who believes in his ") | |
1155 | _T("own divinity the poison shows itself to the same degree as his \"genius\" grows ") | |
1156 | _T("old: one may recall, for example, the case of Napoleon, whose nature certainly ") | |
1157 | _T("grew into the mighty unity that sets him apart from all men of modern times ") | |
1158 | _T("precisely through his belief in himself and his star and through the contempt ") | |
1159 | _T("for men that flowed from it; until in the end, however, this same belief went ") | |
1160 | _T("over into an almost insane fatalism, robbed him of his acuteness and swiftness ") | |
1161 | _T("of perception, and became the cause of his destruction."); |