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