bb489418b0
This has the disadvantage of not using the same accelerators in different wxWidgets builds, but the advantage of appearing logical to a casual user when running the sample, while having "0, 1, 3, 4" sequence was surprising. Alternatively, we could always add all menu items, but disable the ones that are not available in the current build. It could be surprising to see "GDI+" under non-MSW systems too though.
2752 lines
88 KiB
C++
2752 lines
88 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: samples/drawing/drawing.cpp
|
|
// Purpose: shows and tests wxDC features
|
|
// Author: Robert Roebling
|
|
// Modified by:
|
|
// Created: 04/01/98
|
|
// Copyright: (c) Robert Roebling
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ============================================================================
|
|
// declarations
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// For compilers that support precompilation, includes "wx/wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
// for all others, include the necessary headers (this file is usually all you
|
|
// need because it includes almost all "standard" wxWidgets headers
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/wx.h"
|
|
#endif
|
|
|
|
#include "wx/colordlg.h"
|
|
#include "wx/image.h"
|
|
#include "wx/artprov.h"
|
|
#include "wx/dcbuffer.h"
|
|
#include "wx/dcgraph.h"
|
|
#include "wx/overlay.h"
|
|
#include "wx/graphics.h"
|
|
#include "wx/filename.h"
|
|
#include "wx/metafile.h"
|
|
#include "wx/settings.h"
|
|
#if wxUSE_SVG
|
|
#include "wx/dcsvg.h"
|
|
#endif
|
|
#if wxUSE_POSTSCRIPT
|
|
#include "wx/dcps.h"
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// resources
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// the application icon
|
|
#ifndef wxHAS_IMAGES_IN_RESOURCES
|
|
#include "../sample.xpm"
|
|
#endif
|
|
|
|
// Standard DC supports drawing with alpha on OSX and GTK3.
|
|
#if defined(__WXOSX__) || defined(__WXGTK3__)
|
|
#define wxDRAWING_DC_SUPPORTS_ALPHA 1
|
|
#else
|
|
#define wxDRAWING_DC_SUPPORTS_ALPHA 0
|
|
#endif // __WXOSX__ || __WXGTK3__
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// global variables
|
|
// ----------------------------------------------------------------------------
|
|
|
|
static wxBitmap *gs_bmpNoMask = NULL,
|
|
*gs_bmpWithColMask = NULL,
|
|
*gs_bmpMask = NULL,
|
|
*gs_bmpWithMask = NULL,
|
|
*gs_bmp4 = NULL,
|
|
*gs_bmp4_mono = NULL,
|
|
*gs_bmp36 = NULL;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// private classes
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Define a new application type, each program should derive a class from wxApp
|
|
class MyApp : public wxApp
|
|
{
|
|
public:
|
|
// override base class virtuals
|
|
// ----------------------------
|
|
|
|
// this one is called on application startup and is a good place for the app
|
|
// initialization (doing it here and not in the ctor allows to have an error
|
|
// return: if OnInit() returns false, the application terminates)
|
|
virtual bool OnInit() wxOVERRIDE;
|
|
|
|
virtual int OnExit() wxOVERRIDE { DeleteBitmaps(); return 0; }
|
|
|
|
protected:
|
|
void DeleteBitmaps();
|
|
|
|
bool LoadImages();
|
|
};
|
|
|
|
class MyFrame;
|
|
|
|
// define a scrollable canvas for drawing onto
|
|
class MyCanvas: public wxScrolledWindow
|
|
{
|
|
public:
|
|
MyCanvas( MyFrame *parent );
|
|
|
|
void OnPaint(wxPaintEvent &event);
|
|
void OnMouseMove(wxMouseEvent &event);
|
|
void OnMouseDown(wxMouseEvent &event);
|
|
void OnMouseUp(wxMouseEvent &event);
|
|
|
|
void ToShow(int show) { m_show = show; Refresh(); }
|
|
int GetPage() { return m_show; }
|
|
|
|
// set or remove the clipping region
|
|
void Clip(bool clip) { m_clip = clip; Refresh(); }
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
bool HasRenderer() const { return m_renderer != NULL; }
|
|
void UseGraphicRenderer(wxGraphicsRenderer* renderer);
|
|
bool IsDefaultRenderer() const
|
|
{ if ( !m_renderer ) return false;
|
|
return m_renderer == wxGraphicsRenderer::GetDefaultRenderer();
|
|
}
|
|
wxGraphicsRenderer* GetRenderer() const { return m_renderer; }
|
|
void EnableAntiAliasing(bool use) { m_useAntiAliasing = use; Refresh(); }
|
|
#endif // wxUSE_GRAPHICS_CONTEXT
|
|
void UseBuffer(bool use) { m_useBuffer = use; Refresh(); }
|
|
void ShowBoundingBox(bool show) { m_showBBox = show; Refresh(); }
|
|
void GetDrawingSize(int* width, int* height) const;
|
|
|
|
void Draw(wxDC& dc);
|
|
|
|
protected:
|
|
enum DrawMode
|
|
{
|
|
Draw_Normal,
|
|
Draw_Stretch
|
|
};
|
|
|
|
void DrawTestLines( int x, int y, int width, wxDC &dc );
|
|
void DrawCrossHair(int x, int y, int width, int heigth, wxDC &dc);
|
|
void DrawTestPoly(wxDC& dc);
|
|
void DrawTestBrushes(wxDC& dc);
|
|
void DrawText(wxDC& dc);
|
|
void DrawImages(wxDC& dc, DrawMode mode);
|
|
void DrawWithLogicalOps(wxDC& dc);
|
|
#if wxDRAWING_DC_SUPPORTS_ALPHA || wxUSE_GRAPHICS_CONTEXT
|
|
void DrawAlpha(wxDC& dc);
|
|
#endif
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
void DrawGraphics(wxGraphicsContext* gc);
|
|
#endif
|
|
void DrawRegions(wxDC& dc);
|
|
void DrawCircles(wxDC& dc);
|
|
void DrawSplines(wxDC& dc);
|
|
void DrawDefault(wxDC& dc);
|
|
void DrawGradients(wxDC& dc);
|
|
void DrawSystemColours(wxDC& dc);
|
|
|
|
void DrawRegionsHelper(wxDC& dc, wxCoord x, bool firstTime);
|
|
|
|
private:
|
|
MyFrame *m_owner;
|
|
|
|
int m_show;
|
|
wxBitmap m_smile_bmp;
|
|
wxIcon m_std_icon;
|
|
bool m_clip;
|
|
wxOverlay m_overlay;
|
|
bool m_rubberBand;
|
|
wxPoint m_anchorpoint;
|
|
wxPoint m_currentpoint;
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
wxGraphicsRenderer* m_renderer;
|
|
bool m_useAntiAliasing;
|
|
#endif
|
|
bool m_useBuffer;
|
|
bool m_showBBox;
|
|
wxCoord m_sizeX;
|
|
wxCoord m_sizeY;
|
|
|
|
wxDECLARE_EVENT_TABLE();
|
|
};
|
|
|
|
|
|
// Define a new frame type: this is going to be our main frame
|
|
class MyFrame : public wxFrame
|
|
{
|
|
public:
|
|
// ctor(s)
|
|
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
|
|
|
|
// event handlers (these functions should _not_ be virtual)
|
|
void OnQuit(wxCommandEvent& event);
|
|
void OnAbout(wxCommandEvent& event);
|
|
void OnClip(wxCommandEvent& event);
|
|
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
void OnGraphicContextNone(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
m_canvas->UseGraphicRenderer(NULL);
|
|
}
|
|
|
|
void OnGraphicContextDefault(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
m_canvas->UseGraphicRenderer(wxGraphicsRenderer::GetDefaultRenderer());
|
|
}
|
|
|
|
#if wxUSE_CAIRO
|
|
void OnGraphicContextCairo(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
m_canvas->UseGraphicRenderer(wxGraphicsRenderer::GetCairoRenderer());
|
|
}
|
|
#endif // wxUSE_CAIRO
|
|
#ifdef __WXMSW__
|
|
#if wxUSE_GRAPHICS_GDIPLUS
|
|
void OnGraphicContextGDIPlus(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
m_canvas->UseGraphicRenderer(wxGraphicsRenderer::GetGDIPlusRenderer());
|
|
}
|
|
#endif
|
|
#if wxUSE_GRAPHICS_DIRECT2D
|
|
void OnGraphicContextDirect2D(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
m_canvas->UseGraphicRenderer(wxGraphicsRenderer::GetDirect2DRenderer());
|
|
}
|
|
#endif
|
|
#endif // __WXMSW__
|
|
void OnAntiAliasing(wxCommandEvent& event)
|
|
{
|
|
m_canvas->EnableAntiAliasing(event.IsChecked());
|
|
}
|
|
|
|
void OnAntiAliasingUpdateUI(wxUpdateUIEvent& event)
|
|
{
|
|
event.Enable(m_canvas->GetRenderer() != NULL);
|
|
}
|
|
#endif // wxUSE_GRAPHICS_CONTEXT
|
|
|
|
void OnBuffer(wxCommandEvent& event);
|
|
void OnCopy(wxCommandEvent& event);
|
|
void OnSave(wxCommandEvent& event);
|
|
void OnShow(wxCommandEvent &event);
|
|
void OnOption(wxCommandEvent &event);
|
|
void OnBoundingBox(wxCommandEvent& evt);
|
|
void OnBoundingBoxUpdateUI(wxUpdateUIEvent& evt);
|
|
|
|
#if wxUSE_COLOURDLG
|
|
wxColour SelectColour();
|
|
#endif // wxUSE_COLOURDLG
|
|
void PrepareDC(wxDC& dc) wxOVERRIDE;
|
|
|
|
int m_backgroundMode;
|
|
int m_textureBackground;
|
|
wxMappingMode m_mapMode;
|
|
double m_xUserScale;
|
|
double m_yUserScale;
|
|
int m_xLogicalOrigin;
|
|
int m_yLogicalOrigin;
|
|
bool m_xAxisReversed,
|
|
m_yAxisReversed;
|
|
#if wxUSE_DC_TRANSFORM_MATRIX
|
|
wxDouble m_transform_dx;
|
|
wxDouble m_transform_dy;
|
|
wxDouble m_transform_scx;
|
|
wxDouble m_transform_scy;
|
|
wxDouble m_transform_rot;
|
|
#endif // wxUSE_DC_TRANSFORM_MATRIX
|
|
wxColour m_colourForeground, // these are _text_ colours
|
|
m_colourBackground;
|
|
wxBrush m_backgroundBrush;
|
|
MyCanvas *m_canvas;
|
|
wxMenuItem *m_menuItemUseDC;
|
|
private:
|
|
// any class wishing to process wxWidgets events must use this macro
|
|
wxDECLARE_EVENT_TABLE();
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// constants
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// IDs for the controls and the menu commands
|
|
enum
|
|
{
|
|
// menu items
|
|
File_Quit = wxID_EXIT,
|
|
File_About = wxID_ABOUT,
|
|
|
|
MenuShow_First = wxID_HIGHEST,
|
|
File_ShowDefault = MenuShow_First,
|
|
File_ShowText,
|
|
File_ShowLines,
|
|
File_ShowBrushes,
|
|
File_ShowPolygons,
|
|
File_ShowMask,
|
|
File_ShowMaskStretch,
|
|
File_ShowOps,
|
|
File_ShowRegions,
|
|
File_ShowCircles,
|
|
File_ShowSplines,
|
|
#if wxDRAWING_DC_SUPPORTS_ALPHA || wxUSE_GRAPHICS_CONTEXT
|
|
File_ShowAlpha,
|
|
#endif // wxDRAWING_DC_SUPPORTS_ALPHA || wxUSE_GRAPHICS_CONTEXT
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
File_ShowGraphics,
|
|
#endif
|
|
File_ShowSystemColours,
|
|
File_ShowGradients,
|
|
MenuShow_Last = File_ShowGradients,
|
|
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
File_DC,
|
|
File_GC_Default,
|
|
#if wxUSE_CAIRO
|
|
File_GC_Cairo,
|
|
#endif // wxUSE_CAIRO
|
|
#ifdef __WXMSW__
|
|
#if wxUSE_GRAPHICS_GDIPLUS
|
|
File_GC_GDIPlus,
|
|
#endif
|
|
#if wxUSE_GRAPHICS_DIRECT2D
|
|
File_GC_Direct2D,
|
|
#endif
|
|
#endif // __WXMSW__
|
|
#endif // wxUSE_GRAPHICS_CONTEXT
|
|
File_BBox,
|
|
File_Clip,
|
|
File_Buffer,
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
File_AntiAliasing,
|
|
#endif
|
|
File_Copy,
|
|
File_Save,
|
|
|
|
MenuOption_First,
|
|
|
|
MapMode_Text = MenuOption_First,
|
|
MapMode_Lometric,
|
|
MapMode_Twips,
|
|
MapMode_Points,
|
|
MapMode_Metric,
|
|
|
|
UserScale_StretchHoriz,
|
|
UserScale_ShrinkHoriz,
|
|
UserScale_StretchVertic,
|
|
UserScale_ShrinkVertic,
|
|
UserScale_Restore,
|
|
|
|
AxisMirror_Horiz,
|
|
AxisMirror_Vertic,
|
|
|
|
LogicalOrigin_MoveDown,
|
|
LogicalOrigin_MoveUp,
|
|
LogicalOrigin_MoveLeft,
|
|
LogicalOrigin_MoveRight,
|
|
LogicalOrigin_Set,
|
|
LogicalOrigin_Restore,
|
|
|
|
#if wxUSE_DC_TRANSFORM_MATRIX
|
|
TransformMatrix_Set,
|
|
TransformMatrix_Reset,
|
|
#endif // wxUSE_DC_TRANSFORM_MATRIX
|
|
|
|
#if wxUSE_COLOURDLG
|
|
Colour_TextForeground,
|
|
Colour_TextBackground,
|
|
Colour_Background,
|
|
#endif // wxUSE_COLOURDLG
|
|
Colour_BackgroundMode,
|
|
Colour_TextureBackgound,
|
|
|
|
MenuOption_Last = Colour_TextureBackgound
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// event tables and other macros for wxWidgets
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
// Create a new application object: this macro will allow wxWidgets to create
|
|
// the application object during program execution (it's better than using a
|
|
// static object for many reasons) and also declares the accessor function
|
|
// wxGetApp() which will return the reference of the right type (i.e. MyApp and
|
|
// not wxApp)
|
|
wxIMPLEMENT_APP(MyApp);
|
|
|
|
// ============================================================================
|
|
// implementation
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// the application class
|
|
// ----------------------------------------------------------------------------
|
|
|
|
bool MyApp::LoadImages()
|
|
{
|
|
gs_bmpNoMask = new wxBitmap;
|
|
gs_bmpWithColMask = new wxBitmap;
|
|
gs_bmpMask = new wxBitmap;
|
|
gs_bmpWithMask = new wxBitmap;
|
|
gs_bmp4 = new wxBitmap;
|
|
gs_bmp4_mono = new wxBitmap;
|
|
gs_bmp36 = new wxBitmap;
|
|
|
|
wxPathList pathList;
|
|
// special hack for Unix in-tree sample build, don't do this in real
|
|
// programs, use wxStandardPaths instead
|
|
pathList.Add(wxFileName(argv[0]).GetPath());
|
|
pathList.Add(".");
|
|
pathList.Add("..");
|
|
pathList.Add("../drawing");
|
|
pathList.Add("../../../samples/drawing");
|
|
|
|
wxString path = pathList.FindValidPath("pat4.bmp");
|
|
if ( !path )
|
|
return false;
|
|
|
|
/* 4 colour bitmap */
|
|
gs_bmp4->LoadFile(path, wxBITMAP_TYPE_BMP);
|
|
/* turn into mono-bitmap */
|
|
gs_bmp4_mono->LoadFile(path, wxBITMAP_TYPE_BMP);
|
|
wxMask* mask4 = new wxMask(*gs_bmp4_mono, *wxBLACK);
|
|
gs_bmp4_mono->SetMask(mask4);
|
|
|
|
path = pathList.FindValidPath("pat36.bmp");
|
|
if ( !path )
|
|
return false;
|
|
gs_bmp36->LoadFile(path, wxBITMAP_TYPE_BMP);
|
|
wxMask* mask36 = new wxMask(*gs_bmp36, *wxBLACK);
|
|
gs_bmp36->SetMask(mask36);
|
|
|
|
path = pathList.FindValidPath("image.bmp");
|
|
if ( !path )
|
|
return false;
|
|
gs_bmpNoMask->LoadFile(path, wxBITMAP_TYPE_BMP);
|
|
gs_bmpWithMask->LoadFile(path, wxBITMAP_TYPE_BMP);
|
|
gs_bmpWithColMask->LoadFile(path, wxBITMAP_TYPE_BMP);
|
|
|
|
path = pathList.FindValidPath("mask.bmp");
|
|
if ( !path )
|
|
return false;
|
|
gs_bmpMask->LoadFile(path, wxBITMAP_TYPE_BMP);
|
|
|
|
wxMask *mask = new wxMask(*gs_bmpMask, *wxBLACK);
|
|
gs_bmpWithMask->SetMask(mask);
|
|
|
|
mask = new wxMask(*gs_bmpWithColMask, *wxWHITE);
|
|
gs_bmpWithColMask->SetMask(mask);
|
|
|
|
return true;
|
|
}
|
|
|
|
// `Main program' equivalent: the program execution "starts" here
|
|
bool MyApp::OnInit()
|
|
{
|
|
if ( !wxApp::OnInit() )
|
|
return false;
|
|
|
|
#if wxUSE_LIBPNG
|
|
wxImage::AddHandler( new wxPNGHandler );
|
|
#endif
|
|
|
|
// Create the main application window
|
|
MyFrame *frame = new MyFrame("Drawing sample",
|
|
wxDefaultPosition, wxSize(550, 840));
|
|
|
|
// Show it
|
|
frame->Show(true);
|
|
|
|
if ( !LoadImages() )
|
|
{
|
|
wxLogError("Can't load one of the bitmap files needed "
|
|
"for this sample from the current or parent "
|
|
"directory, please copy them there.");
|
|
|
|
// still continue, the sample can be used without images too if they're
|
|
// missing for whatever reason
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void MyApp::DeleteBitmaps()
|
|
{
|
|
wxDELETE(gs_bmpNoMask);
|
|
wxDELETE(gs_bmpWithColMask);
|
|
wxDELETE(gs_bmpMask);
|
|
wxDELETE(gs_bmpWithMask);
|
|
wxDELETE(gs_bmp4);
|
|
wxDELETE(gs_bmp4_mono);
|
|
wxDELETE(gs_bmp36);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// MyCanvas
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// the event tables connect the wxWidgets events with the functions (event
|
|
// handlers) which process them.
|
|
wxBEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
|
|
EVT_PAINT (MyCanvas::OnPaint)
|
|
EVT_MOTION (MyCanvas::OnMouseMove)
|
|
EVT_LEFT_DOWN (MyCanvas::OnMouseDown)
|
|
EVT_LEFT_UP (MyCanvas::OnMouseUp)
|
|
wxEND_EVENT_TABLE()
|
|
|
|
#include "smile.xpm"
|
|
|
|
MyCanvas::MyCanvas(MyFrame *parent)
|
|
: wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
|
|
wxHSCROLL | wxVSCROLL)
|
|
{
|
|
m_owner = parent;
|
|
m_show = File_ShowDefault;
|
|
m_smile_bmp = wxBitmap(smile_xpm);
|
|
m_std_icon = wxArtProvider::GetIcon(wxART_INFORMATION);
|
|
m_clip = false;
|
|
m_rubberBand = false;
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
m_renderer = NULL;
|
|
m_useAntiAliasing = true;
|
|
#endif
|
|
m_useBuffer = false;
|
|
m_showBBox = false;
|
|
m_sizeX = 0;
|
|
m_sizeY = 0;
|
|
}
|
|
|
|
void MyCanvas::DrawTestBrushes(wxDC& dc)
|
|
{
|
|
static const wxCoord WIDTH = 200;
|
|
static const wxCoord HEIGHT = 80;
|
|
|
|
wxCoord x = 10,
|
|
y = 10;
|
|
|
|
dc.SetBrush(*wxGREEN_BRUSH);
|
|
dc.DrawRectangle(x, y, WIDTH, HEIGHT);
|
|
dc.DrawText("Solid green", x + 10, y + 10);
|
|
|
|
y += HEIGHT;
|
|
dc.SetBrush(wxBrush(*wxRED, wxBRUSHSTYLE_CROSSDIAG_HATCH));
|
|
dc.DrawRectangle(x, y, WIDTH, HEIGHT);
|
|
dc.DrawText("Diagonally hatched red", x + 10, y + 10);
|
|
|
|
y += HEIGHT;
|
|
dc.SetBrush(wxBrush(*wxBLUE, wxBRUSHSTYLE_CROSS_HATCH));
|
|
dc.DrawRectangle(x, y, WIDTH, HEIGHT);
|
|
dc.DrawText("Cross hatched blue", x + 10, y + 10);
|
|
|
|
y += HEIGHT;
|
|
dc.SetBrush(wxBrush(*wxCYAN, wxBRUSHSTYLE_VERTICAL_HATCH));
|
|
dc.DrawRectangle(x, y, WIDTH, HEIGHT);
|
|
dc.DrawText("Vertically hatched cyan", x + 10, y + 10);
|
|
|
|
y += HEIGHT;
|
|
dc.SetBrush(wxBrush(*wxBLACK, wxBRUSHSTYLE_HORIZONTAL_HATCH));
|
|
dc.DrawRectangle(x, y, WIDTH, HEIGHT);
|
|
dc.DrawText("Horizontally hatched black", x + 10, y + 10);
|
|
|
|
y += HEIGHT;
|
|
dc.SetBrush(wxBrush(*gs_bmpMask));
|
|
dc.DrawRectangle(x, y, WIDTH, HEIGHT);
|
|
dc.DrawText("Stipple mono", x + 10, y + 10);
|
|
|
|
y += HEIGHT;
|
|
dc.SetBrush(wxBrush(*gs_bmpNoMask));
|
|
dc.DrawRectangle(x, y, WIDTH, HEIGHT);
|
|
dc.DrawText("Stipple colour", x + 10, y + 10);
|
|
}
|
|
|
|
void MyCanvas::DrawTestPoly(wxDC& dc)
|
|
{
|
|
wxBrush brushHatch(*wxRED, wxBRUSHSTYLE_FDIAGONAL_HATCH);
|
|
dc.SetBrush(brushHatch);
|
|
|
|
wxPoint star[5];
|
|
star[0] = wxPoint(100, 60);
|
|
star[1] = wxPoint(60, 150);
|
|
star[2] = wxPoint(160, 100);
|
|
star[3] = wxPoint(40, 100);
|
|
star[4] = wxPoint(140, 150);
|
|
|
|
dc.DrawText("You should see two (irregular) stars below, the left one "
|
|
"hatched", 10, 10);
|
|
dc.DrawText("except for the central region and the right "
|
|
"one entirely hatched", 10, 30);
|
|
dc.DrawText("The third star only has a hatched outline", 10, 50);
|
|
|
|
dc.DrawPolygon(WXSIZEOF(star), star, 0, 30);
|
|
dc.DrawPolygon(WXSIZEOF(star), star, 160, 30, wxWINDING_RULE);
|
|
|
|
wxBrush brushHatchGreen(*wxGREEN, wxBRUSHSTYLE_FDIAGONAL_HATCH);
|
|
dc.SetBrush(brushHatchGreen);
|
|
wxPoint star2[10];
|
|
star2[0] = wxPoint(0, 100);
|
|
star2[1] = wxPoint(-59, -81);
|
|
star2[2] = wxPoint(95, 31);
|
|
star2[3] = wxPoint(-95, 31);
|
|
star2[4] = wxPoint(59, -81);
|
|
star2[5] = wxPoint(0, 80);
|
|
star2[6] = wxPoint(-47, -64);
|
|
star2[7] = wxPoint(76, 24);
|
|
star2[8] = wxPoint(-76, 24);
|
|
star2[9] = wxPoint(47, -64);
|
|
int count[2] = {5, 5};
|
|
|
|
dc.DrawPolyPolygon(WXSIZEOF(count), count, star2, 450, 150);
|
|
}
|
|
|
|
void MyCanvas::DrawTestLines( int x, int y, int width, wxDC &dc )
|
|
{
|
|
dc.SetPen( wxPen( *wxBLACK, width ) );
|
|
dc.SetBrush( *wxWHITE_BRUSH );
|
|
dc.DrawText(wxString::Format("Testing lines of width %d", width), x + 10, y - 10);
|
|
dc.DrawRectangle( x+10, y+10, 100, 190 );
|
|
|
|
dc.DrawText("Solid/dot/short dash/long dash/dot dash", x + 150, y + 10);
|
|
dc.SetPen( wxPen( *wxBLACK, width ) );
|
|
dc.DrawLine( x+20, y+20, 100, y+20 );
|
|
dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_DOT) );
|
|
dc.DrawLine( x+20, y+30, 100, y+30 );
|
|
dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_SHORT_DASH) );
|
|
dc.DrawLine( x+20, y+40, 100, y+40 );
|
|
dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_LONG_DASH) );
|
|
dc.DrawLine( x+20, y+50, 100, y+50 );
|
|
dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_DOT_DASH) );
|
|
dc.DrawLine( x+20, y+60, 100, y+60 );
|
|
|
|
dc.DrawText("Hatches", x + 150, y + 70);
|
|
dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_BDIAGONAL_HATCH) );
|
|
dc.DrawLine( x+20, y+70, 100, y+70 );
|
|
dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_CROSSDIAG_HATCH) );
|
|
dc.DrawLine( x+20, y+80, 100, y+80 );
|
|
dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_FDIAGONAL_HATCH) );
|
|
dc.DrawLine( x+20, y+90, 100, y+90 );
|
|
dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_CROSS_HATCH) );
|
|
dc.DrawLine( x+20, y+100, 100, y+100 );
|
|
dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_HORIZONTAL_HATCH) );
|
|
dc.DrawLine( x+20, y+110, 100, y+110 );
|
|
dc.SetPen( wxPen( *wxBLACK, width, wxPENSTYLE_VERTICAL_HATCH) );
|
|
dc.DrawLine( x+20, y+120, 100, y+120 );
|
|
|
|
dc.DrawText("User dash", x + 150, y + 140);
|
|
wxPen ud( *wxBLACK, width, wxPENSTYLE_USER_DASH );
|
|
wxDash dash1[6];
|
|
dash1[0] = 8; // Long dash <---------+
|
|
dash1[1] = 2; // Short gap |
|
|
dash1[2] = 3; // Short dash |
|
|
dash1[3] = 2; // Short gap |
|
|
dash1[4] = 3; // Short dash |
|
|
dash1[5] = 2; // Short gap and repeat +
|
|
ud.SetDashes( 6, dash1 );
|
|
dc.SetPen( ud );
|
|
dc.DrawLine( x+20, y+140, 100, y+140 );
|
|
dash1[0] = 5; // Make first dash shorter
|
|
ud.SetDashes( 6, dash1 );
|
|
dc.SetPen( ud );
|
|
dc.DrawLine( x+20, y+150, 100, y+150 );
|
|
dash1[2] = 5; // Make second dash longer
|
|
ud.SetDashes( 6, dash1 );
|
|
dc.SetPen( ud );
|
|
dc.DrawLine( x+20, y+160, 100, y+160 );
|
|
dash1[4] = 5; // Make third dash longer
|
|
ud.SetDashes( 6, dash1 );
|
|
dc.SetPen( ud );
|
|
dc.DrawLine( x+20, y+170, 100, y+170 );
|
|
|
|
wxPen penWithCap(*wxBLACK, width);
|
|
dc.SetPen(penWithCap);
|
|
dc.DrawText("Default cap", x+270, y+40);
|
|
dc.DrawLine( x+200, y+50, x+250, y+50);
|
|
|
|
penWithCap.SetCap(wxCAP_BUTT);
|
|
dc.SetPen(penWithCap);
|
|
dc.DrawText("Butt ", x+270, y+60);
|
|
dc.DrawLine( x+200, y+70, x+250, y+70);
|
|
|
|
penWithCap.SetCap(wxCAP_ROUND);
|
|
dc.SetPen(penWithCap);
|
|
dc.DrawText("Round cap", x+270, y+80);
|
|
dc.DrawLine( x+200, y+90, x+250, y+90);
|
|
|
|
penWithCap.SetCap(wxCAP_PROJECTING);
|
|
dc.SetPen(penWithCap);
|
|
dc.DrawText("Projecting cap", x+270, y+100);
|
|
dc.DrawLine( x+200, y+110, x+250, y+110);
|
|
}
|
|
|
|
void MyCanvas::DrawCrossHair(int x, int y, int width, int heigth, wxDC &dc)
|
|
{
|
|
dc.DrawText("Cross hair", x + 10, y + 10);
|
|
dc.SetClippingRegion(x, y, width, heigth);
|
|
dc.SetPen(wxPen(*wxBLUE, 2));
|
|
dc.CrossHair(x + width / 2, y + heigth / 2);
|
|
dc.DestroyClippingRegion();
|
|
}
|
|
|
|
void MyCanvas::DrawDefault(wxDC& dc)
|
|
{
|
|
// 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);
|
|
dc.DrawCheckMark(60, 80, 60, 60);
|
|
|
|
// this is the test for "blitting bitmap into DC damages selected brush" bug
|
|
wxCoord rectSize = m_std_icon.GetWidth() + 10;
|
|
wxCoord x = 100;
|
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
|
dc.SetBrush( *wxGREEN_BRUSH );
|
|
dc.DrawRectangle(x, 10, rectSize, rectSize);
|
|
dc.DrawBitmap(m_std_icon, x + 5, 15, true);
|
|
x += rectSize + 10;
|
|
dc.DrawRectangle(x, 10, rectSize, rectSize);
|
|
dc.DrawIcon(m_std_icon, x + 5, 15);
|
|
x += rectSize + 10;
|
|
dc.DrawRectangle(x, 10, rectSize, rectSize);
|
|
|
|
// test for "transparent" bitmap drawing (it intersects with the last
|
|
// rectangle above)
|
|
//dc.SetBrush( *wxTRANSPARENT_BRUSH );
|
|
|
|
if (m_smile_bmp.IsOk())
|
|
dc.DrawBitmap(m_smile_bmp, x + rectSize - 20, rectSize - 10, true);
|
|
|
|
dc.SetBrush( *wxBLACK_BRUSH );
|
|
dc.DrawRectangle( 0, 160, 1000, 300 );
|
|
|
|
// draw lines
|
|
wxBitmap bitmap(20,70);
|
|
wxMemoryDC memdc;
|
|
memdc.SelectObject( bitmap );
|
|
memdc.SetBrush( *wxBLACK_BRUSH );
|
|
memdc.SetPen( *wxWHITE_PEN );
|
|
memdc.DrawRectangle(0,0,20,70);
|
|
memdc.DrawLine( 10,0,10,70 );
|
|
|
|
// to the right
|
|
wxPen pen = *wxRED_PEN;
|
|
memdc.SetPen(pen);
|
|
memdc.DrawLine( 10, 5,10, 5 );
|
|
memdc.DrawLine( 10,10,11,10 );
|
|
memdc.DrawLine( 10,15,12,15 );
|
|
memdc.DrawLine( 10,20,13,20 );
|
|
|
|
/*
|
|
memdc.SetPen(*wxRED_PEN);
|
|
memdc.DrawLine( 12, 5,12, 5 );
|
|
memdc.DrawLine( 12,10,13,10 );
|
|
memdc.DrawLine( 12,15,14,15 );
|
|
memdc.DrawLine( 12,20,15,20 );
|
|
*/
|
|
|
|
// same to the left
|
|
memdc.DrawLine( 10,25,10,25 );
|
|
memdc.DrawLine( 10,30, 9,30 );
|
|
memdc.DrawLine( 10,35, 8,35 );
|
|
memdc.DrawLine( 10,40, 7,40 );
|
|
|
|
// XOR draw lines
|
|
dc.SetPen(*wxWHITE_PEN);
|
|
memdc.SetLogicalFunction( wxINVERT );
|
|
memdc.SetPen( *wxWHITE_PEN );
|
|
memdc.DrawLine( 10,50,10,50 );
|
|
memdc.DrawLine( 10,55,11,55 );
|
|
memdc.DrawLine( 10,60,12,60 );
|
|
memdc.DrawLine( 10,65,13,65 );
|
|
|
|
memdc.DrawLine( 12,50,12,50 );
|
|
memdc.DrawLine( 12,55,13,55 );
|
|
memdc.DrawLine( 12,60,14,60 );
|
|
memdc.DrawLine( 12,65,15,65 );
|
|
|
|
memdc.SelectObject( wxNullBitmap );
|
|
dc.DrawBitmap( bitmap, 10, 170 );
|
|
wxImage image = bitmap.ConvertToImage();
|
|
image.Rescale( 60,210 );
|
|
bitmap = wxBitmap(image);
|
|
dc.DrawBitmap( bitmap, 50, 170 );
|
|
|
|
// test the rectangle outline drawing - there should be one pixel between
|
|
// the rect and the lines
|
|
dc.SetPen(*wxWHITE_PEN);
|
|
dc.SetBrush( *wxTRANSPARENT_BRUSH );
|
|
dc.DrawRectangle(150, 170, 49, 29);
|
|
dc.DrawRectangle(200, 170, 49, 29);
|
|
dc.SetPen(*wxWHITE_PEN);
|
|
dc.DrawLine(250, 210, 250, 170);
|
|
dc.DrawLine(260, 200, 150, 200);
|
|
|
|
// test the rectangle filled drawing - there should be one pixel between
|
|
// the rect and the lines
|
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
|
dc.SetBrush( *wxWHITE_BRUSH );
|
|
dc.DrawRectangle(300, 170, 49, 29);
|
|
dc.DrawRectangle(350, 170, 49, 29);
|
|
dc.SetPen(*wxWHITE_PEN);
|
|
dc.DrawLine(400, 170, 400, 210);
|
|
dc.DrawLine(300, 200, 410, 200);
|
|
|
|
// a few more tests of this kind
|
|
dc.SetPen(*wxRED_PEN);
|
|
dc.SetBrush( *wxWHITE_BRUSH );
|
|
dc.DrawRectangle(300, 220, 1, 1);
|
|
dc.DrawRectangle(310, 220, 2, 2);
|
|
dc.DrawRectangle(320, 220, 3, 3);
|
|
dc.DrawRectangle(330, 220, 4, 4);
|
|
|
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
|
dc.SetBrush( *wxWHITE_BRUSH );
|
|
dc.DrawRectangle(300, 230, 1, 1);
|
|
dc.DrawRectangle(310, 230, 2, 2);
|
|
dc.DrawRectangle(320, 230, 3, 3);
|
|
dc.DrawRectangle(330, 230, 4, 4);
|
|
|
|
// and now for filled rect with outline
|
|
dc.SetPen(*wxRED_PEN);
|
|
dc.SetBrush( *wxWHITE_BRUSH );
|
|
dc.DrawRectangle(500, 170, 49, 29);
|
|
dc.DrawRectangle(550, 170, 49, 29);
|
|
dc.SetPen(*wxWHITE_PEN);
|
|
dc.DrawLine(600, 170, 600, 210);
|
|
dc.DrawLine(500, 200, 610, 200);
|
|
|
|
// test the rectangle outline drawing - there should be one pixel between
|
|
// the rect and the lines
|
|
dc.SetPen(*wxWHITE_PEN);
|
|
dc.SetBrush( *wxTRANSPARENT_BRUSH );
|
|
dc.DrawRoundedRectangle(150, 270, 49, 29, 6);
|
|
dc.DrawRoundedRectangle(200, 270, 49, 29, 6);
|
|
dc.SetPen(*wxWHITE_PEN);
|
|
dc.DrawLine(250, 270, 250, 310);
|
|
dc.DrawLine(150, 300, 260, 300);
|
|
|
|
// test the rectangle filled drawing - there should be one pixel between
|
|
// the rect and the lines
|
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
|
dc.SetBrush( *wxWHITE_BRUSH );
|
|
dc.DrawRoundedRectangle(300, 270, 49, 29, 6);
|
|
dc.DrawRoundedRectangle(350, 270, 49, 29, 6);
|
|
dc.SetPen(*wxWHITE_PEN);
|
|
dc.DrawLine(400, 270, 400, 310);
|
|
dc.DrawLine(300, 300, 410, 300);
|
|
|
|
// Added by JACS to demonstrate bizarre behaviour.
|
|
// With a size of 70, we get a missing red RHS,
|
|
// and the height is too small, so we get yellow
|
|
// showing. With a size of 40, it draws as expected:
|
|
// it just shows a white rectangle with red outline.
|
|
int totalWidth = 70;
|
|
int totalHeight = 70;
|
|
wxBitmap bitmap2(totalWidth, totalHeight);
|
|
|
|
wxMemoryDC memdc2;
|
|
memdc2.SelectObject(bitmap2);
|
|
|
|
memdc2.SetBackground(*wxYELLOW_BRUSH);
|
|
memdc2.Clear();
|
|
|
|
// Now draw a white rectangle with red outline. It should
|
|
// entirely eclipse the yellow background.
|
|
memdc2.SetPen(*wxRED_PEN);
|
|
memdc2.SetBrush(*wxWHITE_BRUSH);
|
|
|
|
memdc2.DrawRectangle(0, 0, totalWidth, totalHeight);
|
|
|
|
memdc2.SetPen(wxNullPen);
|
|
memdc2.SetBrush(wxNullBrush);
|
|
memdc2.SelectObject(wxNullBitmap);
|
|
|
|
dc.DrawBitmap(bitmap2, 500, 270);
|
|
|
|
// Repeat, but draw directly on dc
|
|
// Draw a yellow rectangle filling the bitmap
|
|
|
|
x = 600; int y = 270;
|
|
dc.SetPen(*wxYELLOW_PEN);
|
|
dc.SetBrush(*wxYELLOW_BRUSH);
|
|
dc.DrawRectangle(x, y, totalWidth, totalHeight);
|
|
|
|
// Now draw a white rectangle with red outline. It should
|
|
// entirely eclipse the yellow background.
|
|
dc.SetPen(*wxRED_PEN);
|
|
dc.SetBrush(*wxWHITE_BRUSH);
|
|
|
|
dc.DrawRectangle(x, y, totalWidth, totalHeight);
|
|
}
|
|
|
|
void MyCanvas::DrawText(wxDC& dc)
|
|
{
|
|
// set underlined font for testing
|
|
dc.SetFont( wxFontInfo(12).Family(wxFONTFAMILY_MODERN).Underlined() );
|
|
dc.DrawText( "This is text", 110, 10 );
|
|
dc.DrawRotatedText( "That is text", 20, 10, -45 );
|
|
|
|
// use wxSWISS_FONT and not wxNORMAL_FONT as the latter can't be rotated
|
|
// under MSW (it is not TrueType)
|
|
dc.SetFont( *wxSWISS_FONT );
|
|
|
|
wxString text;
|
|
dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
|
|
|
|
for ( int n = -180; n < 180; n += 30 )
|
|
{
|
|
text.Printf(" %d rotated text", n);
|
|
dc.DrawRotatedText(text , 400, 400, n);
|
|
}
|
|
|
|
dc.SetFont( wxFontInfo(18).Family(wxFONTFAMILY_SWISS) );
|
|
|
|
dc.DrawText( "This is Swiss 18pt text.", 110, 40 );
|
|
|
|
wxCoord length;
|
|
wxCoord height;
|
|
wxCoord descent;
|
|
dc.GetTextExtent( "This is Swiss 18pt text.", &length, &height, &descent );
|
|
text.Printf( "Dimensions are length %d, height %d, descent %d", length, height, descent );
|
|
dc.DrawText( text, 110, 80 );
|
|
|
|
text.Printf( "CharHeight() returns: %d", dc.GetCharHeight() );
|
|
dc.DrawText( text, 110, 120 );
|
|
|
|
dc.DrawRectangle( 100, 40, 4, height );
|
|
|
|
// test the logical function effect
|
|
wxCoord y = 150;
|
|
dc.SetLogicalFunction(wxINVERT);
|
|
// text drawing should ignore logical function
|
|
dc.DrawText( "There should be a text below", 110, y );
|
|
dc.DrawRectangle( 110, y, 100, height );
|
|
|
|
y += height;
|
|
dc.DrawText( "Visible text", 110, y );
|
|
dc.DrawRectangle( 110, y, 100, height );
|
|
dc.DrawText( "Visible text", 110, y );
|
|
dc.DrawRectangle( 110, y, 100, height );
|
|
dc.SetLogicalFunction(wxCOPY);
|
|
|
|
y += height;
|
|
dc.DrawRectangle( 110, y, 100, height );
|
|
dc.DrawText( "Another visible text", 110, y );
|
|
|
|
y += height;
|
|
dc.DrawText("And\nmore\ntext on\nmultiple\nlines", 110, y);
|
|
y += 5*height;
|
|
|
|
dc.SetTextForeground(*wxBLUE);
|
|
dc.DrawRotatedText("Rotated text\ncan have\nmultiple lines\nas well", 110, y, 15);
|
|
|
|
y += 7*height;
|
|
dc.SetFont(wxFontInfo(12).Family(wxFONTFAMILY_TELETYPE));
|
|
dc.SetTextForeground(wxColour(150, 75, 0));
|
|
dc.DrawText("And some text with tab characters:\n123456789012345678901234567890\n\taa\tbbb\tcccc", 10, y);
|
|
}
|
|
|
|
static const struct
|
|
{
|
|
wxString name;
|
|
wxRasterOperationMode rop;
|
|
} rasterOperations[] =
|
|
{
|
|
{ "wxAND", wxAND },
|
|
{ "wxAND_INVERT", wxAND_INVERT },
|
|
{ "wxAND_REVERSE", wxAND_REVERSE },
|
|
{ "wxCLEAR", wxCLEAR },
|
|
{ "wxCOPY", wxCOPY },
|
|
{ "wxEQUIV", wxEQUIV },
|
|
{ "wxINVERT", wxINVERT },
|
|
{ "wxNAND", wxNAND },
|
|
{ "wxNO_OP", wxNO_OP },
|
|
{ "wxOR", wxOR },
|
|
{ "wxOR_INVERT", wxOR_INVERT },
|
|
{ "wxOR_REVERSE", wxOR_REVERSE },
|
|
{ "wxSET", wxSET },
|
|
{ "wxSRC_INVERT", wxSRC_INVERT },
|
|
{ "wxXOR", wxXOR },
|
|
};
|
|
|
|
void MyCanvas::DrawImages(wxDC& dc, DrawMode mode)
|
|
{
|
|
dc.DrawText("original image", 0, 0);
|
|
dc.DrawBitmap(*gs_bmpNoMask, 0, 20, 0);
|
|
dc.DrawText("with colour mask", 0, 100);
|
|
dc.DrawBitmap(*gs_bmpWithColMask, 0, 120, true);
|
|
dc.DrawText("the mask image", 0, 200);
|
|
dc.DrawBitmap(*gs_bmpMask, 0, 220, 0);
|
|
dc.DrawText("masked image", 0, 300);
|
|
dc.DrawBitmap(*gs_bmpWithMask, 0, 320, true);
|
|
|
|
int cx = gs_bmpWithColMask->GetWidth(),
|
|
cy = gs_bmpWithColMask->GetHeight();
|
|
|
|
wxMemoryDC memDC;
|
|
for ( size_t n = 0; n < WXSIZEOF(rasterOperations); n++ )
|
|
{
|
|
wxCoord x = 120 + 150*(n%4),
|
|
y = 20 + 100*(n/4);
|
|
|
|
dc.DrawText(rasterOperations[n].name, x, y - 20);
|
|
memDC.SelectObject(*gs_bmpWithColMask);
|
|
if ( mode == Draw_Stretch )
|
|
{
|
|
dc.StretchBlit(x, y, cx, cy, &memDC, 0, 0, cx/2, cy/2,
|
|
rasterOperations[n].rop, true);
|
|
}
|
|
else
|
|
{
|
|
dc.Blit(x, y, cx, cy, &memDC, 0, 0, rasterOperations[n].rop, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MyCanvas::DrawWithLogicalOps(wxDC& dc)
|
|
{
|
|
static const wxCoord w = 60;
|
|
static const wxCoord h = 60;
|
|
|
|
// reuse the text colour here
|
|
dc.SetPen(wxPen(m_owner->m_colourForeground));
|
|
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
|
|
|
size_t n;
|
|
for ( n = 0; n < WXSIZEOF(rasterOperations); n++ )
|
|
{
|
|
wxCoord x = 20 + 150*(n%4),
|
|
y = 20 + 100*(n/4);
|
|
|
|
dc.DrawText(rasterOperations[n].name, x, y - 20);
|
|
dc.SetLogicalFunction(rasterOperations[n].rop);
|
|
dc.DrawRectangle(x, y, w, h);
|
|
dc.DrawLine(x, y, x + w, y + h);
|
|
dc.DrawLine(x + w, y, x, y + h);
|
|
}
|
|
|
|
// now some filled rectangles
|
|
dc.SetBrush(wxBrush(m_owner->m_colourForeground));
|
|
|
|
for ( n = 0; n < WXSIZEOF(rasterOperations); n++ )
|
|
{
|
|
wxCoord x = 20 + 150*(n%4),
|
|
y = 500 + 100*(n/4);
|
|
|
|
dc.DrawText(rasterOperations[n].name, x, y - 20);
|
|
dc.SetLogicalFunction(rasterOperations[n].rop);
|
|
dc.DrawRectangle(x, y, w, h);
|
|
}
|
|
}
|
|
|
|
#if wxDRAWING_DC_SUPPORTS_ALPHA || wxUSE_GRAPHICS_CONTEXT
|
|
void MyCanvas::DrawAlpha(wxDC& dc)
|
|
{
|
|
wxDouble margin = 20 ;
|
|
wxDouble width = 180 ;
|
|
wxDouble radius = 30 ;
|
|
|
|
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 ), 12));
|
|
dc.SetBrush( wxColour(0, 0, 255, 192) );
|
|
|
|
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 ), 12));
|
|
dc.SetBrush( wxBrush( wxColour( 192, 192, 0, 192)));
|
|
|
|
r.Offset( width * 0.8 , width *0.5 ) ;
|
|
|
|
dc.DrawRoundedRectangle( r.x, r.y, r.width, r.width, radius ) ;
|
|
|
|
dc.SetPen( *wxTRANSPARENT_PEN ) ;
|
|
dc.SetBrush( wxBrush( wxColour(255,255,128,128) ) );
|
|
dc.DrawRoundedRectangle( 0 , margin + width / 2 , width * 3 , 100 , radius) ;
|
|
|
|
dc.SetTextBackground( wxColour(160, 192, 160, 160) );
|
|
dc.SetTextForeground( wxColour(255, 128, 128, 128) );
|
|
dc.SetFont( wxFontInfo(40).Family(wxFONTFAMILY_SWISS).Italic() );
|
|
dc.DrawText( "Hello!", 120, 80 );
|
|
}
|
|
#endif // wxDRAWING_DC_SUPPORTS_ALPHA || wxUSE_GRAPHICS_CONTEXT
|
|
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
|
|
const int BASE = 80.0;
|
|
const int BASE2 = BASE/2;
|
|
const int BASE4 = BASE/4;
|
|
|
|
|
|
// modeled along Robin Dunn's GraphicsContext.py sample
|
|
|
|
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 );
|
|
path.MoveToPoint(0, -BASE2);
|
|
path.AddLineToPoint(0, BASE2);
|
|
path.MoveToPoint(-BASE2, 0);
|
|
path.AddLineToPoint(BASE2, 0);
|
|
path.CloseSubpath();
|
|
path.AddRectangle(-BASE4, -BASE4/2, BASE2, BASE4);
|
|
|
|
// Now use that path to demonstrate various capabilities of the graphics context
|
|
gc->PushState(); // save current translation/scale/other state
|
|
gc->Translate(60, 75); // reposition the context origin
|
|
|
|
gc->SetPen(wxPen("navy"));
|
|
gc->SetBrush(wxBrush("pink"));
|
|
|
|
for( int i = 0 ; i < 3 ; ++i )
|
|
{
|
|
wxString label;
|
|
switch( i )
|
|
{
|
|
case 0 :
|
|
label = "StrokePath";
|
|
break;
|
|
case 1 :
|
|
label = "FillPath";
|
|
break;
|
|
case 2 :
|
|
label = "DrawPath";
|
|
break;
|
|
}
|
|
wxDouble w, h;
|
|
gc->GetTextExtent(label, &w, &h, NULL, NULL);
|
|
gc->DrawText(label, -w/2, -BASE2-h-4);
|
|
switch( i )
|
|
{
|
|
case 0 :
|
|
gc->StrokePath(path);
|
|
break;
|
|
case 1 :
|
|
gc->FillPath(path);
|
|
break;
|
|
case 2 :
|
|
gc->DrawPath(path);
|
|
break;
|
|
}
|
|
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);
|
|
|
|
gc->SetBrush(wxBrush(wxColour(178, 34, 34, 128)));// 128 == half transparent
|
|
for( int i = 0 ; i < 8 ; ++i )
|
|
{
|
|
gc->Scale(1.08, 1.08); // increase scale by 8%
|
|
gc->Translate(5,5);
|
|
gc->DrawPath(path);
|
|
}
|
|
|
|
gc->PopState(); // restore saved state
|
|
gc->PushState(); // save it again
|
|
gc->Translate(400, 200);
|
|
|
|
gc->DrawText("Rotate", 0, -BASE2);
|
|
|
|
// Move the origin over to the next location
|
|
gc->Translate(0, 75);
|
|
|
|
// draw our path again, rotating it about the central point,
|
|
// and changing colors as we go
|
|
for ( int angle = 0 ; angle < 360 ; angle += 30 )
|
|
{
|
|
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(wxDegToRad(angle)),
|
|
1.5 * BASE2 * sin(wxDegToRad(angle)));
|
|
|
|
// use Rotate to rotate the path
|
|
gc->Rotate(wxDegToRad(angle));
|
|
|
|
// now draw it
|
|
gc->DrawPath(path);
|
|
gc->PopState();
|
|
}
|
|
gc->PopState();
|
|
|
|
gc->PushState();
|
|
gc->Translate(60, 400);
|
|
const wxString labelText("Scaled smiley inside a square");
|
|
gc->DrawText(labelText, 0, 0);
|
|
// Center a bitmap horizontally
|
|
wxDouble textWidth;
|
|
gc->GetTextExtent(labelText, &textWidth, NULL);
|
|
const wxDouble rectWidth = 100;
|
|
wxDouble x0 = (textWidth - rectWidth) / 2;
|
|
gc->DrawRectangle(x0, BASE2, rectWidth, 100);
|
|
gc->DrawBitmap(m_smile_bmp, x0, BASE2, rectWidth, 100);
|
|
gc->PopState();
|
|
|
|
// Draw graphics bitmap and its subbitmap
|
|
gc->PushState();
|
|
gc->Translate(300, 400);
|
|
gc->DrawText("Smiley as a graphics bitmap", 0, 0);
|
|
|
|
wxGraphicsBitmap gbmp1 = gc->CreateBitmap(m_smile_bmp);
|
|
gc->DrawBitmap(gbmp1, 0, BASE2, 50, 50);
|
|
int bmpw = m_smile_bmp.GetWidth();
|
|
int bmph = m_smile_bmp.GetHeight();
|
|
wxGraphicsBitmap gbmp2 = gc->CreateSubBitmap(gbmp1, 0, bmph/5, bmpw/2, bmph/2);
|
|
gc->DrawBitmap(gbmp2, 80, BASE2, 50, 50*(bmph/2)/(bmpw/2));
|
|
gc->PopState();
|
|
}
|
|
#endif // wxUSE_GRAPHICS_CONTEXT
|
|
|
|
void MyCanvas::DrawCircles(wxDC& dc)
|
|
{
|
|
int x = 100,
|
|
y = 100,
|
|
r = 20;
|
|
|
|
dc.SetPen( *wxRED_PEN );
|
|
dc.SetBrush( *wxGREEN_BRUSH );
|
|
|
|
dc.DrawText("Some circles", 0, y);
|
|
dc.DrawCircle(x, y, r);
|
|
dc.DrawCircle(x + 2*r, y, r);
|
|
dc.DrawCircle(x + 4*r, y, r);
|
|
|
|
y += 2*r;
|
|
dc.DrawText("And ellipses", 0, y);
|
|
dc.DrawEllipse(x - r, y, 2*r, r);
|
|
dc.DrawEllipse(x + r, y, 2*r, r);
|
|
dc.DrawEllipse(x + 3*r, y, 2*r, r);
|
|
|
|
y += 2*r;
|
|
dc.DrawText("And arcs", 0, y);
|
|
dc.DrawArc(x - r, y, x + r, y, x, y);
|
|
dc.DrawArc(x + 4*r, y, x + 2*r, y, x + 3*r, y);
|
|
dc.DrawArc(x + 5*r, y, x + 5*r, y, x + 6*r, y);
|
|
|
|
y += 2*r;
|
|
dc.DrawEllipticArc(x - r, y, 2*r, r, 0, 90);
|
|
dc.DrawEllipticArc(x + r, y, 2*r, r, 90, 180);
|
|
dc.DrawEllipticArc(x + 3*r, y, 2*r, r, 180, 270);
|
|
dc.DrawEllipticArc(x + 5*r, y, 2*r, r, 270, 360);
|
|
|
|
// same as above, just transparent brush
|
|
|
|
dc.SetPen( *wxRED_PEN );
|
|
dc.SetBrush( *wxTRANSPARENT_BRUSH );
|
|
|
|
y += 2*r;
|
|
dc.DrawText("Some circles", 0, y);
|
|
dc.DrawCircle(x, y, r);
|
|
dc.DrawCircle(x + 2*r, y, r);
|
|
dc.DrawCircle(x + 4*r, y, r);
|
|
|
|
y += 2*r;
|
|
dc.DrawText("And ellipses", 0, y);
|
|
dc.DrawEllipse(x - r, y, 2*r, r);
|
|
dc.DrawEllipse(x + r, y, 2*r, r);
|
|
dc.DrawEllipse(x + 3*r, y, 2*r, r);
|
|
|
|
y += 2*r;
|
|
dc.DrawText("And arcs", 0, y);
|
|
dc.DrawArc(x - r, y, x + r, y, x, y);
|
|
dc.DrawArc(x + 4*r, y, x + 2*r, y, x + 3*r, y);
|
|
dc.DrawArc(x + 5*r, y, x + 5*r, y, x + 6*r, y);
|
|
|
|
y += 2*r;
|
|
dc.DrawEllipticArc(x - r, y, 2*r, r, 0, 90);
|
|
dc.DrawEllipticArc(x + r, y, 2*r, r, 90, 180);
|
|
dc.DrawEllipticArc(x + 3*r, y, 2*r, r, 180, 270);
|
|
dc.DrawEllipticArc(x + 5*r, y, 2*r, r, 270, 360);
|
|
|
|
}
|
|
|
|
void MyCanvas::DrawSplines(wxDC& dc)
|
|
{
|
|
#if wxUSE_SPLINES
|
|
dc.DrawText("Some splines", 10, 5);
|
|
|
|
// values are hardcoded rather than randomly generated
|
|
// so the output can be compared between native
|
|
// implementations on platforms with different random
|
|
// generators
|
|
|
|
const int R = 300;
|
|
const wxPoint center( R + 20, R + 20 );
|
|
const int angles[7] = { 0, 10, 33, 77, 13, 145, 90 };
|
|
const int radii[5] = { 100 , 59, 85, 33, 90 };
|
|
const int numPoints = 200;
|
|
wxPoint pts[numPoints];
|
|
|
|
// background spline calculation
|
|
unsigned int radius_pos = 0;
|
|
unsigned int angle_pos = 0;
|
|
int angle = 0;
|
|
for ( int i = 0; i < numPoints; i++ )
|
|
{
|
|
angle += angles[ angle_pos ];
|
|
int r = R * radii[ radius_pos ] / 100;
|
|
pts[ i ].x = center.x + (wxCoord)( r * cos( M_PI * angle / 180.0) );
|
|
pts[ i ].y = center.y + (wxCoord)( r * sin( M_PI * angle / 180.0) );
|
|
|
|
angle_pos++;
|
|
if ( angle_pos >= WXSIZEOF(angles) ) angle_pos = 0;
|
|
|
|
radius_pos++;
|
|
if ( radius_pos >= WXSIZEOF(radii) ) radius_pos = 0;
|
|
}
|
|
|
|
// background spline drawing
|
|
dc.SetPen(*wxRED_PEN);
|
|
dc.DrawSpline(WXSIZEOF(pts), pts);
|
|
|
|
// less detailed spline calculation
|
|
wxPoint letters[4][5];
|
|
// w
|
|
letters[0][0] = wxPoint( 0,1); // O O
|
|
letters[0][1] = wxPoint( 1,3); // * *
|
|
letters[0][2] = wxPoint( 2,2); // * O *
|
|
letters[0][3] = wxPoint( 3,3); // * * * *
|
|
letters[0][4] = wxPoint( 4,1); // O O
|
|
// x1
|
|
letters[1][0] = wxPoint( 5,1); // O*O
|
|
letters[1][1] = wxPoint( 6,1); // *
|
|
letters[1][2] = wxPoint( 7,2); // O
|
|
letters[1][3] = wxPoint( 8,3); // *
|
|
letters[1][4] = wxPoint( 9,3); // O*O
|
|
// x2
|
|
letters[2][0] = wxPoint( 5,3); // O*O
|
|
letters[2][1] = wxPoint( 6,3); // *
|
|
letters[2][2] = wxPoint( 7,2); // O
|
|
letters[2][3] = wxPoint( 8,1); // *
|
|
letters[2][4] = wxPoint( 9,1); // O*O
|
|
// W
|
|
letters[3][0] = wxPoint(10,0); // O O
|
|
letters[3][1] = wxPoint(11,3); // * *
|
|
letters[3][2] = wxPoint(12,1); // * O *
|
|
letters[3][3] = wxPoint(13,3); // * * * *
|
|
letters[3][4] = wxPoint(14,0); // O O
|
|
|
|
const int dx = 2 * R / letters[3][4].x;
|
|
const int h[4] = { -R/2, 0, R/4, R/2 };
|
|
|
|
for ( int m = 0; m < 4; m++ )
|
|
{
|
|
for ( int n = 0; n < 5; n++ )
|
|
{
|
|
letters[m][n].x = center.x - R + letters[m][n].x * dx;
|
|
letters[m][n].y = center.y + h[ letters[m][n].y ];
|
|
}
|
|
|
|
dc.SetPen( wxPen( *wxBLUE, 1, wxPENSTYLE_DOT) );
|
|
dc.DrawLines(5, letters[m]);
|
|
dc.SetPen( wxPen( *wxBLACK, 4) );
|
|
dc.DrawSpline(5, letters[m]);
|
|
}
|
|
|
|
#else
|
|
dc.DrawText("Splines not supported.", 10, 5);
|
|
#endif
|
|
}
|
|
|
|
void MyCanvas::DrawGradients(wxDC& dc)
|
|
{
|
|
static const int TEXT_HEIGHT = 15;
|
|
|
|
// LHS: linear
|
|
wxRect r(10, 10, 50, 50);
|
|
dc.DrawText("wxRIGHT", r.x, r.y);
|
|
r.Offset(0, TEXT_HEIGHT);
|
|
dc.GradientFillLinear(r, *wxWHITE, *wxBLUE, wxRIGHT);
|
|
|
|
r.Offset(0, r.height + 10);
|
|
dc.DrawText("wxLEFT", r.x, r.y);
|
|
r.Offset(0, TEXT_HEIGHT);
|
|
dc.GradientFillLinear(r, *wxWHITE, *wxBLUE, wxLEFT);
|
|
|
|
r.Offset(0, r.height + 10);
|
|
dc.DrawText("wxDOWN", r.x, r.y);
|
|
r.Offset(0, TEXT_HEIGHT);
|
|
dc.GradientFillLinear(r, *wxWHITE, *wxBLUE, wxDOWN);
|
|
|
|
r.Offset(0, r.height + 10);
|
|
dc.DrawText("wxUP", r.x, r.y);
|
|
r.Offset(0, TEXT_HEIGHT);
|
|
dc.GradientFillLinear(r, *wxWHITE, *wxBLUE, wxUP);
|
|
|
|
wxRect gfr = wxRect(r);
|
|
|
|
// RHS: concentric
|
|
r = wxRect(200, 10, 50, 50);
|
|
dc.DrawText("Blue inside", r.x, r.y);
|
|
r.Offset(0, TEXT_HEIGHT);
|
|
dc.GradientFillConcentric(r, *wxBLUE, *wxWHITE);
|
|
|
|
r.Offset(0, r.height + 10);
|
|
dc.DrawText("White inside", r.x, r.y);
|
|
r.Offset(0, TEXT_HEIGHT);
|
|
dc.GradientFillConcentric(r, *wxWHITE, *wxBLUE);
|
|
|
|
r.Offset(0, r.height + 10);
|
|
dc.DrawText("Blue in top left corner", r.x, r.y);
|
|
r.Offset(0, TEXT_HEIGHT);
|
|
dc.GradientFillConcentric(r, *wxBLUE, *wxWHITE, wxPoint(0, 0));
|
|
|
|
r.Offset(0, r.height + 10);
|
|
dc.DrawText("Blue in bottom right corner", r.x, r.y);
|
|
r.Offset(0, TEXT_HEIGHT);
|
|
dc.GradientFillConcentric(r, *wxBLUE, *wxWHITE, wxPoint(r.width, r.height));
|
|
|
|
// check that the area filled by the gradient is exactly the interior of
|
|
// the rectangle
|
|
r.x = 350;
|
|
r.y = 30;
|
|
dc.DrawText("The interior should be filled but", r.x, r.y);
|
|
r.y += 15;
|
|
dc.DrawText(" the red border should remain visible:", r.x, r.y);
|
|
r.y += 15;
|
|
|
|
r.width =
|
|
r.height = 50;
|
|
wxRect r2 = r;
|
|
r2.x += 60;
|
|
wxRect r3 = r;
|
|
r3.y += 60;
|
|
wxRect r4 = r2;
|
|
r4.y += 60;
|
|
dc.SetPen(*wxRED_PEN);
|
|
dc.DrawRectangle(r);
|
|
r.Deflate(1);
|
|
dc.GradientFillLinear(r, *wxGREEN, *wxBLACK, wxNORTH);
|
|
dc.DrawRectangle(r2);
|
|
r2.Deflate(1);
|
|
dc.GradientFillLinear(r2, *wxBLACK, *wxGREEN, wxSOUTH);
|
|
dc.DrawRectangle(r3);
|
|
r3.Deflate(1);
|
|
dc.GradientFillLinear(r3, *wxGREEN, *wxBLACK, wxEAST);
|
|
dc.DrawRectangle(r4);
|
|
r4.Deflate(1);
|
|
dc.GradientFillLinear(r4, *wxBLACK, *wxGREEN, wxWEST);
|
|
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
if (m_renderer)
|
|
{
|
|
wxGCDC &gdc = (wxGCDC&)dc;
|
|
wxGraphicsContext *gc = gdc.GetGraphicsContext();
|
|
wxGraphicsPath pth;
|
|
wxGraphicsGradientStops stops;
|
|
double boxX, boxY, boxWidth, boxHeight;
|
|
|
|
gfr.Offset(0, gfr.height + 10);
|
|
dc.DrawText("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);
|
|
pth.GetBox(&boxX, &boxY, &boxWidth, &boxHeight);
|
|
dc.CalcBoundingBox(wxRound(boxX), wxRound(boxY));
|
|
dc.CalcBoundingBox(wxRound(boxX+boxWidth), wxRound(boxY+boxHeight));
|
|
|
|
wxGraphicsGradientStops simpleStops(*wxRED, *wxBLUE);
|
|
|
|
gfr.Offset(0, gfr.height + 10);
|
|
dc.DrawText("Radial Gradient from Red to Blue without intermediary 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,
|
|
simpleStops));
|
|
|
|
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);
|
|
pth.GetBox(&boxX, &boxY, &boxWidth, &boxHeight);
|
|
dc.CalcBoundingBox(wxRound(boxX), wxRound(boxY));
|
|
dc.CalcBoundingBox(wxRound(boxX+boxWidth), wxRound(boxY+boxHeight));
|
|
|
|
gfr.Offset(0, gfr.height + 10);
|
|
dc.DrawText("Radial Gradient from Red to Blue with Yellow and Green 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);
|
|
pth.GetBox(&boxX, &boxY, &boxWidth, &boxHeight);
|
|
dc.CalcBoundingBox(wxRound(boxX), wxRound(boxY));
|
|
dc.CalcBoundingBox(wxRound(boxX+boxWidth), wxRound(boxY+boxHeight));
|
|
|
|
gfr.Offset(0, gfr.height + 10);
|
|
dc.DrawText("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);
|
|
pth.GetBox(&boxX, &boxY, &boxWidth, &boxHeight);
|
|
dc.CalcBoundingBox(wxRound(boxX), wxRound(boxY));
|
|
dc.CalcBoundingBox(wxRound(boxX+boxWidth), wxRound(boxY+boxHeight));
|
|
|
|
gfr.Offset(0, gfr.height + 10);
|
|
dc.DrawText("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);
|
|
pth.GetBox(&boxX, &boxY, &boxWidth, &boxHeight);
|
|
dc.CalcBoundingBox(wxRound(boxX), wxRound(boxY));
|
|
dc.CalcBoundingBox(wxRound(boxX+boxWidth), wxRound(boxY+boxHeight));
|
|
|
|
gfr.Offset(0, gfr.height + 10);
|
|
dc.DrawText("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);
|
|
pth.GetBox(&boxX, &boxY, &boxWidth, &boxHeight);
|
|
dc.CalcBoundingBox(wxRound(boxX), wxRound(boxY));
|
|
dc.CalcBoundingBox(wxRound(boxX+boxWidth), wxRound(boxY+boxHeight));
|
|
|
|
gfr.Offset(0, gfr.height + 10);
|
|
dc.DrawText("Stroked path with a gradient pen", gfr.x, gfr.y);
|
|
gfr.Offset(0, TEXT_HEIGHT);
|
|
|
|
pth = gc->CreatePath();
|
|
pth.MoveToPoint(gfr.x + gfr.width/2, gfr.y);
|
|
pth.AddLineToPoint(gfr.x + gfr.width, gfr.y + gfr.height/2);
|
|
pth.AddLineToPoint(gfr.x + gfr.width/2, gfr.y + gfr.height);
|
|
pth.AddLineToPoint(gfr.x, gfr.y + gfr.height/2);
|
|
pth.CloseSubpath();
|
|
|
|
stops = wxGraphicsGradientStops(*wxRED, *wxBLUE);
|
|
stops.Add(wxColour(255,255,0), 0.33f);
|
|
stops.Add(*wxGREEN, 0.67f);
|
|
|
|
wxGraphicsPen pen = gc->CreatePen(
|
|
wxGraphicsPenInfo(wxColour(0,0,0)).Width(6).Join(wxJOIN_BEVEL).LinearGradient(
|
|
gfr.x + gfr.width/2, gfr.y,
|
|
gfr.x + gfr.width/2, gfr.y + gfr.height,
|
|
stops));
|
|
gc->SetPen(pen);
|
|
gc->StrokePath(pth);
|
|
}
|
|
#endif // wxUSE_GRAPHICS_CONTEXT
|
|
}
|
|
|
|
void MyCanvas::DrawSystemColours(wxDC& dc)
|
|
{
|
|
wxFont mono(wxFontInfo().Family(wxFONTFAMILY_TELETYPE));
|
|
wxSize textSize;
|
|
{
|
|
wxDCFontChanger setMono(dc, mono);
|
|
textSize = dc.GetTextExtent("#01234567");
|
|
}
|
|
|
|
int lineHeight = textSize.GetHeight();
|
|
wxRect r(textSize.GetWidth() + 10, 10, 100, lineHeight);
|
|
|
|
wxString title = "System colours";
|
|
|
|
const wxSystemAppearance appearance = wxSystemSettings::GetAppearance();
|
|
const wxString appearanceName = appearance.GetName();
|
|
if ( !appearanceName.empty() )
|
|
title += wxString::Format(" for \"%s\"", appearanceName);
|
|
if ( appearance.IsDark() )
|
|
title += " (using dark system theme)";
|
|
dc.DrawText(title, 10, r.y);
|
|
r.y += 2*lineHeight;
|
|
dc.DrawText(wxString::Format("Window background is %s",
|
|
appearance.IsUsingDarkBackground() ? "dark"
|
|
: "light"),
|
|
10, r.y);
|
|
r.y += 3*lineHeight;
|
|
|
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
|
|
|
static const struct {
|
|
wxSystemColour index;
|
|
const char* name;
|
|
} sysColours[] =
|
|
{
|
|
{ wxSYS_COLOUR_3DDKSHADOW, "wxSYS_COLOUR_3DDKSHADOW" },
|
|
{ wxSYS_COLOUR_3DLIGHT, "wxSYS_COLOUR_3DLIGHT" },
|
|
{ wxSYS_COLOUR_ACTIVEBORDER, "wxSYS_COLOUR_ACTIVEBORDER" },
|
|
{ wxSYS_COLOUR_ACTIVECAPTION, "wxSYS_COLOUR_ACTIVECAPTION" },
|
|
{ wxSYS_COLOUR_APPWORKSPACE, "wxSYS_COLOUR_APPWORKSPACE" },
|
|
{ wxSYS_COLOUR_BTNFACE, "wxSYS_COLOUR_BTNFACE" },
|
|
{ wxSYS_COLOUR_BTNHIGHLIGHT, "wxSYS_COLOUR_BTNHIGHLIGHT" },
|
|
{ wxSYS_COLOUR_BTNSHADOW, "wxSYS_COLOUR_BTNSHADOW" },
|
|
{ wxSYS_COLOUR_BTNTEXT, "wxSYS_COLOUR_BTNTEXT" },
|
|
{ wxSYS_COLOUR_CAPTIONTEXT, "wxSYS_COLOUR_CAPTIONTEXT" },
|
|
{ wxSYS_COLOUR_DESKTOP, "wxSYS_COLOUR_DESKTOP" },
|
|
{ wxSYS_COLOUR_GRADIENTACTIVECAPTION, "wxSYS_COLOUR_GRADIENTACTIVECAPTION" },
|
|
{ wxSYS_COLOUR_GRADIENTINACTIVECAPTION, "wxSYS_COLOUR_GRADIENTINACTIVECAPTION" },
|
|
{ wxSYS_COLOUR_GRAYTEXT, "wxSYS_COLOUR_GRAYTEXT" },
|
|
{ wxSYS_COLOUR_HIGHLIGHTTEXT, "wxSYS_COLOUR_HIGHLIGHTTEXT" },
|
|
{ wxSYS_COLOUR_HIGHLIGHT, "wxSYS_COLOUR_HIGHLIGHT" },
|
|
{ wxSYS_COLOUR_HOTLIGHT, "wxSYS_COLOUR_HOTLIGHT" },
|
|
{ wxSYS_COLOUR_INACTIVEBORDER, "wxSYS_COLOUR_INACTIVEBORDER" },
|
|
{ wxSYS_COLOUR_INACTIVECAPTIONTEXT, "wxSYS_COLOUR_INACTIVECAPTIONTEXT" },
|
|
{ wxSYS_COLOUR_INACTIVECAPTION, "wxSYS_COLOUR_INACTIVECAPTION" },
|
|
{ wxSYS_COLOUR_INFOBK, "wxSYS_COLOUR_INFOBK" },
|
|
{ wxSYS_COLOUR_INFOTEXT, "wxSYS_COLOUR_INFOTEXT" },
|
|
{ wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT, "wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT" },
|
|
{ wxSYS_COLOUR_LISTBOXTEXT, "wxSYS_COLOUR_LISTBOXTEXT" },
|
|
{ wxSYS_COLOUR_LISTBOX, "wxSYS_COLOUR_LISTBOX" },
|
|
{ wxSYS_COLOUR_MENUBAR, "wxSYS_COLOUR_MENUBAR" },
|
|
{ wxSYS_COLOUR_MENUHILIGHT, "wxSYS_COLOUR_MENUHILIGHT" },
|
|
{ wxSYS_COLOUR_MENUTEXT, "wxSYS_COLOUR_MENUTEXT" },
|
|
{ wxSYS_COLOUR_MENU, "wxSYS_COLOUR_MENU" },
|
|
{ wxSYS_COLOUR_SCROLLBAR, "wxSYS_COLOUR_SCROLLBAR" },
|
|
{ wxSYS_COLOUR_WINDOWFRAME, "wxSYS_COLOUR_WINDOWFRAME" },
|
|
{ wxSYS_COLOUR_WINDOWTEXT, "wxSYS_COLOUR_WINDOWTEXT" },
|
|
{ wxSYS_COLOUR_WINDOW, "wxSYS_COLOUR_WINDOW" }
|
|
};
|
|
|
|
for (int i = 0; i < wxSYS_COLOUR_MAX; i++)
|
|
{
|
|
wxString colourName(sysColours[i].name);
|
|
wxColour c(wxSystemSettings::GetColour(sysColours[i].index));
|
|
|
|
{
|
|
wxDCFontChanger setMono(dc, mono);
|
|
dc.DrawText(c.GetAsString(wxC2S_HTML_SYNTAX), 10, r.y);
|
|
}
|
|
|
|
dc.SetBrush(wxBrush(c));
|
|
dc.DrawRectangle(r);
|
|
|
|
dc.DrawText(colourName, r.GetRight() + 10, r.y);
|
|
|
|
r.y += lineHeight;
|
|
}
|
|
}
|
|
|
|
void MyCanvas::DrawRegions(wxDC& dc)
|
|
{
|
|
dc.DrawText("You should see a red rect partly covered by a cyan one "
|
|
"on the left", 10, 5);
|
|
dc.DrawText("and 5 smileys from which 4 are partially clipped on the right",
|
|
10, 5 + dc.GetCharHeight());
|
|
dc.DrawText("The second copy should be identical but right part of it "
|
|
"should be offset by 10 pixels.",
|
|
10, 5 + 2*dc.GetCharHeight());
|
|
|
|
DrawRegionsHelper(dc, 10, true);
|
|
DrawRegionsHelper(dc, 350, false);
|
|
}
|
|
|
|
void MyCanvas::DrawRegionsHelper(wxDC& dc, wxCoord x, bool firstTime)
|
|
{
|
|
wxCoord y = 100;
|
|
|
|
dc.DestroyClippingRegion();
|
|
dc.SetBrush( *wxWHITE_BRUSH );
|
|
dc.SetPen( *wxTRANSPARENT_PEN );
|
|
dc.DrawRectangle( x, y, 310, 310 );
|
|
|
|
dc.SetClippingRegion( x + 10, y + 10, 100, 270 );
|
|
|
|
dc.SetBrush( *wxRED_BRUSH );
|
|
dc.DrawRectangle( x, y, 310, 310 );
|
|
|
|
dc.SetClippingRegion( x + 10, y + 10, 100, 100 );
|
|
|
|
dc.SetBrush( *wxCYAN_BRUSH );
|
|
dc.DrawRectangle( x, y, 310, 310 );
|
|
|
|
dc.DestroyClippingRegion();
|
|
|
|
wxRegion region(x + 110, y + 20, 100, 270);
|
|
#if !defined(__WXMOTIF__)
|
|
if ( !firstTime )
|
|
region.Offset(10, 10);
|
|
#endif
|
|
dc.SetDeviceClippingRegion(region);
|
|
|
|
dc.SetBrush( *wxGREY_BRUSH );
|
|
dc.DrawRectangle( x, y, 310, 310 );
|
|
|
|
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 );
|
|
dc.DrawBitmap( m_smile_bmp, x + 130, y + 280, true );
|
|
dc.DrawBitmap( m_smile_bmp, x + 100, y + 70, true );
|
|
dc.DrawBitmap( m_smile_bmp, x + 200, y + 70, true );
|
|
}
|
|
}
|
|
|
|
void MyCanvas::GetDrawingSize(int* width, int* height) const
|
|
{
|
|
if ( width )
|
|
*width = m_sizeX;
|
|
|
|
if ( height )
|
|
*height = m_sizeY;
|
|
}
|
|
|
|
void MyCanvas::OnPaint(wxPaintEvent &WXUNUSED(event))
|
|
{
|
|
if ( m_useBuffer )
|
|
{
|
|
wxBufferedPaintDC bpdc(this);
|
|
Draw(bpdc);
|
|
}
|
|
else
|
|
{
|
|
wxPaintDC pdc(this);
|
|
Draw(pdc);
|
|
}
|
|
}
|
|
|
|
void MyCanvas::Draw(wxDC& pdc)
|
|
{
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
wxGCDC gdc;
|
|
|
|
if ( m_renderer )
|
|
{
|
|
wxGraphicsContext* context;
|
|
if ( wxPaintDC *paintdc = wxDynamicCast(&pdc, wxPaintDC) )
|
|
{
|
|
context = m_renderer->CreateContext(*paintdc);
|
|
}
|
|
else if ( wxMemoryDC *memdc = wxDynamicCast(&pdc, wxMemoryDC) )
|
|
{
|
|
context = m_renderer->CreateContext(*memdc);
|
|
}
|
|
#if wxUSE_METAFILE && defined(wxMETAFILE_IS_ENH)
|
|
else if ( wxMetafileDC *metadc = wxDynamicCast(&pdc, wxMetafileDC) )
|
|
{
|
|
context = m_renderer->CreateContext(*metadc);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
wxFAIL_MSG( "Unknown wxDC kind" );
|
|
return;
|
|
}
|
|
|
|
context->SetAntialiasMode(m_useAntiAliasing ? wxANTIALIAS_DEFAULT : wxANTIALIAS_NONE);
|
|
|
|
gdc.SetBackground(GetBackgroundColour());
|
|
gdc.SetGraphicsContext(context);
|
|
}
|
|
|
|
wxDC &dc = m_renderer ? static_cast<wxDC&>(gdc) : pdc;
|
|
#else
|
|
wxDC &dc = pdc ;
|
|
#endif
|
|
|
|
// Adjust scrolled contents for screen drawing operations only.
|
|
if ( wxDynamicCast(&pdc, wxBufferedPaintDC) ||
|
|
wxDynamicCast(&pdc, wxPaintDC) )
|
|
{
|
|
PrepareDC(dc);
|
|
}
|
|
|
|
m_owner->PrepareDC(dc);
|
|
|
|
dc.SetBackgroundMode( m_owner->m_backgroundMode );
|
|
if ( m_owner->m_backgroundBrush.IsOk() )
|
|
dc.SetBackground( m_owner->m_backgroundBrush );
|
|
if ( m_owner->m_colourForeground.IsOk() )
|
|
dc.SetTextForeground( m_owner->m_colourForeground );
|
|
if ( m_owner->m_colourBackground.IsOk() )
|
|
dc.SetTextBackground( m_owner->m_colourBackground );
|
|
|
|
if ( m_owner->m_textureBackground) {
|
|
if ( ! m_owner->m_backgroundBrush.IsOk() ) {
|
|
dc.SetBackground(wxBrush(wxColour(0, 128, 0)));
|
|
}
|
|
}
|
|
|
|
if ( m_clip )
|
|
dc.SetClippingRegion(100, 100, 100, 100);
|
|
|
|
dc.Clear();
|
|
|
|
if ( m_owner->m_textureBackground )
|
|
{
|
|
dc.SetPen(*wxMEDIUM_GREY_PEN);
|
|
for ( int i = 0; i < 200; i++ )
|
|
dc.DrawLine(0, i*10, i*10, 0);
|
|
}
|
|
|
|
switch ( m_show )
|
|
{
|
|
case File_ShowDefault:
|
|
DrawDefault(dc);
|
|
break;
|
|
|
|
case File_ShowCircles:
|
|
DrawCircles(dc);
|
|
break;
|
|
|
|
case File_ShowSplines:
|
|
DrawSplines(dc);
|
|
break;
|
|
|
|
case File_ShowRegions:
|
|
DrawRegions(dc);
|
|
break;
|
|
|
|
case File_ShowText:
|
|
DrawText(dc);
|
|
break;
|
|
|
|
case File_ShowLines:
|
|
DrawTestLines( 0, 100, 0, dc );
|
|
DrawTestLines( 0, 320, 1, dc );
|
|
DrawTestLines( 0, 540, 2, dc );
|
|
DrawTestLines( 0, 760, 6, dc );
|
|
DrawCrossHair( 0, 0, 400, 90, dc);
|
|
break;
|
|
|
|
case File_ShowBrushes:
|
|
DrawTestBrushes(dc);
|
|
break;
|
|
|
|
case File_ShowPolygons:
|
|
DrawTestPoly(dc);
|
|
break;
|
|
|
|
case File_ShowMask:
|
|
DrawImages(dc, Draw_Normal);
|
|
break;
|
|
|
|
case File_ShowMaskStretch:
|
|
DrawImages(dc, Draw_Stretch);
|
|
break;
|
|
|
|
case File_ShowOps:
|
|
DrawWithLogicalOps(dc);
|
|
break;
|
|
|
|
#if wxDRAWING_DC_SUPPORTS_ALPHA || wxUSE_GRAPHICS_CONTEXT
|
|
case File_ShowAlpha:
|
|
DrawAlpha(dc);
|
|
break;
|
|
#endif // wxDRAWING_DC_SUPPORTS_ALPHA || wxUSE_GRAPHICS_CONTEXT
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
case File_ShowGraphics:
|
|
DrawGraphics(gdc.GetGraphicsContext());
|
|
break;
|
|
#endif
|
|
|
|
case File_ShowGradients:
|
|
DrawGradients(dc);
|
|
break;
|
|
|
|
case File_ShowSystemColours:
|
|
DrawSystemColours(dc);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// For drawing with raw wxGraphicsContext
|
|
// there is no bounding box to obtain.
|
|
if ( m_showBBox
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
&& m_show != File_ShowGraphics
|
|
#endif // wxUSE_GRAPHICS_CONTEXT
|
|
)
|
|
{
|
|
dc.SetPen(wxPen(wxColor(0, 128, 0), 1, wxPENSTYLE_DOT));
|
|
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
|
dc.DrawRectangle(dc.MinX(), dc.MinY(), dc.MaxX()-dc.MinX()+1, dc.MaxY()-dc.MinY()+1);
|
|
}
|
|
|
|
// Adjust drawing area dimensions only if screen drawing is invoked.
|
|
if ( wxDynamicCast(&pdc, wxBufferedPaintDC) ||
|
|
wxDynamicCast(&pdc, wxPaintDC) )
|
|
{
|
|
wxCoord x0, y0;
|
|
dc.GetDeviceOrigin(&x0, &y0);
|
|
m_sizeX = dc.LogicalToDeviceX(dc.MaxX()) - x0 + 1;
|
|
m_sizeY = dc.LogicalToDeviceY(dc.MaxY()) - y0 + 1;
|
|
}
|
|
}
|
|
|
|
void MyCanvas::OnMouseMove(wxMouseEvent &event)
|
|
{
|
|
#if wxUSE_STATUSBAR
|
|
{
|
|
wxClientDC dc(this);
|
|
PrepareDC(dc);
|
|
m_owner->PrepareDC(dc);
|
|
|
|
wxPoint pos = event.GetPosition();
|
|
long x = dc.DeviceToLogicalX( pos.x );
|
|
long y = dc.DeviceToLogicalY( pos.y );
|
|
wxString str;
|
|
str.Printf( "Current mouse position: %d,%d", (int)x, (int)y );
|
|
m_owner->SetStatusText( str );
|
|
}
|
|
|
|
if ( m_rubberBand )
|
|
{
|
|
int x,y, xx, yy ;
|
|
event.GetPosition(&x,&y);
|
|
CalcUnscrolledPosition( x, y, &xx, &yy );
|
|
m_currentpoint = wxPoint( xx , yy ) ;
|
|
wxRect newrect ( m_anchorpoint , m_currentpoint ) ;
|
|
|
|
wxClientDC dc( this ) ;
|
|
PrepareDC( dc ) ;
|
|
|
|
wxDCOverlay overlaydc( m_overlay, &dc );
|
|
overlaydc.Clear();
|
|
#ifdef __WXMAC__
|
|
dc.SetPen( *wxGREY_PEN );
|
|
dc.SetBrush( wxColour( 192,192,192,64 ) );
|
|
#else
|
|
dc.SetPen( wxPen( *wxLIGHT_GREY, 2 ) );
|
|
dc.SetBrush( *wxTRANSPARENT_BRUSH );
|
|
#endif
|
|
dc.DrawRectangle( newrect );
|
|
}
|
|
#else
|
|
wxUnusedVar(event);
|
|
#endif // wxUSE_STATUSBAR
|
|
}
|
|
|
|
void MyCanvas::OnMouseDown(wxMouseEvent &event)
|
|
{
|
|
int x,y,xx,yy ;
|
|
event.GetPosition(&x,&y);
|
|
CalcUnscrolledPosition( x, y, &xx, &yy );
|
|
m_anchorpoint = wxPoint( xx , yy ) ;
|
|
m_currentpoint = m_anchorpoint ;
|
|
m_rubberBand = true ;
|
|
CaptureMouse() ;
|
|
}
|
|
|
|
void MyCanvas::OnMouseUp(wxMouseEvent &event)
|
|
{
|
|
if ( m_rubberBand )
|
|
{
|
|
ReleaseMouse();
|
|
{
|
|
wxClientDC dc( this );
|
|
PrepareDC( dc );
|
|
wxDCOverlay overlaydc( m_overlay, &dc );
|
|
overlaydc.Clear();
|
|
}
|
|
m_overlay.Reset();
|
|
m_rubberBand = false;
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
void MyCanvas::UseGraphicRenderer(wxGraphicsRenderer* renderer)
|
|
{
|
|
m_renderer = renderer;
|
|
if (renderer)
|
|
{
|
|
int major, minor, micro;
|
|
renderer->GetVersion(&major, &minor, µ);
|
|
wxString str = wxString::Format("Graphics renderer: %s %i.%i.%i",
|
|
renderer->GetName(), major, minor, micro);
|
|
m_owner->SetStatusText(str, 1);
|
|
}
|
|
else
|
|
{
|
|
m_owner->SetStatusText(wxEmptyString, 1);
|
|
}
|
|
|
|
Refresh();
|
|
}
|
|
#endif // wxUSE_GRAPHICS_CONTEXT
|
|
|
|
|
|
#if wxUSE_DC_TRANSFORM_MATRIX
|
|
#include <wx/valnum.h>
|
|
|
|
class TransformDataDialog : public wxDialog
|
|
{
|
|
public:
|
|
TransformDataDialog(wxWindow* parent, wxDouble dx, wxDouble dy, wxDouble scx, wxDouble scy, wxDouble rotAngle)
|
|
: wxDialog(parent, wxID_ANY, "Affine transformation parameters")
|
|
, m_dx(dx)
|
|
, m_dy(dy)
|
|
, m_scx(scx)
|
|
, m_scy(scy)
|
|
, m_rotAngle(rotAngle)
|
|
{
|
|
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
|
|
|
const int border = wxSizerFlags::GetDefaultBorder();
|
|
wxFlexGridSizer* paramSizer = new wxFlexGridSizer(2, wxSize(border, border));
|
|
paramSizer->Add(new wxStaticText(this, wxID_ANY, "Translation X:"), wxSizerFlags().CentreVertical());
|
|
wxFloatingPointValidator<wxDouble> val_dx(1, &m_dx, wxNUM_VAL_NO_TRAILING_ZEROES);
|
|
paramSizer->Add(new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, 0, val_dx), wxSizerFlags().CentreVertical());
|
|
paramSizer->Add(new wxStaticText(this, wxID_ANY, "Translation Y:"), wxSizerFlags().CentreVertical());
|
|
wxFloatingPointValidator<wxDouble> val_dy(1, &m_dy, wxNUM_VAL_NO_TRAILING_ZEROES);
|
|
paramSizer->Add(new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, 0, val_dy), wxSizerFlags().CentreVertical());
|
|
paramSizer->Add(new wxStaticText(this, wxID_ANY, "Scale X (0.2 - 5):"), wxSizerFlags().CentreVertical());
|
|
wxFloatingPointValidator<wxDouble> val_scx(2, &m_scx, wxNUM_VAL_NO_TRAILING_ZEROES);
|
|
paramSizer->Add(new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, 0, val_scx), wxSizerFlags().CentreVertical());
|
|
paramSizer->Add(new wxStaticText(this, wxID_ANY, "Scale Y (0.2 - 5):"), wxSizerFlags().CentreVertical());
|
|
wxFloatingPointValidator<wxDouble> val_scy(2, &m_scy, wxNUM_VAL_NO_TRAILING_ZEROES);
|
|
paramSizer->Add(new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, 0, val_scy), wxSizerFlags().CentreVertical());
|
|
paramSizer->Add(new wxStaticText(this, wxID_ANY, "Rotation angle (deg):"), wxSizerFlags().CentreVertical());
|
|
wxFloatingPointValidator<wxDouble> val_rot(1, &m_rotAngle, wxNUM_VAL_NO_TRAILING_ZEROES);
|
|
paramSizer->Add(new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, 0, val_rot), wxSizerFlags().CentreVertical());
|
|
sizer->Add(paramSizer, wxSizerFlags().DoubleBorder());
|
|
|
|
wxSizer *btnSizer = CreateSeparatedButtonSizer(wxOK | wxCANCEL);
|
|
sizer->Add(btnSizer, wxSizerFlags().Expand().Border());
|
|
|
|
SetSizerAndFit(sizer);
|
|
}
|
|
|
|
virtual bool TransferDataFromWindow() wxOVERRIDE
|
|
{
|
|
if ( !wxDialog::TransferDataFromWindow() )
|
|
return false;
|
|
|
|
if ( m_scx < 0.2 || m_scx > 5.0 || m_scy < 0.2 || m_scy > 5.0 )
|
|
{
|
|
if ( !wxValidator::IsSilent() )
|
|
wxBell();
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void GetTransformationData(wxDouble* dx, wxDouble* dy, wxDouble* scx, wxDouble* scy, wxDouble* rotAngle) const
|
|
{
|
|
if ( dx )
|
|
*dx = m_dx;
|
|
|
|
if ( dy )
|
|
*dy = m_dy;
|
|
|
|
if ( scx )
|
|
*scx = m_scx;
|
|
|
|
if ( scy )
|
|
*scy = m_scy;
|
|
|
|
if ( rotAngle )
|
|
*rotAngle = m_rotAngle;
|
|
}
|
|
|
|
private:
|
|
wxDouble m_dx;
|
|
wxDouble m_dy;
|
|
wxDouble m_scx;
|
|
wxDouble m_scy;
|
|
wxDouble m_rotAngle;
|
|
};
|
|
#endif // wxUSE_DC_TRANSFORM_MATRIX
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// MyFrame
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// the event tables connect the wxWidgets events with the functions (event
|
|
// handlers) which process them. It can be also done at run-time, but for the
|
|
// simple menu events like this the static method is much simpler.
|
|
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
|
|
EVT_MENU (File_Quit, MyFrame::OnQuit)
|
|
EVT_MENU (File_About, MyFrame::OnAbout)
|
|
EVT_MENU (File_Clip, MyFrame::OnClip)
|
|
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
EVT_MENU (File_GC_Default, MyFrame::OnGraphicContextDefault)
|
|
EVT_MENU (File_DC, MyFrame::OnGraphicContextNone)
|
|
#if wxUSE_CAIRO
|
|
EVT_MENU (File_GC_Cairo, MyFrame::OnGraphicContextCairo)
|
|
#endif // wxUSE_CAIRO
|
|
#ifdef __WXMSW__
|
|
#if wxUSE_GRAPHICS_GDIPLUS
|
|
EVT_MENU (File_GC_GDIPlus, MyFrame::OnGraphicContextGDIPlus)
|
|
#endif
|
|
#if wxUSE_GRAPHICS_DIRECT2D
|
|
EVT_MENU (File_GC_Direct2D, MyFrame::OnGraphicContextDirect2D)
|
|
#endif
|
|
#endif // __WXMSW__
|
|
EVT_MENU (File_AntiAliasing, MyFrame::OnAntiAliasing)
|
|
EVT_UPDATE_UI (File_AntiAliasing, MyFrame::OnAntiAliasingUpdateUI)
|
|
#endif // wxUSE_GRAPHICS_CONTEXT
|
|
|
|
EVT_MENU (File_Buffer, MyFrame::OnBuffer)
|
|
EVT_MENU (File_Copy, MyFrame::OnCopy)
|
|
EVT_MENU (File_Save, MyFrame::OnSave)
|
|
EVT_MENU (File_BBox, MyFrame::OnBoundingBox)
|
|
EVT_UPDATE_UI (File_BBox, MyFrame::OnBoundingBoxUpdateUI)
|
|
|
|
EVT_MENU_RANGE(MenuShow_First, MenuShow_Last, MyFrame::OnShow)
|
|
|
|
EVT_MENU_RANGE(MenuOption_First, MenuOption_Last, MyFrame::OnOption)
|
|
wxEND_EVENT_TABLE()
|
|
|
|
// frame constructor
|
|
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
|
|
: wxFrame((wxFrame *)NULL, wxID_ANY, title, pos, size)
|
|
{
|
|
// set the frame icon
|
|
SetIcon(wxICON(sample));
|
|
|
|
wxMenu *menuScreen = new wxMenu;
|
|
menuScreen->Append(File_ShowDefault, "&Default screen\tF1");
|
|
menuScreen->Append(File_ShowText, "&Text screen\tF2");
|
|
menuScreen->Append(File_ShowLines, "&Lines screen\tF3");
|
|
menuScreen->Append(File_ShowBrushes, "&Brushes screen\tF4");
|
|
menuScreen->Append(File_ShowPolygons, "&Polygons screen\tF5");
|
|
menuScreen->Append(File_ShowMask, "&Mask screen\tF6");
|
|
menuScreen->Append(File_ShowMaskStretch, "1/&2 scaled mask\tShift-F6");
|
|
menuScreen->Append(File_ShowOps, "&Raster operations screen\tF7");
|
|
menuScreen->Append(File_ShowRegions, "Re&gions screen\tF8");
|
|
menuScreen->Append(File_ShowCircles, "&Circles screen\tF9");
|
|
#if wxDRAWING_DC_SUPPORTS_ALPHA || wxUSE_GRAPHICS_CONTEXT
|
|
menuScreen->Append(File_ShowAlpha, "&Alpha screen\tF10");
|
|
#endif // wxDRAWING_DC_SUPPORTS_ALPHA || wxUSE_GRAPHICS_CONTEXT
|
|
menuScreen->Append(File_ShowSplines, "Spl&ines screen\tF11");
|
|
menuScreen->Append(File_ShowGradients, "&Gradients screen\tF12");
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
menuScreen->Append(File_ShowGraphics, "&Graphics screen");
|
|
#endif
|
|
menuScreen->Append(File_ShowSystemColours, "System &colours");
|
|
|
|
wxMenu *menuFile = new wxMenu;
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
// Number the different renderer choices consecutively, starting from 0.
|
|
int accel = 0;
|
|
m_menuItemUseDC = menuFile->AppendRadioItem
|
|
(
|
|
File_DC,
|
|
wxString::Format("Use wx&DC\t%d", accel++)
|
|
);
|
|
menuFile->AppendRadioItem
|
|
(
|
|
File_GC_Default,
|
|
wxString::Format("Use default wx&GraphicContext\t%d", accel++)
|
|
);
|
|
#if wxUSE_CAIRO
|
|
menuFile->AppendRadioItem
|
|
(
|
|
File_GC_Cairo,
|
|
wxString::Format("Use &Cairo\t%d", accel++)
|
|
);
|
|
#endif // wxUSE_CAIRO
|
|
#ifdef __WXMSW__
|
|
#if wxUSE_GRAPHICS_GDIPLUS
|
|
menuFile->AppendRadioItem
|
|
(
|
|
File_GC_GDIPlus,
|
|
wxString::Format("Use &GDI+\t%d", accel++)
|
|
);
|
|
#endif
|
|
#if wxUSE_GRAPHICS_DIRECT2D
|
|
menuFile->AppendRadioItem
|
|
(
|
|
File_GC_Direct2D,
|
|
wxString::Format("Use &Direct2D\t%d", accel++)
|
|
);
|
|
#endif
|
|
#endif // __WXMSW__
|
|
#endif // wxUSE_GRAPHICS_CONTEXT
|
|
menuFile->AppendSeparator();
|
|
menuFile->AppendCheckItem(File_BBox, "Show bounding box\tCtrl-E",
|
|
"Show extents used in drawing operations");
|
|
menuFile->AppendCheckItem(File_Clip, "&Clip\tCtrl-C", "Clip/unclip drawing");
|
|
menuFile->AppendCheckItem(File_Buffer, "&Use wx&BufferedPaintDC\tCtrl-Z", "Buffer painting");
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
menuFile->AppendCheckItem(File_AntiAliasing,
|
|
"&Anti-Aliasing in wxGraphicContext\tCtrl-Shift-A",
|
|
"Enable Anti-Aliasing in wxGraphicContext")
|
|
->Check();
|
|
#endif
|
|
menuFile->AppendSeparator();
|
|
#if wxUSE_METAFILE && defined(wxMETAFILE_IS_ENH)
|
|
menuFile->Append(File_Copy, "Copy to clipboard");
|
|
#endif
|
|
menuFile->Append(File_Save, "&Save...\tCtrl-S", "Save drawing to file");
|
|
menuFile->AppendSeparator();
|
|
menuFile->Append(File_About, "&About\tCtrl-A", "Show about dialog");
|
|
menuFile->AppendSeparator();
|
|
menuFile->Append(File_Quit, "E&xit\tAlt-X", "Quit this program");
|
|
|
|
wxMenu *menuMapMode = new wxMenu;
|
|
menuMapMode->Append( MapMode_Text, "&TEXT map mode" );
|
|
menuMapMode->Append( MapMode_Lometric, "&LOMETRIC map mode" );
|
|
menuMapMode->Append( MapMode_Twips, "T&WIPS map mode" );
|
|
menuMapMode->Append( MapMode_Points, "&POINTS map mode" );
|
|
menuMapMode->Append( MapMode_Metric, "&METRIC map mode" );
|
|
|
|
wxMenu *menuUserScale = new wxMenu;
|
|
menuUserScale->Append( UserScale_StretchHoriz, "Stretch &horizontally\tCtrl-H" );
|
|
menuUserScale->Append( UserScale_ShrinkHoriz, "Shrin&k horizontally\tCtrl-G" );
|
|
menuUserScale->Append( UserScale_StretchVertic, "Stretch &vertically\tCtrl-V" );
|
|
menuUserScale->Append( UserScale_ShrinkVertic, "&Shrink vertically\tCtrl-W" );
|
|
menuUserScale->AppendSeparator();
|
|
menuUserScale->Append( UserScale_Restore, "&Restore to normal\tCtrl-0" );
|
|
|
|
wxMenu *menuAxis = new wxMenu;
|
|
menuAxis->AppendCheckItem( AxisMirror_Horiz, "Mirror horizontally\tCtrl-M" );
|
|
menuAxis->AppendCheckItem( AxisMirror_Vertic, "Mirror vertically\tCtrl-N" );
|
|
|
|
wxMenu *menuLogical = new wxMenu;
|
|
menuLogical->Append( LogicalOrigin_MoveDown, "Move &down\tCtrl-D" );
|
|
menuLogical->Append( LogicalOrigin_MoveUp, "Move &up\tCtrl-U" );
|
|
menuLogical->Append( LogicalOrigin_MoveLeft, "Move &right\tCtrl-L" );
|
|
menuLogical->Append( LogicalOrigin_MoveRight, "Move &left\tCtrl-R" );
|
|
menuLogical->AppendSeparator();
|
|
menuLogical->Append( LogicalOrigin_Set, "Set to (&100, 100)\tShift-Ctrl-1" );
|
|
menuLogical->Append( LogicalOrigin_Restore, "&Restore to normal\tShift-Ctrl-0" );
|
|
|
|
#if wxUSE_DC_TRANSFORM_MATRIX
|
|
wxMenu *menuTransformMatrix = new wxMenu;
|
|
menuTransformMatrix->Append(TransformMatrix_Set, "Set &transformation matrix");
|
|
menuTransformMatrix->AppendSeparator();
|
|
menuTransformMatrix->Append(TransformMatrix_Reset, "Restore to &normal");
|
|
#endif // wxUSE_DC_TRANSFORM_MATRIX
|
|
|
|
wxMenu *menuColour = new wxMenu;
|
|
#if wxUSE_COLOURDLG
|
|
menuColour->Append( Colour_TextForeground, "Text &foreground..." );
|
|
menuColour->Append( Colour_TextBackground, "Text &background..." );
|
|
menuColour->Append( Colour_Background, "Background &colour..." );
|
|
#endif // wxUSE_COLOURDLG
|
|
menuColour->AppendCheckItem( Colour_BackgroundMode, "&Opaque/transparent\tCtrl-B" );
|
|
menuColour->AppendCheckItem( Colour_TextureBackgound, "Draw textured back&ground\tCtrl-T" );
|
|
|
|
// now append the freshly created menu to the menu bar...
|
|
wxMenuBar *menuBar = new wxMenuBar;
|
|
menuBar->Append(menuFile, "&Drawing");
|
|
menuBar->Append(menuScreen, "Scree&n");
|
|
menuBar->Append(menuMapMode, "&Mode");
|
|
menuBar->Append(menuUserScale, "&Scale");
|
|
menuBar->Append(menuAxis, "&Axis");
|
|
menuBar->Append(menuLogical, "&Origin");
|
|
#if wxUSE_DC_TRANSFORM_MATRIX
|
|
menuBar->Append(menuTransformMatrix, "&Transformation");
|
|
#endif // wxUSE_DC_TRANSFORM_MATRIX
|
|
menuBar->Append(menuColour, "&Colours");
|
|
|
|
// ... and attach this menu bar to the frame
|
|
SetMenuBar(menuBar);
|
|
|
|
#if wxUSE_STATUSBAR
|
|
CreateStatusBar(2);
|
|
SetStatusText("Welcome to wxWidgets!");
|
|
#endif // wxUSE_STATUSBAR
|
|
|
|
m_mapMode = wxMM_TEXT;
|
|
m_xUserScale = 1.0;
|
|
m_yUserScale = 1.0;
|
|
m_xLogicalOrigin = 0;
|
|
m_yLogicalOrigin = 0;
|
|
m_xAxisReversed =
|
|
m_yAxisReversed = false;
|
|
#if wxUSE_DC_TRANSFORM_MATRIX
|
|
m_transform_dx = 0.0;
|
|
m_transform_dy = 0.0;
|
|
m_transform_scx = 1.0;
|
|
m_transform_scy = 1.0;
|
|
m_transform_rot = 0.0;
|
|
#endif // wxUSE_DC_TRANSFORM_MATRIX
|
|
m_backgroundMode = wxBRUSHSTYLE_SOLID;
|
|
m_colourForeground = *wxBLACK;
|
|
m_colourBackground = *wxLIGHT_GREY;
|
|
m_textureBackground = false;
|
|
|
|
m_canvas = new MyCanvas( this );
|
|
m_canvas->SetScrollbars( 10, 10, 100, 240 );
|
|
}
|
|
|
|
// event handlers
|
|
|
|
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
// true is to force the frame to close
|
|
Close(true);
|
|
}
|
|
|
|
void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
wxString msg;
|
|
msg.Printf( "This is the about dialog of the drawing sample.\n"
|
|
"This sample tests various primitive drawing functions\n"
|
|
"(without any attempts to prevent flicker).\n"
|
|
"Copyright (c) Robert Roebling 1999"
|
|
);
|
|
|
|
wxMessageBox(msg, "About Drawing", wxOK | wxICON_INFORMATION, this);
|
|
}
|
|
|
|
void MyFrame::OnClip(wxCommandEvent& event)
|
|
{
|
|
m_canvas->Clip(event.IsChecked());
|
|
}
|
|
|
|
void MyFrame::OnBuffer(wxCommandEvent& event)
|
|
{
|
|
m_canvas->UseBuffer(event.IsChecked());
|
|
}
|
|
|
|
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))
|
|
{
|
|
wxString wildCard = "Bitmap image (*.bmp)|*.bmp;*.BMP";
|
|
#if wxUSE_LIBPNG
|
|
wildCard.Append("|PNG image (*.png)|*.png;*.PNG");
|
|
#endif
|
|
#if wxUSE_SVG
|
|
wildCard.Append("|SVG image (*.svg)|*.svg;*.SVG");
|
|
#endif
|
|
#if wxUSE_POSTSCRIPT
|
|
wildCard.Append("|PostScript file (*.ps)|*.ps;*.PS");
|
|
#endif
|
|
|
|
wxFileDialog dlg(this, "Save as bitmap", wxEmptyString, wxEmptyString,
|
|
wildCard,
|
|
wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
|
if (dlg.ShowModal() == wxID_OK)
|
|
{
|
|
int width, height;
|
|
m_canvas->GetDrawingSize(&width, &height);
|
|
wxFileName fn(dlg.GetPath());
|
|
wxString ext = fn.GetExt().Lower();
|
|
#if wxUSE_SVG
|
|
if (ext == "svg")
|
|
{
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
// Graphics screen can only be drawn using GraphicsContext
|
|
if (m_canvas->GetPage() == File_ShowGraphics) {
|
|
wxLogMessage("Graphics screen can not be saved as SVG.");
|
|
return;
|
|
}
|
|
wxGraphicsRenderer* tempRenderer = m_canvas->GetRenderer();
|
|
m_canvas->UseGraphicRenderer(NULL);
|
|
#endif
|
|
wxSVGFileDC svgdc(dlg.GetPath(), width, height, 72, "Drawing sample");
|
|
svgdc.SetBitmapHandler(new wxSVGBitmapEmbedHandler());
|
|
m_canvas->Draw(svgdc);
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
m_canvas->UseGraphicRenderer(tempRenderer);
|
|
#endif
|
|
}
|
|
else
|
|
#endif
|
|
#if wxUSE_POSTSCRIPT
|
|
if ( ext == "ps" )
|
|
{
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
// Graphics screen can only be drawn using wxGraphicsContext
|
|
if (m_canvas->GetPage() == File_ShowGraphics)
|
|
{
|
|
wxLogMessage("Graphics screen can not be saved as PostScript file.");
|
|
return;
|
|
}
|
|
wxGraphicsRenderer* curRenderer = m_canvas->GetRenderer();
|
|
m_canvas->UseGraphicRenderer(NULL);
|
|
#endif // wxUSE_GRAPHICS_CONTEXT
|
|
wxPrintData printData;
|
|
printData.SetPrintMode(wxPRINT_MODE_FILE);
|
|
printData.SetFilename(dlg.GetPath());
|
|
printData.SetOrientation(wxPORTRAIT);
|
|
printData.SetPaperId(wxPAPER_A4);
|
|
wxPostScriptDC psdc(printData);
|
|
// Save current scale factor
|
|
const double curUserScaleX = m_xUserScale;
|
|
const double curUserScaleY = m_yUserScale;
|
|
// Change the scale temporarily to fit the drawing into the page.
|
|
int w, h;
|
|
psdc.GetSize(&w, &h);
|
|
double sc = wxMin((double)w / width, (double)h / height);
|
|
m_xUserScale *= sc;
|
|
m_yUserScale *= sc;
|
|
psdc.StartDoc("Drawing sample");
|
|
// Define default font.
|
|
psdc.SetFont( wxFontInfo(10).Family(wxFONTFAMILY_MODERN) );
|
|
psdc.StartPage();
|
|
m_canvas->Draw(psdc);
|
|
psdc.EndPage();
|
|
psdc.EndDoc();
|
|
// Restore original scale facor
|
|
m_xUserScale = curUserScaleX;
|
|
m_yUserScale = curUserScaleY;
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
m_canvas->UseGraphicRenderer(curRenderer);
|
|
#endif // wxUSE_GRAPHICS_CONTEXT
|
|
}
|
|
else
|
|
#endif // wxUSE_POSTSCRIPT
|
|
{
|
|
wxBitmap bmp(width, height);
|
|
wxMemoryDC mdc(bmp);
|
|
mdc.SetBackground(*wxWHITE_BRUSH);
|
|
mdc.Clear();
|
|
m_canvas->Draw(mdc);
|
|
bmp.ConvertToImage().SaveFile(dlg.GetPath());
|
|
}
|
|
}
|
|
}
|
|
|
|
void MyFrame::OnShow(wxCommandEvent& event)
|
|
{
|
|
const int show = event.GetId();
|
|
|
|
#if wxDRAWING_DC_SUPPORTS_ALPHA || wxUSE_GRAPHICS_CONTEXT
|
|
// Make sure we do use a graphics context when selecting one of the screens
|
|
// requiring it.
|
|
#if wxDRAWING_DC_SUPPORTS_ALPHA
|
|
// If DC supports drawing with alpha
|
|
// then GC is necessary only for graphics screen.
|
|
if ( show == File_ShowGraphics )
|
|
#else // wxUSE_GRAPHICS_CONTEXT
|
|
// DC doesn't support drawing with alpha
|
|
// so GC is necessary both for alpha and graphics screen.
|
|
if ( show == File_ShowAlpha || show == File_ShowGraphics )
|
|
#endif // wxDRAWING_DC_SUPPORTS_ALPHA, wxUSE_GRAPHICS_CONTEXT
|
|
{
|
|
if ( !m_canvas->HasRenderer() )
|
|
m_canvas->UseGraphicRenderer(wxGraphicsRenderer::GetDefaultRenderer());
|
|
// Disable selecting wxDC, if necessary.
|
|
m_menuItemUseDC->Enable(!m_canvas->HasRenderer());
|
|
}
|
|
else
|
|
{
|
|
m_menuItemUseDC->Enable(true);
|
|
}
|
|
#endif // wxDRAWING_DC_SUPPORTS_ALPHA || wxUSE_GRAPHICS_CONTEXT
|
|
m_canvas->ToShow(show);
|
|
}
|
|
|
|
void MyFrame::OnOption(wxCommandEvent& event)
|
|
{
|
|
switch (event.GetId())
|
|
{
|
|
case MapMode_Text:
|
|
m_mapMode = wxMM_TEXT;
|
|
break;
|
|
case MapMode_Lometric:
|
|
m_mapMode = wxMM_LOMETRIC;
|
|
break;
|
|
case MapMode_Twips:
|
|
m_mapMode = wxMM_TWIPS;
|
|
break;
|
|
case MapMode_Points:
|
|
m_mapMode = wxMM_POINTS;
|
|
break;
|
|
case MapMode_Metric:
|
|
m_mapMode = wxMM_METRIC;
|
|
break;
|
|
|
|
case LogicalOrigin_MoveDown:
|
|
m_yLogicalOrigin += 10;
|
|
break;
|
|
case LogicalOrigin_MoveUp:
|
|
m_yLogicalOrigin -= 10;
|
|
break;
|
|
case LogicalOrigin_MoveLeft:
|
|
m_xLogicalOrigin += 10;
|
|
break;
|
|
case LogicalOrigin_MoveRight:
|
|
m_xLogicalOrigin -= 10;
|
|
break;
|
|
case LogicalOrigin_Set:
|
|
m_xLogicalOrigin =
|
|
m_yLogicalOrigin = -100;
|
|
break;
|
|
case LogicalOrigin_Restore:
|
|
m_xLogicalOrigin =
|
|
m_yLogicalOrigin = 0;
|
|
break;
|
|
|
|
case UserScale_StretchHoriz:
|
|
m_xUserScale *= 1.10;
|
|
break;
|
|
case UserScale_ShrinkHoriz:
|
|
m_xUserScale /= 1.10;
|
|
break;
|
|
case UserScale_StretchVertic:
|
|
m_yUserScale *= 1.10;
|
|
break;
|
|
case UserScale_ShrinkVertic:
|
|
m_yUserScale /= 1.10;
|
|
break;
|
|
case UserScale_Restore:
|
|
m_xUserScale =
|
|
m_yUserScale = 1.0;
|
|
break;
|
|
|
|
case AxisMirror_Vertic:
|
|
m_yAxisReversed = !m_yAxisReversed;
|
|
break;
|
|
case AxisMirror_Horiz:
|
|
m_xAxisReversed = !m_xAxisReversed;
|
|
break;
|
|
|
|
#if wxUSE_DC_TRANSFORM_MATRIX
|
|
case TransformMatrix_Set:
|
|
{
|
|
TransformDataDialog dlg(this, m_transform_dx, m_transform_dy,
|
|
m_transform_scx, m_transform_scy, m_transform_rot);
|
|
if ( dlg.ShowModal() == wxID_OK )
|
|
{
|
|
dlg.GetTransformationData(&m_transform_dx, &m_transform_dy,
|
|
&m_transform_scx, &m_transform_scy, &m_transform_rot);
|
|
}
|
|
}
|
|
break;
|
|
case TransformMatrix_Reset:
|
|
m_transform_dx = 0.0;
|
|
m_transform_dy = 0.0;
|
|
m_transform_scx = 1.0;
|
|
m_transform_scy = 1.0;
|
|
m_transform_rot = 0.0;
|
|
break;
|
|
#endif // wxUSE_DC_TRANSFORM_MATRIX
|
|
|
|
#if wxUSE_COLOURDLG
|
|
case Colour_TextForeground:
|
|
m_colourForeground = SelectColour();
|
|
break;
|
|
case Colour_TextBackground:
|
|
m_colourBackground = SelectColour();
|
|
break;
|
|
case Colour_Background:
|
|
{
|
|
wxColour col = SelectColour();
|
|
if ( col.IsOk() )
|
|
{
|
|
m_backgroundBrush.SetColour(col);
|
|
}
|
|
}
|
|
break;
|
|
#endif // wxUSE_COLOURDLG
|
|
|
|
case Colour_BackgroundMode:
|
|
m_backgroundMode = m_backgroundMode == wxBRUSHSTYLE_SOLID
|
|
? wxBRUSHSTYLE_TRANSPARENT
|
|
: wxBRUSHSTYLE_SOLID;
|
|
break;
|
|
|
|
case Colour_TextureBackgound:
|
|
m_textureBackground = ! m_textureBackground;
|
|
break;
|
|
|
|
default:
|
|
// skip Refresh()
|
|
return;
|
|
}
|
|
|
|
m_canvas->Refresh();
|
|
}
|
|
|
|
void MyFrame::OnBoundingBox(wxCommandEvent& evt)
|
|
{
|
|
m_canvas->ShowBoundingBox(evt.IsChecked());
|
|
}
|
|
|
|
void MyFrame::OnBoundingBoxUpdateUI(wxUpdateUIEvent& evt)
|
|
{
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
evt.Enable(m_canvas->GetPage() != File_ShowGraphics);
|
|
#else
|
|
wxUnusedVar(evt);
|
|
#endif // wxUSE_GRAPHICS_CONTEXT / !wxUSE_GRAPHICS_CONTEXT
|
|
}
|
|
|
|
void MyFrame::PrepareDC(wxDC& dc)
|
|
{
|
|
#if wxUSE_DC_TRANSFORM_MATRIX
|
|
if ( dc.CanUseTransformMatrix() )
|
|
{
|
|
wxAffineMatrix2D mtx;
|
|
mtx.Translate(m_transform_dx, m_transform_dy);
|
|
mtx.Rotate(wxDegToRad(m_transform_rot));
|
|
mtx.Scale(m_transform_scx, m_transform_scy);
|
|
dc.SetTransformMatrix(mtx);
|
|
}
|
|
#endif // wxUSE_DC_TRANSFORM_MATRIX
|
|
dc.SetLogicalOrigin( m_xLogicalOrigin, m_yLogicalOrigin );
|
|
dc.SetAxisOrientation( !m_xAxisReversed, m_yAxisReversed );
|
|
dc.SetUserScale( m_xUserScale, m_yUserScale );
|
|
dc.SetMapMode( m_mapMode );
|
|
}
|
|
|
|
#if wxUSE_COLOURDLG
|
|
wxColour MyFrame::SelectColour()
|
|
{
|
|
wxColour col;
|
|
wxColourData data;
|
|
wxColourDialog dialog(this, &data);
|
|
|
|
if ( dialog.ShowModal() == wxID_OK )
|
|
{
|
|
col = dialog.GetColourData().GetColour();
|
|
}
|
|
|
|
return col;
|
|
}
|
|
#endif // wxUSE_COLOURDLG
|