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