From 1d117b75f74e849ac4e94fe699d1e547014edc33 Mon Sep 17 00:00:00 2001 From: Jay Nabonne Date: Wed, 16 Jan 2019 09:23:12 +0000 Subject: [PATCH] Add wxGraphicsContext implementation for wxQt Add graphics renderer using Qt classes and use it by default in wxQt port under MSW. Closes https://github.com/wxWidgets/wxWidgets/pull/1139 --- Makefile.in | 24 +- build/bakefiles/files.bkl | 1 + build/cmake/files.cmake | 1 + build/files | 1 + src/generic/graphicc.cpp | 8 +- src/qt/graphics.cpp | 1371 +++++++++++++++++++++++++++++++++++++ 6 files changed, 1398 insertions(+), 8 deletions(-) create mode 100644 src/qt/graphics.cpp diff --git a/Makefile.in b/Makefile.in index b72e564934..91d6281b53 100644 --- a/Makefile.in +++ b/Makefile.in @@ -5747,7 +5747,8 @@ COND_PLATFORM_WIN32_1___QT_PLATFORM_SRC_OBJECTS = \ monodll_uuid.o \ monodll_safearray.o \ monodll_msw_sound.o \ - monodll_automtn.o + monodll_automtn.o \ + monodll_qt_graphics.o @COND_PLATFORM_WIN32_1@__QT_PLATFORM_SRC_OBJECTS = $(COND_PLATFORM_WIN32_1___QT_PLATFORM_SRC_OBJECTS) COND_TOOLKIT_DFB___LOWLEVEL_SRC_OBJECTS_1 = \ monodll_fontmgrcmn.o \ @@ -7725,7 +7726,8 @@ COND_PLATFORM_WIN32_1___QT_PLATFORM_SRC_OBJECTS_1 = \ monolib_uuid.o \ monolib_safearray.o \ monolib_msw_sound.o \ - monolib_automtn.o + monolib_automtn.o \ + monolib_qt_graphics.o @COND_PLATFORM_WIN32_1@__QT_PLATFORM_SRC_OBJECTS_1 = $(COND_PLATFORM_WIN32_1___QT_PLATFORM_SRC_OBJECTS_1) COND_TOOLKIT_DFB___LOWLEVEL_SRC_OBJECTS_3 = \ monolib_fontmgrcmn.o \ @@ -9850,7 +9852,8 @@ COND_PLATFORM_WIN32_1___QT_PLATFORM_SRC_OBJECTS_2 = \ coredll_uuid.o \ coredll_safearray.o \ coredll_msw_sound.o \ - coredll_automtn.o + coredll_automtn.o \ + coredll_qt_graphics.o @COND_PLATFORM_WIN32_1@__QT_PLATFORM_SRC_OBJECTS_2 = $(COND_PLATFORM_WIN32_1___QT_PLATFORM_SRC_OBJECTS_2) COND_TOOLKIT_DFB___LOWLEVEL_SRC_OBJECTS_5 = \ coredll_fontmgrcmn.o \ @@ -11570,7 +11573,8 @@ COND_PLATFORM_WIN32_1___QT_PLATFORM_SRC_OBJECTS_3 = \ corelib_uuid.o \ corelib_safearray.o \ corelib_msw_sound.o \ - corelib_automtn.o + corelib_automtn.o \ + corelib_qt_graphics.o @COND_PLATFORM_WIN32_1@__QT_PLATFORM_SRC_OBJECTS_3 = $(COND_PLATFORM_WIN32_1___QT_PLATFORM_SRC_OBJECTS_3) COND_TOOLKIT_DFB___LOWLEVEL_SRC_OBJECTS_7 = \ corelib_fontmgrcmn.o \ @@ -16826,6 +16830,9 @@ monodll_qt_utils.o: $(srcdir)/src/qt/utils.cpp $(MONODLL_ODEP) monodll_qt_window.o: $(srcdir)/src/qt/window.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/qt/window.cpp +monodll_qt_graphics.o: $(srcdir)/src/qt/graphics.cpp $(MONODLL_ODEP) + $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/qt/graphics.cpp + monodll_univ_anybutton.o: $(srcdir)/src/univ/anybutton.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/univ/anybutton.cpp @@ -22082,6 +22089,9 @@ monolib_qt_utils.o: $(srcdir)/src/qt/utils.cpp $(MONOLIB_ODEP) monolib_qt_window.o: $(srcdir)/src/qt/window.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/qt/window.cpp +monolib_qt_graphics.o: $(srcdir)/src/qt/graphics.cpp $(MONOLIB_ODEP) + $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/qt/graphics.cpp + monolib_univ_anybutton.o: $(srcdir)/src/univ/anybutton.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/univ/anybutton.cpp @@ -27998,6 +28008,9 @@ coredll_qt_utils.o: $(srcdir)/src/qt/utils.cpp $(COREDLL_ODEP) coredll_qt_window.o: $(srcdir)/src/qt/window.cpp $(COREDLL_ODEP) $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/qt/window.cpp +coredll_qt_graphics.o: $(srcdir)/src/qt/graphics.cpp $(COREDLL_ODEP) + $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/qt/graphics.cpp + coredll_univ_anybutton.o: $(srcdir)/src/univ/anybutton.cpp $(COREDLL_ODEP) $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/univ/anybutton.cpp @@ -32249,6 +32262,9 @@ corelib_qt_utils.o: $(srcdir)/src/qt/utils.cpp $(CORELIB_ODEP) corelib_qt_window.o: $(srcdir)/src/qt/window.cpp $(CORELIB_ODEP) $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/qt/window.cpp +corelib_qt_graphics.o: $(srcdir)/src/qt/graphics.cpp $(CORELIB_ODEP) + $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/qt/graphics.cpp + corelib_univ_anybutton.o: $(srcdir)/src/univ/anybutton.cpp $(CORELIB_ODEP) $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/univ/anybutton.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index 6001ccbd34..b7cc9e1699 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -252,6 +252,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/msw/ole/safearray.cpp src/msw/sound.cpp src/msw/ole/automtn.cpp + src/qt/graphics.cpp diff --git a/build/cmake/files.cmake b/build/cmake/files.cmake index c126d0f237..75cc4a916f 100644 --- a/build/cmake/files.cmake +++ b/build/cmake/files.cmake @@ -175,6 +175,7 @@ set(QT_WIN32_SRC src/msw/dialup.cpp src/msw/dib.cpp src/msw/joystick.cpp + src/qt/graphics.cpp ) set(QT_WIN32_HDR diff --git a/build/files b/build/files index 13a542b9c9..8df05a9460 100644 --- a/build/files +++ b/build/files @@ -199,6 +199,7 @@ QT_WIN32_SRC= src/msw/dib.cpp src/msw/joystick.cpp src/msw/sound.cpp + src/qt/graphics.cpp QT_WIN32_HDR= wx/msw/ole/automtn.h diff --git a/src/generic/graphicc.cpp b/src/generic/graphicc.cpp index a8876075ef..f855e1e37e 100644 --- a/src/generic/graphicc.cpp +++ b/src/generic/graphicc.cpp @@ -3330,13 +3330,13 @@ wxGraphicsRenderer* wxGraphicsRenderer::GetCairoRenderer() #endif // wxUSE_CAIRO/!wxUSE_CAIRO -// MSW and OS X have their own native default renderers, but the other ports -// use Cairo by default -#if !(defined(__WXMSW__) || defined(__WXOSX__)) +// MSW and OS X and Qt on Windows have their own native default renderers, but the other ports +// use Cairo by default. +#if !(defined(__WXMSW__) || defined(__WXOSX__) || (defined(__WXQT__) && defined(__WIN32__))) wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer() { return GetCairoRenderer(); } -#endif // !(__WXMSW__ || __WXOSX__) +#endif // !(__WXMSW__ || __WXOSX__ || (defined(__WXQT__) && defined(__WIN32__))) #endif // wxUSE_GRAPHICS_CONTEXT diff --git a/src/qt/graphics.cpp b/src/qt/graphics.cpp new file mode 100644 index 0000000000..97feabff96 --- /dev/null +++ b/src/qt/graphics.cpp @@ -0,0 +1,1371 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/qt/graphics.cpp +// Purpose: Graphics context methods for the Qt platform +// Author: Jay Nabonne +// Created: 2018-12-13 +// Copyright: (c) Jay Nabonne +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#if wxUSE_GRAPHICS_CONTEXT + +#include +#include +#include + +#ifndef WX_PRECOMP + #include "wx/bitmap.h" + #include "wx/icon.h" + #include "wx/dcclient.h" + #include "wx/dcmemory.h" + #include "wx/dcprint.h" + #include "wx/window.h" +#endif + +#include "wx/graphics.h" +#include "wx/tokenzr.h" + +#include "wx/private/graphics.h" + +class WXDLLIMPEXP_CORE wxQtBrushData : public wxGraphicsObjectRefData +{ +public: + wxQtBrushData(wxGraphicsRenderer* renderer) + : wxGraphicsObjectRefData(renderer) + { + } + + wxQtBrushData(wxGraphicsRenderer* renderer, const wxBrush& wxbrush) + : wxGraphicsObjectRefData(renderer), + m_brush(wxbrush.GetHandle()) + { + } + + void CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops) + { + QLinearGradient gradient(x1, y1, x2, y2); + SetStops(gradient, stops); + m_brush = QBrush(gradient); + } + + void CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops) + { + QRadialGradient gradient(QPointF(xc, yc), radius, QPointF(xo, yo)); + SetStops(gradient, stops); + m_brush = QBrush(gradient); + } + + const QBrush& getBrush() const + { + return m_brush; + } + +private: + static void + SetStops(QGradient& gradient, const wxGraphicsGradientStops& stops) + { + QGradientStops qstops; + for ( size_t i = 0; i < stops.GetCount(); ++i ) + { + const wxGraphicsGradientStop stop = stops.Item(i); + qstops.append(QGradientStop(stop.GetPosition(), + stop.GetColour().GetQColor())); + } + + gradient.setStops(qstops); + } + + QBrush m_brush; + + wxDECLARE_NO_COPY_CLASS(wxQtBrushData); +}; + +class WXDLLIMPEXP_CORE wxQtPenData : public wxGraphicsObjectRefData +{ +public: + wxQtPenData(wxGraphicsRenderer* renderer, const wxGraphicsPenInfo& info) + : wxGraphicsObjectRefData(renderer), + m_pen(CreatePenFromInfo(info)) + { + } + + const QPen& GetPen() const + { + return m_pen; + } + +private: + static QPen CreatePenFromInfo(const wxGraphicsPenInfo& info) + { + wxPen wxpen(info.GetColour(), info.GetWidth(), info.GetStyle()); + wxpen.SetDashes(info.GetDashCount(), info.GetDash()); + wxpen.SetJoin(info.GetJoin()); + wxpen.SetCap(info.GetCap()); + switch ( info.GetStyle() ) + { + case wxPENSTYLE_STIPPLE: + case wxPENSTYLE_STIPPLE_MASK: + case wxPENSTYLE_STIPPLE_MASK_OPAQUE: + { + wxpen.SetStipple(info.GetStipple()); + break; + } + default: + break; + } + + return wxpen.GetHandle(); + } + QPen m_pen; + + wxDECLARE_NO_COPY_CLASS(wxQtPenData); +}; + +class WXDLLIMPEXP_CORE wxQtBitmapData : public wxGraphicsBitmapData +{ +public: + wxQtBitmapData(wxGraphicsRenderer* renderer, QPixmap* pixmap) + : wxGraphicsBitmapData(renderer), + m_pixmap(pixmap) + { + } + + wxQtBitmapData(wxGraphicsRenderer* renderer, const wxBitmap& bmp) + : wxGraphicsBitmapData(renderer), + m_pixmap(bmp.GetHandle()) + { + } + + QPixmap* GetPixmap() const + { + return m_pixmap; + } + + virtual void* GetNativeBitmap() const wxOVERRIDE + { + return m_pixmap; + } + + static const QPixmap* GetPixmapFromBitmap(const wxGraphicsBitmap& bitmap) + { + const wxQtBitmapData* const + data = static_cast(bitmap.GetBitmapData()); + return data->GetPixmap(); + } + + +#if wxUSE_IMAGE + wxImage DoConvertToImage() const + { + wxBitmap bitmap(*m_pixmap); + return bitmap.ConvertToImage(); + } +#endif // wxUSE_IMAGE + +private: + QPixmap* m_pixmap; + + wxDECLARE_NO_COPY_CLASS(wxQtBitmapData); +}; + + +class WXDLLIMPEXP_CORE wxQtMatrixData : public wxGraphicsMatrixData +{ +public: + explicit wxQtMatrixData(wxGraphicsRenderer* renderer) + : wxGraphicsMatrixData(renderer), + m_transform(new QTransform) + { + } + + wxQtMatrixData(wxGraphicsRenderer* renderer, const QTransform& transform) + : wxGraphicsMatrixData(renderer), + m_transform(new QTransform(transform)) + { + } + + virtual ~wxQtMatrixData() + { + delete m_transform; + } + + virtual wxGraphicsObjectRefData* Clone() const wxOVERRIDE + { + wxQtMatrixData* newMatrix = new wxQtMatrixData(m_renderer); + *newMatrix->m_transform = *m_transform; + return newMatrix; + } + + // concatenates the matrix + virtual void Concat(const wxGraphicsMatrixData *t) wxOVERRIDE + { + const wxQtMatrixData* rhs = static_cast(t); + *m_transform = *rhs->m_transform* (*m_transform); + } + + // sets the matrix to the respective values + virtual void Set(wxDouble a = 1.0, wxDouble b = 0.0, + wxDouble c = 0.0, wxDouble d = 1.0, + wxDouble tx = 0.0, wxDouble ty = 0.0) wxOVERRIDE + { + m_transform->setMatrix(a, b, 0.0, + c, d, 0.0, + tx, ty, 1.0); + } + + // gets the component values of the matrix + virtual void Get(wxDouble* a, wxDouble* b, + wxDouble* c, wxDouble* d, + wxDouble* tx, wxDouble* ty) const wxOVERRIDE + { + if ( a ) + *a = m_transform->m11(); + if ( b ) + *b = m_transform->m12(); + if ( c ) + *c = m_transform->m21(); + if ( d ) + *d = m_transform->m22(); + if ( tx ) + *tx = m_transform->m31(); + if ( ty ) + *ty = m_transform->m32(); + } + + // makes this the inverse matrix + virtual void Invert() wxOVERRIDE + { + bool invertible = false; + const QTransform invTransform = m_transform->inverted(&invertible); + if ( invertible ) + { + *m_transform = invTransform; + } + } + + // returns true if the elements of the transformation matrix are equal ? + virtual bool IsEqual(const wxGraphicsMatrixData* t) const wxOVERRIDE + { + const wxQtMatrixData* rhs = static_cast(t); + return *m_transform == *rhs->m_transform; + } + + // return true if this is the identity matrix + virtual bool IsIdentity() const wxOVERRIDE + { + return m_transform->isIdentity(); + } + + // + // transformation + // + + // add the translation to this matrix + virtual void Translate(wxDouble dx, wxDouble dy) wxOVERRIDE + { + m_transform->translate(dx, dy); + } + + // add the scale to this matrix + virtual void Scale(wxDouble xScale, wxDouble yScale) wxOVERRIDE + { + m_transform->scale(xScale, yScale); + } + + // add the rotation to this matrix (radians) + virtual void Rotate(wxDouble angle) wxOVERRIDE + { + m_transform->rotateRadians(angle); + } + + // + // apply the transforms + // + + // applies that matrix to the point + virtual void TransformPoint(wxDouble *x, wxDouble *y) const wxOVERRIDE + { + qreal transformed_x, transformed_y; + m_transform->map(static_cast(*x), static_cast(*y), + &transformed_x, &transformed_y); + *x = transformed_x; + *y = transformed_y; + } + + // applies the matrix except for translations + virtual void TransformDistance(wxDouble *dx, wxDouble *dy) const wxOVERRIDE + { + const QTransform untransTransform( + m_transform->m11(), + m_transform->m12(), + m_transform->m13(), + m_transform->m21(), + m_transform->m22(), + m_transform->m23(), + 0.0, + 0.0, + 1.0); + + qreal transformed_x, transformed_y; + untransTransform.map(static_cast(*dx), static_cast(*dy), + &transformed_x, &transformed_y); + + *dx = transformed_x; + *dy = transformed_y; + } + + // returns the native representation + virtual void* GetNativeMatrix() const wxOVERRIDE + { + return static_cast(m_transform); + } + + const QTransform& GetQTransform() const + { + return *m_transform; + } +private: + QTransform* m_transform; + + wxDECLARE_NO_COPY_CLASS(wxQtMatrixData); +}; + +class wxQtFontData : public wxGraphicsObjectRefData +{ +public: + wxQtFontData(wxGraphicsRenderer* renderer, + const wxFont& font, + const wxColour& col) + : wxGraphicsObjectRefData(renderer), + m_font(font.GetHandle()), + m_color(col.GetQColor()) + { + } + + wxQtFontData( + wxGraphicsRenderer* renderer, + double sizeInPixels, + const wxString& facename, + int flags, + const wxColour& col) + : wxGraphicsObjectRefData(renderer), + m_color(col.GetQColor()) + { + m_font.setFamily(QString(facename)); + m_font.setPixelSize(static_cast(sizeInPixels)); + if ( flags & wxFONTFLAG_LIGHT ) + m_font.setWeight(QFont::Light); + if ( flags & wxFONTFLAG_BOLD ) + m_font.setWeight(QFont::Bold); + if ( flags & (wxFONTFLAG_ITALIC | wxFONTFLAG_SLANT) ) + m_font.setItalic(true); + if ( flags & wxFONTFLAG_ANTIALIASED ) + m_font.setStyleStrategy(QFont::PreferAntialias); + if ( flags & wxFONTFLAG_NOT_ANTIALIASED ) + m_font.setStyleStrategy(QFont::NoAntialias); + if ( flags & wxFONTFLAG_UNDERLINED ) + m_font.setUnderline(true); + if ( flags & wxFONTFLAG_STRIKETHROUGH ) + m_font.setStrikeOut(true); + } + + const QFont& GetFont() const + { + return m_font; + } + + const QColor& GetColor() const + { + return m_color; + } + +private: + QFont m_font; + QColor m_color; + + wxDECLARE_NO_COPY_CLASS(wxQtFontData); +}; + +//----------------------------------------------------------------------------- +// wxQtGraphicsPathData +//----------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxQtGraphicsPathData : public wxGraphicsPathData +{ +public: + wxQtGraphicsPathData(wxGraphicsRenderer* renderer) + : wxGraphicsPathData(renderer), + m_path(new QPainterPath()), + m_current_subpath_start(-1) + { + } + + ~wxQtGraphicsPathData() + { + delete m_path; + } + + virtual wxGraphicsObjectRefData *Clone() const wxOVERRIDE + { + return new wxQtGraphicsPathData(*this); + } + + // + // These are the path primitives from which everything else can be + // constructed. + // + + // begins a new subpath at (x,y) + virtual void MoveToPoint(wxDouble x, wxDouble y) wxOVERRIDE + { + m_path->moveTo(x, y); + m_current_subpath_start = m_path->elementCount() - 1; + } + + // adds a straight line from the current point to (x,y) + // if there is no current path, it is equivalent to a moveTo. + virtual void AddLineToPoint(wxDouble x, wxDouble y) wxOVERRIDE + { + if ( !HasCurrentSubpath() ) + MoveToPoint(x, y); + else + m_path->lineTo(x, y); + } + + // adds a cubic Bezier curve from the current point, using two control + // points and an end point + virtual void + AddCurveToPoint(wxDouble cx1, wxDouble cy1, + wxDouble cx2, wxDouble cy2, + wxDouble x, wxDouble y) wxOVERRIDE + { + if ( !HasCurrentSubpath() ) + MoveToPoint(cx1, cy1); + m_path->cubicTo(QPointF(cx1, cy1), QPointF(cx2, cy2), QPointF(x, y)); + } + + // adds an arc of a circle centering at (x,y) with radius (r) from + // startAngle to endAngle + virtual void + AddArc(wxDouble x, wxDouble y, wxDouble r, + wxDouble startAngle, wxDouble endAngle, + bool clockwise) wxOVERRIDE + { + const bool fixupFirst = !HasCurrentSubpath(); + if ( fixupFirst ) + MoveToPoint(x, y); + + qreal arcLength; + if ( clockwise ) + { + if ( endAngle < startAngle ) + endAngle += 2* M_PI; + arcLength = -wxRadToDeg(endAngle - startAngle); + } + else + { + if ( endAngle > startAngle ) + endAngle -= 2* M_PI; + arcLength = -wxRadToDeg(endAngle - startAngle); + } + m_path->arcTo(x-r, y-r, r*2, r*2, -wxRadToDeg(startAngle), arcLength); + if ( fixupFirst ) + { + QPainterPath::Element + element = m_path->elementAt(m_current_subpath_start+1); + m_path->setElementPositionAt(m_current_subpath_start, + element.x, element.y); + } + } + + // gets the last point of the current path, (0,0) if not yet set + virtual void GetCurrentPoint(wxDouble* x, wxDouble* y) const wxOVERRIDE + { + QPointF position = m_path->currentPosition(); + *x = position.x(); + *y = position.y(); + } + + // adds another path + virtual void AddPath(const wxGraphicsPathData* path) wxOVERRIDE + { + const wxQtGraphicsPathData* + pathAdded = static_cast(path); + m_path->addPath(*pathAdded->m_path); + } + + // closes the current sub-path + virtual void CloseSubpath() wxOVERRIDE + { + // Current position must be end of last path after close, not (0,0) as + // Qt sets. + if ( !HasCurrentSubpath() ) + return; + + const QPainterPath::Element + firstElement = m_path->elementAt(m_current_subpath_start); + + m_path->closeSubpath(); + MoveToPoint(firstElement.x, firstElement.y); + } + + // + // These are convenience functions which - if not available natively will + // be assembled using the primitives from above + // + + // appends a circle as a new closed subpath + virtual void AddCircle(wxDouble x, wxDouble y, wxDouble r) wxOVERRIDE + { + m_path->addEllipse(x - r, y - r, r*2, r*2); + } + + // appends an ellipse as a new closed subpath fitting the passed rectangle + virtual void + AddEllipse(wxDouble x, wxDouble y, wxDouble w, wxDouble h) wxOVERRIDE + { + m_path->addEllipse(x, y, w, h); + } + + // returns the native path + virtual void* GetNativePath() const wxOVERRIDE + { + return static_cast(m_path); + } + + // give the native path returned by GetNativePath() back (there might be + // some deallocations necessary) + virtual void UnGetNativePath(void *) const wxOVERRIDE + { + } + + // transforms each point of this path by the matrix + virtual void Transform(const wxGraphicsMatrixData* matrix) wxOVERRIDE + { + const wxQtMatrixData* + qmatrix = static_cast(matrix); + *m_path = qmatrix->GetQTransform().map(*m_path); + } + + // gets the bounding box enclosing all points (possibly including control + // points) + virtual void + GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const wxOVERRIDE + { + QRectF boundingRect = m_path->controlPointRect(); + + if ( !boundingRect.isValid() ) + boundingRect = QRectF(); + + if ( x ) *x = boundingRect.left(); + if ( y ) *y = boundingRect.top(); + if ( w ) *w = boundingRect.width(); + if ( h ) *h = boundingRect.height(); + } + + virtual bool + Contains(wxDouble x, wxDouble y, + wxPolygonFillMode /*fillStyle = wxWINDING_RULE*/) const wxOVERRIDE + { + return m_path->contains(QPointF(x, y)); + } + +private: + // for Clone + wxQtGraphicsPathData(const wxQtGraphicsPathData& rhs) + : wxGraphicsPathData(rhs.GetRenderer()), + m_path(new QPainterPath(*rhs.m_path)), + m_current_subpath_start(rhs.m_current_subpath_start) + { + } + + bool HasCurrentSubpath() const + { + return m_current_subpath_start != -1; + } + + QPainterPath* m_path; + int m_current_subpath_start; + + wxQtGraphicsPathData& operator=(const wxQtGraphicsPathData&); +}; + +class WXDLLIMPEXP_CORE wxQtGraphicsContext : public wxGraphicsContext +{ + void InitFromDC(const wxDC& dc) + { + m_qtPainter = static_cast(dc.GetHandle()); + m_ownsPainter = false; + + const wxSize sz = dc.GetSize(); + m_width = sz.x; + m_height = sz.y; + } + +protected: + wxQtGraphicsContext(wxGraphicsRenderer* renderer) + : wxGraphicsContext(renderer), + m_qtPainter(NULL), + m_ownsPainter(false) + { + } + +public: + wxQtGraphicsContext(wxGraphicsRenderer* renderer, QPaintDevice* device) + : wxGraphicsContext(renderer) + { + m_qtPainter = new QPainter(device); + m_ownsPainter = true; + + m_width = device->width(); + m_height = device->height(); + } + + wxQtGraphicsContext(wxGraphicsRenderer* renderer, const wxWindowDC& dc) + : wxGraphicsContext(renderer) + { + InitFromDC(dc); + } + + wxQtGraphicsContext(wxGraphicsRenderer* renderer, const wxMemoryDC& dc) + : wxGraphicsContext(renderer) + { + InitFromDC(dc); + } + +#if wxUSE_PRINTING_ARCHITECTURE + wxQtGraphicsContext(wxGraphicsRenderer* renderer, const wxPrinterDC& dc) + : wxGraphicsContext(renderer) + { + InitFromDC(dc); + } + +#endif + + wxQtGraphicsContext(wxGraphicsRenderer* renderer, wxWindow *window) + : wxGraphicsContext(renderer) + { + m_qtPainter = static_cast(window->QtGetPainter()); + m_ownsPainter = false; + + const wxSize sz = window->GetClientSize(); + m_width = sz.x; + m_height = sz.y; + } + + virtual ~wxQtGraphicsContext() + { + if ( m_ownsPainter ) + delete m_qtPainter; + } + + virtual bool ShouldOffset() const wxOVERRIDE + { + return false; + } + + virtual void Clip(const wxRegion& region) wxOVERRIDE + { + m_qtPainter->setClipRegion(region.GetHandle()); + } + + // clips drawings to the rect + virtual void Clip(wxDouble x, wxDouble y, wxDouble w, wxDouble h) wxOVERRIDE + { + m_qtPainter->setClipRect(x, y, w, h); + } + + // resets the clipping to original extent + virtual void ResetClip() wxOVERRIDE + { + m_qtPainter->setClipping(false); + } + + // returns bounding box of the clipping region + virtual void + GetClipBox(wxDouble* x, wxDouble* y, wxDouble* w, wxDouble* h) wxOVERRIDE + { + const QRectF box = m_qtPainter->clipBoundingRect(); + if ( x ) + *x = box.left(); + if ( y ) + *y = box.top(); + if ( w ) + *w = box.width(); + if ( h ) + *h = box.height(); + } + + virtual void* GetNativeContext() wxOVERRIDE + { + return static_cast(m_qtPainter); + } + + virtual bool SetAntialiasMode(wxAntialiasMode antialias) wxOVERRIDE + { + bool enableAA = false; + switch ( antialias ) + { + case wxANTIALIAS_DEFAULT: + enableAA = true; + break; + + case wxANTIALIAS_NONE: + enableAA = false; + break; + } + + m_qtPainter->setRenderHints(QPainter::Antialiasing | + QPainter::TextAntialiasing, + enableAA); + + m_antialias = antialias; + return true; + } + + virtual bool + SetInterpolationQuality(wxInterpolationQuality interpolation) wxOVERRIDE + { + m_qtPainter->setRenderHint(QPainter::SmoothPixmapTransform, + interpolation == wxINTERPOLATION_BEST); + m_interpolation = interpolation; + return true; + } + + virtual bool SetCompositionMode(wxCompositionMode composition) wxOVERRIDE + { + QPainter::CompositionMode q_composition_mode; + switch ( composition ) + { + case wxCOMPOSITION_CLEAR: + q_composition_mode = QPainter::CompositionMode_Clear; + break; + case wxCOMPOSITION_SOURCE: + q_composition_mode = QPainter::CompositionMode_Source; + break; + case wxCOMPOSITION_OVER: + q_composition_mode = QPainter::CompositionMode_SourceOver; + break; + case wxCOMPOSITION_IN: + q_composition_mode = QPainter::CompositionMode_SourceIn; + break; + case wxCOMPOSITION_OUT: + q_composition_mode = QPainter::CompositionMode_SourceOut; + break; + case wxCOMPOSITION_ATOP: + q_composition_mode = QPainter::CompositionMode_SourceAtop; + break; + case wxCOMPOSITION_DEST: + q_composition_mode = QPainter::CompositionMode_Destination; + break; + case wxCOMPOSITION_DEST_OVER: + q_composition_mode = QPainter::CompositionMode_DestinationOver; + break; + case wxCOMPOSITION_DEST_IN: + q_composition_mode = QPainter::CompositionMode_DestinationIn; + break; + case wxCOMPOSITION_DEST_OUT: + q_composition_mode = QPainter::CompositionMode_DestinationOut; + break; + case wxCOMPOSITION_DEST_ATOP: + q_composition_mode = QPainter::CompositionMode_DestinationAtop; + break; + case wxCOMPOSITION_XOR: + q_composition_mode = QPainter::CompositionMode_Xor; + break; + case wxCOMPOSITION_ADD: + q_composition_mode = QPainter::CompositionMode_Plus; + break; + default: + return false; + } + m_qtPainter->setCompositionMode(q_composition_mode); + m_composition = composition; + return true; + } + + virtual void BeginLayer(wxDouble /*opacity*/) wxOVERRIDE + { + wxFAIL_MSG("BeginLayer not implemented"); + } + + virtual void EndLayer() wxOVERRIDE + { + wxFAIL_MSG("EndLayer not implemented"); + } + + virtual void StrokePath(const wxGraphicsPath& p) wxOVERRIDE + { + if ( m_pen.IsNull() ) + { + return; + } + + const QPainterPath* + pathData = static_cast(p.GetNativePath()); + const QPen& + pen = static_cast(m_pen.GetRefData())->GetPen(); + m_qtPainter->strokePath(*pathData, pen); + } + + virtual void + FillPath(const wxGraphicsPath& p, + wxPolygonFillMode /*fillStyle = wxWINDING_RULE*/) wxOVERRIDE + { + if ( m_brush.IsNull() ) + { + return; + } + + const QPainterPath* + pathData = static_cast(p.GetNativePath()); + const QBrush& + brush = static_cast(m_brush.GetRefData())->getBrush(); + m_qtPainter->fillPath(*pathData, brush); + } + + virtual void + ClearRectangle(wxDouble x, wxDouble y, wxDouble w, wxDouble h) wxOVERRIDE + { + m_qtPainter->fillRect(x, y, w, h, QBrush(QColor(0, 0, 0, 0))); + } + + virtual void Translate(wxDouble dx, wxDouble dy) wxOVERRIDE + { + m_qtPainter->translate(dx, dy); + } + + virtual void Scale(wxDouble xScale, wxDouble yScale) wxOVERRIDE + { + m_qtPainter->scale(xScale, yScale); + } + + virtual void Rotate(wxDouble angle) wxOVERRIDE + { + // wx angle is in radians. Qt angle is in degrees. + m_qtPainter->rotate(wxRadToDeg(angle)); + } + + // concatenates this transform with the current transform of this context + virtual void ConcatTransform(const wxGraphicsMatrix& matrix) wxOVERRIDE + { + wxGraphicsMatrix currentMatrix = GetTransform(); + currentMatrix.Concat(matrix); + SetTransform(currentMatrix); + } + + // sets the transform of this context + virtual void SetTransform(const wxGraphicsMatrix& matrix) wxOVERRIDE + { + const wxQtMatrixData* + qmatrix = static_cast(matrix.GetRefData()); + m_qtPainter->setTransform(qmatrix->GetQTransform()); + } + + // gets the matrix of this context + virtual wxGraphicsMatrix GetTransform() const wxOVERRIDE + { + const QTransform& transform = m_qtPainter->transform(); + wxGraphicsMatrix m; + m.SetRefData(new wxQtMatrixData(GetRenderer(), transform)); + return m; + } + + virtual void + DrawBitmap(const wxGraphicsBitmap& bmp, + wxDouble x, wxDouble y, wxDouble w, wxDouble h) wxOVERRIDE + { + const QPixmap* pixmap = wxQtBitmapData::GetPixmapFromBitmap(bmp); + m_qtPainter->drawPixmap(x, y, w, h, *pixmap); + } + + virtual void + DrawBitmap(const wxBitmap& bmp, + wxDouble x, wxDouble y, wxDouble w, wxDouble h) wxOVERRIDE + { + DoDrawBitmap(bmp, x, y, w, h, true); + } + + virtual void + DrawIcon(const wxIcon& icon, + wxDouble x, wxDouble y, wxDouble w, wxDouble h) wxOVERRIDE + { + DoDrawBitmap(icon, x, y, w, h, true); + } + + virtual void PushState() wxOVERRIDE + { + m_qtPainter->save(); + } + + virtual void PopState() wxOVERRIDE + { + m_qtPainter->restore(); + } + + virtual void Flush() wxOVERRIDE + { + } + + virtual void GetTextExtent(const wxString& str, + wxDouble *width, + wxDouble *height, + wxDouble *descent, + wxDouble *externalLeading) const wxOVERRIDE + { + wxCHECK_RET( !m_font.IsNull(), + "wxQtContext::GetTextExtent - no valid font set" ); + + const wxQtFontData* + fontData = static_cast(m_font.GetRefData()); + m_qtPainter->setFont(fontData->GetFont()); + + const QFontMetrics metrics = m_qtPainter->fontMetrics(); + const QRect boundingRect = metrics.boundingRect(QString(str)); + + if ( width ) + *width = boundingRect.width(); + if ( height ) + *height = boundingRect.height(); + if ( descent ) + *descent = metrics.descent(); + if ( externalLeading ) + *externalLeading = metrics.leading() - (metrics.ascent() + metrics.descent()); + } + + virtual void + GetPartialTextExtents(const wxString& text, + wxArrayDouble& widths) const wxOVERRIDE + { + wxCHECK_RET( !m_font.IsNull(), + "wxQtContext::GetPartialTextExtents - no valid font set" ); + + const wxQtFontData* + fontData = static_cast(m_font.GetRefData()); + m_qtPainter->setFont(fontData->GetFont()); + + const QFontMetrics metrics = m_qtPainter->fontMetrics(); + + const size_t textLength = text.length(); + + widths.clear(); + widths.insert(widths.end(), textLength, 0); + + for ( size_t i = 0; i < textLength; ++i ) + { + const wxString subString = text.substr(0, i+1); + const QRect + boundingRect = metrics.boundingRect(QString(subString)); + widths[i] = boundingRect.width(); + } + } + +protected: + virtual void + DoDrawText(const wxString& str, wxDouble x, wxDouble y) wxOVERRIDE + { + wxCHECK_RET( !m_font.IsNull(), + "wxQtContext::DrawText - no valid font set" ); + + const wxQtFontData* + fontData = static_cast(m_font.GetRefData()); + + m_qtPainter->setFont(fontData->GetFont()); + m_qtPainter->setPen(QPen(fontData->GetColor())); + + QFontMetrics metrics = m_qtPainter->fontMetrics(); + + wxStringTokenizer tokenizer(str, "\n"); + while ( tokenizer.HasMoreTokens() ) + { + const wxString line = tokenizer.GetNextToken(); + m_qtPainter->drawText(x, y + metrics.ascent(), QString(line)); + y += metrics.lineSpacing(); + } + } + + void + DoDrawBitmap(const wxBitmap& bmp, + wxDouble x, wxDouble y, + wxDouble w, wxDouble h, bool useMask) const + { + QPixmap pix = *bmp.GetHandle(); + + if (useMask && bmp.GetMask() && bmp.GetMask()->GetHandle()) + pix.setMask(*bmp.GetMask()->GetHandle()); + + m_qtPainter->drawPixmap(x, y, w, h, pix); + } + + QPainter* m_qtPainter; + bool m_ownsPainter; + +private: + wxDECLARE_NO_COPY_CLASS(wxQtGraphicsContext); +}; + +class wxQtMeasuringContext : public wxQtGraphicsContext +{ +public: + wxQtMeasuringContext(wxGraphicsRenderer* renderer) + : wxQtGraphicsContext(renderer, QApplication::desktop()) + { + } + +private: + QPainter painter; +}; + +class wxQtImageContext : public wxQtGraphicsContext +{ +public: + wxQtImageContext(wxGraphicsRenderer* renderer, wxImage& image) : + wxQtGraphicsContext(renderer), + m_image(image) + { + const wxBitmap wxbitmap(image); + m_pixmap = *wxbitmap.GetHandle(); + m_qtPainter = new QPainter(&m_pixmap); + m_ownsPainter = false; + } + + ~wxQtImageContext() + { + wxQtBitmapData bitmap(GetRenderer(), &m_pixmap); + m_image = bitmap.DoConvertToImage(); + delete m_qtPainter; + } + +private: + QPixmap m_pixmap; + wxImage& m_image; +}; + +//----------------------------------------------------------------------------- +// wxQtGraphicsRenderer declaration +//----------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxQtGraphicsRenderer : public wxGraphicsRenderer +{ +public: + wxQtGraphicsRenderer() {} + + virtual ~wxQtGraphicsRenderer() {} + + // Context + + virtual wxGraphicsContext* CreateContext(const wxWindowDC& dc) wxOVERRIDE; + virtual wxGraphicsContext* CreateContext(const wxMemoryDC& dc) wxOVERRIDE; +#if wxUSE_PRINTING_ARCHITECTURE + virtual wxGraphicsContext* CreateContext(const wxPrinterDC& dc) wxOVERRIDE; +#endif + + virtual wxGraphicsContext* CreateContextFromNativeContext(void* context) wxOVERRIDE; + + virtual wxGraphicsContext* CreateContextFromNativeWindow(void* window) wxOVERRIDE; + +#if wxUSE_IMAGE + virtual wxGraphicsContext* CreateContextFromImage(wxImage& image) wxOVERRIDE; +#endif // wxUSE_IMAGE + + virtual wxGraphicsContext* CreateContext(wxWindow* window) wxOVERRIDE; + + virtual wxGraphicsContext* CreateMeasuringContext() wxOVERRIDE; + + // Path + + virtual wxGraphicsPath CreatePath() wxOVERRIDE; + + // Matrix + + virtual wxGraphicsMatrix CreateMatrix(wxDouble a = 1.0, wxDouble b = 0.0, + wxDouble c = 0.0, wxDouble d = 1.0, + wxDouble tx = 0.0, wxDouble ty = 0.0) wxOVERRIDE; + + virtual wxGraphicsPen CreatePen(const wxGraphicsPenInfo& info) wxOVERRIDE; + + virtual wxGraphicsBrush CreateBrush(const wxBrush& brush) wxOVERRIDE; + + virtual wxGraphicsBrush + CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops) wxOVERRIDE; + + virtual wxGraphicsBrush + CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops) wxOVERRIDE; + + // sets the font + virtual wxGraphicsFont CreateFont(const wxFont& font, + const wxColour& col = *wxBLACK) wxOVERRIDE; + virtual wxGraphicsFont CreateFont(double sizeInPixels, + const wxString& facename, + int flags = wxFONTFLAG_DEFAULT, + const wxColour& col = *wxBLACK) wxOVERRIDE; + + // create a native bitmap representation + virtual wxGraphicsBitmap CreateBitmap(const wxBitmap& bitmap) wxOVERRIDE; +#if wxUSE_IMAGE + virtual wxGraphicsBitmap CreateBitmapFromImage(const wxImage& image) wxOVERRIDE; + virtual wxImage CreateImageFromBitmap(const wxGraphicsBitmap& bmp) wxOVERRIDE; +#endif // wxUSE_IMAGE + + // create a graphics bitmap from a native bitmap + virtual wxGraphicsBitmap CreateBitmapFromNativeBitmap(void* bitmap) wxOVERRIDE; + + // create a subimage from a native image representation + virtual wxGraphicsBitmap CreateSubBitmap(const wxGraphicsBitmap& bitmap, + wxDouble x, wxDouble y, + wxDouble w, wxDouble h) wxOVERRIDE; + + virtual wxString GetName() const wxOVERRIDE; + virtual void GetVersion(int *major, + int *minor, + int *micro) const wxOVERRIDE; + + wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxQtGraphicsRenderer); +}; + +//----------------------------------------------------------------------------- +// wxQtGraphicsRenderer implementation +//----------------------------------------------------------------------------- + +wxIMPLEMENT_DYNAMIC_CLASS(wxQtGraphicsRenderer, wxGraphicsRenderer); + +wxGraphicsContext* wxQtGraphicsRenderer::CreateContext(const wxWindowDC& dc) +{ + return new wxQtGraphicsContext(this, dc); +} + +wxGraphicsContext* wxQtGraphicsRenderer::CreateContext(const wxMemoryDC& dc) +{ + return new wxQtGraphicsContext(this, dc); +} + +#if wxUSE_PRINTING_ARCHITECTURE +wxGraphicsContext* wxQtGraphicsRenderer::CreateContext(const wxPrinterDC& dc) +{ + return new wxQtGraphicsContext(this, dc); +} +#endif + +wxGraphicsContext* +wxQtGraphicsRenderer::CreateContextFromNativeContext(void* context) +{ + return new wxQtGraphicsContext(this, static_cast(context)); +} + +wxGraphicsContext* +wxQtGraphicsRenderer::CreateContextFromNativeWindow(void* window) +{ + return new wxQtGraphicsContext(this, static_cast(window)); +} + +#if wxUSE_IMAGE +wxGraphicsContext* wxQtGraphicsRenderer::CreateContextFromImage(wxImage& image) +{ + return new wxQtImageContext(this, image); +} +#endif // wxUSE_IMAGE + +wxGraphicsContext* wxQtGraphicsRenderer::CreateMeasuringContext() +{ + return new wxQtMeasuringContext(this); +} + +wxGraphicsContext* wxQtGraphicsRenderer::CreateContext(wxWindow* window) +{ + return new wxQtGraphicsContext(this, window); +} + +// Path + +wxGraphicsPath wxQtGraphicsRenderer::CreatePath() +{ + wxGraphicsPath path; + path.SetRefData(new wxQtGraphicsPathData(this)); + return path; +} + +// Matrix + +wxGraphicsMatrix wxQtGraphicsRenderer::CreateMatrix(wxDouble a, wxDouble b, + wxDouble c, wxDouble d, + wxDouble tx, wxDouble ty) + +{ + wxGraphicsMatrix m; + wxQtMatrixData* data = new wxQtMatrixData(this); + data->Set(a, b, c, d, tx, ty); + m.SetRefData(data); + return m; +} + +wxGraphicsPen wxQtGraphicsRenderer::CreatePen(const wxGraphicsPenInfo& info) +{ + wxGraphicsPen p; + if ( info.GetStyle() != wxPENSTYLE_TRANSPARENT ) + { + p.SetRefData(new wxQtPenData(this, info)); + } + return p; +} + +wxGraphicsBrush wxQtGraphicsRenderer::CreateBrush(const wxBrush& brush) +{ + wxGraphicsBrush p; + if ( brush.IsOk() && brush.GetStyle() != wxBRUSHSTYLE_TRANSPARENT ) + { + p.SetRefData(new wxQtBrushData(this, brush)); + } + return p; +} + +wxGraphicsBrush wxQtGraphicsRenderer::CreateLinearGradientBrush( + wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops) +{ + wxGraphicsBrush p; + wxQtBrushData* d = new wxQtBrushData(this); + d->CreateLinearGradientBrush(x1, y1, x2, y2, stops); + p.SetRefData(d); + return p; +} + +wxGraphicsBrush wxQtGraphicsRenderer::CreateRadialGradientBrush( + wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, wxDouble r, + const wxGraphicsGradientStops& stops) +{ + wxGraphicsBrush p; + wxQtBrushData* d = new wxQtBrushData(this); + d->CreateRadialGradientBrush(xo, yo, xc, yc, r, stops); + p.SetRefData(d); + return p; +} + +wxGraphicsFont +wxQtGraphicsRenderer::CreateFont(const wxFont& font, const wxColour& col) +{ + wxGraphicsFont p; + if ( font.IsOk() ) + { + p.SetRefData(new wxQtFontData(this, font, col)); + } + return p; +} + +wxGraphicsFont wxQtGraphicsRenderer::CreateFont( + double sizeInPixels, + const wxString& facename, + int flags, + const wxColour& col) +{ + wxGraphicsFont font; + font.SetRefData(new wxQtFontData(this, sizeInPixels, facename, flags, col)); + return font; +} + +wxGraphicsBitmap wxQtGraphicsRenderer::CreateBitmap(const wxBitmap& bmp) +{ + wxGraphicsBitmap p; + if ( bmp.IsOk() ) + { + p.SetRefData(new wxQtBitmapData(this, bmp)); + } + return p; +} + +#if wxUSE_IMAGE + +wxGraphicsBitmap +wxQtGraphicsRenderer::CreateBitmapFromImage(const wxImage& image) +{ + wxGraphicsBitmap bmp; + if ( image.IsOk() ) + { + bmp.SetRefData(new wxQtBitmapData(this, image)); + } + return bmp; +} + +wxImage wxQtGraphicsRenderer::CreateImageFromBitmap(const wxGraphicsBitmap& bmp) +{ + const wxQtBitmapData* const + data = static_cast(bmp.GetBitmapData()); + return data->DoConvertToImage(); +} +#endif // wxUSE_IMAGE + +wxGraphicsBitmap +wxQtGraphicsRenderer::CreateBitmapFromNativeBitmap(void* bitmap) +{ + wxGraphicsBitmap p; + if ( bitmap != NULL ) + { + p.SetRefData(new wxQtBitmapData(this, (QPixmap*)bitmap)); + } + return p; +} + +wxGraphicsBitmap +wxQtGraphicsRenderer::CreateSubBitmap(const wxGraphicsBitmap& bitmap, + wxDouble x, wxDouble y, + wxDouble w, wxDouble h) +{ + wxCHECK_MSG(!bitmap.IsNull(), wxNullGraphicsBitmap, wxS("Invalid bitmap")); + + const QPixmap* sourcePixmap = wxQtBitmapData::GetPixmapFromBitmap(bitmap); + wxCHECK_MSG(sourcePixmap, wxNullGraphicsBitmap, wxS("Invalid bitmap")); + + const int srcWidth = sourcePixmap->width(); + const int srcHeight = sourcePixmap->height(); + const int dstWidth = wxRound(w); + const int dstHeight = wxRound(h); + + wxCHECK_MSG(x >= 0.0 && y >= 0.0 && dstWidth > 0 && dstHeight > 0 && + x + dstWidth <= srcWidth && y + dstHeight <= srcHeight, + wxNullGraphicsBitmap, wxS("Invalid bitmap region")); + + QPixmap* subPixmap = new QPixmap(sourcePixmap->copy(x, y, w, h)); + + wxGraphicsBitmap bmpRes; + bmpRes.SetRefData(new wxQtBitmapData(this, subPixmap)); + return bmpRes; +} + +wxString wxQtGraphicsRenderer::GetName() const +{ + return "qt"; +} + +void wxQtGraphicsRenderer::GetVersion(int *major, int *minor, int *micro) const +{ + if ( major ) *major = QT_VERSION_MAJOR; + if ( minor ) *minor = QT_VERSION_MINOR; + if ( micro ) *micro = QT_VERSION_PATCH; +} + +static wxQtGraphicsRenderer gs_qtGraphicsRenderer; + +wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer() +{ + return &gs_qtGraphicsRenderer; +} + +#endif // wxUSE_GRAPHICS_CONTEXT