some brush tests
[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);
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 "
845 "right (2 copies should be identical)",
846 10, 5 + dc.GetCharHeight());
847
848 DrawRegionsHelper(dc, 10);
849 DrawRegionsHelper(dc, 350);
850 }
851
852 void MyCanvas::DrawRegionsHelper(wxDC& dc, wxCoord x)
853 {
854 dc.DestroyClippingRegion();
855 dc.SetBrush( *wxWHITE_BRUSH );
856 dc.SetPen( *wxTRANSPARENT_PEN );
857 dc.DrawRectangle( x,50,310,310 );
858
859 dc.SetClippingRegion( x+10,60,100,270 );
860
861 dc.SetBrush( *wxRED_BRUSH );
862 dc.DrawRectangle( x,50,310,310 );
863
864 dc.SetClippingRegion( x+10,60,100,100 );
865
866 dc.SetBrush( *wxCYAN_BRUSH );
867 dc.DrawRectangle( x,50,310,310 );
868
869 // when drawing the left half, destroy the clipping region, when drawing
870 // the right one - leave it
871 //
872 // normally it shouldn't make any difference as SetClippingRegion()
873 // replaces the old clipping region
874 if ( x < 300 )
875 dc.DestroyClippingRegion();
876 dc.SetClippingRegion( x+110,70,100,270 );
877
878 dc.SetBrush( *wxGREY_BRUSH );
879 dc.DrawRectangle( x,50,310,310 );
880
881 if (m_smile_bmp.Ok())
882 {
883 dc.DrawBitmap( m_smile_bmp, x+150, 200, TRUE );
884 dc.DrawBitmap( m_smile_bmp, x+130, 60, TRUE );
885 dc.DrawBitmap( m_smile_bmp, x+130, 330, TRUE );
886 dc.DrawBitmap( m_smile_bmp, x+100, 120, TRUE );
887 dc.DrawBitmap( m_smile_bmp, x+200, 120, TRUE );
888 }
889 }
890
891 void MyCanvas::OnPaint(wxPaintEvent &WXUNUSED(event))
892 {
893 wxPaintDC dc(this);
894 PrepareDC(dc);
895
896 m_owner->PrepareDC(dc);
897
898 dc.SetBackgroundMode( m_owner->m_backgroundMode );
899 if ( m_owner->m_backgroundBrush.Ok() )
900 dc.SetBackground( m_owner->m_backgroundBrush );
901 if ( m_owner->m_colourForeground.Ok() )
902 dc.SetTextForeground( m_owner->m_colourForeground );
903 if ( m_owner->m_colourBackground.Ok() )
904 dc.SetTextBackground( m_owner->m_colourBackground );
905
906 if ( m_owner->m_textureBackground) {
907 if ( ! m_owner->m_backgroundBrush.Ok() ) {
908 wxBrush b(wxColour(0,128,0), wxSOLID);
909 dc.SetBackground(b);
910 }
911 }
912
913 dc.Clear();
914
915 if ( m_owner->m_textureBackground) {
916 dc.SetPen(*wxMEDIUM_GREY_PEN);
917 for (int i=0; i<200; i++)
918 dc.DrawLine(0, i*10, i*10, 0);
919 }
920
921 switch ( m_show )
922 {
923 case Show_Default:
924 DrawDefault(dc);
925 break;
926
927 case Show_Circles:
928 DrawCircles(dc);
929 break;
930
931 case Show_Regions:
932 DrawRegions(dc);
933 break;
934
935 case Show_Text:
936 DrawText(dc);
937 break;
938
939 case Show_Lines:
940 DrawTestLines( 0, 100, 0, dc );
941 DrawTestLines( 0, 320, 1, dc );
942 DrawTestLines( 0, 540, 2, dc );
943 DrawTestLines( 0, 760, 6, dc );
944 break;
945
946 case Show_Brushes:
947 DrawTestBrushes(dc);
948 break;
949
950 case Show_Polygons:
951 DrawTestPoly(dc);
952 break;
953
954 case Show_Mask:
955 DrawImages(dc);
956 break;
957
958 case Show_Ops:
959 DrawWithLogicalOps(dc);
960 break;
961 }
962 }
963
964 void MyCanvas::OnMouseMove(wxMouseEvent &event)
965 {
966 wxClientDC dc(this);
967 PrepareDC(dc);
968 m_owner->PrepareDC(dc);
969
970 wxPoint pos = event.GetPosition();
971 long x = dc.DeviceToLogicalX( pos.x );
972 long y = dc.DeviceToLogicalY( pos.y );
973 wxString str;
974 str.Printf( wxT("Current mouse position: %d,%d"), (int)x, (int)y );
975 m_owner->SetStatusText( str );
976 }
977
978 // ----------------------------------------------------------------------------
979 // MyFrame
980 // ----------------------------------------------------------------------------
981
982 // the event tables connect the wxWindows events with the functions (event
983 // handlers) which process them. It can be also done at run-time, but for the
984 // simple menu events like this the static method is much simpler.
985 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
986 EVT_MENU (File_Quit, MyFrame::OnQuit)
987 EVT_MENU (File_About, MyFrame::OnAbout)
988
989 EVT_MENU_RANGE(MenuShow_First, MenuShow_Last, MyFrame::OnShow)
990
991 EVT_MENU_RANGE(MenuOption_First, MenuOption_Last, MyFrame::OnOption)
992 END_EVENT_TABLE()
993
994 // frame constructor
995 MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
996 : wxFrame((wxFrame *)NULL, -1, title, pos, size,
997 wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE)
998 {
999 // set the frame icon
1000 SetIcon(wxICON(mondrian));
1001
1002 wxMenu *menuFile = new wxMenu;
1003 menuFile->Append(File_ShowDefault, "&Default screen\tF1");
1004 menuFile->Append(File_ShowText, "&Text screen\tF2");
1005 menuFile->Append(File_ShowLines, "&Lines screen\tF3");
1006 menuFile->Append(File_ShowBrushes, "&Brushes screen\tF4");
1007 menuFile->Append(File_ShowPolygons, "&Polygons screen\tF5");
1008 menuFile->Append(File_ShowMask, "&Mask screen\tF6");
1009 menuFile->Append(File_ShowOps, "&ROP screen\tF7");
1010 menuFile->Append(File_ShowRegions, "Re&gions screen\tF8");
1011 menuFile->Append(File_ShowCircles, "&Circles screen\tF9");
1012 menuFile->AppendSeparator();
1013 menuFile->Append(File_About, "&About...\tCtrl-A", "Show about dialog");
1014 menuFile->AppendSeparator();
1015 menuFile->Append(File_Quit, "E&xit\tAlt-X", "Quit this program");
1016
1017 wxMenu *menuMapMode = new wxMenu;
1018 menuMapMode->Append( MapMode_Text, "&TEXT map mode" );
1019 menuMapMode->Append( MapMode_Lometric, "&LOMETRIC map mode" );
1020 menuMapMode->Append( MapMode_Twips, "T&WIPS map mode" );
1021 menuMapMode->Append( MapMode_Points, "&POINTS map mode" );
1022 menuMapMode->Append( MapMode_Metric, "&METRIC map mode" );
1023
1024 wxMenu *menuUserScale = new wxMenu;
1025 menuUserScale->Append( UserScale_StretchHoriz, "Stretch horizontally\tCtrl-H" );
1026 menuUserScale->Append( UserScale_ShrinkHoriz, "Shrink horizontally\tCtrl-G" );
1027 menuUserScale->Append( UserScale_StretchVertic, "Stretch vertically\tCtrl-V" );
1028 menuUserScale->Append( UserScale_ShrinkVertic, "Shrink vertically\tCtrl-W" );
1029 menuUserScale->AppendSeparator();
1030 menuUserScale->Append( UserScale_Restore, "Restore to normal\tCtrl-0" );
1031
1032 wxMenu *menuAxis = new wxMenu;
1033 menuAxis->Append( AxisMirror_Horiz, "Mirror horizontally\tCtrl-M", "", TRUE );
1034 menuAxis->Append( AxisMirror_Vertic, "Mirror vertically\tCtrl-N", "", TRUE );
1035
1036 wxMenu *menuLogical = new wxMenu;
1037 menuLogical->Append( LogicalOrigin_MoveDown, "Move &down\tCtrl-D" );
1038 menuLogical->Append( LogicalOrigin_MoveUp, "Move &up\tCtrl-U" );
1039 menuLogical->Append( LogicalOrigin_MoveLeft, "Move &right\tCtrl-L" );
1040 menuLogical->Append( LogicalOrigin_MoveRight, "Move &left\tCtrl-R" );
1041
1042 wxMenu *menuColour = new wxMenu;
1043 menuColour->Append( Colour_TextForeground, "Text foreground..." );
1044 menuColour->Append( Colour_TextBackground, "Text background..." );
1045 menuColour->Append( Colour_Background, "Background colour..." );
1046 menuColour->Append( Colour_BackgroundMode, "Opaque/transparent\tCtrl-B", "", TRUE );
1047 menuColour->Append( Colour_TextureBackgound, "Draw textured background\tCtrl-T", "", TRUE);
1048
1049 // now append the freshly created menu to the menu bar...
1050 wxMenuBar *menuBar = new wxMenuBar;
1051 menuBar->Append(menuFile, "&File");
1052 menuBar->Append(menuMapMode, "&MapMode");
1053 menuBar->Append(menuUserScale, "&UserScale");
1054 menuBar->Append(menuAxis, "&Axis");
1055 menuBar->Append(menuLogical, "&LogicalOrigin");
1056 menuBar->Append(menuColour, "&Colours");
1057
1058 // ... and attach this menu bar to the frame
1059 SetMenuBar(menuBar);
1060
1061 // create a status bar just for fun (by default with 1 pane only)
1062 CreateStatusBar(2);
1063 SetStatusText("Welcome to wxWindows!");
1064
1065 m_mapMode = wxMM_TEXT;
1066 m_xUserScale = 1.0;
1067 m_yUserScale = 1.0;
1068 m_xLogicalOrigin = 0;
1069 m_yLogicalOrigin = 0;
1070 m_xAxisReversed =
1071 m_yAxisReversed = FALSE;
1072 m_backgroundMode = wxSOLID;
1073 m_colourForeground = *wxRED;
1074 m_colourBackground = *wxBLUE;
1075 m_textureBackground = FALSE;
1076
1077 m_canvas = new MyCanvas( this );
1078 m_canvas->SetScrollbars( 10, 10, 100, 240 );
1079 }
1080
1081 // event handlers
1082
1083 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
1084 {
1085 // TRUE is to force the frame to close
1086 Close(TRUE);
1087 }
1088
1089 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
1090 {
1091 wxString msg;
1092 msg.Printf( wxT("This is the about dialog of the drawing sample.\n")
1093 wxT("This sample tests various primitive drawing functions\n")
1094 wxT("(without any attempts to prevent flicker).\n")
1095 wxT("Copyright (c) Robert Roebling 1999")
1096 );
1097
1098 wxMessageBox(msg, "About Drawing", wxOK | wxICON_INFORMATION, this);
1099 }
1100
1101 void MyFrame::OnShow(wxCommandEvent& event)
1102 {
1103 m_canvas->Show((ScreenToShow)(event.GetId() - MenuShow_First));
1104 }
1105
1106 void MyFrame::OnOption(wxCommandEvent& event)
1107 {
1108 switch (event.GetId())
1109 {
1110 case MapMode_Text:
1111 m_mapMode = wxMM_TEXT;
1112 break;
1113 case MapMode_Lometric:
1114 m_mapMode = wxMM_LOMETRIC;
1115 break;
1116 case MapMode_Twips:
1117 m_mapMode = wxMM_TWIPS;
1118 break;
1119 case MapMode_Points:
1120 m_mapMode = wxMM_POINTS;
1121 break;
1122 case MapMode_Metric:
1123 m_mapMode = wxMM_METRIC;
1124 break;
1125
1126 case LogicalOrigin_MoveDown:
1127 m_yLogicalOrigin += 10;
1128 break;
1129 case LogicalOrigin_MoveUp:
1130 m_yLogicalOrigin -= 10;
1131 break;
1132 case LogicalOrigin_MoveLeft:
1133 m_xLogicalOrigin += 10;
1134 break;
1135 case LogicalOrigin_MoveRight:
1136 m_xLogicalOrigin -= 10;
1137 break;
1138
1139 case UserScale_StretchHoriz:
1140 m_xUserScale *= 1.10;
1141 break;
1142 case UserScale_ShrinkHoriz:
1143 m_xUserScale /= 1.10;
1144 break;
1145 case UserScale_StretchVertic:
1146 m_yUserScale *= 1.10;
1147 break;
1148 case UserScale_ShrinkVertic:
1149 m_yUserScale /= 1.10;
1150 break;
1151 case UserScale_Restore:
1152 m_xUserScale =
1153 m_yUserScale = 1.0;
1154 break;
1155
1156 case AxisMirror_Vertic:
1157 m_yAxisReversed = !m_yAxisReversed;
1158 break;
1159 case AxisMirror_Horiz:
1160 m_xAxisReversed = !m_xAxisReversed;
1161 break;
1162
1163 case Colour_TextForeground:
1164 m_colourForeground = SelectColour();
1165 break;
1166 case Colour_TextBackground:
1167 m_colourBackground = SelectColour();
1168 break;
1169 case Colour_Background:
1170 {
1171 wxColour col = SelectColour();
1172 if ( col.Ok() )
1173 {
1174 m_backgroundBrush.SetColour(col);
1175 }
1176 }
1177 break;
1178 case Colour_BackgroundMode:
1179 m_backgroundMode = m_backgroundMode == wxSOLID ? wxTRANSPARENT
1180 : wxSOLID;
1181 break;
1182
1183 case Colour_TextureBackgound:
1184 m_textureBackground = ! m_textureBackground;
1185 break;
1186
1187 default:
1188 // skip Refresh()
1189 return;
1190 }
1191
1192 m_canvas->Refresh();
1193 }
1194
1195 void MyFrame::PrepareDC(wxDC& dc)
1196 {
1197 dc.SetMapMode( m_mapMode );
1198 dc.SetUserScale( m_xUserScale, m_yUserScale );
1199 dc.SetLogicalOrigin( m_xLogicalOrigin, m_yLogicalOrigin );
1200 dc.SetAxisOrientation( !m_xAxisReversed, m_yAxisReversed );
1201 }
1202
1203 wxColour MyFrame::SelectColour()
1204 {
1205 wxColour col;
1206 wxColourData data;
1207 wxColourDialog dialog(this, &data);
1208
1209 if ( dialog.ShowModal() == wxID_OK )
1210 {
1211 col = dialog.GetColourData().GetColour();
1212 }
1213
1214 return col;
1215 }