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