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