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