Allow saving the drawing sample canvas to a file or clipboard.
[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 #include "wx/dcgraph.h"
37 #include "wx/overlay.h"
38 #include "wx/graphics.h"
39 #include "wx/filename.h"
40 #include "wx/metafile.h"
41
42 #define TEST_CAIRO_EVERYWHERE 0
43
44 // ----------------------------------------------------------------------------
45 // resources
46 // ----------------------------------------------------------------------------
47
48 // the application icon
49 #if !defined(__WXMSW__) && !defined(__WXPM__)
50 #include "../sample.xpm"
51 #endif
52
53 // ----------------------------------------------------------------------------
54 // global variables
55 // ----------------------------------------------------------------------------
56
57 static wxBitmap *gs_bmpNoMask = NULL,
58 *gs_bmpWithColMask = NULL,
59 *gs_bmpMask = NULL,
60 *gs_bmpWithMask = NULL,
61 *gs_bmp4 = NULL,
62 *gs_bmp4_mono = NULL,
63 *gs_bmp36 = NULL;
64
65 // ----------------------------------------------------------------------------
66 // private classes
67 // ----------------------------------------------------------------------------
68
69 // Define a new application type, each program should derive a class from wxApp
70 class MyApp : public wxApp
71 {
72 public:
73 // override base class virtuals
74 // ----------------------------
75
76 // this one is called on application startup and is a good place for the app
77 // initialization (doing it here and not in the ctor allows to have an error
78 // return: if OnInit() returns false, the application terminates)
79 virtual bool OnInit();
80
81 virtual int OnExit() { DeleteBitmaps(); return 0; }
82
83 protected:
84 void DeleteBitmaps();
85
86 bool LoadImages();
87 };
88
89 class MyCanvas;
90
91 // Define a new frame type: this is going to be our main frame
92 class MyFrame : public wxFrame
93 {
94 public:
95 // ctor(s)
96 MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
97
98 // event handlers (these functions should _not_ be virtual)
99 void OnQuit(wxCommandEvent& event);
100 void OnAbout(wxCommandEvent& event);
101 void OnClip(wxCommandEvent& event);
102 #if wxUSE_GRAPHICS_CONTEXT
103 void OnGraphicContext(wxCommandEvent& event);
104 #endif
105 void OnCopy(wxCommandEvent& event);
106 void OnSave(wxCommandEvent& event);
107 void OnShow(wxCommandEvent &event);
108 void OnOption(wxCommandEvent &event);
109
110 #if wxUSE_COLOURDLG
111 wxColour SelectColour();
112 #endif // wxUSE_COLOURDLG
113 void PrepareDC(wxDC& dc);
114
115 int m_backgroundMode;
116 int m_textureBackground;
117 wxMappingMode m_mapMode;
118 double m_xUserScale;
119 double m_yUserScale;
120 int m_xLogicalOrigin;
121 int m_yLogicalOrigin;
122 bool m_xAxisReversed,
123 m_yAxisReversed;
124 wxColour m_colourForeground, // these are _text_ colours
125 m_colourBackground;
126 wxBrush m_backgroundBrush;
127 MyCanvas *m_canvas;
128
129 private:
130 // any class wishing to process wxWidgets events must use this macro
131 DECLARE_EVENT_TABLE()
132 };
133
134 // define a scrollable canvas for drawing onto
135 class MyCanvas: public wxScrolledWindow
136 {
137 public:
138 MyCanvas( MyFrame *parent );
139
140 void OnPaint(wxPaintEvent &event);
141 void OnMouseMove(wxMouseEvent &event);
142 void OnMouseDown(wxMouseEvent &event);
143 void OnMouseUp(wxMouseEvent &event);
144
145 void ToShow(int show) { m_show = show; Refresh(); }
146
147 // set or remove the clipping region
148 void Clip(bool clip) { m_clip = clip; Refresh(); }
149 #if wxUSE_GRAPHICS_CONTEXT
150 void UseGraphicContext(bool use) { m_useContext = use; Refresh(); }
151 #endif
152 template <typename T> void Draw(T& dc);
153
154 protected:
155 enum DrawMode
156 {
157 Draw_Normal,
158 Draw_Stretch
159 };
160
161 void DrawTestLines( int x, int y, int width, wxDC &dc );
162 void DrawTestPoly(wxDC& dc);
163 void DrawTestBrushes(wxDC& dc);
164 void DrawText(wxDC& dc);
165 void DrawImages(wxDC& dc, DrawMode mode);
166 void DrawWithLogicalOps(wxDC& dc);
167 #if wxUSE_GRAPHICS_CONTEXT
168 void DrawAlpha(wxDC& dc);
169 void DrawGraphics(wxGraphicsContext* gc);
170 #endif
171 void DrawRegions(wxDC& dc);
172 void DrawCircles(wxDC& dc);
173 void DrawSplines(wxDC& dc);
174 void DrawDefault(wxDC& dc);
175 void DrawGradients(wxDC& dc);
176
177 void DrawRegionsHelper(wxDC& dc, wxCoord x, bool firstTime);
178
179 private:
180 MyFrame *m_owner;
181
182 int m_show;
183 wxBitmap m_smile_bmp;
184 wxIcon m_std_icon;
185 bool m_clip;
186 wxOverlay m_overlay;
187 bool m_rubberBand;
188 wxPoint m_anchorpoint;
189 wxPoint m_currentpoint;
190 #if wxUSE_GRAPHICS_CONTEXT
191 bool m_useContext ;
192 #endif
193
194 DECLARE_EVENT_TABLE()
195 };
196
197 // ----------------------------------------------------------------------------
198 // constants
199 // ----------------------------------------------------------------------------
200
201 // IDs for the controls and the menu commands
202 enum
203 {
204 // menu items
205 File_Quit = wxID_EXIT,
206 File_About = wxID_ABOUT,
207
208 MenuShow_First = wxID_HIGHEST,
209 File_ShowDefault = MenuShow_First,
210 File_ShowText,
211 File_ShowLines,
212 File_ShowBrushes,
213 File_ShowPolygons,
214 File_ShowMask,
215 File_ShowMaskStretch,
216 File_ShowOps,
217 File_ShowRegions,
218 File_ShowCircles,
219 File_ShowSplines,
220 #if wxUSE_GRAPHICS_CONTEXT
221 File_ShowAlpha,
222 File_ShowGraphics,
223 #endif
224 File_ShowGradients,
225 MenuShow_Last = File_ShowGradients,
226
227 File_Clip,
228 #if wxUSE_GRAPHICS_CONTEXT
229 File_GraphicContext,
230 #endif
231 File_Copy,
232 File_Save,
233
234 MenuOption_First,
235
236 MapMode_Text = MenuOption_First,
237 MapMode_Lometric,
238 MapMode_Twips,
239 MapMode_Points,
240 MapMode_Metric,
241
242 UserScale_StretchHoriz,
243 UserScale_ShrinkHoriz,
244 UserScale_StretchVertic,
245 UserScale_ShrinkVertic,
246 UserScale_Restore,
247
248 AxisMirror_Horiz,
249 AxisMirror_Vertic,
250
251 LogicalOrigin_MoveDown,
252 LogicalOrigin_MoveUp,
253 LogicalOrigin_MoveLeft,
254 LogicalOrigin_MoveRight,
255 LogicalOrigin_Set,
256 LogicalOrigin_Restore,
257
258 #if wxUSE_COLOURDLG
259 Colour_TextForeground,
260 Colour_TextBackground,
261 Colour_Background,
262 #endif // wxUSE_COLOURDLG
263 Colour_BackgroundMode,
264 Colour_TextureBackgound,
265
266 MenuOption_Last = Colour_TextureBackgound
267 };
268
269 // ----------------------------------------------------------------------------
270 // event tables and other macros for wxWidgets
271 // ----------------------------------------------------------------------------
272
273
274 // Create a new application object: this macro will allow wxWidgets to create
275 // the application object during program execution (it's better than using a
276 // static object for many reasons) and also declares the accessor function
277 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
278 // not wxApp)
279 IMPLEMENT_APP(MyApp)
280
281 // ============================================================================
282 // implementation
283 // ============================================================================
284
285 // ----------------------------------------------------------------------------
286 // the application class
287 // ----------------------------------------------------------------------------
288
289 bool MyApp::LoadImages()
290 {
291 gs_bmpNoMask = new wxBitmap;
292 gs_bmpWithColMask = new wxBitmap;
293 gs_bmpMask = new wxBitmap;
294 gs_bmpWithMask = new wxBitmap;
295 gs_bmp4 = new wxBitmap;
296 gs_bmp4_mono = new wxBitmap;
297 gs_bmp36 = new wxBitmap;
298
299 wxPathList pathList;
300 // special hack for Unix in-tree sample build, don't do this in real
301 // programs, use wxStandardPaths instead
302 pathList.Add(wxFileName(argv[0]).GetPath());
303 pathList.Add(wxT("."));
304 pathList.Add(wxT(".."));
305 pathList.Add(wxT("../.."));
306
307 wxString path = pathList.FindValidPath(wxT("pat4.bmp"));
308 if ( !path )
309 return false;
310
311 /* 4 colour bitmap */
312 gs_bmp4->LoadFile(path, wxBITMAP_TYPE_BMP);
313 /* turn into mono-bitmap */
314 gs_bmp4_mono->LoadFile(path, wxBITMAP_TYPE_BMP);
315 wxMask* mask4 = new wxMask(*gs_bmp4_mono, *wxBLACK);
316 gs_bmp4_mono->SetMask(mask4);
317
318 path = pathList.FindValidPath(wxT("pat36.bmp"));
319 if ( !path )
320 return false;
321 gs_bmp36->LoadFile(path, wxBITMAP_TYPE_BMP);
322 wxMask* mask36 = new wxMask(*gs_bmp36, *wxBLACK);
323 gs_bmp36->SetMask(mask36);
324
325 path = pathList.FindValidPath(wxT("image.bmp"));
326 if ( !path )
327 return false;
328 gs_bmpNoMask->LoadFile(path, wxBITMAP_TYPE_BMP);
329 gs_bmpWithMask->LoadFile(path, wxBITMAP_TYPE_BMP);
330 gs_bmpWithColMask->LoadFile(path, wxBITMAP_TYPE_BMP);
331
332 path = pathList.FindValidPath(wxT("mask.bmp"));
333 if ( !path )
334 return false;
335 gs_bmpMask->LoadFile(path, wxBITMAP_TYPE_BMP);
336
337 wxMask *mask = new wxMask(*gs_bmpMask, *wxBLACK);
338 gs_bmpWithMask->SetMask(mask);
339
340 mask = new wxMask(*gs_bmpWithColMask, *wxWHITE);
341 gs_bmpWithColMask->SetMask(mask);
342
343 return true;
344 }
345
346 // `Main program' equivalent: the program execution "starts" here
347 bool MyApp::OnInit()
348 {
349 if ( !wxApp::OnInit() )
350 return false;
351
352 // Create the main application window
353 MyFrame *frame = new MyFrame(wxT("Drawing sample"),
354 wxDefaultPosition, wxSize(550, 840));
355
356 // Show it
357 frame->Show(true);
358
359 if ( !LoadImages() )
360 {
361 wxLogError(wxT("Can't load one of the bitmap files needed ")
362 wxT("for this sample from the current or parent ")
363 wxT("directory, please copy them there."));
364
365 // still continue, the sample can be used without images too if they're
366 // missing for whatever reason
367 }
368 #if wxUSE_LIBPNG
369 wxImage::AddHandler( new wxPNGHandler );
370 #endif
371
372 return true;
373 }
374
375 void MyApp::DeleteBitmaps()
376 {
377 wxDELETE(gs_bmpNoMask);
378 wxDELETE(gs_bmpWithColMask);
379 wxDELETE(gs_bmpMask);
380 wxDELETE(gs_bmpWithMask);
381 wxDELETE(gs_bmp4);
382 wxDELETE(gs_bmp4_mono);
383 wxDELETE(gs_bmp36);
384 }
385
386 // ----------------------------------------------------------------------------
387 // MyCanvas
388 // ----------------------------------------------------------------------------
389
390 // the event tables connect the wxWidgets events with the functions (event
391 // handlers) which process them.
392 BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
393 EVT_PAINT (MyCanvas::OnPaint)
394 EVT_MOTION (MyCanvas::OnMouseMove)
395 EVT_LEFT_DOWN (MyCanvas::OnMouseDown)
396 EVT_LEFT_UP (MyCanvas::OnMouseUp)
397 END_EVENT_TABLE()
398
399 #include "smile.xpm"
400
401 MyCanvas::MyCanvas(MyFrame *parent)
402 : wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
403 wxHSCROLL | wxVSCROLL | wxNO_FULL_REPAINT_ON_RESIZE)
404 {
405 m_owner = parent;
406 m_show = File_ShowDefault;
407 m_smile_bmp = wxBitmap(smile_xpm);
408 m_std_icon = wxArtProvider::GetIcon(wxART_INFORMATION);
409 m_clip = false;
410 m_rubberBand = false;
411 #if wxUSE_GRAPHICS_CONTEXT
412 m_useContext = false;
413 #endif
414 }
415
416 void MyCanvas::DrawTestBrushes(wxDC& dc)
417 {
418 static const wxCoord WIDTH = 200;
419 static const wxCoord HEIGHT = 80;
420
421 wxCoord x = 10,
422 y = 10;
423
424 dc.SetBrush(wxBrush(*wxGREEN, wxSOLID));
425 dc.DrawRectangle(x, y, WIDTH, HEIGHT);
426 dc.DrawText(wxT("Solid green"), x + 10, y + 10);
427
428 y += HEIGHT;
429 dc.SetBrush(wxBrush(*wxRED, wxCROSSDIAG_HATCH));
430 dc.DrawRectangle(x, y, WIDTH, HEIGHT);
431 dc.DrawText(wxT("Diagonally hatched red"), x + 10, y + 10);
432
433 y += HEIGHT;
434 dc.SetBrush(wxBrush(*wxBLUE, wxCROSS_HATCH));
435 dc.DrawRectangle(x, y, WIDTH, HEIGHT);
436 dc.DrawText(wxT("Cross hatched blue"), x + 10, y + 10);
437
438 y += HEIGHT;
439 dc.SetBrush(wxBrush(*wxCYAN, wxVERTICAL_HATCH));
440 dc.DrawRectangle(x, y, WIDTH, HEIGHT);
441 dc.DrawText(wxT("Vertically hatched cyan"), x + 10, y + 10);
442
443 y += HEIGHT;
444 dc.SetBrush(wxBrush(*wxBLACK, wxHORIZONTAL_HATCH));
445 dc.DrawRectangle(x, y, WIDTH, HEIGHT);
446 dc.DrawText(wxT("Horizontally hatched black"), x + 10, y + 10);
447
448 y += HEIGHT;
449 dc.SetBrush(wxBrush(*gs_bmpMask));
450 dc.DrawRectangle(x, y, WIDTH, HEIGHT);
451 dc.DrawText(wxT("Stipple mono"), x + 10, y + 10);
452
453 y += HEIGHT;
454 dc.SetBrush(wxBrush(*gs_bmpNoMask));
455 dc.DrawRectangle(x, y, WIDTH, HEIGHT);
456 dc.DrawText(wxT("Stipple colour"), x + 10, y + 10);
457 }
458
459 void MyCanvas::DrawTestPoly(wxDC& dc)
460 {
461 wxBrush brushHatch(*wxRED, wxFDIAGONAL_HATCH);
462 dc.SetBrush(brushHatch);
463
464 wxPoint star[5];
465 star[0] = wxPoint(100, 60);
466 star[1] = wxPoint(60, 150);
467 star[2] = wxPoint(160, 100);
468 star[3] = wxPoint(40, 100);
469 star[4] = wxPoint(140, 150);
470
471 dc.DrawText(wxT("You should see two (irregular) stars below, the left one ")
472 wxT("hatched"), 10, 10);
473 dc.DrawText(wxT("except for the central region and the right ")
474 wxT("one entirely hatched"), 10, 30);
475 dc.DrawText(wxT("The third star only has a hatched outline"), 10, 50);
476
477 dc.DrawPolygon(WXSIZEOF(star), star, 0, 30);
478 dc.DrawPolygon(WXSIZEOF(star), star, 160, 30, wxWINDING_RULE);
479
480 wxPoint star2[10];
481 star2[0] = wxPoint(0, 100);
482 star2[1] = wxPoint(-59, -81);
483 star2[2] = wxPoint(95, 31);
484 star2[3] = wxPoint(-95, 31);
485 star2[4] = wxPoint(59, -81);
486 star2[5] = wxPoint(0, 80);
487 star2[6] = wxPoint(-47, -64);
488 star2[7] = wxPoint(76, 24);
489 star2[8] = wxPoint(-76, 24);
490 star2[9] = wxPoint(47, -64);
491 int count[2] = {5, 5};
492
493 dc.DrawPolyPolygon(WXSIZEOF(count), count, star2, 450, 150);
494 }
495
496 void MyCanvas::DrawTestLines( int x, int y, int width, wxDC &dc )
497 {
498 dc.SetPen( wxPen( wxT("black"), width, wxSOLID) );
499 dc.SetBrush( *wxRED_BRUSH );
500 dc.DrawText(wxString::Format(wxT("Testing lines of width %d"), width), x + 10, y - 10);
501 dc.DrawRectangle( x+10, y+10, 100, 190 );
502
503 dc.DrawText(wxT("Solid/dot/short dash/long dash/dot dash"), x + 150, y + 10);
504 dc.SetPen( wxPen( wxT("black"), width, wxSOLID) );
505 dc.DrawLine( x+20, y+20, 100, y+20 );
506 dc.SetPen( wxPen( wxT("black"), width, wxDOT) );
507 dc.DrawLine( x+20, y+30, 100, y+30 );
508 dc.SetPen( wxPen( wxT("black"), width, wxSHORT_DASH) );
509 dc.DrawLine( x+20, y+40, 100, y+40 );
510 dc.SetPen( wxPen( wxT("black"), width, wxLONG_DASH) );
511 dc.DrawLine( x+20, y+50, 100, y+50 );
512 dc.SetPen( wxPen( wxT("black"), width, wxDOT_DASH) );
513 dc.DrawLine( x+20, y+60, 100, y+60 );
514
515 dc.DrawText(wxT("Misc hatches"), x + 150, y + 70);
516 dc.SetPen( wxPen( wxT("black"), width, wxBDIAGONAL_HATCH) );
517 dc.DrawLine( x+20, y+70, 100, y+70 );
518 dc.SetPen( wxPen( wxT("black"), width, wxCROSSDIAG_HATCH) );
519 dc.DrawLine( x+20, y+80, 100, y+80 );
520 dc.SetPen( wxPen( wxT("black"), width, wxFDIAGONAL_HATCH) );
521 dc.DrawLine( x+20, y+90, 100, y+90 );
522 dc.SetPen( wxPen( wxT("black"), width, wxCROSS_HATCH) );
523 dc.DrawLine( x+20, y+100, 100, y+100 );
524 dc.SetPen( wxPen( wxT("black"), width, wxHORIZONTAL_HATCH) );
525 dc.DrawLine( x+20, y+110, 100, y+110 );
526 dc.SetPen( wxPen( wxT("black"), width, wxVERTICAL_HATCH) );
527 dc.DrawLine( x+20, y+120, 100, y+120 );
528
529 dc.DrawText(wxT("User dash"), x + 150, y + 140);
530 wxPen ud( wxT("black"), width, wxUSER_DASH );
531 wxDash dash1[6];
532 dash1[0] = 8; // Long dash <---------+
533 dash1[1] = 2; // Short gap |
534 dash1[2] = 3; // Short dash |
535 dash1[3] = 2; // Short gap |
536 dash1[4] = 3; // Short dash |
537 dash1[5] = 2; // Short gap and repeat +
538 ud.SetDashes( 6, dash1 );
539 dc.SetPen( ud );
540 dc.DrawLine( x+20, y+140, 100, y+140 );
541 dash1[0] = 5; // Make first dash shorter
542 ud.SetDashes( 6, dash1 );
543 dc.SetPen( ud );
544 dc.DrawLine( x+20, y+150, 100, y+150 );
545 dash1[2] = 5; // Make second dash longer
546 ud.SetDashes( 6, dash1 );
547 dc.SetPen( ud );
548 dc.DrawLine( x+20, y+160, 100, y+160 );
549 dash1[4] = 5; // Make third dash longer
550 ud.SetDashes( 6, dash1 );
551 dc.SetPen( ud );
552 dc.DrawLine( x+20, y+170, 100, y+170 );
553 }
554
555 void MyCanvas::DrawDefault(wxDC& dc)
556 {
557 // mark the origin
558 dc.DrawCircle(0, 0, 10);
559
560 #if !defined(wxMAC_USE_CORE_GRAPHICS) || !wxMAC_USE_CORE_GRAPHICS
561 // GetPixel and FloodFill not supported by Mac OS X CoreGraphics
562 // (FloodFill uses Blit from a non-wxMemoryDC)
563 //flood fill using brush, starting at 1,1 and replacing whatever colour we find there
564 dc.SetBrush(wxBrush(wxColour(128,128,0), wxSOLID));
565
566 wxColour tmpColour ;
567 dc.GetPixel(1,1, &tmpColour);
568 dc.FloodFill(1,1, tmpColour, wxFLOOD_SURFACE);
569 #endif
570
571 dc.DrawCheckMark(5, 80, 15, 15);
572 dc.DrawCheckMark(25, 80, 30, 30);
573 dc.DrawCheckMark(60, 80, 60, 60);
574
575 // this is the test for "blitting bitmap into DC damages selected brush" bug
576 wxCoord rectSize = m_std_icon.GetWidth() + 10;
577 wxCoord x = 100;
578 dc.SetPen(*wxTRANSPARENT_PEN);
579 dc.SetBrush( *wxGREEN_BRUSH );
580 dc.DrawRectangle(x, 10, rectSize, rectSize);
581 dc.DrawBitmap(m_std_icon, x + 5, 15, true);
582 x += rectSize + 10;
583 dc.DrawRectangle(x, 10, rectSize, rectSize);
584 dc.DrawIcon(m_std_icon, x + 5, 15);
585 x += rectSize + 10;
586 dc.DrawRectangle(x, 10, rectSize, rectSize);
587
588 // test for "transparent" bitmap drawing (it intersects with the last
589 // rectangle above)
590 //dc.SetBrush( *wxTRANSPARENT_BRUSH );
591
592 if (m_smile_bmp.IsOk())
593 dc.DrawBitmap(m_smile_bmp, x + rectSize - 20, rectSize - 10, true);
594
595 dc.SetBrush( *wxBLACK_BRUSH );
596 dc.DrawRectangle( 0, 160, 1000, 300 );
597
598 // draw lines
599 wxBitmap bitmap(20,70);
600 wxMemoryDC memdc;
601 memdc.SelectObject( bitmap );
602 memdc.SetBrush( *wxBLACK_BRUSH );
603 memdc.SetPen( *wxWHITE_PEN );
604 memdc.DrawRectangle(0,0,20,70);
605 memdc.DrawLine( 10,0,10,70 );
606
607 // to the right
608 wxPen pen = *wxRED_PEN;
609 memdc.SetPen(pen);
610 memdc.DrawLine( 10, 5,10, 5 );
611 memdc.DrawLine( 10,10,11,10 );
612 memdc.DrawLine( 10,15,12,15 );
613 memdc.DrawLine( 10,20,13,20 );
614
615 /*
616 memdc.SetPen(*wxRED_PEN);
617 memdc.DrawLine( 12, 5,12, 5 );
618 memdc.DrawLine( 12,10,13,10 );
619 memdc.DrawLine( 12,15,14,15 );
620 memdc.DrawLine( 12,20,15,20 );
621 */
622
623 // same to the left
624 memdc.DrawLine( 10,25,10,25 );
625 memdc.DrawLine( 10,30, 9,30 );
626 memdc.DrawLine( 10,35, 8,35 );
627 memdc.DrawLine( 10,40, 7,40 );
628
629 // XOR draw lines
630 dc.SetPen(*wxWHITE_PEN);
631 memdc.SetLogicalFunction( wxINVERT );
632 memdc.SetPen( *wxWHITE_PEN );
633 memdc.DrawLine( 10,50,10,50 );
634 memdc.DrawLine( 10,55,11,55 );
635 memdc.DrawLine( 10,60,12,60 );
636 memdc.DrawLine( 10,65,13,65 );
637
638 memdc.DrawLine( 12,50,12,50 );
639 memdc.DrawLine( 12,55,13,55 );
640 memdc.DrawLine( 12,60,14,60 );
641 memdc.DrawLine( 12,65,15,65 );
642
643 memdc.SelectObject( wxNullBitmap );
644 dc.DrawBitmap( bitmap, 10, 170 );
645 wxImage image = bitmap.ConvertToImage();
646 image.Rescale( 60,210 );
647 bitmap = wxBitmap(image);
648 dc.DrawBitmap( bitmap, 50, 170 );
649
650 // test the rectangle outline drawing - there should be one pixel between
651 // the rect and the lines
652 dc.SetPen(*wxWHITE_PEN);
653 dc.SetBrush( *wxTRANSPARENT_BRUSH );
654 dc.DrawRectangle(150, 170, 49, 29);
655 dc.DrawRectangle(200, 170, 49, 29);
656 dc.SetPen(*wxWHITE_PEN);
657 dc.DrawLine(250, 210, 250, 170);
658 dc.DrawLine(260, 200, 150, 200);
659
660 // test the rectangle filled drawing - there should be one pixel between
661 // the rect and the lines
662 dc.SetPen(*wxTRANSPARENT_PEN);
663 dc.SetBrush( *wxWHITE_BRUSH );
664 dc.DrawRectangle(300, 170, 49, 29);
665 dc.DrawRectangle(350, 170, 49, 29);
666 dc.SetPen(*wxWHITE_PEN);
667 dc.DrawLine(400, 170, 400, 210);
668 dc.DrawLine(300, 200, 410, 200);
669
670 // a few more tests of this kind
671 dc.SetPen(*wxRED_PEN);
672 dc.SetBrush( *wxWHITE_BRUSH );
673 dc.DrawRectangle(300, 220, 1, 1);
674 dc.DrawRectangle(310, 220, 2, 2);
675 dc.DrawRectangle(320, 220, 3, 3);
676 dc.DrawRectangle(330, 220, 4, 4);
677
678 dc.SetPen(*wxTRANSPARENT_PEN);
679 dc.SetBrush( *wxWHITE_BRUSH );
680 dc.DrawRectangle(300, 230, 1, 1);
681 dc.DrawRectangle(310, 230, 2, 2);
682 dc.DrawRectangle(320, 230, 3, 3);
683 dc.DrawRectangle(330, 230, 4, 4);
684
685 // and now for filled rect with outline
686 dc.SetPen(*wxRED_PEN);
687 dc.SetBrush( *wxWHITE_BRUSH );
688 dc.DrawRectangle(500, 170, 49, 29);
689 dc.DrawRectangle(550, 170, 49, 29);
690 dc.SetPen(*wxWHITE_PEN);
691 dc.DrawLine(600, 170, 600, 210);
692 dc.DrawLine(500, 200, 610, 200);
693
694 // test the rectangle outline drawing - there should be one pixel between
695 // the rect and the lines
696 dc.SetPen(*wxWHITE_PEN);
697 dc.SetBrush( *wxTRANSPARENT_BRUSH );
698 dc.DrawRoundedRectangle(150, 270, 49, 29, 6);
699 dc.DrawRoundedRectangle(200, 270, 49, 29, 6);
700 dc.SetPen(*wxWHITE_PEN);
701 dc.DrawLine(250, 270, 250, 310);
702 dc.DrawLine(150, 300, 260, 300);
703
704 // test the rectangle filled drawing - there should be one pixel between
705 // the rect and the lines
706 dc.SetPen(*wxTRANSPARENT_PEN);
707 dc.SetBrush( *wxWHITE_BRUSH );
708 dc.DrawRoundedRectangle(300, 270, 49, 29, 6);
709 dc.DrawRoundedRectangle(350, 270, 49, 29, 6);
710 dc.SetPen(*wxWHITE_PEN);
711 dc.DrawLine(400, 270, 400, 310);
712 dc.DrawLine(300, 300, 410, 300);
713
714 // Added by JACS to demonstrate bizarre behaviour.
715 // With a size of 70, we get a missing red RHS,
716 // and the height is too small, so we get yellow
717 // showing. With a size of 40, it draws as expected:
718 // it just shows a white rectangle with red outline.
719 int totalWidth = 70;
720 int totalHeight = 70;
721 wxBitmap bitmap2(totalWidth, totalHeight);
722
723 wxMemoryDC memdc2;
724 memdc2.SelectObject(bitmap2);
725
726 wxColour clr(255, 255, 0);
727 wxBrush yellowBrush(clr, wxSOLID);
728 memdc2.SetBackground(yellowBrush);
729 memdc2.Clear();
730
731 wxPen yellowPen(clr, 1, wxSOLID);
732
733 // Now draw a white rectangle with red outline. It should
734 // entirely eclipse the yellow background.
735 memdc2.SetPen(*wxRED_PEN);
736 memdc2.SetBrush(*wxWHITE_BRUSH);
737
738 memdc2.DrawRectangle(0, 0, totalWidth, totalHeight);
739
740 memdc2.SetPen(wxNullPen);
741 memdc2.SetBrush(wxNullBrush);
742 memdc2.SelectObject(wxNullBitmap);
743
744 dc.DrawBitmap(bitmap2, 500, 270);
745
746 // Repeat, but draw directly on dc
747 // Draw a yellow rectangle filling the bitmap
748
749 x = 600; int y = 270;
750 dc.SetPen(yellowPen);
751 dc.SetBrush(yellowBrush);
752 dc.DrawRectangle(x, y, totalWidth, totalHeight);
753
754 // Now draw a white rectangle with red outline. It should
755 // entirely eclipse the yellow background.
756 dc.SetPen(*wxRED_PEN);
757 dc.SetBrush(*wxWHITE_BRUSH);
758
759 dc.DrawRectangle(x, y, totalWidth, totalHeight);
760 }
761
762 void MyCanvas::DrawText(wxDC& dc)
763 {
764 // set underlined font for testing
765 dc.SetFont( wxFont(12, wxMODERN, wxNORMAL, wxNORMAL, true) );
766 dc.DrawText( wxT("This is text"), 110, 10 );
767 dc.DrawRotatedText( wxT("That is text"), 20, 10, -45 );
768
769 // use wxSWISS_FONT and not wxNORMAL_FONT as the latter can't be rotated
770 // under Win9x (it is not TrueType)
771 dc.SetFont( *wxSWISS_FONT );
772
773 wxString text;
774 dc.SetBackgroundMode(wxTRANSPARENT);
775
776 for ( int n = -180; n < 180; n += 30 )
777 {
778 text.Printf(wxT(" %d rotated text"), n);
779 dc.DrawRotatedText(text , 400, 400, n);
780 }
781
782 dc.SetFont( wxFont( 18, wxSWISS, wxNORMAL, wxNORMAL ) );
783
784 dc.DrawText( wxT("This is Swiss 18pt text."), 110, 40 );
785
786 wxCoord length;
787 wxCoord height;
788 wxCoord descent;
789 dc.GetTextExtent( wxT("This is Swiss 18pt text."), &length, &height, &descent );
790 text.Printf( wxT("Dimensions are length %d, height %d, descent %d"), length, height, descent );
791 dc.DrawText( text, 110, 80 );
792
793 text.Printf( wxT("CharHeight() returns: %d"), dc.GetCharHeight() );
794 dc.DrawText( text, 110, 120 );
795
796 dc.DrawRectangle( 100, 40, 4, height );
797
798 // test the logical function effect
799 wxCoord y = 150;
800 dc.SetLogicalFunction(wxINVERT);
801 // text drawing should ignore logical function
802 dc.DrawText( wxT("There should be a text below"), 110, 150 );
803 dc.DrawRectangle( 110, y, 100, height );
804
805 y += height;
806 dc.DrawText( wxT("Visible text"), 110, y );
807 dc.DrawRectangle( 110, y, 100, height );
808 dc.DrawText( wxT("Visible text"), 110, y );
809 dc.DrawRectangle( 110, y, 100, height );
810 dc.SetLogicalFunction(wxCOPY);
811
812 y += height;
813 dc.DrawRectangle( 110, y, 100, height );
814 dc.DrawText( wxT("Another visible text"), 110, y );
815
816 y += height;
817 dc.DrawText("And\nmore\ntext on\nmultiple\nlines", 110, y);
818 }
819
820 static const struct
821 {
822 const wxChar *name;
823 wxRasterOperationMode rop;
824 } rasterOperations[] =
825 {
826 { wxT("wxAND"), wxAND },
827 { wxT("wxAND_INVERT"), wxAND_INVERT },
828 { wxT("wxAND_REVERSE"), wxAND_REVERSE },
829 { wxT("wxCLEAR"), wxCLEAR },
830 { wxT("wxCOPY"), wxCOPY },
831 { wxT("wxEQUIV"), wxEQUIV },
832 { wxT("wxINVERT"), wxINVERT },
833 { wxT("wxNAND"), wxNAND },
834 { wxT("wxNO_OP"), wxNO_OP },
835 { wxT("wxOR"), wxOR },
836 { wxT("wxOR_INVERT"), wxOR_INVERT },
837 { wxT("wxOR_REVERSE"), wxOR_REVERSE },
838 { wxT("wxSET"), wxSET },
839 { wxT("wxSRC_INVERT"), wxSRC_INVERT },
840 { wxT("wxXOR"), wxXOR },
841 };
842
843 void MyCanvas::DrawImages(wxDC& dc, DrawMode mode)
844 {
845 dc.DrawText(wxT("original image"), 0, 0);
846 dc.DrawBitmap(*gs_bmpNoMask, 0, 20, 0);
847 dc.DrawText(wxT("with colour mask"), 0, 100);
848 dc.DrawBitmap(*gs_bmpWithColMask, 0, 120, true);
849 dc.DrawText(wxT("the mask image"), 0, 200);
850 dc.DrawBitmap(*gs_bmpMask, 0, 220, 0);
851 dc.DrawText(wxT("masked image"), 0, 300);
852 dc.DrawBitmap(*gs_bmpWithMask, 0, 320, true);
853
854 int cx = gs_bmpWithColMask->GetWidth(),
855 cy = gs_bmpWithColMask->GetHeight();
856
857 wxMemoryDC memDC;
858 for ( size_t n = 0; n < WXSIZEOF(rasterOperations); n++ )
859 {
860 wxCoord x = 120 + 150*(n%4),
861 y = 20 + 100*(n/4);
862
863 dc.DrawText(rasterOperations[n].name, x, y - 20);
864 memDC.SelectObject(*gs_bmpWithColMask);
865 if ( mode == Draw_Stretch )
866 {
867 dc.StretchBlit(x, y, cx, cy, &memDC, 0, 0, cx/2, cy/2,
868 rasterOperations[n].rop, true);
869 }
870 else
871 {
872 dc.Blit(x, y, cx, cy, &memDC, 0, 0, rasterOperations[n].rop, true);
873 }
874 }
875 }
876
877 void MyCanvas::DrawWithLogicalOps(wxDC& dc)
878 {
879 static const wxCoord w = 60;
880 static const wxCoord h = 60;
881
882 // reuse the text colour here
883 dc.SetPen(wxPen(m_owner->m_colourForeground, 1, wxSOLID));
884 dc.SetBrush(*wxTRANSPARENT_BRUSH);
885
886 size_t n;
887 for ( n = 0; n < WXSIZEOF(rasterOperations); n++ )
888 {
889 wxCoord x = 20 + 150*(n%4),
890 y = 20 + 100*(n/4);
891
892 dc.DrawText(rasterOperations[n].name, x, y - 20);
893 dc.SetLogicalFunction(rasterOperations[n].rop);
894 dc.DrawRectangle(x, y, w, h);
895 dc.DrawLine(x, y, x + w, y + h);
896 dc.DrawLine(x + w, y, x, y + h);
897 }
898
899 // now some filled rectangles
900 dc.SetBrush(wxBrush(m_owner->m_colourForeground, wxSOLID));
901
902 for ( n = 0; n < WXSIZEOF(rasterOperations); n++ )
903 {
904 wxCoord x = 20 + 150*(n%4),
905 y = 500 + 100*(n/4);
906
907 dc.DrawText(rasterOperations[n].name, x, y - 20);
908 dc.SetLogicalFunction(rasterOperations[n].rop);
909 dc.DrawRectangle(x, y, w, h);
910 }
911 }
912
913 #if wxUSE_GRAPHICS_CONTEXT
914 #ifdef __WXGTK20__
915 void MyCanvas::DrawAlpha(wxDC& WXUNUSED(dummyDC))
916 #else
917 void MyCanvas::DrawAlpha(wxDC& dc)
918 #endif
919 {
920 #ifdef __WXGTK__
921 wxGCDC dc( this );
922 PrepareDC( dc );
923 #endif
924
925 wxDouble margin = 20 ;
926 wxDouble width = 180 ;
927 wxDouble radius = 30 ;
928
929 dc.SetPen( wxPen( wxColour( 128, 0, 0, 255 ),12, wxSOLID));
930 dc.SetBrush( wxBrush( wxColour( 255, 0, 0, 255),wxSOLID));
931
932 wxRect r(margin,margin+width*0.66,width,width) ;
933
934 dc.DrawRoundedRectangle( r.x, r.y, r.width, r.width, radius ) ;
935
936 dc.SetPen( wxPen( wxColour( 0, 0, 128, 255 ),12, wxSOLID));
937 dc.SetBrush( wxBrush( wxColour( 0, 0, 255, 255),wxSOLID));
938
939 r.Offset( width * 0.8 , - width * 0.66 ) ;
940
941 dc.DrawRoundedRectangle( r.x, r.y, r.width, r.width, radius ) ;
942
943 dc.SetPen( wxPen( wxColour( 128, 128, 0, 255 ),12, wxSOLID));
944 dc.SetBrush( wxBrush( wxColour( 192, 192, 0, 255),wxSOLID));
945
946 r.Offset( width * 0.8 , width *0.5 ) ;
947
948 dc.DrawRoundedRectangle( r.x, r.y, r.width, r.width, radius ) ;
949
950 dc.SetPen( *wxTRANSPARENT_PEN ) ;
951 dc.SetBrush( wxBrush( wxColour(255,255,128,128) ) );
952 dc.DrawRoundedRectangle( 0 , margin + width / 2 , width * 3 , 100 , radius) ;
953
954 dc.SetTextForeground( wxColour(255,255,0,128) );
955 dc.SetFont( wxFont( 40, wxFONTFAMILY_SWISS, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_NORMAL ) );
956 dc.DrawText( wxT("Hello!"), 120, 80 );
957 }
958
959 #endif
960
961 #if wxUSE_GRAPHICS_CONTEXT
962
963 const int BASE = 80.0;
964 const int BASE2 = BASE/2;
965 const int BASE4 = BASE/4;
966
967 static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
968
969
970 // modeled along Robin Dunn's GraphicsContext.py sample
971
972 void MyCanvas::DrawGraphics(wxGraphicsContext* gc)
973 {
974 wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
975 gc->SetFont(font,*wxBLACK);
976
977 // make a path that contains a circle and some lines, centered at 0,0
978 wxGraphicsPath path = gc->CreatePath() ;
979 path.AddCircle( 0, 0, BASE2 );
980 path.MoveToPoint(0, -BASE2);
981 path.AddLineToPoint(0, BASE2);
982 path.MoveToPoint(-BASE2, 0);
983 path.AddLineToPoint(BASE2, 0);
984 path.CloseSubpath();
985 path.AddRectangle(-BASE4, -BASE4/2, BASE2, BASE4);
986
987 // Now use that path to demonstrate various capbilites of the grpahics context
988 gc->PushState(); // save current translation/scale/other state
989 gc->Translate(60, 75); // reposition the context origin
990
991 gc->SetPen(wxPen("navy", 1));
992 gc->SetBrush(wxBrush("pink"));
993
994 for( int i = 0 ; i < 3 ; ++i )
995 {
996 wxString label;
997 switch( i )
998 {
999 case 0 :
1000 label = "StrokePath";
1001 break;
1002 case 1 :
1003 label = "FillPath";
1004 break;
1005 case 2 :
1006 label = "DrawPath";
1007 break;
1008 }
1009 wxDouble w, h;
1010 gc->GetTextExtent(label, &w, &h, NULL, NULL);
1011 gc->DrawText(label, -w/2, -BASE2-h-4);
1012 switch( i )
1013 {
1014 case 0 :
1015 gc->StrokePath(path);
1016 break;
1017 case 1 :
1018 gc->FillPath(path);
1019 break;
1020 case 2 :
1021 gc->DrawPath(path);
1022 break;
1023 }
1024 gc->Translate(2*BASE, 0);
1025 }
1026
1027 gc->PopState(); // restore saved state
1028 gc->PushState(); // save it again
1029 gc->Translate(60, 200); // offset to the lower part of the window
1030
1031 gc->DrawText("Scale", 0, -BASE2);
1032 gc->Translate(0, 20);
1033
1034 gc->SetBrush(wxBrush(wxColour(178, 34, 34, 128)));// 128 == half transparent
1035 for( int i = 0 ; i < 8 ; ++i )
1036 {
1037 gc->Scale(1.08, 1.08); // increase scale by 8%
1038 gc->Translate(5,5);
1039 gc->DrawPath(path);
1040 }
1041
1042 gc->PopState(); // restore saved state
1043 gc->PushState(); // save it again
1044 gc->Translate(400, 200);
1045
1046 gc->DrawText("Rotate", 0, -BASE2);
1047
1048 // Move the origin over to the next location
1049 gc->Translate(0, 75);
1050
1051 // draw our path again, rotating it about the central point,
1052 // and changing colors as we go
1053 for ( int angle = 0 ; angle < 360 ; angle += 30 )
1054 {
1055 gc->PushState(); // save this new current state so we can
1056 // pop back to it at the end of the loop
1057 wxImage::RGBValue val = wxImage::HSVtoRGB(wxImage::HSVValue(float(angle)/360, 1, 1));
1058 gc->SetBrush(wxBrush(wxColour(val.red, val.green, val.blue, 64)));
1059 gc->SetPen(wxPen(wxColour(val.red, val.green, val.blue, 128)));
1060
1061 // use translate to artfully reposition each drawn path
1062 gc->Translate(1.5 * BASE2 * cos(DegToRad(angle)),
1063 1.5 * BASE2 * sin(DegToRad(angle)));
1064
1065 // use Rotate to rotate the path
1066 gc->Rotate(DegToRad(angle));
1067
1068 // now draw it
1069 gc->DrawPath(path);
1070 gc->PopState();
1071 }
1072 gc->PopState();
1073
1074 gc->PushState();
1075 gc->Translate(60, 400);
1076 gc->DrawText("Scaled smiley inside a square", 0, 0);
1077 gc->DrawRectangle(BASE2, BASE2, 100, 100);
1078 gc->DrawBitmap(m_smile_bmp, BASE2, BASE2, 100, 100);
1079 gc->PopState();
1080 }
1081 #endif // wxUSE_GRAPHICS_CONTEXT
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(wxT("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(wxT("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(wxT("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(wxT("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(wxT("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(wxT("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(wxT("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(wxT("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(wxT("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(wxT("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(wxT("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(wxT("wxUP"), r.x, r.y);
1256 r.Offset(0, TEXT_HEIGHT);
1257 dc.GradientFillLinear(r, *wxWHITE, *wxBLUE, wxUP);
1258
1259 wxRect gfr = wxRect(r);
1260
1261 // RHS: concentric
1262 r = wxRect(200, 10, 50, 50);
1263 dc.DrawText(wxT("Blue inside"), r.x, r.y);
1264 r.Offset(0, TEXT_HEIGHT);
1265 dc.GradientFillConcentric(r, *wxBLUE, *wxWHITE);
1266
1267 r.Offset(0, r.height + 10);
1268 dc.DrawText(wxT("White inside"), r.x, r.y);
1269 r.Offset(0, TEXT_HEIGHT);
1270 dc.GradientFillConcentric(r, *wxWHITE, *wxBLUE);
1271
1272 r.Offset(0, r.height + 10);
1273 dc.DrawText(wxT("Blue in top left corner"), r.x, r.y);
1274 r.Offset(0, TEXT_HEIGHT);
1275 dc.GradientFillConcentric(r, *wxBLUE, *wxWHITE, wxPoint(0, 0));
1276
1277 r.Offset(0, r.height + 10);
1278 dc.DrawText(wxT("Blue in bottom right corner"), r.x, r.y);
1279 r.Offset(0, TEXT_HEIGHT);
1280 dc.GradientFillConcentric(r, *wxBLUE, *wxWHITE, wxPoint(r.width, r.height));
1281
1282 // check that the area filled by the gradient is exactly the interior of
1283 // the rectangle
1284 r.x = 350;
1285 r.y = 30;
1286 dc.DrawText("The interior should be filled but", r.x, r.y);
1287 r.y += 15;
1288 dc.DrawText(" the red border should remain visible:", r.x, r.y);
1289 r.y += 15;
1290
1291 r.width =
1292 r.height = 50;
1293 wxRect r2 = r;
1294 r2.x += 60;
1295 wxRect r3 = r;
1296 r3.y += 60;
1297 wxRect r4 = r2;
1298 r4.y += 60;
1299 dc.SetPen(wxPen(wxColour(255, 0, 0)));
1300 dc.DrawRectangle(r);
1301 r.Deflate(1);
1302 dc.GradientFillLinear(r, wxColour(0,255,0), wxColour(0,0,0), wxNORTH);
1303 dc.DrawRectangle(r2);
1304 r2.Deflate(1);
1305 dc.GradientFillLinear(r2, wxColour(0,0,0), wxColour(0,255,0), wxSOUTH);
1306 dc.DrawRectangle(r3);
1307 r3.Deflate(1);
1308 dc.GradientFillLinear(r3, wxColour(0,255,0), wxColour(0,0,0), wxEAST);
1309 dc.DrawRectangle(r4);
1310 r4.Deflate(1);
1311 dc.GradientFillLinear(r4, wxColour(0,0,0), wxColour(0,255,0), wxWEST);
1312
1313 #if wxUSE_GRAPHICS_CONTEXT
1314 if (m_useContext)
1315 {
1316 wxGCDC &gdc = (wxGCDC&)dc;
1317 wxGraphicsContext *gc = gdc.GetGraphicsContext();
1318 wxGraphicsPath pth;
1319 wxGraphicsGradientStops stops;
1320
1321 gfr.Offset(0, gfr.height + 10);
1322 dc.DrawText(wxT("Linear Gradient with Stops"), gfr.x, gfr.y);
1323 gfr.Offset(0, TEXT_HEIGHT);
1324
1325 stops = wxGraphicsGradientStops(wxColour(255,0,0), wxColour(0,0,255));
1326 stops.Add(wxColour(255,255,0), 0.33f);
1327 stops.Add(wxColour(0,255,0), 0.67f);
1328
1329 gc->SetBrush(gc->CreateLinearGradientBrush(gfr.x, gfr.y,
1330 gfr.x + gfr.width, gfr.y + gfr.height,
1331 stops));
1332 pth = gc->CreatePath();
1333 pth.MoveToPoint(gfr.x,gfr.y);
1334 pth.AddLineToPoint(gfr.x + gfr.width,gfr.y);
1335 pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height);
1336 pth.AddLineToPoint(gfr.x,gfr.y+gfr.height);
1337 pth.CloseSubpath();
1338 gc->FillPath(pth);
1339
1340 gfr.Offset(0, gfr.height + 10);
1341 dc.DrawText(wxT("Radial Gradient with Stops"), gfr.x, gfr.y);
1342 gfr.Offset(0, TEXT_HEIGHT);
1343
1344 gc->SetBrush(gc->CreateRadialGradientBrush(gfr.x + gfr.width / 2,
1345 gfr.y + gfr.height / 2,
1346 gfr.x + gfr.width / 2,
1347 gfr.y + gfr.height / 2,
1348 gfr.width / 2,
1349 stops));
1350 pth = gc->CreatePath();
1351 pth.MoveToPoint(gfr.x,gfr.y);
1352 pth.AddLineToPoint(gfr.x + gfr.width,gfr.y);
1353 pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height);
1354 pth.AddLineToPoint(gfr.x,gfr.y+gfr.height);
1355 pth.CloseSubpath();
1356 gc->FillPath(pth);
1357
1358 gfr.Offset(0, gfr.height + 10);
1359 dc.DrawText(wxT("Linear Gradient with Stops and Gaps"), gfr.x, gfr.y);
1360 gfr.Offset(0, TEXT_HEIGHT);
1361
1362 stops = wxGraphicsGradientStops(wxColour(255,0,0), wxColour(0,0,255));
1363 stops.Add(wxColour(255,255,0), 0.33f);
1364 stops.Add(wxTransparentColour, 0.33f);
1365 stops.Add(wxTransparentColour, 0.67f);
1366 stops.Add(wxColour(0,255,0), 0.67f);
1367
1368 gc->SetBrush(gc->CreateLinearGradientBrush(gfr.x, gfr.y + gfr.height,
1369 gfr.x + gfr.width, gfr.y,
1370 stops));
1371 pth = gc->CreatePath();
1372 pth.MoveToPoint(gfr.x,gfr.y);
1373 pth.AddLineToPoint(gfr.x + gfr.width,gfr.y);
1374 pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height);
1375 pth.AddLineToPoint(gfr.x,gfr.y+gfr.height);
1376 pth.CloseSubpath();
1377 gc->FillPath(pth);
1378
1379 gfr.Offset(0, gfr.height + 10);
1380 dc.DrawText(wxT("Radial Gradient with Stops and Gaps"), gfr.x, gfr.y);
1381 gfr.Offset(0, TEXT_HEIGHT);
1382
1383 gc->SetBrush(gc->CreateRadialGradientBrush(gfr.x + gfr.width / 2,
1384 gfr.y + gfr.height / 2,
1385 gfr.x + gfr.width / 2,
1386 gfr.y + gfr.height / 2,
1387 gfr.width / 2,
1388 stops));
1389 pth = gc->CreatePath();
1390 pth.MoveToPoint(gfr.x,gfr.y);
1391 pth.AddLineToPoint(gfr.x + gfr.width,gfr.y);
1392 pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height);
1393 pth.AddLineToPoint(gfr.x,gfr.y+gfr.height);
1394 pth.CloseSubpath();
1395 gc->FillPath(pth);
1396
1397 gfr.Offset(0, gfr.height + 10);
1398 dc.DrawText(wxT("Gradients with Stops and Transparency"), gfr.x, gfr.y);
1399 gfr.Offset(0, TEXT_HEIGHT);
1400
1401 stops = wxGraphicsGradientStops(wxColour(255,0,0), wxTransparentColour);
1402 stops.Add(wxColour(255,0,0), 0.33f);
1403 stops.Add(wxTransparentColour, 0.33f);
1404 stops.Add(wxTransparentColour, 0.67f);
1405 stops.Add(wxColour(0,0,255), 0.67f);
1406 stops.Add(wxColour(0,0,255), 1.0f);
1407
1408 pth = gc->CreatePath();
1409 pth.MoveToPoint(gfr.x,gfr.y);
1410 pth.AddLineToPoint(gfr.x + gfr.width,gfr.y);
1411 pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height);
1412 pth.AddLineToPoint(gfr.x,gfr.y+gfr.height);
1413 pth.CloseSubpath();
1414
1415 gc->SetBrush(gc->CreateRadialGradientBrush(gfr.x + gfr.width / 2,
1416 gfr.y + gfr.height / 2,
1417 gfr.x + gfr.width / 2,
1418 gfr.y + gfr.height / 2,
1419 gfr.width / 2,
1420 stops));
1421 gc->FillPath(pth);
1422
1423 stops = wxGraphicsGradientStops(wxColour(255,0,0, 128), wxColour(0,0,255, 128));
1424 stops.Add(wxColour(255,255,0,128), 0.33f);
1425 stops.Add(wxColour(0,255,0,128), 0.67f);
1426
1427 gc->SetBrush(gc->CreateLinearGradientBrush(gfr.x, gfr.y,
1428 gfr.x + gfr.width, gfr.y,
1429 stops));
1430 gc->FillPath(pth);
1431 }
1432 #endif // wxUSE_GRAPHICS_CONTEXT
1433 }
1434
1435 void MyCanvas::DrawRegions(wxDC& dc)
1436 {
1437 dc.DrawText(wxT("You should see a red rect partly covered by a cyan one ")
1438 wxT("on the left"), 10, 5);
1439 dc.DrawText(wxT("and 5 smileys from which 4 are partially clipped on the right"),
1440 10, 5 + dc.GetCharHeight());
1441 dc.DrawText(wxT("The second copy should be identical but right part of it ")
1442 wxT("should be offset by 10 pixels."),
1443 10, 5 + 2*dc.GetCharHeight());
1444
1445 DrawRegionsHelper(dc, 10, true);
1446 DrawRegionsHelper(dc, 350, false);
1447 }
1448
1449 void MyCanvas::DrawRegionsHelper(wxDC& dc, wxCoord x, bool firstTime)
1450 {
1451 wxCoord y = 100;
1452
1453 dc.DestroyClippingRegion();
1454 dc.SetBrush( *wxWHITE_BRUSH );
1455 dc.SetPen( *wxTRANSPARENT_PEN );
1456 dc.DrawRectangle( x, y, 310, 310 );
1457
1458 dc.SetClippingRegion( x + 10, y + 10, 100, 270 );
1459
1460 dc.SetBrush( *wxRED_BRUSH );
1461 dc.DrawRectangle( x, y, 310, 310 );
1462
1463 dc.SetClippingRegion( x + 10, y + 10, 100, 100 );
1464
1465 dc.SetBrush( *wxCYAN_BRUSH );
1466 dc.DrawRectangle( x, y, 310, 310 );
1467
1468 dc.DestroyClippingRegion();
1469
1470 wxRegion region(x + 110, y + 20, 100, 270);
1471 #if !defined(__WXMOTIF__)
1472 if ( !firstTime )
1473 region.Offset(10, 10);
1474 #endif
1475 dc.SetDeviceClippingRegion(region);
1476
1477 dc.SetBrush( *wxGREY_BRUSH );
1478 dc.DrawRectangle( x, y, 310, 310 );
1479
1480 if (m_smile_bmp.IsOk())
1481 {
1482 dc.DrawBitmap( m_smile_bmp, x + 150, y + 150, true );
1483 dc.DrawBitmap( m_smile_bmp, x + 130, y + 10, true );
1484 dc.DrawBitmap( m_smile_bmp, x + 130, y + 280, true );
1485 dc.DrawBitmap( m_smile_bmp, x + 100, y + 70, true );
1486 dc.DrawBitmap( m_smile_bmp, x + 200, y + 70, true );
1487 }
1488 }
1489
1490 #if TEST_CAIRO_EVERYWHERE
1491 extern wxGraphicsRenderer* gCairoRenderer;
1492 #endif
1493
1494 void MyCanvas::OnPaint(wxPaintEvent &WXUNUSED(event))
1495 {
1496 wxPaintDC pdc(this);
1497 Draw(pdc);
1498 }
1499
1500 template <typename T>
1501 void MyCanvas::Draw(T& pdc)
1502 {
1503 #if wxUSE_GRAPHICS_CONTEXT
1504 #if TEST_CAIRO_EVERYWHERE
1505 wxGCDC gdc;
1506 gdc.SetGraphicsContext( gCairoRenderer->CreateContext( pdc ) );
1507 #else
1508 wxGCDC gdc( pdc ) ;
1509 #endif
1510 wxDC &dc = m_useContext ? (wxDC&) gdc : (wxDC&) pdc ;
1511 #else
1512 wxDC &dc = pdc ;
1513 #endif
1514
1515 PrepareDC(dc);
1516
1517 m_owner->PrepareDC(dc);
1518
1519 dc.SetBackgroundMode( m_owner->m_backgroundMode );
1520 if ( m_owner->m_backgroundBrush.IsOk() )
1521 dc.SetBackground( m_owner->m_backgroundBrush );
1522 if ( m_owner->m_colourForeground.IsOk() )
1523 dc.SetTextForeground( m_owner->m_colourForeground );
1524 if ( m_owner->m_colourBackground.IsOk() )
1525 dc.SetTextBackground( m_owner->m_colourBackground );
1526
1527 if ( m_owner->m_textureBackground) {
1528 if ( ! m_owner->m_backgroundBrush.IsOk() ) {
1529 wxColour clr(0,128,0);
1530 wxBrush b(clr, wxSOLID);
1531 dc.SetBackground(b);
1532 }
1533 }
1534
1535 if ( m_clip )
1536 dc.SetClippingRegion(100, 100, 100, 100);
1537
1538 dc.Clear();
1539
1540 if ( m_owner->m_textureBackground )
1541 {
1542 dc.SetPen(*wxMEDIUM_GREY_PEN);
1543 for ( int i = 0; i < 200; i++ )
1544 dc.DrawLine(0, i*10, i*10, 0);
1545 }
1546
1547 switch ( m_show )
1548 {
1549 case File_ShowDefault:
1550 DrawDefault(dc);
1551 break;
1552
1553 case File_ShowCircles:
1554 DrawCircles(dc);
1555 break;
1556
1557 case File_ShowSplines:
1558 DrawSplines(dc);
1559 break;
1560
1561 case File_ShowRegions:
1562 DrawRegions(dc);
1563 break;
1564
1565 case File_ShowText:
1566 DrawText(dc);
1567 break;
1568
1569 case File_ShowLines:
1570 DrawTestLines( 0, 100, 0, dc );
1571 DrawTestLines( 0, 320, 1, dc );
1572 DrawTestLines( 0, 540, 2, dc );
1573 DrawTestLines( 0, 760, 6, dc );
1574 break;
1575
1576 case File_ShowBrushes:
1577 DrawTestBrushes(dc);
1578 break;
1579
1580 case File_ShowPolygons:
1581 DrawTestPoly(dc);
1582 break;
1583
1584 case File_ShowMask:
1585 DrawImages(dc, Draw_Normal);
1586 break;
1587
1588 case File_ShowMaskStretch:
1589 DrawImages(dc, Draw_Stretch);
1590 break;
1591
1592 case File_ShowOps:
1593 DrawWithLogicalOps(dc);
1594 break;
1595
1596 #if wxUSE_GRAPHICS_CONTEXT
1597 case File_ShowAlpha:
1598 DrawAlpha(dc);
1599 break;
1600 case File_ShowGraphics:
1601 DrawGraphics(gdc.GetGraphicsContext());
1602 break;
1603 #endif
1604
1605 case File_ShowGradients:
1606 DrawGradients(dc);
1607 break;
1608
1609 default:
1610 break;
1611 }
1612 }
1613
1614 void MyCanvas::OnMouseMove(wxMouseEvent &event)
1615 {
1616 #if wxUSE_STATUSBAR
1617 {
1618 wxClientDC dc(this);
1619 PrepareDC(dc);
1620 m_owner->PrepareDC(dc);
1621
1622 wxPoint pos = event.GetPosition();
1623 long x = dc.DeviceToLogicalX( pos.x );
1624 long y = dc.DeviceToLogicalY( pos.y );
1625 wxString str;
1626 str.Printf( wxT("Current mouse position: %d,%d"), (int)x, (int)y );
1627 m_owner->SetStatusText( str );
1628 }
1629
1630 if ( m_rubberBand )
1631 {
1632 int x,y, xx, yy ;
1633 event.GetPosition(&x,&y);
1634 CalcUnscrolledPosition( x, y, &xx, &yy );
1635 m_currentpoint = wxPoint( xx , yy ) ;
1636 wxRect newrect ( m_anchorpoint , m_currentpoint ) ;
1637
1638 wxClientDC dc( this ) ;
1639 PrepareDC( dc ) ;
1640
1641 wxDCOverlay overlaydc( m_overlay, &dc );
1642 overlaydc.Clear();
1643 #ifdef __WXMAC__
1644 dc.SetPen( *wxGREY_PEN );
1645 dc.SetBrush( wxColour( 192,192,192,64 ) );
1646 #else
1647 dc.SetPen( wxPen( *wxLIGHT_GREY, 2, wxSOLID ) );
1648 dc.SetBrush( *wxTRANSPARENT_BRUSH );
1649 #endif
1650 dc.DrawRectangle( newrect );
1651 }
1652 #else
1653 wxUnusedVar(event);
1654 #endif // wxUSE_STATUSBAR
1655 }
1656
1657 void MyCanvas::OnMouseDown(wxMouseEvent &event)
1658 {
1659 int x,y,xx,yy ;
1660 event.GetPosition(&x,&y);
1661 CalcUnscrolledPosition( x, y, &xx, &yy );
1662 m_anchorpoint = wxPoint( xx , yy ) ;
1663 m_currentpoint = m_anchorpoint ;
1664 m_rubberBand = true ;
1665 CaptureMouse() ;
1666 }
1667
1668 void MyCanvas::OnMouseUp(wxMouseEvent &event)
1669 {
1670 if ( m_rubberBand )
1671 {
1672 ReleaseMouse();
1673 {
1674 wxClientDC dc( this );
1675 PrepareDC( dc );
1676 wxDCOverlay overlaydc( m_overlay, &dc );
1677 overlaydc.Clear();
1678 }
1679 m_overlay.Reset();
1680 m_rubberBand = false;
1681
1682 wxPoint endpoint = CalcUnscrolledPosition(event.GetPosition());
1683
1684 // Don't pop up the message box if nothing was actually selected.
1685 if ( endpoint != m_anchorpoint )
1686 {
1687 wxLogMessage("Selected rectangle from (%d, %d) to (%d, %d)",
1688 m_anchorpoint.x, m_anchorpoint.y,
1689 endpoint.x, endpoint.y);
1690 }
1691 }
1692 }
1693
1694 // ----------------------------------------------------------------------------
1695 // MyFrame
1696 // ----------------------------------------------------------------------------
1697
1698 // the event tables connect the wxWidgets events with the functions (event
1699 // handlers) which process them. It can be also done at run-time, but for the
1700 // simple menu events like this the static method is much simpler.
1701 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
1702 EVT_MENU (File_Quit, MyFrame::OnQuit)
1703 EVT_MENU (File_About, MyFrame::OnAbout)
1704 EVT_MENU (File_Clip, MyFrame::OnClip)
1705 #if wxUSE_GRAPHICS_CONTEXT
1706 EVT_MENU (File_GraphicContext, MyFrame::OnGraphicContext)
1707 #endif
1708 EVT_MENU (File_Copy, MyFrame::OnCopy)
1709 EVT_MENU (File_Save, MyFrame::OnSave)
1710
1711 EVT_MENU_RANGE(MenuShow_First, MenuShow_Last, MyFrame::OnShow)
1712
1713 EVT_MENU_RANGE(MenuOption_First, MenuOption_Last, MyFrame::OnOption)
1714 END_EVENT_TABLE()
1715
1716 // frame constructor
1717 MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
1718 : wxFrame((wxFrame *)NULL, wxID_ANY, title, pos, size,
1719 wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE)
1720 {
1721 // set the frame icon
1722 SetIcon(wxICON(sample));
1723
1724 wxMenu *menuFile = new wxMenu;
1725 menuFile->Append(File_ShowDefault, wxT("&Default screen\tF1"));
1726 menuFile->Append(File_ShowText, wxT("&Text screen\tF2"));
1727 menuFile->Append(File_ShowLines, wxT("&Lines screen\tF3"));
1728 menuFile->Append(File_ShowBrushes, wxT("&Brushes screen\tF4"));
1729 menuFile->Append(File_ShowPolygons, wxT("&Polygons screen\tF5"));
1730 menuFile->Append(File_ShowMask, wxT("&Mask screen\tF6"));
1731 menuFile->Append(File_ShowMaskStretch, wxT("1/&2 scaled mask\tShift-F6"));
1732 menuFile->Append(File_ShowOps, wxT("&Raster operations screen\tF7"));
1733 menuFile->Append(File_ShowRegions, wxT("Re&gions screen\tF8"));
1734 menuFile->Append(File_ShowCircles, wxT("&Circles screen\tF9"));
1735 #if wxUSE_GRAPHICS_CONTEXT
1736 menuFile->Append(File_ShowAlpha, wxT("&Alpha screen\tF10"));
1737 #endif
1738 menuFile->Append(File_ShowSplines, wxT("Spl&ines screen\tF11"));
1739 menuFile->Append(File_ShowGradients, wxT("&Gradients screen\tF12"));
1740 #if wxUSE_GRAPHICS_CONTEXT
1741 menuFile->Append(File_ShowGraphics, wxT("&Graphics screen"));
1742 #endif
1743 menuFile->AppendSeparator();
1744 menuFile->AppendCheckItem(File_Clip, wxT("&Clip\tCtrl-C"), wxT("Clip/unclip drawing"));
1745 #if wxUSE_GRAPHICS_CONTEXT
1746 menuFile->AppendCheckItem(File_GraphicContext, wxT("&Use GraphicContext\tCtrl-Y"), wxT("Use GraphicContext"));
1747 #endif
1748 menuFile->AppendSeparator();
1749 #if wxUSE_METAFILE && defined(wxMETAFILE_IS_ENH)
1750 menuFile->Append(File_Copy, wxT("Copy to clipboard"));
1751 #endif
1752 menuFile->Append(File_Save, wxT("&Save...\tCtrl-S"), wxT("Save drawing to file"));
1753 menuFile->AppendSeparator();
1754 menuFile->Append(File_About, wxT("&About...\tCtrl-A"), wxT("Show about dialog"));
1755 menuFile->AppendSeparator();
1756 menuFile->Append(File_Quit, wxT("E&xit\tAlt-X"), wxT("Quit this program"));
1757
1758 wxMenu *menuMapMode = new wxMenu;
1759 menuMapMode->Append( MapMode_Text, wxT("&TEXT map mode") );
1760 menuMapMode->Append( MapMode_Lometric, wxT("&LOMETRIC map mode") );
1761 menuMapMode->Append( MapMode_Twips, wxT("T&WIPS map mode") );
1762 menuMapMode->Append( MapMode_Points, wxT("&POINTS map mode") );
1763 menuMapMode->Append( MapMode_Metric, wxT("&METRIC map mode") );
1764
1765 wxMenu *menuUserScale = new wxMenu;
1766 menuUserScale->Append( UserScale_StretchHoriz, wxT("Stretch &horizontally\tCtrl-H") );
1767 menuUserScale->Append( UserScale_ShrinkHoriz, wxT("Shrin&k horizontally\tCtrl-G") );
1768 menuUserScale->Append( UserScale_StretchVertic, wxT("Stretch &vertically\tCtrl-V") );
1769 menuUserScale->Append( UserScale_ShrinkVertic, wxT("&Shrink vertically\tCtrl-W") );
1770 menuUserScale->AppendSeparator();
1771 menuUserScale->Append( UserScale_Restore, wxT("&Restore to normal\tCtrl-0") );
1772
1773 wxMenu *menuAxis = new wxMenu;
1774 menuAxis->AppendCheckItem( AxisMirror_Horiz, wxT("Mirror horizontally\tCtrl-M") );
1775 menuAxis->AppendCheckItem( AxisMirror_Vertic, wxT("Mirror vertically\tCtrl-N") );
1776
1777 wxMenu *menuLogical = new wxMenu;
1778 menuLogical->Append( LogicalOrigin_MoveDown, wxT("Move &down\tCtrl-D") );
1779 menuLogical->Append( LogicalOrigin_MoveUp, wxT("Move &up\tCtrl-U") );
1780 menuLogical->Append( LogicalOrigin_MoveLeft, wxT("Move &right\tCtrl-L") );
1781 menuLogical->Append( LogicalOrigin_MoveRight, wxT("Move &left\tCtrl-R") );
1782 menuLogical->AppendSeparator();
1783 menuLogical->Append( LogicalOrigin_Set, wxT("Set to (&100, 100)\tShift-Ctrl-1") );
1784 menuLogical->Append( LogicalOrigin_Restore, wxT("&Restore to normal\tShift-Ctrl-0") );
1785
1786 wxMenu *menuColour = new wxMenu;
1787 #if wxUSE_COLOURDLG
1788 menuColour->Append( Colour_TextForeground, wxT("Text &foreground...") );
1789 menuColour->Append( Colour_TextBackground, wxT("Text &background...") );
1790 menuColour->Append( Colour_Background, wxT("Background &colour...") );
1791 #endif // wxUSE_COLOURDLG
1792 menuColour->AppendCheckItem( Colour_BackgroundMode, wxT("&Opaque/transparent\tCtrl-B") );
1793 menuColour->AppendCheckItem( Colour_TextureBackgound, wxT("Draw textured back&ground\tCtrl-T") );
1794
1795 // now append the freshly created menu to the menu bar...
1796 wxMenuBar *menuBar = new wxMenuBar;
1797 menuBar->Append(menuFile, wxT("&File"));
1798 menuBar->Append(menuMapMode, wxT("&Mode"));
1799 menuBar->Append(menuUserScale, wxT("&Scale"));
1800 menuBar->Append(menuAxis, wxT("&Axis"));
1801 menuBar->Append(menuLogical, wxT("&Origin"));
1802 menuBar->Append(menuColour, wxT("&Colours"));
1803
1804 // ... and attach this menu bar to the frame
1805 SetMenuBar(menuBar);
1806
1807 #if wxUSE_STATUSBAR
1808 CreateStatusBar(2);
1809 SetStatusText(wxT("Welcome to wxWidgets!"));
1810 #endif // wxUSE_STATUSBAR
1811
1812 m_mapMode = wxMM_TEXT;
1813 m_xUserScale = 1.0;
1814 m_yUserScale = 1.0;
1815 m_xLogicalOrigin = 0;
1816 m_yLogicalOrigin = 0;
1817 m_xAxisReversed =
1818 m_yAxisReversed = false;
1819 m_backgroundMode = wxSOLID;
1820 m_colourForeground = *wxBLACK;
1821 m_colourBackground = *wxLIGHT_GREY;
1822 m_textureBackground = false;
1823
1824 m_canvas = new MyCanvas( this );
1825 m_canvas->SetScrollbars( 10, 10, 100, 240 );
1826 }
1827
1828 // event handlers
1829
1830 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
1831 {
1832 // true is to force the frame to close
1833 Close(true);
1834 }
1835
1836 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
1837 {
1838 wxString msg;
1839 msg.Printf( wxT("This is the about dialog of the drawing sample.\n")
1840 wxT("This sample tests various primitive drawing functions\n")
1841 wxT("(without any attempts to prevent flicker).\n")
1842 wxT("Copyright (c) Robert Roebling 1999")
1843 );
1844
1845 wxMessageBox(msg, wxT("About Drawing"), wxOK | wxICON_INFORMATION, this);
1846 }
1847
1848 void MyFrame::OnClip(wxCommandEvent& event)
1849 {
1850 m_canvas->Clip(event.IsChecked());
1851 }
1852
1853 #if wxUSE_GRAPHICS_CONTEXT
1854 void MyFrame::OnGraphicContext(wxCommandEvent& event)
1855 {
1856 m_canvas->UseGraphicContext(event.IsChecked());
1857 }
1858 #endif
1859
1860 void MyFrame::OnCopy(wxCommandEvent& WXUNUSED(event))
1861 {
1862 #if wxUSE_METAFILE && defined(wxMETAFILE_IS_ENH)
1863 wxMetafileDC dc;
1864 if (!dc.IsOk())
1865 return;
1866 m_canvas->Draw(dc);
1867 wxMetafile *mf = dc.Close();
1868 if (!mf)
1869 return;
1870 mf->SetClipboard();
1871 delete mf;
1872 #endif
1873 }
1874
1875 void MyFrame::OnSave(wxCommandEvent& WXUNUSED(event))
1876 {
1877 wxFileDialog dlg(this, wxT("Save as bitmap"), wxT(""), wxT(""),
1878 #if wxUSE_LIBPNG
1879 wxT("PNG image (*.png)|*.png;*.PNG|")
1880 #endif
1881 wxT("Bitmap image (*.bmp)|*.bmp;*.BMP"),
1882 wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
1883 if (dlg.ShowModal() == wxID_OK)
1884 {
1885 wxBitmap bmp(500, 800);
1886 wxMemoryDC mdc(bmp);
1887 m_canvas->Draw(mdc);
1888 bmp.ConvertToImage().SaveFile(dlg.GetPath());
1889 }
1890 }
1891
1892 void MyFrame::OnShow(wxCommandEvent& event)
1893 {
1894 m_canvas->ToShow(event.GetId());
1895 }
1896
1897 void MyFrame::OnOption(wxCommandEvent& event)
1898 {
1899 switch (event.GetId())
1900 {
1901 case MapMode_Text:
1902 m_mapMode = wxMM_TEXT;
1903 break;
1904 case MapMode_Lometric:
1905 m_mapMode = wxMM_LOMETRIC;
1906 break;
1907 case MapMode_Twips:
1908 m_mapMode = wxMM_TWIPS;
1909 break;
1910 case MapMode_Points:
1911 m_mapMode = wxMM_POINTS;
1912 break;
1913 case MapMode_Metric:
1914 m_mapMode = wxMM_METRIC;
1915 break;
1916
1917 case LogicalOrigin_MoveDown:
1918 m_yLogicalOrigin += 10;
1919 break;
1920 case LogicalOrigin_MoveUp:
1921 m_yLogicalOrigin -= 10;
1922 break;
1923 case LogicalOrigin_MoveLeft:
1924 m_xLogicalOrigin += 10;
1925 break;
1926 case LogicalOrigin_MoveRight:
1927 m_xLogicalOrigin -= 10;
1928 break;
1929 case LogicalOrigin_Set:
1930 m_xLogicalOrigin =
1931 m_yLogicalOrigin = -100;
1932 break;
1933 case LogicalOrigin_Restore:
1934 m_xLogicalOrigin =
1935 m_yLogicalOrigin = 0;
1936 break;
1937
1938 case UserScale_StretchHoriz:
1939 m_xUserScale *= 1.10;
1940 break;
1941 case UserScale_ShrinkHoriz:
1942 m_xUserScale /= 1.10;
1943 break;
1944 case UserScale_StretchVertic:
1945 m_yUserScale *= 1.10;
1946 break;
1947 case UserScale_ShrinkVertic:
1948 m_yUserScale /= 1.10;
1949 break;
1950 case UserScale_Restore:
1951 m_xUserScale =
1952 m_yUserScale = 1.0;
1953 break;
1954
1955 case AxisMirror_Vertic:
1956 m_yAxisReversed = !m_yAxisReversed;
1957 break;
1958 case AxisMirror_Horiz:
1959 m_xAxisReversed = !m_xAxisReversed;
1960 break;
1961
1962 #if wxUSE_COLOURDLG
1963 case Colour_TextForeground:
1964 m_colourForeground = SelectColour();
1965 break;
1966 case Colour_TextBackground:
1967 m_colourBackground = SelectColour();
1968 break;
1969 case Colour_Background:
1970 {
1971 wxColour col = SelectColour();
1972 if ( col.IsOk() )
1973 {
1974 m_backgroundBrush.SetColour(col);
1975 }
1976 }
1977 break;
1978 #endif // wxUSE_COLOURDLG
1979
1980 case Colour_BackgroundMode:
1981 m_backgroundMode = m_backgroundMode == wxSOLID ? wxTRANSPARENT
1982 : wxSOLID;
1983 break;
1984
1985 case Colour_TextureBackgound:
1986 m_textureBackground = ! m_textureBackground;
1987 break;
1988
1989 default:
1990 // skip Refresh()
1991 return;
1992 }
1993
1994 m_canvas->Refresh();
1995 }
1996
1997 void MyFrame::PrepareDC(wxDC& dc)
1998 {
1999 dc.SetLogicalOrigin( m_xLogicalOrigin, m_yLogicalOrigin );
2000 dc.SetAxisOrientation( !m_xAxisReversed, m_yAxisReversed );
2001 dc.SetUserScale( m_xUserScale, m_yUserScale );
2002 dc.SetMapMode( m_mapMode );
2003 }
2004
2005 #if wxUSE_COLOURDLG
2006 wxColour MyFrame::SelectColour()
2007 {
2008 wxColour col;
2009 wxColourData data;
2010 wxColourDialog dialog(this, &data);
2011
2012 if ( dialog.ShowModal() == wxID_OK )
2013 {
2014 col = dialog.GetColourData().GetColour();
2015 }
2016
2017 return col;
2018 }
2019 #endif // wxUSE_COLOURDLG