]> git.saurik.com Git - wxWidgets.git/blobdiff - samples/drawing/drawing.cpp
move treeentry_gtk.h to include/wx/gtk/private/
[wxWidgets.git] / samples / drawing / drawing.cpp
index 8da014ba7226a875ea908532d29dae918fcdc2ec..1404a120d96097d95db4fa6f8b0cd232fe7b46a7 100644 (file)
@@ -37,6 +37,7 @@
 #include "wx/overlay.h"
 #include "wx/graphics.h"
 #include "wx/filename.h"
+#include "wx/metafile.h"
 
 #define TEST_CAIRO_EVERYWHERE 0
 
@@ -45,8 +46,8 @@
 // ----------------------------------------------------------------------------
 
 // the application icon
-#if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__) || defined(__WXX11__)
-    #include "mondrian.xpm"
+#ifndef wxHAS_IMAGES_IN_RESOURCES
+    #include "../sample.xpm"
 #endif
 
 // ----------------------------------------------------------------------------
@@ -101,6 +102,8 @@ public:
 #if wxUSE_GRAPHICS_CONTEXT
     void OnGraphicContext(wxCommandEvent& event);
 #endif
+    void OnCopy(wxCommandEvent& event);
+    void OnSave(wxCommandEvent& event);
     void OnShow(wxCommandEvent &event);
     void OnOption(wxCommandEvent &event);
 
@@ -146,6 +149,7 @@ public:
 #if wxUSE_GRAPHICS_CONTEXT
     void UseGraphicContext(bool use) { m_useContext = use; Refresh(); }
 #endif
+    void Draw(wxDC& dc);
 
 protected:
     enum DrawMode
@@ -224,6 +228,8 @@ enum
 #if wxUSE_GRAPHICS_CONTEXT
     File_GraphicContext,
 #endif
+    File_Copy,
+    File_Save,
 
     MenuOption_First,
 
@@ -345,11 +351,10 @@ bool MyApp::OnInit()
 
     // Create the main application window
     MyFrame *frame = new MyFrame(wxT("Drawing sample"),
-                                 wxPoint(50, 50), wxSize(550, 340));
+                                 wxDefaultPosition, wxSize(550, 840));
 
-    // Show it and tell the application that it's our main window
+    // Show it
     frame->Show(true);
-    SetTopWindow(frame);
 
     if ( !LoadImages() )
     {
@@ -360,27 +365,22 @@ bool MyApp::OnInit()
         // still continue, the sample can be used without images too if they're
         // missing for whatever reason
     }
+#if wxUSE_LIBPNG
+      wxImage::AddHandler( new wxPNGHandler );
+#endif
 
     return true;
 }
 
 void MyApp::DeleteBitmaps()
 {
-    delete gs_bmpNoMask;
-    delete gs_bmpWithColMask;
-    delete gs_bmpMask;
-    delete gs_bmpWithMask;
-    delete gs_bmp4;
-    delete gs_bmp4_mono;
-    delete gs_bmp36;
-
-    gs_bmpNoMask = NULL;
-    gs_bmpWithColMask = NULL;
-    gs_bmpMask = NULL;
-    gs_bmpWithMask = NULL;
-    gs_bmp4 = NULL;
-    gs_bmp4_mono = NULL;
-    gs_bmp36 = NULL;
+    wxDELETE(gs_bmpNoMask);
+    wxDELETE(gs_bmpWithColMask);
+    wxDELETE(gs_bmpMask);
+    wxDELETE(gs_bmpWithMask);
+    wxDELETE(gs_bmp4);
+    wxDELETE(gs_bmp4_mono);
+    wxDELETE(gs_bmp36);
 }
 
 // ----------------------------------------------------------------------------
@@ -421,14 +421,29 @@ void MyCanvas::DrawTestBrushes(wxDC& dc)
     wxCoord x = 10,
             y = 10;
 
-    dc.SetBrush(wxBrush(*wxGREEN, wxSOLID));
+    dc.SetBrush(*wxGREEN_BRUSH);
     dc.DrawRectangle(x, y, WIDTH, HEIGHT);
     dc.DrawText(wxT("Solid green"), x + 10, y + 10);
 
     y += HEIGHT;
-    dc.SetBrush(wxBrush(*wxRED, wxCROSSDIAG_HATCH));
+    dc.SetBrush(wxBrush(*wxRED, wxBRUSHSTYLE_CROSSDIAG_HATCH));
+    dc.DrawRectangle(x, y, WIDTH, HEIGHT);
+    dc.DrawText(wxT("Diagonally hatched red"), x + 10, y + 10);
+
+    y += HEIGHT;
+    dc.SetBrush(wxBrush(*wxBLUE, wxBRUSHSTYLE_CROSS_HATCH));
+    dc.DrawRectangle(x, y, WIDTH, HEIGHT);
+    dc.DrawText(wxT("Cross hatched blue"), x + 10, y + 10);
+
+    y += HEIGHT;
+    dc.SetBrush(wxBrush(*wxCYAN, wxBRUSHSTYLE_VERTICAL_HATCH));
+    dc.DrawRectangle(x, y, WIDTH, HEIGHT);
+    dc.DrawText(wxT("Vertically hatched cyan"), x + 10, y + 10);
+
+    y += HEIGHT;
+    dc.SetBrush(wxBrush(*wxBLACK, wxBRUSHSTYLE_HORIZONTAL_HATCH));
     dc.DrawRectangle(x, y, WIDTH, HEIGHT);
-    dc.DrawText(wxT("Hatched red"), x + 10, y + 10);
+    dc.DrawText(wxT("Horizontally hatched black"), x + 10, y + 10);
 
     y += HEIGHT;
     dc.SetBrush(wxBrush(*gs_bmpMask));
@@ -443,7 +458,7 @@ void MyCanvas::DrawTestBrushes(wxDC& dc)
 
 void MyCanvas::DrawTestPoly(wxDC& dc)
 {
-    wxBrush brushHatch(*wxRED, wxFDIAGONAL_HATCH);
+    wxBrush brushHatch(*wxRED, wxBRUSHSTYLE_FDIAGONAL_HATCH);
     dc.SetBrush(brushHatch);
 
     wxPoint star[5];
@@ -480,39 +495,39 @@ void MyCanvas::DrawTestPoly(wxDC& dc)
 
 void MyCanvas::DrawTestLines( int x, int y, int width, wxDC &dc )
 {
-    dc.SetPen( wxPen( wxT("black"), width, wxSOLID) );
+    dc.SetPen( wxPen( *wxBLACK, width ) );
     dc.SetBrush( *wxRED_BRUSH );
     dc.DrawText(wxString::Format(wxT("Testing lines of width %d"), width), x + 10, y - 10);
     dc.DrawRectangle( x+10, y+10, 100, 190 );
 
     dc.DrawText(wxT("Solid/dot/short dash/long dash/dot dash"), x + 150, y + 10);
-    dc.SetPen( wxPen( wxT("black"), width, wxSOLID) );
+    dc.SetPen( wxPen( *wxBLACK, width ) );
     dc.DrawLine( x+20, y+20, 100, y+20 );
-    dc.SetPen( wxPen( wxT("black"), width, wxDOT) );
+    dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_DOT) );
     dc.DrawLine( x+20, y+30, 100, y+30 );
-    dc.SetPen( wxPen( wxT("black"), width, wxSHORT_DASH) );
+    dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_SHORT_DASH) );
     dc.DrawLine( x+20, y+40, 100, y+40 );
-    dc.SetPen( wxPen( wxT("black"), width, wxLONG_DASH) );
+    dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_LONG_DASH) );
     dc.DrawLine( x+20, y+50, 100, y+50 );
-    dc.SetPen( wxPen( wxT("black"), width, wxDOT_DASH) );
+    dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_DOT_DASH) );
     dc.DrawLine( x+20, y+60, 100, y+60 );
 
     dc.DrawText(wxT("Misc hatches"), x + 150, y + 70);
-    dc.SetPen( wxPen( wxT("black"), width, wxBDIAGONAL_HATCH) );
+    dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_BDIAGONAL_HATCH) );
     dc.DrawLine( x+20, y+70, 100, y+70 );
-    dc.SetPen( wxPen( wxT("black"), width, wxCROSSDIAG_HATCH) );
+    dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_CROSSDIAG_HATCH) );
     dc.DrawLine( x+20, y+80, 100, y+80 );
-    dc.SetPen( wxPen( wxT("black"), width, wxFDIAGONAL_HATCH) );
+    dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_FDIAGONAL_HATCH) );
     dc.DrawLine( x+20, y+90, 100, y+90 );
-    dc.SetPen( wxPen( wxT("black"), width, wxCROSS_HATCH) );
+    dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_CROSS_HATCH) );
     dc.DrawLine( x+20, y+100, 100, y+100 );
-    dc.SetPen( wxPen( wxT("black"), width, wxHORIZONTAL_HATCH) );
+    dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_HORIZONTAL_HATCH) );
     dc.DrawLine( x+20, y+110, 100, y+110 );
-    dc.SetPen( wxPen( wxT("black"), width, wxVERTICAL_HATCH) );
+    dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_VERTICAL_HATCH) );
     dc.DrawLine( x+20, y+120, 100, y+120 );
 
     dc.DrawText(wxT("User dash"), x + 150, y + 140);
-    wxPen ud( wxT("black"), width, wxUSER_DASH );
+    wxPen ud( *wxBLACK, width, wxPENSTYLE_USER_DASH );
     wxDash dash1[6];
     dash1[0] = 8;  // Long dash  <---------+
     dash1[1] = 2;  // Short gap            |
@@ -539,19 +554,29 @@ void MyCanvas::DrawTestLines( int x, int y, int width, wxDC &dc )
 
 void MyCanvas::DrawDefault(wxDC& dc)
 {
-    // mark the origin
-    dc.DrawCircle(0, 0, 10);
-
-#if !defined(wxMAC_USE_CORE_GRAPHICS) || !wxMAC_USE_CORE_GRAPHICS
-    // GetPixel and FloodFill not supported by Mac OS X CoreGraphics
-    // (FloodFill uses Blit from a non-wxMemoryDC)
-    //flood fill using brush, starting at 1,1 and replacing whatever colour we find there
-    dc.SetBrush(wxBrush(wxColour(128,128,0), wxSOLID));
-
-    wxColour tmpColour ;
-    dc.GetPixel(1,1, &tmpColour);
-    dc.FloodFill(1,1, tmpColour, wxFLOOD_SURFACE);
-#endif
+    // Draw circle centered at the origin, then flood fill it with a different
+    // color. Done with a wxMemoryDC because Blit (used by generic
+    // wxDoFloodFill) from a window that is being painted gives unpredictable
+    // results on wxGTK
+    {
+        wxImage img(21, 21, false);
+        img.Clear(1);
+        wxBitmap bmp(img);
+        {
+            wxMemoryDC mdc(bmp);
+            mdc.SetBrush(dc.GetBrush());
+            mdc.SetPen(dc.GetPen());
+            mdc.DrawCircle(10, 10, 10);
+            wxColour c;
+            if (mdc.GetPixel(11, 11, &c))
+            {
+                mdc.SetBrush(wxColour(128, 128, 0));
+                mdc.FloodFill(11, 11, c, wxFLOOD_SURFACE);
+            }
+        }
+        bmp.SetMask(new wxMask(bmp, wxColour(1, 1, 1)));
+        dc.DrawBitmap(bmp, -10, -10, true);
+    }
 
     dc.DrawCheckMark(5, 80, 15, 15);
     dc.DrawCheckMark(25, 80, 30, 30);
@@ -574,7 +599,7 @@ void MyCanvas::DrawDefault(wxDC& dc)
     // rectangle above)
     //dc.SetBrush( *wxTRANSPARENT_BRUSH );
 
-    if (m_smile_bmp.Ok())
+    if (m_smile_bmp.IsOk())
         dc.DrawBitmap(m_smile_bmp, x + rectSize - 20, rectSize - 10, true);
 
     dc.SetBrush( *wxBLACK_BRUSH );
@@ -708,13 +733,9 @@ void MyCanvas::DrawDefault(wxDC& dc)
     wxMemoryDC memdc2;
     memdc2.SelectObject(bitmap2);
 
-    wxColour clr(255, 255, 0);
-    wxBrush yellowBrush(clr, wxSOLID);
-    memdc2.SetBackground(yellowBrush);
+    memdc2.SetBackground(*wxYELLOW_BRUSH);
     memdc2.Clear();
 
-    wxPen yellowPen(clr, 1, wxSOLID);
-
     // Now draw a white rectangle with red outline. It should
     // entirely eclipse the yellow background.
     memdc2.SetPen(*wxRED_PEN);
@@ -732,8 +753,8 @@ void MyCanvas::DrawDefault(wxDC& dc)
     // Draw a yellow rectangle filling the bitmap
 
     x = 600; int y = 270;
-    dc.SetPen(yellowPen);
-    dc.SetBrush(yellowBrush);
+    dc.SetPen(*wxYELLOW_PEN);
+    dc.SetBrush(*wxYELLOW_BRUSH);
     dc.DrawRectangle(x, y, totalWidth, totalHeight);
 
     // Now draw a white rectangle with red outline. It should
@@ -772,7 +793,7 @@ void MyCanvas::DrawText(wxDC& dc)
     wxCoord height;
     wxCoord descent;
     dc.GetTextExtent( wxT("This is Swiss 18pt text."), &length, &height, &descent );
-    text.Printf( wxT("Dimensions are length %ld, height %ld, descent %ld"), length, height, descent );
+    text.Printf( wxT("Dimensions are length %d, height %d, descent %d"), length, height, descent );
     dc.DrawText( text, 110, 80 );
 
     text.Printf( wxT("CharHeight() returns: %d"), dc.GetCharHeight() );
@@ -797,6 +818,9 @@ void MyCanvas::DrawText(wxDC& dc)
     y += height;
     dc.DrawRectangle( 110, y, 100, height );
     dc.DrawText( wxT("Another visible text"), 110, y );
+
+    y += height;
+    dc.DrawText("And\nmore\ntext on\nmultiple\nlines", 110, y);
 }
 
 static const struct
@@ -862,7 +886,7 @@ void MyCanvas::DrawWithLogicalOps(wxDC& dc)
     static const wxCoord h = 60;
 
     // reuse the text colour here
-    dc.SetPen(wxPen(m_owner->m_colourForeground, 1, wxSOLID));
+    dc.SetPen(wxPen(m_owner->m_colourForeground));
     dc.SetBrush(*wxTRANSPARENT_BRUSH);
 
     size_t n;
@@ -879,7 +903,7 @@ void MyCanvas::DrawWithLogicalOps(wxDC& dc)
     }
 
     // now some filled rectangles
-    dc.SetBrush(wxBrush(m_owner->m_colourForeground, wxSOLID));
+    dc.SetBrush(wxBrush(m_owner->m_colourForeground));
 
     for ( n = 0; n < WXSIZEOF(rasterOperations); n++ )
     {
@@ -894,7 +918,7 @@ void MyCanvas::DrawWithLogicalOps(wxDC& dc)
 
 #if wxUSE_GRAPHICS_CONTEXT
 #ifdef __WXGTK20__
-void MyCanvas::DrawAlpha(wxDC& no_dc)
+void MyCanvas::DrawAlpha(wxDC& WXUNUSED(dummyDC))
 #else
 void MyCanvas::DrawAlpha(wxDC& dc)
 #endif
@@ -908,22 +932,22 @@ void MyCanvas::DrawAlpha(wxDC& dc)
     wxDouble width = 180 ;
     wxDouble radius = 30 ;
 
-    dc.SetPen( wxPen( wxColour( 128, 0, 0, 255 ),12, wxSOLID));
-    dc.SetBrush( wxBrush( wxColour( 255, 0, 0, 255),wxSOLID));
+    dc.SetPen( wxPen( wxColour( 128, 0, 0 ), 12 ));
+    dc.SetBrush(*wxRED_BRUSH);
 
     wxRect r(margin,margin+width*0.66,width,width) ;
 
     dc.DrawRoundedRectangle( r.x, r.y, r.width, r.width, radius ) ;
 
-    dc.SetPen( wxPen( wxColour( 0, 0, 128, 255 ),12, wxSOLID));
-    dc.SetBrush( wxBrush( wxColour( 0, 0, 255, 255),wxSOLID));
+    dc.SetPen( wxPen( wxColour( 0, 0, 128 ), 12));
+    dc.SetBrush(*wxBLUE_BRUSH);
 
     r.Offset( width * 0.8 , - width * 0.66 ) ;
 
     dc.DrawRoundedRectangle( r.x, r.y, r.width, r.width, radius ) ;
 
-    dc.SetPen( wxPen( wxColour( 128, 128, 0, 255 ),12, wxSOLID));
-    dc.SetBrush( wxBrush( wxColour( 192, 192, 0, 255),wxSOLID));
+    dc.SetPen( wxPen( wxColour( 128, 128, 0 ), 12));
+    dc.SetBrush( wxBrush( wxColour( 192, 192, 0)));
 
     r.Offset( width * 0.8 , width *0.5 ) ;
 
@@ -955,7 +979,7 @@ void MyCanvas::DrawGraphics(wxGraphicsContext* gc)
 {
     wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
     gc->SetFont(font,*wxBLACK);
-    
+
     // make a path that contains a circle and some lines, centered at 0,0
     wxGraphicsPath path = gc->CreatePath() ;
     path.AddCircle( 0, 0, BASE2 );
@@ -965,14 +989,14 @@ void MyCanvas::DrawGraphics(wxGraphicsContext* gc)
     path.AddLineToPoint(BASE2, 0);
     path.CloseSubpath();
     path.AddRectangle(-BASE4, -BASE4/2, BASE2, BASE4);
-    
+
     // Now use that path to demonstrate various capbilites of the grpahics context
-    gc->PushState(); // save current translation/scale/other state 
+    gc->PushState(); // save current translation/scale/other state
     gc->Translate(60, 75); // reposition the context origin
 
-    gc->SetPen(wxPen("navy", 1));
+    gc->SetPen(wxPen("navy"));
     gc->SetBrush(wxBrush("pink"));
-    
+
     for( int i = 0 ; i < 3 ; ++i )
     {
         wxString label;
@@ -1005,11 +1029,11 @@ void MyCanvas::DrawGraphics(wxGraphicsContext* gc)
         }
         gc->Translate(2*BASE, 0);
     }
-            
+
     gc->PopState(); // restore saved state
     gc->PushState(); // save it again
     gc->Translate(60, 200); // offset to the lower part of the window
-        
+
     gc->DrawText("Scale", 0, -BASE2);
     gc->Translate(0, 20);
 
@@ -1017,14 +1041,14 @@ void MyCanvas::DrawGraphics(wxGraphicsContext* gc)
     for( int i = 0 ; i < 8 ; ++i )
     {
         gc->Scale(1.08, 1.08); // increase scale by 8%
-        gc->Translate(5,5);    
+        gc->Translate(5,5);
         gc->DrawPath(path);
     }
 
     gc->PopState(); // restore saved state
     gc->PushState(); // save it again
-    gc->Translate(400, 200); 
-    
+    gc->Translate(400, 200);
+
     gc->DrawText("Rotate", 0, -BASE2);
 
     // Move the origin over to the next location
@@ -1034,16 +1058,16 @@ void MyCanvas::DrawGraphics(wxGraphicsContext* gc)
     // and changing colors as we go
     for ( int angle = 0 ; angle < 360 ; angle += 30 )
     {
-        gc->PushState(); // save this new current state so we can 
+        gc->PushState(); // save this new current state so we can
         //  pop back to it at the end of the loop
         wxImage::RGBValue val = wxImage::HSVtoRGB(wxImage::HSVValue(float(angle)/360, 1, 1));
         gc->SetBrush(wxBrush(wxColour(val.red, val.green, val.blue, 64)));
         gc->SetPen(wxPen(wxColour(val.red, val.green, val.blue, 128)));
-        
+
         // use translate to artfully reposition each drawn path
         gc->Translate(1.5 * BASE2 * cos(DegToRad(angle)),
                      1.5 * BASE2 * sin(DegToRad(angle)));
-                     
+
         // use Rotate to rotate the path
         gc->Rotate(DegToRad(angle));
 
@@ -1052,8 +1076,15 @@ void MyCanvas::DrawGraphics(wxGraphicsContext* gc)
         gc->PopState();
     }
     gc->PopState();
+
+    gc->PushState();
+    gc->Translate(60, 400);
+    gc->DrawText("Scaled smiley inside a square", 0, 0);
+    gc->DrawRectangle(BASE2, BASE2, 100, 100);
+    gc->DrawBitmap(m_smile_bmp, BASE2, BASE2, 100, 100);
+    gc->PopState();
 }
-#endif
+#endif // wxUSE_GRAPHICS_CONTEXT
 
 void MyCanvas::DrawCircles(wxDC& dc)
 {
@@ -1195,9 +1226,9 @@ void MyCanvas::DrawSplines(wxDC& dc)
             letters[m][n].y = center.y + h[ letters[m][n].y ];
         }
 
-        dc.SetPen( wxPen( wxT("blue"), 1, wxDOT) );
+        dc.SetPen( wxPen( *wxBLUE, 1, wxDOT) );
         dc.DrawLines(5, letters[m]);
-        dc.SetPen( wxPen( wxT("black"), 4, wxSOLID) );
+        dc.SetPen( wxPen( *wxBLACK, 4) );
         dc.DrawSpline(5, letters[m]);
     }
 
@@ -1231,6 +1262,7 @@ void MyCanvas::DrawGradients(wxDC& dc)
     r.Offset(0, TEXT_HEIGHT);
     dc.GradientFillLinear(r, *wxWHITE, *wxBLUE, wxUP);
 
+    wxRect  gfr = wxRect(r);
 
     // RHS: concentric
     r = wxRect(200, 10, 50, 50);
@@ -1270,19 +1302,140 @@ void MyCanvas::DrawGradients(wxDC& dc)
     r3.y += 60;
     wxRect r4 = r2;
     r4.y += 60;
-    dc.SetPen(wxPen(wxColour(255, 0, 0)));
+    dc.SetPen(*wxRED_PEN);
     dc.DrawRectangle(r);
     r.Deflate(1);
-    dc.GradientFillLinear(r, wxColour(0,255,0), wxColour(0,0,0), wxNORTH);
+    dc.GradientFillLinear(r, *wxGREEN, *wxBLACK, wxNORTH);
     dc.DrawRectangle(r2);
     r2.Deflate(1);
-    dc.GradientFillLinear(r2, wxColour(0,0,0), wxColour(0,255,0), wxSOUTH);
+    dc.GradientFillLinear(r2, *wxBLACK, *wxGREEN, wxSOUTH);
     dc.DrawRectangle(r3);
     r3.Deflate(1);
-    dc.GradientFillLinear(r3, wxColour(0,255,0), wxColour(0,0,0), wxEAST);
+    dc.GradientFillLinear(r3, *wxGREEN, *wxBLACK, wxEAST);
     dc.DrawRectangle(r4);
     r4.Deflate(1);
-    dc.GradientFillLinear(r4, wxColour(0,0,0), wxColour(0,255,0), wxWEST);
+    dc.GradientFillLinear(r4, *wxBLACK, *wxGREEN, wxWEST);
+
+#if wxUSE_GRAPHICS_CONTEXT
+    if (m_useContext)
+    {
+        wxGCDC                      &gdc = (wxGCDC&)dc;
+        wxGraphicsContext           *gc = gdc.GetGraphicsContext();
+        wxGraphicsPath              pth;
+        wxGraphicsGradientStops     stops;
+
+        gfr.Offset(0, gfr.height + 10);
+        dc.DrawText(wxT("Linear Gradient with Stops"), gfr.x, gfr.y);
+        gfr.Offset(0, TEXT_HEIGHT);
+
+        stops = wxGraphicsGradientStops(*wxRED, *wxBLUE);
+        stops.Add(wxColour(255,255,0), 0.33f);
+        stops.Add(*wxGREEN, 0.67f);
+
+        gc->SetBrush(gc->CreateLinearGradientBrush(gfr.x, gfr.y,
+                                                   gfr.x + gfr.width, gfr.y + gfr.height,
+                                                   stops));
+        pth = gc->CreatePath();
+        pth.MoveToPoint(gfr.x,gfr.y);
+        pth.AddLineToPoint(gfr.x + gfr.width,gfr.y);
+        pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height);
+        pth.AddLineToPoint(gfr.x,gfr.y+gfr.height);
+        pth.CloseSubpath();
+        gc->FillPath(pth);
+
+        gfr.Offset(0, gfr.height + 10);
+        dc.DrawText(wxT("Radial Gradient with Stops"), gfr.x, gfr.y);
+        gfr.Offset(0, TEXT_HEIGHT);
+
+        gc->SetBrush(gc->CreateRadialGradientBrush(gfr.x + gfr.width / 2,
+                                                   gfr.y + gfr.height / 2,
+                                                   gfr.x + gfr.width / 2,
+                                                   gfr.y + gfr.height / 2,
+                                                   gfr.width / 2,
+                                                   stops));
+        pth = gc->CreatePath();
+        pth.MoveToPoint(gfr.x,gfr.y);
+        pth.AddLineToPoint(gfr.x + gfr.width,gfr.y);
+        pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height);
+        pth.AddLineToPoint(gfr.x,gfr.y+gfr.height);
+        pth.CloseSubpath();
+        gc->FillPath(pth);
+
+        gfr.Offset(0, gfr.height + 10);
+        dc.DrawText(wxT("Linear Gradient with Stops and Gaps"), gfr.x, gfr.y);
+        gfr.Offset(0, TEXT_HEIGHT);
+
+        stops = wxGraphicsGradientStops(*wxRED, *wxBLUE);
+        stops.Add(wxColour(255,255,0), 0.33f);
+        stops.Add(wxTransparentColour, 0.33f);
+        stops.Add(wxTransparentColour, 0.67f);
+        stops.Add(*wxGREEN, 0.67f);
+
+        gc->SetBrush(gc->CreateLinearGradientBrush(gfr.x, gfr.y + gfr.height,
+                                                   gfr.x + gfr.width, gfr.y,
+                                                   stops));
+        pth = gc->CreatePath();
+        pth.MoveToPoint(gfr.x,gfr.y);
+        pth.AddLineToPoint(gfr.x + gfr.width,gfr.y);
+        pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height);
+        pth.AddLineToPoint(gfr.x,gfr.y+gfr.height);
+        pth.CloseSubpath();
+        gc->FillPath(pth);
+
+        gfr.Offset(0, gfr.height + 10);
+        dc.DrawText(wxT("Radial Gradient with Stops and Gaps"), gfr.x, gfr.y);
+        gfr.Offset(0, TEXT_HEIGHT);
+
+        gc->SetBrush(gc->CreateRadialGradientBrush(gfr.x + gfr.width / 2,
+                                                   gfr.y + gfr.height / 2,
+                                                   gfr.x + gfr.width / 2,
+                                                   gfr.y + gfr.height / 2,
+                                                   gfr.width / 2,
+                                                   stops));
+        pth = gc->CreatePath();
+        pth.MoveToPoint(gfr.x,gfr.y);
+        pth.AddLineToPoint(gfr.x + gfr.width,gfr.y);
+        pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height);
+        pth.AddLineToPoint(gfr.x,gfr.y+gfr.height);
+        pth.CloseSubpath();
+        gc->FillPath(pth);
+
+        gfr.Offset(0, gfr.height + 10);
+        dc.DrawText(wxT("Gradients with Stops and Transparency"), gfr.x, gfr.y);
+        gfr.Offset(0, TEXT_HEIGHT);
+
+        stops = wxGraphicsGradientStops(*wxRED, wxTransparentColour);
+        stops.Add(*wxRED, 0.33f);
+        stops.Add(wxTransparentColour, 0.33f);
+        stops.Add(wxTransparentColour, 0.67f);
+        stops.Add(*wxBLUE, 0.67f);
+        stops.Add(*wxBLUE, 1.0f);
+
+        pth = gc->CreatePath();
+        pth.MoveToPoint(gfr.x,gfr.y);
+        pth.AddLineToPoint(gfr.x + gfr.width,gfr.y);
+        pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height);
+        pth.AddLineToPoint(gfr.x,gfr.y+gfr.height);
+        pth.CloseSubpath();
+
+        gc->SetBrush(gc->CreateRadialGradientBrush(gfr.x + gfr.width / 2,
+                                                   gfr.y + gfr.height / 2,
+                                                   gfr.x + gfr.width / 2,
+                                                   gfr.y + gfr.height / 2,
+                                                   gfr.width / 2,
+                                                   stops));
+        gc->FillPath(pth);
+
+        stops = wxGraphicsGradientStops(wxColour(255,0,0, 128), wxColour(0,0,255, 128));
+        stops.Add(wxColour(255,255,0,128), 0.33f);
+        stops.Add(wxColour(0,255,0,128), 0.67f);
+
+        gc->SetBrush(gc->CreateLinearGradientBrush(gfr.x, gfr.y,
+                                                   gfr.x + gfr.width, gfr.y,
+                                                   stops));
+        gc->FillPath(pth);
+    }
+#endif // wxUSE_GRAPHICS_CONTEXT
 }
 
 void MyCanvas::DrawRegions(wxDC& dc)
@@ -1330,7 +1483,7 @@ void MyCanvas::DrawRegionsHelper(wxDC& dc, wxCoord x, bool firstTime)
     dc.SetBrush( *wxGREY_BRUSH );
     dc.DrawRectangle( x, y, 310, 310 );
 
-    if (m_smile_bmp.Ok())
+    if (m_smile_bmp.IsOk())
     {
         dc.DrawBitmap( m_smile_bmp, x + 150, y + 150, true );
         dc.DrawBitmap( m_smile_bmp, x + 130, y + 10,  true );
@@ -1340,21 +1493,47 @@ void MyCanvas::DrawRegionsHelper(wxDC& dc, wxCoord x, bool firstTime)
     }
 }
 
-#if TEST_CAIRO_EVERYWHERE
-extern wxGraphicsRenderer* gCairoRenderer;
-#endif
-
 void MyCanvas::OnPaint(wxPaintEvent &WXUNUSED(event))
 {
     wxPaintDC pdc(this);
+    Draw(pdc);
+}
 
+void MyCanvas::Draw(wxDC& pdc)
+{
 #if wxUSE_GRAPHICS_CONTEXT
-#if TEST_CAIRO_EVERYWHERE
     wxGCDC gdc;
-    gdc.SetGraphicsContext( gCairoRenderer->CreateContext( pdc ) );
+    wxGraphicsRenderer* const renderer = wxGraphicsRenderer::
+#if TEST_CAIRO_EVERYWHERE
+        GetCairoRenderer()
 #else
-     wxGCDC gdc( pdc ) ;
+        GetDefaultRenderer()
+#endif
+        ;
+
+    wxGraphicsContext* context;
+    if ( wxPaintDC *paintdc = wxDynamicCast(&pdc, wxPaintDC) )
+    {
+        context = renderer->CreateContext(*paintdc);
+    }
+    else if ( wxMemoryDC *memdc = wxDynamicCast(&pdc, wxMemoryDC) )
+    {
+        context = renderer->CreateContext(*memdc);
+    }
+#if wxUSE_METAFILE && defined(wxMETAFILE_IS_ENH)
+    else if ( wxMetafileDC *metadc = wxDynamicCast(&pdc, wxMetafileDC) )
+    {
+        context = renderer->CreateContext(*metadc);
+    }
 #endif
+    else
+    {
+        wxFAIL_MSG( "Unknown wxDC kind" );
+        return;
+    }
+
+    gdc.SetGraphicsContext(context);
+
     wxDC &dc = m_useContext ? (wxDC&) gdc : (wxDC&) pdc ;
 #else
     wxDC &dc = pdc ;
@@ -1365,18 +1544,16 @@ void MyCanvas::OnPaint(wxPaintEvent &WXUNUSED(event))
     m_owner->PrepareDC(dc);
 
     dc.SetBackgroundMode( m_owner->m_backgroundMode );
-    if ( m_owner->m_backgroundBrush.Ok() )
+    if ( m_owner->m_backgroundBrush.IsOk() )
         dc.SetBackground( m_owner->m_backgroundBrush );
-    if ( m_owner->m_colourForeground.Ok() )
+    if ( m_owner->m_colourForeground.IsOk() )
         dc.SetTextForeground( m_owner->m_colourForeground );
-    if ( m_owner->m_colourBackground.Ok() )
+    if ( m_owner->m_colourBackground.IsOk() )
         dc.SetTextBackground( m_owner->m_colourBackground );
 
     if ( m_owner->m_textureBackground) {
-        if ( ! m_owner->m_backgroundBrush.Ok() ) {
-            wxColour clr(0,128,0);
-            wxBrush b(clr, wxSOLID);
-            dc.SetBackground(b);
+        if ( ! m_owner->m_backgroundBrush.IsOk() ) {
+            dc.SetBackground(wxBrush(wxColour(0, 128, 0)));
         }
     }
 
@@ -1474,7 +1651,7 @@ void MyCanvas::OnMouseMove(wxMouseEvent &event)
         str.Printf( wxT("Current mouse position: %d,%d"), (int)x, (int)y );
         m_owner->SetStatusText( str );
     }
-    
+
     if ( m_rubberBand )
     {
         int x,y, xx, yy ;
@@ -1492,7 +1669,7 @@ void MyCanvas::OnMouseMove(wxMouseEvent &event)
         dc.SetPen( *wxGREY_PEN );
         dc.SetBrush( wxColour( 192,192,192,64 ) );
 #else
-        dc.SetPen( wxPen( *wxLIGHT_GREY, 2, wxSOLID ) );
+        dc.SetPen( wxPen( *wxLIGHT_GREY, 2 ) );
         dc.SetBrush( *wxTRANSPARENT_BRUSH );
 #endif
         dc.DrawRectangle( newrect );
@@ -1504,8 +1681,8 @@ void MyCanvas::OnMouseMove(wxMouseEvent &event)
 
 void MyCanvas::OnMouseDown(wxMouseEvent &event)
 {
-       int x,y,xx,yy ;
-       event.GetPosition(&x,&y);
+    int x,y,xx,yy ;
+    event.GetPosition(&x,&y);
     CalcUnscrolledPosition( x, y, &xx, &yy );
     m_anchorpoint = wxPoint( xx , yy ) ;
     m_currentpoint = m_anchorpoint ;
@@ -1527,15 +1704,15 @@ void MyCanvas::OnMouseUp(wxMouseEvent &event)
         m_overlay.Reset();
         m_rubberBand = false;
 
-        int x,y,xx,yy ;
-        event.GetPosition(&x,&y);
-        CalcUnscrolledPosition( x, y, &xx, &yy );
-        
-        wxString str;
-        str.Printf( wxT("Rectangle selection from %d,%d to %d,%d"), 
-            m_anchorpoint.x, m_anchorpoint.y , (int)xx, (int)yy );
-        wxMessageBox( str , wxT("Rubber-Banding") );
+        wxPoint endpoint = CalcUnscrolledPosition(event.GetPosition());
 
+        // Don't pop up the message box if nothing was actually selected.
+        if ( endpoint != m_anchorpoint )
+        {
+            wxLogMessage("Selected rectangle from (%d, %d) to (%d, %d)",
+                         m_anchorpoint.x, m_anchorpoint.y,
+                         endpoint.x, endpoint.y);
+        }
     }
 }
 
@@ -1553,6 +1730,8 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
 #if wxUSE_GRAPHICS_CONTEXT
     EVT_MENU      (File_GraphicContext, MyFrame::OnGraphicContext)
 #endif
+    EVT_MENU      (File_Copy,     MyFrame::OnCopy)
+    EVT_MENU      (File_Save,     MyFrame::OnSave)
 
     EVT_MENU_RANGE(MenuShow_First,   MenuShow_Last,   MyFrame::OnShow)
 
@@ -1565,7 +1744,7 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
                  wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE)
 {
     // set the frame icon
-    SetIcon(wxICON(mondrian));
+    SetIcon(wxICON(sample));
 
     wxMenu *menuFile = new wxMenu;
     menuFile->Append(File_ShowDefault, wxT("&Default screen\tF1"));
@@ -1581,7 +1760,7 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
 #if wxUSE_GRAPHICS_CONTEXT
     menuFile->Append(File_ShowAlpha, wxT("&Alpha screen\tF10"));
 #endif
-    menuFile->Append(File_ShowSplines, wxT("&Splines screen\tF11"));
+    menuFile->Append(File_ShowSplines, wxT("Spl&ines screen\tF11"));
     menuFile->Append(File_ShowGradients, wxT("&Gradients screen\tF12"));
 #if wxUSE_GRAPHICS_CONTEXT
      menuFile->Append(File_ShowGraphics, wxT("&Graphics screen"));
@@ -1592,7 +1771,12 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
     menuFile->AppendCheckItem(File_GraphicContext, wxT("&Use GraphicContext\tCtrl-Y"), wxT("Use GraphicContext"));
 #endif
     menuFile->AppendSeparator();
-    menuFile->Append(File_About, wxT("&About...\tCtrl-A"), wxT("Show about dialog"));
+#if wxUSE_METAFILE && defined(wxMETAFILE_IS_ENH)
+    menuFile->Append(File_Copy, wxT("Copy to clipboard"));
+#endif
+    menuFile->Append(File_Save, wxT("&Save...\tCtrl-S"), wxT("Save drawing to file"));
+    menuFile->AppendSeparator();
+    menuFile->Append(File_About, wxT("&About\tCtrl-A"), wxT("Show about dialog"));
     menuFile->AppendSeparator();
     menuFile->Append(File_Quit, wxT("E&xit\tAlt-X"), wxT("Quit this program"));
 
@@ -1658,8 +1842,8 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
     m_xAxisReversed =
     m_yAxisReversed = false;
     m_backgroundMode = wxSOLID;
-    m_colourForeground = *wxRED;
-    m_colourBackground = *wxBLUE;
+    m_colourForeground = *wxBLACK;
+    m_colourBackground = *wxLIGHT_GREY;
     m_textureBackground = false;
 
     m_canvas = new MyCanvas( this );
@@ -1698,6 +1882,38 @@ void MyFrame::OnGraphicContext(wxCommandEvent& event)
 }
 #endif
 
+void MyFrame::OnCopy(wxCommandEvent& WXUNUSED(event))
+{
+#if wxUSE_METAFILE && defined(wxMETAFILE_IS_ENH)
+    wxMetafileDC dc;
+    if (!dc.IsOk())
+        return;
+    m_canvas->Draw(dc);
+    wxMetafile *mf = dc.Close();
+    if (!mf)
+        return;
+    mf->SetClipboard();
+    delete mf;
+#endif
+}
+
+void MyFrame::OnSave(wxCommandEvent& WXUNUSED(event))
+{
+    wxFileDialog dlg(this, wxT("Save as bitmap"), wxT(""), wxT(""),
+#if wxUSE_LIBPNG
+                     wxT("PNG image (*.png)|*.png;*.PNG|")
+#endif
+                     wxT("Bitmap image (*.bmp)|*.bmp;*.BMP"),
+                     wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+    if (dlg.ShowModal() == wxID_OK)
+    {
+        wxBitmap bmp(500, 800);
+        wxMemoryDC mdc(bmp);
+        m_canvas->Draw(mdc);
+        bmp.ConvertToImage().SaveFile(dlg.GetPath());
+    }
+}
+
 void MyFrame::OnShow(wxCommandEvent& event)
 {
     m_canvas->ToShow(event.GetId());
@@ -1778,7 +1994,7 @@ void MyFrame::OnOption(wxCommandEvent& event)
         case Colour_Background:
             {
                 wxColour col = SelectColour();
-                if ( col.Ok() )
+                if ( col.IsOk() )
                 {
                     m_backgroundBrush.SetColour(col);
                 }