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