don't crash if bitmaps are not found
[wxWidgets.git] / samples / drawing / drawing.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: drawing.cpp
3 // Purpose: shows and tests wxDC features
4 // Author: Robert Roebling
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Robert Roebling
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "drawing.cpp"
22 #pragma interface "drawing.cpp"
23 #endif
24
25 // For compilers that support precompilation, includes "wx/wx.h".
26 #include "wx/wxprec.h"
27
28 #ifdef __BORLANDC__
29 #pragma hdrstop
30 #endif
31
32 // for all others, include the necessary headers (this file is usually all you
33 // need because it includes almost all "standard" wxWindows headers
34 #ifndef WX_PRECOMP
35 #include "wx/wx.h"
36 #endif
37
38 #include "wx/colordlg.h"
39 #include "wx/image.h"
40
41 // ----------------------------------------------------------------------------
42 // ressources
43 // ----------------------------------------------------------------------------
44
45 // the application icon
46 #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__)
47 #include "mondrian.xpm"
48 #endif
49
50 // ----------------------------------------------------------------------------
51 // constants
52 // ----------------------------------------------------------------------------
53
54 // what do we show on screen (there are too many shapes to put them all on
55 // screen simultaneously)
56 enum ScreenToShow
57 {
58 Show_Default,
59 Show_Text,
60 Show_Lines,
61 Show_Polygons,
62 Show_Mask,
63 Show_Ops,
64 Show_Regions,
65 Show_Circles
66 };
67
68 // ----------------------------------------------------------------------------
69 // global variables
70 // ----------------------------------------------------------------------------
71
72 static wxBitmap *gs_bmpNoMask = NULL,
73 *gs_bmpWithColMask = NULL,
74 *gs_bmpMask = NULL,
75 *gs_bmpWithMask = NULL,
76 *gs_bmp4 = NULL,
77 *gs_bmp4_mono = NULL,
78 *gs_bmp36 = NULL;
79
80 // ----------------------------------------------------------------------------
81 // private classes
82 // ----------------------------------------------------------------------------
83
84 // Define a new application type, each program should derive a class from wxApp
85 class MyApp : public wxApp
86 {
87 public:
88 // override base class virtuals
89 // ----------------------------
90
91 // this one is called on application startup and is a good place for the app
92 // initialization (doing it here and not in the ctor allows to have an error
93 // return: if OnInit() returns false, the application terminates)
94 virtual bool OnInit();
95
96 virtual int OnExit() { DeleteBitmaps(); return 0; }
97
98 protected:
99 void DeleteBitmaps();
100
101 bool LoadImages();
102 };
103
104 class MyCanvas;
105
106 // Define a new frame type: this is going to be our main frame
107 class MyFrame : public wxFrame
108 {
109 public:
110 // ctor(s)
111 MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
112
113 // event handlers (these functions should _not_ be virtual)
114 void OnQuit(wxCommandEvent& event);
115 void OnAbout(wxCommandEvent& event);
116 void OnShow(wxCommandEvent &event);
117 void OnOption(wxCommandEvent &event);
118
119 wxColour SelectColour();
120 void PrepareDC(wxDC& dc);
121
122 int m_backgroundMode;
123 int m_textureBackground;
124 int m_mapMode;
125 double m_xUserScale;
126 double m_yUserScale;
127 int m_xLogicalOrigin;
128 int m_yLogicalOrigin;
129 bool m_xAxisReversed,
130 m_yAxisReversed;
131 wxColour m_colourForeground, // these are _text_ colours
132 m_colourBackground;
133 wxBrush m_backgroundBrush;
134 MyCanvas *m_canvas;
135
136 private:
137 // any class wishing to process wxWindows events must use this macro
138 DECLARE_EVENT_TABLE()
139 };
140
141 // define a scrollable canvas for drawing onto
142 class MyCanvas: public wxScrolledWindow
143 {
144 public:
145 MyCanvas( MyFrame *parent );
146
147 void OnPaint(wxPaintEvent &event);
148 void OnMouseMove(wxMouseEvent &event);
149
150 void Show(ScreenToShow show) { m_show = show; Refresh(); }
151
152 protected:
153 void DrawTestPoly( int x, int y, wxDC &dc ,int transparent );
154 void DrawTestLines( int x, int y, int width, wxDC &dc );
155 void DrawText(wxDC& dc);
156 void DrawImages(wxDC& dc);
157 void DrawWithLogicalOps(wxDC& dc);
158 void DrawRegions(wxDC& dc);
159 void DrawCircles(wxDC& dc);
160 void DrawDefault(wxDC& dc);
161
162 void DrawRegionsHelper(wxDC& dc, wxCoord x);
163
164 private:
165 MyFrame *m_owner;
166
167 ScreenToShow m_show;
168 wxBitmap m_smile_bmp;
169 wxIcon m_std_icon;
170
171 DECLARE_EVENT_TABLE()
172 };
173
174 // ----------------------------------------------------------------------------
175 // constants
176 // ----------------------------------------------------------------------------
177
178 // IDs for the controls and the menu commands
179 enum
180 {
181 // menu items
182 File_Quit = 1,
183 File_About,
184
185 MenuShow_First,
186 File_ShowDefault = MenuShow_First,
187 File_ShowText,
188 File_ShowLines,
189 File_ShowPolygons,
190 File_ShowMask,
191 File_ShowOps,
192 File_ShowRegions,
193 File_ShowCircles,
194 MenuShow_Last = File_ShowCircles,
195
196 MenuOption_First,
197
198 MapMode_Text = MenuOption_First,
199 MapMode_Lometric,
200 MapMode_Twips,
201 MapMode_Points,
202 MapMode_Metric,
203
204 UserScale_StretchHoriz,
205 UserScale_ShrinkHoriz,
206 UserScale_StretchVertic,
207 UserScale_ShrinkVertic,
208 UserScale_Restore,
209
210 AxisMirror_Horiz,
211 AxisMirror_Vertic,
212
213 LogicalOrigin_MoveDown,
214 LogicalOrigin_MoveUp,
215 LogicalOrigin_MoveLeft,
216 LogicalOrigin_MoveRight,
217
218 Colour_TextForeground,
219 Colour_TextBackground,
220 Colour_Background,
221 Colour_BackgroundMode,
222 Colour_TextureBackgound,
223
224 MenuOption_Last = Colour_TextureBackgound
225 };
226
227 // ----------------------------------------------------------------------------
228 // event tables and other macros for wxWindows
229 // ----------------------------------------------------------------------------
230
231
232 // Create a new application object: this macro will allow wxWindows to create
233 // the application object during program execution (it's better than using a
234 // static object for many reasons) and also declares the accessor function
235 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
236 // not wxApp)
237 IMPLEMENT_APP(MyApp)
238
239 // ============================================================================
240 // implementation
241 // ============================================================================
242
243 // ----------------------------------------------------------------------------
244 // the application class
245 // ----------------------------------------------------------------------------
246
247 bool MyApp::LoadImages()
248 {
249 gs_bmpNoMask = new wxBitmap;
250 gs_bmpWithColMask = new wxBitmap;
251 gs_bmpMask = new wxBitmap;
252 gs_bmpWithMask = new wxBitmap;
253 gs_bmp4 = new wxBitmap;
254 gs_bmp4_mono = new wxBitmap;
255 gs_bmp36 = new wxBitmap;
256
257 wxPathList pathList;
258 pathList.Add(".");
259 pathList.Add("..");
260
261 wxString path = pathList.FindValidPath("pat4.bmp");
262 if ( !path )
263 return FALSE;
264
265 /* 4 colour bitmap */
266 gs_bmp4->LoadFile(path, wxBITMAP_TYPE_BMP);
267 /* turn into mono-bitmap */
268 gs_bmp4_mono->LoadFile(path, wxBITMAP_TYPE_BMP);
269 wxMask* mask4 = new wxMask(*gs_bmp4_mono, *wxBLACK);
270 gs_bmp4_mono->SetMask(mask4);
271
272 path = pathList.FindValidPath("pat36.bmp");
273 if ( !path )
274 return FALSE;
275 gs_bmp36->LoadFile(path, wxBITMAP_TYPE_BMP);
276 wxMask* mask36 = new wxMask(*gs_bmp36, *wxBLACK);
277 gs_bmp36->SetMask(mask36);
278
279 path = pathList.FindValidPath("image.bmp");
280 if ( !path )
281 return FALSE;
282 gs_bmpNoMask->LoadFile(path, wxBITMAP_TYPE_BMP);
283 gs_bmpWithMask->LoadFile(path, wxBITMAP_TYPE_BMP);
284 gs_bmpWithColMask->LoadFile(path, wxBITMAP_TYPE_BMP);
285
286 path = pathList.FindValidPath("mask.bmp");
287 if ( !path )
288 return FALSE;
289 gs_bmpMask->LoadFile(path, wxBITMAP_TYPE_BMP);
290
291 wxMask *mask = new wxMask(*gs_bmpMask, *wxBLACK);
292 gs_bmpWithMask->SetMask(mask);
293
294 {
295 wxStopWatch sw;
296 wxMask m;
297 for ( int i = 0; i < 1000; i++ )
298 {
299 m.Create(*gs_bmpWithColMask, *wxWHITE);
300 }
301 wxLogMessage("Total time: %ldms", sw.Time());
302 }
303
304 mask = new wxMask(*gs_bmpWithColMask, *wxWHITE);
305 gs_bmpWithColMask->SetMask(mask);
306
307 return TRUE;
308 }
309
310 // `Main program' equivalent: the program execution "starts" here
311 bool MyApp::OnInit()
312 {
313 // Create the main application window
314 MyFrame *frame = new MyFrame("Drawing sample",
315 wxPoint(50, 50), wxSize(550, 340));
316
317 // Show it and tell the application that it's our main window
318 frame->Show(TRUE);
319 SetTopWindow(frame);
320
321 if ( !LoadImages() )
322 {
323 wxLogError(wxT("Can't load one of the bitmap files needed ")
324 wxT("for this sample from the current or parent ")
325 wxT("directory, please copy them there."));
326
327 // stop here
328 DeleteBitmaps();
329
330 return FALSE;
331 }
332
333 // ok, continue
334 return TRUE;
335 }
336
337 void MyApp::DeleteBitmaps()
338 {
339 delete gs_bmpNoMask;
340 delete gs_bmpWithColMask;
341 delete gs_bmpMask;
342 delete gs_bmpWithMask;
343 delete gs_bmp4;
344 delete gs_bmp4_mono;
345 delete gs_bmp36;
346
347 gs_bmpNoMask = NULL;
348 gs_bmpWithColMask = NULL;
349 gs_bmpMask = NULL;
350 gs_bmpWithMask = NULL;
351 gs_bmp4 = NULL;
352 gs_bmp4_mono = NULL;
353 gs_bmp36 = NULL;
354 }
355
356 // ----------------------------------------------------------------------------
357 // MyCanvas
358 // ----------------------------------------------------------------------------
359
360 // the event tables connect the wxWindows events with the functions (event
361 // handlers) which process them.
362 BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
363 EVT_PAINT (MyCanvas::OnPaint)
364 EVT_MOTION (MyCanvas::OnMouseMove)
365 END_EVENT_TABLE()
366
367 #include "smile.xpm"
368
369 MyCanvas::MyCanvas(MyFrame *parent)
370 : wxScrolledWindow(parent, -1, wxDefaultPosition, wxDefaultSize,
371 wxHSCROLL | wxVSCROLL | wxNO_FULL_REPAINT_ON_RESIZE)
372 {
373 m_owner = parent;
374 m_show = Show_Default;
375 m_smile_bmp = wxBitmap(smile_xpm);
376 m_std_icon = wxTheApp->GetStdIcon(wxICON_INFORMATION);
377 }
378
379 // Draw a polygon and an overlapping rectangle
380 // If transparent is 1, the fill pattern is made transparent.
381 // If transparent is 2, the fill pattern is made transparent but inversed
382 // If is transparent is 0 the text for and background color will be used to represent/map
383 // the colors of the monochrome bitmap pixels to the fillpattern
384 //
385 // I abused the the menu items for setting so called back and fore ground color
386 // just to show how the those colors do influence the fillpatterns just play
387 // with those, and with the code variations are endless using other logical
388 // functions.
389
390 void MyCanvas::DrawTestPoly( int x, int y,wxDC &dc,int transparent )
391 {
392 // wxBrush* brush4 = new wxBrush(*gs_bmp4);
393 wxBrush* brush4 = new wxBrush(*wxBLACK,wxFDIAGONAL_HATCH);
394 wxBrush* brush4_mono = new wxBrush(*gs_bmp4_mono);
395 wxBrush* brush36 = new wxBrush(*gs_bmp36);
396
397 wxPoint todraw[5];
398 todraw[0].x=(long)x+100;
399 todraw[0].y=(long)y+100;
400 todraw[1].x=(long)x+300;
401 todraw[1].y=(long)y+100;
402 todraw[2].x=(long)x+300;
403 todraw[2].y=(long)y+300;
404 todraw[3].x=(long)x+150;
405 todraw[3].y=(long)y+350;
406 todraw[4].x=(long)x+100;
407 todraw[4].y=(long)y+300;
408
409 wxPoint todraw2[5];
410 todraw2[0].x=100;
411 todraw2[0].y=100;
412 todraw2[1].x=300;
413 todraw2[1].y=100;
414 todraw2[2].x=300;
415 todraw2[2].y=300;
416 todraw2[3].x=150;
417 todraw2[3].y=350;
418 todraw2[4].x=100;
419 todraw2[4].y=300;
420
421 switch (transparent)
422 {
423 case 0:
424 {
425 dc.SetLogicalFunction(wxCOPY);
426
427 dc.SetPen( wxPen( wxT("black"), 4, wxSOLID) );
428 dc.SetBrush( *brush4 );
429 dc.DrawPolygon(5,todraw,0,0,wxWINDING_RULE);
430
431 dc.SetPen( wxPen( wxT("red"), 4, wxSOLID) );
432 dc.SetBrush( *brush36 );
433 dc.SetTextForeground(*wxCYAN);
434 dc.SetTextBackground(m_owner->m_colourBackground);
435 dc.DrawRectangle( x+10, y+10, 200, 200 );
436
437 dc.SetPen( wxPen( wxT("green"), 4, wxSOLID) );
438 dc.SetBrush( *brush4_mono );
439 dc.SetTextForeground(*wxCYAN);
440 dc.SetTextBackground(m_owner->m_colourBackground);
441 dc.DrawRectangle( x+50, y+50, 200, 200 );
442
443 dc.DrawCircle( x+400, y+50, 130 );
444
445 dc.SetBrush(wxNullBrush);
446 dc.SetPen(wxNullPen);
447 break;
448 }
449 case 1: //now with transparent fillpatterns
450 {
451
452 wxBitmap* bmpBlit = new wxBitmap(600,400);
453 wxMemoryDC* memDC= new wxMemoryDC();
454 // wxBrush _clearbrush(*wxGREEN,wxSOLID);
455 wxBrush _clearbrush(*wxBLACK,wxSOLID);
456 memDC->SelectObject(*bmpBlit);
457 memDC->BeginDrawing();
458 memDC->SetBackground(_clearbrush);
459 memDC->Clear();
460 memDC->SetBackground(wxNullBrush);
461
462 memDC->SetPen( wxPen( wxT("black"), 4, wxSOLID) );
463 memDC->SetBrush( wxNullBrush);
464 memDC->SetBrush( *brush4 );
465 memDC->SetTextForeground(*wxBLACK); // 0s --> 0x000000 (black)
466 memDC->SetTextBackground(*wxWHITE); // 1s --> 0xFFFFFF (white)
467 memDC->SetLogicalFunction(wxAND_INVERT);
468
469 // BLACK OUT the opaque pixels and leave the rest as is
470 memDC->DrawPolygon(5,todraw2,0,0,wxWINDING_RULE);
471
472 // Set background and foreground colors for fill pattern
473 //the previous blacked out pixels are now merged with the layer color
474 //while the non blacked out pixels stay as they are.
475 memDC->SetTextForeground(*wxBLACK); // 0s --> 0x000000 (black)
476
477 //now define what will be the color of the fillpattern parts that are not transparent
478 // memDC->SetTextBackground(*wxBLUE);
479 memDC->SetTextBackground(m_owner->m_colourForeground);
480 memDC->SetLogicalFunction(wxOR);
481
482
483 //don't understand how but the outline is also depending on logicalfunction
484 memDC->SetPen( wxPen( wxT("red"), 4, wxSOLID) );
485 memDC->DrawPolygon(5,todraw2,0,0,wxWINDING_RULE);
486
487 memDC->SetLogicalFunction(wxCOPY);
488
489 memDC->SetPen( wxPen( wxT("black"), 4, wxSOLID) );
490 memDC->SetBrush( wxNullBrush);
491 memDC->SetBrush( *brush36 );
492 memDC->SetTextForeground(*wxBLACK); // 0s --> 0x000000 (black)
493 memDC->SetTextBackground(*wxWHITE); // 1s --> 0xFFFFFF (white)
494 memDC->SetLogicalFunction(wxAND_INVERT);
495
496 memDC->DrawRectangle( 10, 10, 200, 200 );
497
498 // Set background and foreground colors for fill pattern
499 //the previous blacked out pixels are now merged with the layer color
500 //while the non blacked out pixels stay as they are.
501 memDC->SetTextForeground(*wxBLACK); // 0s --> 0x000000 (black)
502 //now define what will be the color of the fillpattern parts that are not transparent
503 // memDC->SetTextBackground(*wxRED);
504 memDC->SetTextBackground(m_owner->m_colourBackground);
505 memDC->SetLogicalFunction(wxOR);
506
507 //don't understand how but the outline is also depending on logicalfunction
508 memDC->SetPen( wxPen( wxT("yellow"), 4, wxSOLID) );
509 memDC->DrawRectangle( 10, 10, 200, 200 );
510
511 memDC->SetBrush(wxNullBrush);
512 memDC->SetPen(wxNullPen);
513
514 memDC->EndDrawing();
515 dc.Blit(x,y,600,400,memDC,0,0,wxCOPY);
516 delete bmpBlit;
517 delete memDC;
518 break;
519 }
520 case 2: //now with transparent inversed fillpatterns
521 {
522 wxBitmap* bmpBlit = new wxBitmap(600,400);
523 wxMemoryDC* memDC= new wxMemoryDC();
524 wxBrush _clearbrush(*wxWHITE,wxSOLID);
525 memDC->SelectObject(*bmpBlit);
526 memDC->BeginDrawing();
527 memDC->SetBackground(_clearbrush);
528 memDC->Clear();
529 memDC->SetBackground(wxNullBrush);
530
531 memDC->SetPen( wxPen( wxT("black"), 4, wxSOLID) );
532 memDC->SetBrush( *brush4 );
533 memDC->SetTextBackground(*wxBLACK); // 0s --> 0x000000 (black)
534 memDC->SetTextForeground(*wxWHITE); // 1s --> 0xFFFFFF (white)
535 memDC->SetLogicalFunction(wxAND_INVERT);
536
537 // BLACK OUT the opaque pixels and leave the rest as is
538 memDC->DrawPolygon(5,todraw2,0,0,wxWINDING_RULE);
539
540 // Set background and foreground colors for fill pattern
541 //the previous blacked out pixels are now merged with the layer color
542 //while the non blacked out pixels stay as they are.
543 memDC->SetTextBackground(*wxBLACK); // 0s --> 0x000000 (black)
544
545 //now define what will be the color of the fillpattern parts that are not transparent
546 memDC->SetTextForeground(m_owner->m_colourForeground);
547 memDC->SetLogicalFunction(wxOR);
548
549
550 //don't understand how but the outline is also depending on logicalfunction
551 memDC->SetPen( wxPen( wxT("red"), 4, wxSOLID) );
552 memDC->DrawPolygon(5,todraw2,0,0,wxWINDING_RULE);
553
554 memDC->SetLogicalFunction(wxCOPY);
555
556 memDC->SetPen( wxPen( wxT("black"), 4, wxSOLID) );
557 memDC->SetBrush( *brush36 );
558 memDC->SetTextBackground(*wxBLACK); // 0s --> 0x000000 (black)
559 memDC->SetTextForeground(*wxWHITE); // 1s --> 0xFFFFFF (white)
560 memDC->SetLogicalFunction(wxAND_INVERT);
561
562 memDC->DrawRectangle( 10,10, 200, 200 );
563
564 // Set background and foreground colors for fill pattern
565 //the previous blacked out pixels are now merged with the layer color
566 //while the non blacked out pixels stay as they are.
567 memDC->SetTextBackground(*wxBLACK); // 0s --> 0x000000 (black)
568 //now define what will be the color of the fillpattern parts that are not transparent
569 memDC->SetTextForeground(m_owner->m_colourBackground);
570 memDC->SetLogicalFunction(wxOR);
571
572 //don't understand how but the outline is also depending on logicalfunction
573 memDC->SetPen( wxPen( wxT("yellow"), 4, wxSOLID) );
574 memDC->DrawRectangle( 10, 10, 200, 200 );
575
576 memDC->SetBrush(wxNullBrush);
577 memDC->SetPen(wxNullPen);
578 dc.Blit(x,y,600,400,memDC,0,0,wxCOPY);
579 delete bmpBlit;
580 delete memDC;
581 }
582 }
583
584 delete brush4;
585 delete brush4_mono;
586 delete brush36;
587 }
588
589 void MyCanvas::DrawTestLines( int x, int y, int width, wxDC &dc )
590 {
591 dc.SetPen( wxPen( wxT("black"), width, wxSOLID) );
592 dc.SetBrush( *wxRED_BRUSH );
593 dc.DrawText(wxString::Format(wxT("Testing lines of width %d"), width), x + 10, y - 10);
594 dc.DrawRectangle( x+10, y+10, 100, 190 );
595
596 dc.DrawText("Solid/dot/short dash/long dash/dot dash", x + 150, y + 10);
597 dc.SetPen( wxPen( wxT("black"), width, wxSOLID) );
598 dc.DrawLine( x+20, y+20, 100, y+20 );
599 dc.SetPen( wxPen( wxT("black"), width, wxDOT) );
600 dc.DrawLine( x+20, y+30, 100, y+30 );
601 dc.SetPen( wxPen( wxT("black"), width, wxSHORT_DASH) );
602 dc.DrawLine( x+20, y+40, 100, y+40 );
603 dc.SetPen( wxPen( wxT("black"), width, wxLONG_DASH) );
604 dc.DrawLine( x+20, y+50, 100, y+50 );
605 dc.SetPen( wxPen( wxT("black"), width, wxDOT_DASH) );
606 dc.DrawLine( x+20, y+60, 100, y+60 );
607
608 dc.DrawText("Misc hatches", x + 150, y + 70);
609 dc.SetPen( wxPen( wxT("black"), width, wxBDIAGONAL_HATCH) );
610 dc.DrawLine( x+20, y+70, 100, y+70 );
611 dc.SetPen( wxPen( wxT("black"), width, wxCROSSDIAG_HATCH) );
612 dc.DrawLine( x+20, y+80, 100, y+80 );
613 dc.SetPen( wxPen( wxT("black"), width, wxFDIAGONAL_HATCH) );
614 dc.DrawLine( x+20, y+90, 100, y+90 );
615 dc.SetPen( wxPen( wxT("black"), width, wxCROSS_HATCH) );
616 dc.DrawLine( x+20, y+100, 100, y+100 );
617 dc.SetPen( wxPen( wxT("black"), width, wxHORIZONTAL_HATCH) );
618 dc.DrawLine( x+20, y+110, 100, y+110 );
619 dc.SetPen( wxPen( wxT("black"), width, wxVERTICAL_HATCH) );
620 dc.DrawLine( x+20, y+120, 100, y+120 );
621
622 dc.DrawText("User dash", x + 150, y + 140);
623 wxPen ud( wxT("black"), width, wxUSER_DASH );
624 wxDash dash1[1];
625 dash1[0] = 0;
626 ud.SetDashes( 1, dash1 );
627 dc.DrawLine( x+20, y+140, 100, y+140 );
628 dash1[0] = 1;
629 ud.SetDashes( 1, dash1 );
630 dc.DrawLine( x+20, y+150, 100, y+150 );
631 dash1[0] = 2;
632 ud.SetDashes( 1, dash1 );
633 dc.DrawLine( x+20, y+160, 100, y+160 );
634 dash1[0] = 0x7F;
635 ud.SetDashes( 1, dash1 );
636 dc.DrawLine( x+20, y+170, 100, y+170 );
637 }
638
639 void MyCanvas::DrawDefault(wxDC& dc)
640 {
641 // mark the origin
642 dc.DrawCircle(0, 0, 10);
643 #if !(defined __WXGTK__) && !(defined __WXMOTIF__) && !(defined __WXMGL__)
644 // not implemented in wxGTK or wxMOTIF :-(
645 dc.FloodFill(0, 0, wxColour(255, 0, 0));
646 #endif //
647
648 dc.DrawCheckMark(5, 80, 15, 15);
649 dc.DrawCheckMark(25, 80, 30, 30);
650 dc.DrawCheckMark(60, 80, 60, 60);
651
652 // this is the test for "blitting bitmap into DC damages selected brush" bug
653 wxCoord rectSize = m_std_icon.GetWidth() + 10;
654 wxCoord x = 100;
655 dc.SetPen(*wxTRANSPARENT_PEN);
656 dc.SetBrush( *wxGREEN_BRUSH );
657 dc.DrawRectangle(x, 10, rectSize, rectSize);
658 dc.DrawBitmap(m_std_icon, x + 5, 15, TRUE);
659 x += rectSize + 10;
660 dc.DrawRectangle(x, 10, rectSize, rectSize);
661 dc.DrawIcon(m_std_icon, x + 5, 15);
662 x += rectSize + 10;
663 dc.DrawRectangle(x, 10, rectSize, rectSize);
664
665 // test for "transparent" bitmap drawing (it intersects with the last
666 // rectangle above)
667 //dc.SetBrush( *wxTRANSPARENT_BRUSH );
668
669 if (m_smile_bmp.Ok())
670 dc.DrawBitmap(m_smile_bmp, x + rectSize - 20, rectSize - 10, TRUE);
671
672 dc.SetBrush( *wxBLACK_BRUSH );
673 dc.DrawRectangle( 0, 160, 1000, 300 );
674
675 // draw lines
676 wxBitmap bitmap(20,70);
677 wxMemoryDC memdc;
678 memdc.SelectObject( bitmap );
679 memdc.SetBrush( *wxBLACK_BRUSH );
680 memdc.SetPen( *wxWHITE_PEN );
681 memdc.DrawRectangle(0,0,20,70);
682 memdc.DrawLine( 10,0,10,70 );
683
684 // to the right
685 wxPen pen = *wxRED_PEN;
686 memdc.SetPen(pen);
687 memdc.DrawLine( 10, 5,10, 5 );
688 memdc.DrawLine( 10,10,11,10 );
689 memdc.DrawLine( 10,15,12,15 );
690 memdc.DrawLine( 10,20,13,20 );
691
692 /*
693 memdc.SetPen(*wxRED_PEN);
694 memdc.DrawLine( 12, 5,12, 5 );
695 memdc.DrawLine( 12,10,13,10 );
696 memdc.DrawLine( 12,15,14,15 );
697 memdc.DrawLine( 12,20,15,20 );
698 */
699
700 // same to the left
701 memdc.DrawLine( 10,25,10,25 );
702 memdc.DrawLine( 10,30, 9,30 );
703 memdc.DrawLine( 10,35, 8,35 );
704 memdc.DrawLine( 10,40, 7,40 );
705
706 // XOR draw lines
707 dc.SetPen(*wxWHITE_PEN);
708 memdc.SetLogicalFunction( wxINVERT );
709 memdc.SetPen( *wxWHITE_PEN );
710 memdc.DrawLine( 10,50,10,50 );
711 memdc.DrawLine( 10,55,11,55 );
712 memdc.DrawLine( 10,60,12,60 );
713 memdc.DrawLine( 10,65,13,65 );
714
715 memdc.DrawLine( 12,50,12,50 );
716 memdc.DrawLine( 12,55,13,55 );
717 memdc.DrawLine( 12,60,14,60 );
718 memdc.DrawLine( 12,65,15,65 );
719
720 memdc.SelectObject( wxNullBitmap );
721 dc.DrawBitmap( bitmap, 10, 170 );
722 wxImage image( bitmap );
723 image.Rescale( 60,210 );
724 bitmap = image.ConvertToBitmap();
725 dc.DrawBitmap( bitmap, 50, 170 );
726
727 // test the rectangle outline drawing - there should be one pixel between
728 // the rect and the lines
729 dc.SetPen(*wxWHITE_PEN);
730 dc.SetBrush( *wxTRANSPARENT_BRUSH );
731 dc.DrawRectangle(150, 170, 49, 29);
732 dc.DrawRectangle(200, 170, 49, 29);
733 dc.SetPen(*wxWHITE_PEN);
734 dc.DrawLine(250, 210, 250, 170);
735 dc.DrawLine(260, 200, 150, 200);
736
737 // test the rectangle filled drawing - there should be one pixel between
738 // the rect and the lines
739 dc.SetPen(*wxTRANSPARENT_PEN);
740 dc.SetBrush( *wxWHITE_BRUSH );
741 dc.DrawRectangle(300, 170, 49, 29);
742 dc.DrawRectangle(350, 170, 49, 29);
743 dc.SetPen(*wxWHITE_PEN);
744 dc.DrawLine(400, 170, 400, 210);
745 dc.DrawLine(300, 200, 410, 200);
746
747 // a few more tests of this kind
748 dc.SetPen(*wxRED_PEN);
749 dc.SetBrush( *wxWHITE_BRUSH );
750 dc.DrawRectangle(300, 220, 1, 1);
751 dc.DrawRectangle(310, 220, 2, 2);
752 dc.DrawRectangle(320, 220, 3, 3);
753 dc.DrawRectangle(330, 220, 4, 4);
754
755 dc.SetPen(*wxTRANSPARENT_PEN);
756 dc.SetBrush( *wxWHITE_BRUSH );
757 dc.DrawRectangle(300, 230, 1, 1);
758 dc.DrawRectangle(310, 230, 2, 2);
759 dc.DrawRectangle(320, 230, 3, 3);
760 dc.DrawRectangle(330, 230, 4, 4);
761
762 // and now for filled rect with outline
763 dc.SetPen(*wxRED_PEN);
764 dc.SetBrush( *wxWHITE_BRUSH );
765 dc.DrawRectangle(500, 170, 49, 29);
766 dc.DrawRectangle(550, 170, 49, 29);
767 dc.SetPen(*wxWHITE_PEN);
768 dc.DrawLine(600, 170, 600, 210);
769 dc.DrawLine(500, 200, 610, 200);
770
771 // test the rectangle outline drawing - there should be one pixel between
772 // the rect and the lines
773 dc.SetPen(*wxWHITE_PEN);
774 dc.SetBrush( *wxTRANSPARENT_BRUSH );
775 dc.DrawRoundedRectangle(150, 270, 49, 29, 6);
776 dc.DrawRoundedRectangle(200, 270, 49, 29, 6);
777 dc.SetPen(*wxWHITE_PEN);
778 dc.DrawLine(250, 270, 250, 310);
779 dc.DrawLine(150, 300, 260, 300);
780
781 // test the rectangle filled drawing - there should be one pixel between
782 // the rect and the lines
783 dc.SetPen(*wxTRANSPARENT_PEN);
784 dc.SetBrush( *wxWHITE_BRUSH );
785 dc.DrawRoundedRectangle(300, 270, 49, 29, 6);
786 dc.DrawRoundedRectangle(350, 270, 49, 29, 6);
787 dc.SetPen(*wxWHITE_PEN);
788 dc.DrawLine(400, 270, 400, 310);
789 dc.DrawLine(300, 300, 410, 300);
790
791 // Added by JACS to demonstrate bizarre behaviour.
792 // With a size of 70, we get a missing red RHS,
793 // and the hight is too small, so we get yellow
794 // showing. With a size of 40, it draws as expected:
795 // it just shows a white rectangle with red outline.
796 int totalWidth = 70;
797 int totalHeight = 70;
798 wxBitmap bitmap2(totalWidth, totalHeight);
799
800 wxMemoryDC memdc2;
801 memdc2.SelectObject(bitmap2);
802
803 wxBrush yellowBrush(wxColour(255, 255, 0), wxSOLID);
804 memdc2.SetBackground(yellowBrush);
805 memdc2.Clear();
806
807 wxPen yellowPen(wxColour(255, 255, 0), 1, wxSOLID);
808
809 // Now draw a white rectangle with red outline. It should
810 // entirely eclipse the yellow background.
811 memdc2.SetPen(*wxRED_PEN);
812 memdc2.SetBrush(*wxWHITE_BRUSH);
813
814 memdc2.DrawRectangle(0, 0, totalWidth, totalHeight);
815
816 memdc2.SetPen(wxNullPen);
817 memdc2.SetBrush(wxNullBrush);
818 memdc2.SelectObject(wxNullBitmap);
819
820 dc.DrawBitmap(bitmap2, 500, 270);
821
822 // Repeat, but draw directly on dc
823 // Draw a yellow rectangle filling the bitmap
824
825 x = 600; int y = 270;
826 dc.SetPen(yellowPen);
827 dc.SetBrush(yellowBrush);
828 dc.DrawRectangle(x, y, totalWidth, totalHeight);
829
830 // Now draw a white rectangle with red outline. It should
831 // entirely eclipse the yellow background.
832 dc.SetPen(*wxRED_PEN);
833 dc.SetBrush(*wxWHITE_BRUSH);
834
835 dc.DrawRectangle(x, y, totalWidth, totalHeight);
836 }
837
838 void MyCanvas::DrawText(wxDC& dc)
839 {
840 // set underlined font for testing
841 dc.SetFont( wxFont(12, wxMODERN, wxNORMAL, wxNORMAL, TRUE) );
842 dc.DrawText( "This is text", 110, 10 );
843 dc.DrawRotatedText( "That is text", 20, 10, -45 );
844
845 // use wxSWISS_FONT and not wxNORMAL_FONT as the latter can't be rotated
846 // under Win9x (it is not TrueType)
847 dc.SetFont( *wxSWISS_FONT );
848
849 wxString text;
850 dc.SetBackgroundMode(wxTRANSPARENT);
851
852 for ( int n = -180; n < 180; n += 30 )
853 {
854 text.Printf(wxT(" %d rotated text"), n);
855 dc.DrawRotatedText(text , 400, 400, n);
856 }
857
858 dc.SetFont( wxFont( 18, wxSWISS, wxNORMAL, wxNORMAL ) );
859
860 dc.DrawText( "This is Swiss 18pt text.", 110, 40 );
861
862 long length;
863 long height;
864 long descent;
865 dc.GetTextExtent( "This is Swiss 18pt text.", &length, &height, &descent );
866 text.Printf( wxT("Dimensions are length %ld, height %ld, descent %ld"), length, height, descent );
867 dc.DrawText( text, 110, 80 );
868
869 text.Printf( wxT("CharHeight() returns: %d"), dc.GetCharHeight() );
870 dc.DrawText( text, 110, 120 );
871
872 dc.DrawRectangle( 100, 40, 4, height );
873
874 // test the logical function effect
875 wxCoord y = 150;
876 dc.SetLogicalFunction(wxINVERT);
877 dc.DrawText( "There should be no text below", 110, 150 );
878 dc.DrawRectangle( 110, y, 100, height );
879
880 // twice drawn inverted should result in invisible
881 y += height;
882 dc.DrawText( "Invisible text", 110, y );
883 dc.DrawRectangle( 110, y, 100, height );
884 dc.DrawText( "Invisible text", 110, y );
885 dc.DrawRectangle( 110, y, 100, height );
886 dc.SetLogicalFunction(wxCOPY);
887
888 y += height;
889 dc.DrawRectangle( 110, y, 100, height );
890 dc.DrawText( "Visible text", 110, y );
891 }
892
893 static const struct
894 {
895 const wxChar *name;
896 int rop;
897 } rasterOperations[] =
898 {
899 { wxT("wxAND"), wxAND },
900 { wxT("wxAND_INVERT"), wxAND_INVERT },
901 { wxT("wxAND_REVERSE"), wxAND_REVERSE },
902 { wxT("wxCLEAR"), wxCLEAR },
903 { wxT("wxCOPY"), wxCOPY },
904 { wxT("wxEQUIV"), wxEQUIV },
905 { wxT("wxINVERT"), wxINVERT },
906 { wxT("wxNAND"), wxNAND },
907 { wxT("wxNO_OP"), wxNO_OP },
908 { wxT("wxOR"), wxOR },
909 { wxT("wxOR_INVERT"), wxOR_INVERT },
910 { wxT("wxOR_REVERSE"), wxOR_REVERSE },
911 { wxT("wxSET"), wxSET },
912 { wxT("wxSRC_INVERT"), wxSRC_INVERT },
913 { wxT("wxXOR"), wxXOR },
914 };
915
916 void MyCanvas::DrawImages(wxDC& dc)
917 {
918 dc.DrawText("original image", 0, 0);
919 dc.DrawBitmap(*gs_bmpNoMask, 0, 20, 0);
920 dc.DrawText("with colour mask", 0, 100);
921 dc.DrawBitmap(*gs_bmpWithColMask, 0, 120, TRUE);
922 dc.DrawText("the mask image", 0, 200);
923 dc.DrawBitmap(*gs_bmpMask, 0, 220, 0);
924 dc.DrawText("masked image", 0, 300);
925 dc.DrawBitmap(*gs_bmpWithMask, 0, 320, TRUE);
926
927 int cx = gs_bmpWithColMask->GetWidth(),
928 cy = gs_bmpWithColMask->GetHeight();
929
930 wxMemoryDC memDC;
931 for ( size_t n = 0; n < WXSIZEOF(rasterOperations); n++ )
932 {
933 wxCoord x = 120 + 150*(n%4),
934 y = 20 + 100*(n/4);
935
936 dc.DrawText(rasterOperations[n].name, x, y - 20);
937 memDC.SelectObject(*gs_bmpWithColMask);
938 dc.Blit(x, y, cx, cy, &memDC, 0, 0, rasterOperations[n].rop, TRUE);
939 }
940 }
941
942 void MyCanvas::DrawWithLogicalOps(wxDC& dc)
943 {
944 static const wxCoord w = 60;
945 static const wxCoord h = 60;
946
947 // reuse the text colour here
948 dc.SetPen(wxPen(m_owner->m_colourForeground, 1, wxSOLID));
949 dc.SetBrush(*wxTRANSPARENT_BRUSH);
950
951 size_t n;
952 for ( n = 0; n < WXSIZEOF(rasterOperations); n++ )
953 {
954 wxCoord x = 20 + 150*(n%4),
955 y = 20 + 100*(n/4);
956
957 dc.DrawText(rasterOperations[n].name, x, y - 20);
958 dc.SetLogicalFunction(rasterOperations[n].rop);
959 dc.DrawRectangle(x, y, w, h);
960 dc.DrawLine(x, y, x + w, y + h);
961 dc.DrawLine(x + w, y, x, y + h);
962 }
963
964 // now some filled rectangles
965 dc.SetBrush(wxBrush(m_owner->m_colourForeground, wxSOLID));
966
967 for ( n = 0; n < WXSIZEOF(rasterOperations); n++ )
968 {
969 wxCoord x = 20 + 150*(n%4),
970 y = 500 + 100*(n/4);
971
972 dc.DrawText(rasterOperations[n].name, x, y - 20);
973 dc.SetLogicalFunction(rasterOperations[n].rop);
974 dc.DrawRectangle(x, y, w, h);
975 }
976 }
977
978 void MyCanvas::DrawCircles(wxDC& dc)
979 {
980 int x = 100,
981 y = 100,
982 r = 20;
983
984 dc.DrawText("Some circles", 0, y);
985 dc.DrawCircle(x, y, r);
986 dc.DrawCircle(x + 2*r, y, r);
987 dc.DrawCircle(x + 4*r, y, r);
988
989 y += 2*r;
990 dc.DrawText("And ellipses", 0, y);
991 dc.DrawEllipse(x - r, y, 2*r, r);
992 dc.DrawEllipse(x + r, y, 2*r, r);
993 dc.DrawEllipse(x + 3*r, y, 2*r, r);
994
995 y += 2*r;
996 dc.DrawText("And arcs", 0, y);
997 dc.DrawArc(x - r, y, x + r, y, x, y);
998 dc.DrawArc(x + 4*r, y, x + 2*r, y, x + 3*r, y);
999 dc.DrawArc(x + 5*r, y, x + 5*r, y, x + 6*r, y);
1000
1001 y += 2*r;
1002 dc.DrawEllipticArc(x - r, y, 2*r, r, 0, 90);
1003 dc.DrawEllipticArc(x + r, y, 2*r, r, 90, 180);
1004 dc.DrawEllipticArc(x + 3*r, y, 2*r, r, 180, 270);
1005 dc.DrawEllipticArc(x + 5*r, y, 2*r, r, 270, 360);
1006 }
1007
1008 void MyCanvas::DrawRegions(wxDC& dc)
1009 {
1010 dc.DrawText("You should see a red rect partly covered by a cyan one "
1011 "on the left", 10, 5);
1012 dc.DrawText("and 5 smileys from which 4 are partially clipped on the "
1013 "right (2 copies should be identical)",
1014 10, 5 + dc.GetCharHeight());
1015
1016 DrawRegionsHelper(dc, 10);
1017 DrawRegionsHelper(dc, 350);
1018 }
1019
1020 void MyCanvas::DrawRegionsHelper(wxDC& dc, wxCoord x)
1021 {
1022 dc.DestroyClippingRegion();
1023 dc.SetBrush( *wxWHITE_BRUSH );
1024 dc.SetPen( *wxTRANSPARENT_PEN );
1025 dc.DrawRectangle( x,50,310,310 );
1026
1027 dc.SetClippingRegion( x+10,60,100,270 );
1028
1029 dc.SetBrush( *wxRED_BRUSH );
1030 dc.DrawRectangle( x,50,310,310 );
1031
1032 dc.SetClippingRegion( x+10,60,100,100 );
1033
1034 dc.SetBrush( *wxCYAN_BRUSH );
1035 dc.DrawRectangle( x,50,310,310 );
1036
1037 // when drawing the left half, destroy the clipping region, when drawing
1038 // the right one - leave it
1039 //
1040 // normally it shouldn't make any difference as SetClippingRegion()
1041 // replaces the old clipping region
1042 if ( x < 300 )
1043 dc.DestroyClippingRegion();
1044 dc.SetClippingRegion( x+110,70,100,270 );
1045
1046 dc.SetBrush( *wxGREY_BRUSH );
1047 dc.DrawRectangle( x,50,310,310 );
1048
1049 if (m_smile_bmp.Ok())
1050 {
1051 dc.DrawBitmap( m_smile_bmp, x+150, 200, TRUE );
1052 dc.DrawBitmap( m_smile_bmp, x+130, 60, TRUE );
1053 dc.DrawBitmap( m_smile_bmp, x+130, 330, TRUE );
1054 dc.DrawBitmap( m_smile_bmp, x+100, 120, TRUE );
1055 dc.DrawBitmap( m_smile_bmp, x+200, 120, TRUE );
1056 }
1057 }
1058
1059 void MyCanvas::OnPaint(wxPaintEvent &WXUNUSED(event))
1060 {
1061 wxPaintDC dc(this);
1062 PrepareDC(dc);
1063
1064 m_owner->PrepareDC(dc);
1065
1066 dc.SetBackgroundMode( m_owner->m_backgroundMode );
1067 if ( m_owner->m_backgroundBrush.Ok() )
1068 dc.SetBackground( m_owner->m_backgroundBrush );
1069 if ( m_owner->m_colourForeground.Ok() )
1070 dc.SetTextForeground( m_owner->m_colourForeground );
1071 if ( m_owner->m_colourBackground.Ok() )
1072 dc.SetTextBackground( m_owner->m_colourBackground );
1073
1074 if ( m_owner->m_textureBackground) {
1075 if ( ! m_owner->m_backgroundBrush.Ok() ) {
1076 wxBrush b(wxColour(0,128,0), wxSOLID);
1077 dc.SetBackground(b);
1078 }
1079 }
1080
1081 dc.Clear();
1082
1083 if ( m_owner->m_textureBackground) {
1084 dc.SetPen(*wxMEDIUM_GREY_PEN);
1085 for (int i=0; i<200; i++)
1086 dc.DrawLine(0, i*10, i*10, 0);
1087 }
1088
1089 switch ( m_show )
1090 {
1091 case Show_Default:
1092 DrawDefault(dc);
1093 break;
1094
1095 case Show_Circles:
1096 DrawCircles(dc);
1097 break;
1098
1099 case Show_Regions:
1100 DrawRegions(dc);
1101 break;
1102
1103 case Show_Text:
1104 DrawText(dc);
1105 break;
1106
1107 case Show_Lines:
1108 DrawTestLines( 0, 100, 0, dc );
1109 DrawTestLines( 0, 320, 1, dc );
1110 DrawTestLines( 0, 540, 2, dc );
1111 DrawTestLines( 0, 760, 6, dc );
1112 break;
1113
1114 case Show_Polygons:
1115 DrawTestPoly( 0, 100, dc, 0 );
1116 /*
1117 DrawTestPoly( 33, 500, dc, 1 );
1118 DrawTestPoly( 43, 1000, dc, 2 );
1119 */
1120 break;
1121
1122 case Show_Mask:
1123 DrawImages(dc);
1124 break;
1125
1126 case Show_Ops:
1127 DrawWithLogicalOps(dc);
1128 break;
1129
1130 default:
1131 {
1132 dc.SetPen( *wxBLACK_PEN );
1133 dc.DrawLine( 0,0,100,100 );
1134 }
1135
1136 }
1137 }
1138
1139 void MyCanvas::OnMouseMove(wxMouseEvent &event)
1140 {
1141 wxClientDC dc(this);
1142 PrepareDC(dc);
1143 m_owner->PrepareDC(dc);
1144
1145 wxPoint pos = event.GetPosition();
1146 long x = dc.DeviceToLogicalX( pos.x );
1147 long y = dc.DeviceToLogicalY( pos.y );
1148 wxString str;
1149 str.Printf( wxT("Current mouse position: %d,%d"), (int)x, (int)y );
1150 m_owner->SetStatusText( str );
1151 }
1152
1153 // ----------------------------------------------------------------------------
1154 // MyFrame
1155 // ----------------------------------------------------------------------------
1156
1157 // the event tables connect the wxWindows events with the functions (event
1158 // handlers) which process them. It can be also done at run-time, but for the
1159 // simple menu events like this the static method is much simpler.
1160 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
1161 EVT_MENU (File_Quit, MyFrame::OnQuit)
1162 EVT_MENU (File_About, MyFrame::OnAbout)
1163
1164 EVT_MENU_RANGE(MenuShow_First, MenuShow_Last, MyFrame::OnShow)
1165
1166 EVT_MENU_RANGE(MenuOption_First, MenuOption_Last, MyFrame::OnOption)
1167 END_EVENT_TABLE()
1168
1169 // frame constructor
1170 MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
1171 : wxFrame((wxFrame *)NULL, -1, title, pos, size,
1172 wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE)
1173 {
1174 // set the frame icon
1175 SetIcon(wxICON(mondrian));
1176
1177 wxMenu *menuFile = new wxMenu;
1178 menuFile->Append(File_ShowDefault, "&Default screen\tF1");
1179 menuFile->Append(File_ShowText, "&Text screen\tF2");
1180 menuFile->Append(File_ShowLines, "&Lines screen\tF3");
1181 menuFile->Append(File_ShowPolygons, "&Polygons screen\tF4");
1182 menuFile->Append(File_ShowMask, "wx&Mask screen\tF5");
1183 menuFile->Append(File_ShowOps, "&ROP screen\tF6");
1184 menuFile->Append(File_ShowRegions, "Re&gions screen\tF7");
1185 menuFile->Append(File_ShowCircles, "&Circles screen\tF8");
1186 menuFile->AppendSeparator();
1187 menuFile->Append(File_About, "&About...\tCtrl-A", "Show about dialog");
1188 menuFile->AppendSeparator();
1189 menuFile->Append(File_Quit, "E&xit\tAlt-X", "Quit this program");
1190
1191 wxMenu *menuMapMode = new wxMenu;
1192 menuMapMode->Append( MapMode_Text, "&TEXT map mode" );
1193 menuMapMode->Append( MapMode_Lometric, "&LOMETRIC map mode" );
1194 menuMapMode->Append( MapMode_Twips, "T&WIPS map mode" );
1195 menuMapMode->Append( MapMode_Points, "&POINTS map mode" );
1196 menuMapMode->Append( MapMode_Metric, "&METRIC map mode" );
1197
1198 wxMenu *menuUserScale = new wxMenu;
1199 menuUserScale->Append( UserScale_StretchHoriz, "Stretch horizontally\tCtrl-H" );
1200 menuUserScale->Append( UserScale_ShrinkHoriz, "Shrink horizontally\tCtrl-G" );
1201 menuUserScale->Append( UserScale_StretchVertic, "Stretch vertically\tCtrl-V" );
1202 menuUserScale->Append( UserScale_ShrinkVertic, "Shrink vertically\tCtrl-W" );
1203 menuUserScale->AppendSeparator();
1204 menuUserScale->Append( UserScale_Restore, "Restore to normal\tCtrl-0" );
1205
1206 wxMenu *menuAxis = new wxMenu;
1207 menuAxis->Append( AxisMirror_Horiz, "Mirror horizontally\tCtrl-M", "", TRUE );
1208 menuAxis->Append( AxisMirror_Vertic, "Mirror vertically\tCtrl-N", "", TRUE );
1209
1210 wxMenu *menuLogical = new wxMenu;
1211 menuLogical->Append( LogicalOrigin_MoveDown, "Move &down\tCtrl-D" );
1212 menuLogical->Append( LogicalOrigin_MoveUp, "Move &up\tCtrl-U" );
1213 menuLogical->Append( LogicalOrigin_MoveLeft, "Move &right\tCtrl-L" );
1214 menuLogical->Append( LogicalOrigin_MoveRight, "Move &left\tCtrl-R" );
1215
1216 wxMenu *menuColour = new wxMenu;
1217 menuColour->Append( Colour_TextForeground, "Text foreground..." );
1218 menuColour->Append( Colour_TextBackground, "Text background..." );
1219 menuColour->Append( Colour_Background, "Background colour..." );
1220 menuColour->Append( Colour_BackgroundMode, "Opaque/transparent\tCtrl-B", "", TRUE );
1221 menuColour->Append( Colour_TextureBackgound, "Draw textured background\tCtrl-T", "", TRUE);
1222
1223 // now append the freshly created menu to the menu bar...
1224 wxMenuBar *menuBar = new wxMenuBar;
1225 menuBar->Append(menuFile, "&File");
1226 menuBar->Append(menuMapMode, "&MapMode");
1227 menuBar->Append(menuUserScale, "&UserScale");
1228 menuBar->Append(menuAxis, "&Axis");
1229 menuBar->Append(menuLogical, "&LogicalOrigin");
1230 menuBar->Append(menuColour, "&Colours");
1231
1232 // ... and attach this menu bar to the frame
1233 SetMenuBar(menuBar);
1234
1235 // create a status bar just for fun (by default with 1 pane only)
1236 CreateStatusBar(2);
1237 SetStatusText("Welcome to wxWindows!");
1238
1239 m_mapMode = wxMM_TEXT;
1240 m_xUserScale = 1.0;
1241 m_yUserScale = 1.0;
1242 m_xLogicalOrigin = 0;
1243 m_yLogicalOrigin = 0;
1244 m_xAxisReversed =
1245 m_yAxisReversed = FALSE;
1246 m_backgroundMode = wxSOLID;
1247 m_colourForeground = *wxRED;
1248 m_colourBackground = *wxBLUE;
1249 m_textureBackground = FALSE;
1250
1251 m_canvas = new MyCanvas( this );
1252 m_canvas->SetScrollbars( 10, 10, 100, 240 );
1253 }
1254
1255 // event handlers
1256
1257 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
1258 {
1259 // TRUE is to force the frame to close
1260 Close(TRUE);
1261 }
1262
1263 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
1264 {
1265 wxString msg;
1266 msg.Printf( wxT("This is the about dialog of the drawing sample.\n")
1267 wxT("This sample tests various primitive drawing functions\n")
1268 wxT("without any tests to prevent flicker.\n")
1269 wxT("Copyright (c) Robert Roebling 1999")
1270 );
1271
1272 wxMessageBox(msg, "About Drawing", wxOK | wxICON_INFORMATION, this);
1273 }
1274
1275 void MyFrame::OnShow(wxCommandEvent& event)
1276 {
1277 m_canvas->Show((ScreenToShow)(event.GetId() - MenuShow_First));
1278 }
1279
1280 void MyFrame::OnOption(wxCommandEvent& event)
1281 {
1282 switch (event.GetId())
1283 {
1284 case MapMode_Text:
1285 m_mapMode = wxMM_TEXT;
1286 break;
1287 case MapMode_Lometric:
1288 m_mapMode = wxMM_LOMETRIC;
1289 break;
1290 case MapMode_Twips:
1291 m_mapMode = wxMM_TWIPS;
1292 break;
1293 case MapMode_Points:
1294 m_mapMode = wxMM_POINTS;
1295 break;
1296 case MapMode_Metric:
1297 m_mapMode = wxMM_METRIC;
1298 break;
1299
1300 case LogicalOrigin_MoveDown:
1301 m_yLogicalOrigin += 10;
1302 break;
1303 case LogicalOrigin_MoveUp:
1304 m_yLogicalOrigin -= 10;
1305 break;
1306 case LogicalOrigin_MoveLeft:
1307 m_xLogicalOrigin += 10;
1308 break;
1309 case LogicalOrigin_MoveRight:
1310 m_xLogicalOrigin -= 10;
1311 break;
1312
1313 case UserScale_StretchHoriz:
1314 m_xUserScale *= 1.10;
1315 break;
1316 case UserScale_ShrinkHoriz:
1317 m_xUserScale /= 1.10;
1318 break;
1319 case UserScale_StretchVertic:
1320 m_yUserScale *= 1.10;
1321 break;
1322 case UserScale_ShrinkVertic:
1323 m_yUserScale /= 1.10;
1324 break;
1325 case UserScale_Restore:
1326 m_xUserScale =
1327 m_yUserScale = 1.0;
1328 break;
1329
1330 case AxisMirror_Vertic:
1331 m_yAxisReversed = !m_yAxisReversed;
1332 break;
1333 case AxisMirror_Horiz:
1334 m_xAxisReversed = !m_xAxisReversed;
1335 break;
1336
1337 case Colour_TextForeground:
1338 m_colourForeground = SelectColour();
1339 break;
1340 case Colour_TextBackground:
1341 m_colourBackground = SelectColour();
1342 break;
1343 case Colour_Background:
1344 {
1345 wxColour col = SelectColour();
1346 if ( col.Ok() )
1347 {
1348 m_backgroundBrush.SetColour(col);
1349 }
1350 }
1351 break;
1352 case Colour_BackgroundMode:
1353 m_backgroundMode = m_backgroundMode == wxSOLID ? wxTRANSPARENT
1354 : wxSOLID;
1355 break;
1356
1357 case Colour_TextureBackgound:
1358 m_textureBackground = ! m_textureBackground;
1359 break;
1360
1361 default:
1362 // skip Refresh()
1363 return;
1364 }
1365
1366 m_canvas->Refresh();
1367 }
1368
1369 void MyFrame::PrepareDC(wxDC& dc)
1370 {
1371 dc.SetMapMode( m_mapMode );
1372 dc.SetUserScale( m_xUserScale, m_yUserScale );
1373 dc.SetLogicalOrigin( m_xLogicalOrigin, m_yLogicalOrigin );
1374 dc.SetAxisOrientation( !m_xAxisReversed, m_yAxisReversed );
1375 }
1376
1377 wxColour MyFrame::SelectColour()
1378 {
1379 wxColour col;
1380 wxColourData data;
1381 wxColourDialog dialog(this, &data);
1382
1383 if ( dialog.ShowModal() == wxID_OK )
1384 {
1385 col = dialog.GetColourData().GetColour();
1386 }
1387
1388 return col;
1389 }