All (GUI):
- Added wxTreebook (uses a wxTreeCtrl to control pages).
+- Added wxDC::GradientFillLinear/Concentric()
- Added wxKeyEvent::GetModifiers()
- Added wxDialog::SetEscapeId().
- wxItemContainerImmutable::FindString unified (affects wxRadioBox, wxListBox,
array {\tt ( x, y )}}
+\membersection{wxDC::GradientFillConcentric}\label{wxdcgradientfillconcentric}
+
+\func{void}{GradientFillConcentric}{\param{const wxRect\&}{ rect}, \param{const wxColour\&}{ initialColour}, \param{const wxColour\&}{ destColour}}
+
+\func{void}{GradientFillConcentric}{\param{const wxRect\&}{ rect}, \param{const wxColour\&}{ initialColour}, \param{const wxColour\&}{ destColour}, \param{const wxPoint\& }{circleCenter}}
+
+Fill the area specified by rect with a radial gradient, starting from
+\arg{initialColour} at the centre of the circle and fading to \arg{destColour}
+on the circle outside.
+
+\arg{circleCenter} are the relative coordinates of centre of the circle in
+the specified \arg{rect}. If not specified, the cercle is placed at the
+centre of rect.
+
+\textbf{Note: } Currently this function is very slow, don't use it for
+real-time drawing.
+
+
+\membersection{wxDC::GradientFillLinear}\label{wxdcgradientfilllinear}
+
+\func{void}{GradientFillLinear}{\param{const wxRect\&}{ rect}, \param{const wxColour\&}{ initialColour}, \param{const wxColour\&}{ destColour}, \param{wxDirection}{ nDirection = wxEAST}}
+
+Fill the area specified by \arg{rect} with a linear gradient, starting from
+\arg{initialColour} and eventually fading to \arg{destColour}. The
+\arg{nDirection} specifies the direction of the colour change, default is to
+use \arg{initialColour} on the left part of the rectangle and
+\arg{destColour} on the right one.
+
+
\membersection{wxDC::LogicalToDeviceX}\label{wxdclogicaltodevicex}
\func{wxCoord}{LogicalToDeviceX}{\param{wxCoord}{ x}}
int style = wxFLOOD_SURFACE)
{ return DoFloodFill(pt.x, pt.y, col, style); }
+ // fill the area specified by rect with a radial gradient, starting from
+ // initialColour in the centre of the cercle and fading to destColour.
+ void GradientFillConcentric(const wxRect& rect,
+ const wxColour& initialColour,
+ const wxColour& destColour)
+ { GradientFillConcentric(rect, initialColour, destColour,
+ wxPoint(rect.GetWidth() / 2,
+ rect.GetHeight() / 2)); }
+
+ void GradientFillConcentric(const wxRect& rect,
+ const wxColour& initialColour,
+ const wxColour& destColour,
+ const wxPoint& circleCenter);
+
+ // fill the area specified by rect with a linear gradient
+ void GradientFillLinear(const wxRect& rect,
+ const wxColour& initialColour,
+ const wxColour& destColour,
+ wxDirection nDirection = wxEAST)
+ { DoGradientFillLinear(rect, initialColour, destColour, nDirection); }
+
bool GetPixel(wxCoord x, wxCoord y, wxColour *col) const
{ return DoGetPixel(x, y, col); }
bool GetPixel(const wxPoint& pt, wxColour *col) const
virtual bool DoFloodFill(wxCoord x, wxCoord y, const wxColour& col,
int style = wxFLOOD_SURFACE) = 0;
+ virtual void DoGradientFillLinear(const wxRect& rect,
+ const wxColour& initialColour,
+ const wxColour& destColour,
+ wxDirection nDirection = wxEAST);
+
virtual bool DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const = 0;
virtual void DoDrawPoint(wxCoord x, wxCoord y) = 0;
virtual bool DoFloodFill(wxCoord x, wxCoord y, const wxColour& col,
int style = wxFLOOD_SURFACE);
+ virtual void DoGradientFillLinear(const wxRect& rect,
+ const wxColour& initialColour,
+ const wxColour& destColour,
+ wxDirection nDirection = wxEAST);
+
virtual bool DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const;
virtual void DoDrawPoint(wxCoord x, wxCoord y);
Show_Ops,
Show_Regions,
Show_Circles,
- Show_Splines
+ Show_Splines,
+ Show_Gradient,
+ Show_Max
};
// ----------------------------------------------------------------------------
void DrawCircles(wxDC& dc);
void DrawSplines(wxDC& dc);
void DrawDefault(wxDC& dc);
+ void DrawGradients(wxDC& dc);
void DrawRegionsHelper(wxDC& dc, wxCoord x, bool firstTime);
File_ShowRegions,
File_ShowCircles,
File_ShowSplines,
- MenuShow_Last = File_ShowSplines,
+ File_ShowGradients,
+ MenuShow_Last = File_ShowGradients,
File_Clip,
#endif
}
+void MyCanvas::DrawGradients(wxDC& dc)
+{
+ // LHS: linear
+ wxRect r(10, 10, 100, 100);
+ dc.GradientFillLinear(r, *wxWHITE, *wxBLUE, wxRIGHT);
+
+ r.Offset(0, 110);
+ dc.GradientFillLinear(r, *wxWHITE, *wxBLUE, wxLEFT);
+
+ r.Offset(0, 110);
+ dc.GradientFillLinear(r, *wxWHITE, *wxBLUE, wxDOWN);
+
+ r.Offset(0, 110);
+ dc.GradientFillLinear(r, *wxWHITE, *wxBLUE, wxUP);
+
+
+ // RHS: concentric
+ r = wxRect(200, 10, 100, 100);
+ dc.GradientFillConcentric(r, *wxBLUE, *wxWHITE);
+
+ r.Offset(0, 110);
+ dc.GradientFillConcentric(r, *wxWHITE, *wxBLUE);
+
+ r.Offset(0, 110);
+ dc.GradientFillConcentric(r, *wxBLUE, *wxWHITE, wxPoint(0, 0));
+
+ r.Offset(0, 110);
+ dc.GradientFillConcentric(r, *wxBLUE, *wxWHITE, wxPoint(100, 100));
+}
+
void MyCanvas::DrawRegions(wxDC& dc)
{
dc.DrawText(_T("You should see a red rect partly covered by a cyan one ")
case Show_Ops:
DrawWithLogicalOps(dc);
break;
+
+ case Show_Gradient:
+ DrawGradients(dc);
+ break;
}
}
menuFile->Append(File_ShowOps, _T("&ROP screen\tF7"));
menuFile->Append(File_ShowRegions, _T("Re&gions screen\tF8"));
menuFile->Append(File_ShowCircles, _T("&Circles screen\tF9"));
- menuFile->Append(File_ShowSplines, _T("&Splines screen"));
+ menuFile->Append(File_ShowSplines, _T("&Splines screen\tF11"));
+ menuFile->Append(File_ShowGradients, _T("&Gradients screen\tF12"));
menuFile->AppendSeparator();
menuFile->AppendCheckItem(File_Clip, _T("&Clip\tCtrl-C"), _T("Clip/unclip drawing"));
menuFile->AppendSeparator();
CalcBoundingBox(x0 + width0, y0 + height);
}
+
+void wxDCBase::DoGradientFillLinear(const wxRect& rect,
+ const wxColour& initialColour,
+ const wxColour& destColour,
+ wxDirection nDirection)
+{
+ // save old pen
+ wxPen oldPen = m_pen;
+
+ wxUint8 nR1 = destColour.Red();
+ wxUint8 nG1 = destColour.Green();
+ wxUint8 nB1 = destColour.Blue();
+ wxUint8 nR2 = initialColour.Red();
+ wxUint8 nG2 = initialColour.Green();
+ wxUint8 nB2 = initialColour.Blue();
+ wxUint8 nR, nG, nB;
+
+ if ( nDirection == wxEAST || nDirection == wxWEST )
+ {
+ wxInt32 x = rect.GetWidth();
+ wxInt32 w = x; // width of area to shade
+ wxInt32 xDelta = w/256; // height of one shade bend
+ if (xDelta < 1)
+ xDelta = 1;
+
+ while (x >= xDelta)
+ {
+ x -= xDelta;
+ if (nR1 > nR2)
+ nR = nR1 - (nR1-nR2)*(w-x)/w;
+ else
+ nR = nR1 + (nR2-nR1)*(w-x)/w;
+
+ if (nG1 > nG2)
+ nG = nG1 - (nG1-nG2)*(w-x)/w;
+ else
+ nG = nG1 + (nG2-nG1)*(w-x)/w;
+
+ if (nB1 > nB2)
+ nB = nB1 - (nB1-nB2)*(w-x)/w;
+ else
+ nB = nB1 + (nB2-nB1)*(w-x)/w;
+
+ SetPen(wxPen(wxColour(nR, nG, nB), 1, wxSOLID));
+ if(nDirection == wxEAST)
+ DrawRectangle(rect.GetLeft()+x, rect.GetTop(),
+ xDelta, rect.GetHeight());
+ else //nDirection == wxWEST
+ DrawRectangle(rect.GetRight()-x-xDelta, rect.GetTop(),
+ xDelta, rect.GetHeight());
+ }
+ }
+ else // nDirection == wxNORTH || nDirection == wxSOUTH
+ {
+ wxInt32 y = rect.GetHeight();
+ wxInt32 w = y; // height of area to shade
+ wxInt32 yDelta = w/255; // height of one shade bend
+ if (yDelta < 1)
+ yDelta = 1;
+
+ while (y > 0)
+ {
+ y -= yDelta;
+ if (nR1 > nR2)
+ nR = nR1 - (nR1-nR2)*(w-y)/w;
+ else
+ nR = nR1 + (nR2-nR1)*(w-y)/w;
+
+ if (nG1 > nG2)
+ nG = nG1 - (nG1-nG2)*(w-y)/w;
+ else
+ nG = nG1 + (nG2-nG1)*(w-y)/w;
+
+ if (nB1 > nB2)
+ nB = nB1 - (nB1-nB2)*(w-y)/w;
+ else
+ nB = nB1 + (nB2-nB1)*(w-y)/w;
+
+ SetPen(wxPen(wxColour(nR, nG, nB), 1, wxSOLID));
+ if(nDirection == wxNORTH)
+ DrawRectangle(rect.GetLeft(), rect.GetTop()+y,
+ rect.GetWidth(), yDelta);
+ else //nDirection == wxSOUTH
+ DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta,
+ rect.GetWidth(), yDelta);
+ }
+ }
+
+ SetPen(oldPen);
+}
+
+void wxDCBase::GradientFillConcentric(const wxRect& rect,
+ const wxColour& initialColour,
+ const wxColour& destColour,
+ const wxPoint& circleCenter)
+{
+ //save the old pen color
+ wxColour oldPenColour = m_pen.GetColour();
+
+ wxUint8 nR1 = destColour.Red();
+ wxUint8 nG1 = destColour.Green();
+ wxUint8 nB1 = destColour.Blue();
+ wxUint8 nR2 = initialColour.Red();
+ wxUint8 nG2 = initialColour.Green();
+ wxUint8 nB2 = initialColour.Blue();
+ wxUint8 nR, nG, nB;
+
+
+ //offsets of the current pixel
+ wxInt32 x, y;
+
+ //Color difference
+ wxInt32 nGradient;
+
+ //Radius
+ wxInt32 cx = rect.GetWidth() / 2;
+ wxInt32 cy = rect.GetHeight() / 2;
+ wxInt32 nRadius;
+ if (cx < cy)
+ nRadius = cx;
+ else
+ nRadius = cy;
+
+ //Offset of circle
+ wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
+ wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
+
+ for (x = 0; x < rect.GetWidth(); x++)
+ {
+ for (y = 0; y < rect.GetHeight(); y++)
+ {
+ //get color difference
+ nGradient = (
+ (nRadius -
+ (wxInt32)sqrt(
+ pow(x - cx - nCircleOffX, 2) +
+ pow(y - cy - nCircleOffY, 2)
+ )
+ ) * 100
+ ) / nRadius;
+
+ //normalize Gradient
+ if (nGradient < 0 )
+ nGradient = 0;
+
+ //get dest colors
+ nR = nR1 + ((nR2 - nR1) * nGradient / 100);
+ nG = nG1 + ((nG2 - nG1) * nGradient / 100);
+ nB = nB1 + ((nB2 - nB1) * nGradient / 100);
+
+ //set the pixel
+ m_pen.SetColour(wxColour(nR,nG,nB));
+ DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop()));
+ }
+ }
+ //return old pen color
+ m_pen.SetColour(oldPenColour);
+}
+
/*
Notes for wxWidgets DrawEllipticArcRot(...)
DECLARE_NO_COPY_CLASS(StretchBltModeChanger)
};
+// support for dynamic loading of msimg32.dll which we use for some functions
+class wxMSImg32DLL
+{
+public:
+ // return the symbol with the given name if the DLL not loaded or symbol
+ // not present
+ static void *GetSymbol(const wxChar *name)
+ {
+ wxLogNull noLog;
+
+ if ( !ms_triedToLoad )
+ {
+ ms_triedToLoad = true;
+ ms_dll.Load(_T("msimg32"));
+ }
+
+ return ms_dll.IsLoaded() ? ms_dll.GetSymbol(name) : NULL;
+ }
+
+private:
+ static wxDynamicLibrary ms_dll;
+ static bool ms_triedToLoad;
+};
+
+wxDynamicLibrary wxMSImg32DLL::ms_dll;
+bool wxMSImg32DLL::ms_triedToLoad = false;
+
+// helper macro for getting the symbols from msimg32.dll: it supposes that a
+// type "name_t" is defined and casts the returned symbol to it automatically
+#define wxMSIMG32_SYMBOL(name) (name ## _t)wxMSImg32DLL::GetSymbol(_T(#name))
+
// ===========================================================================
// implementation
// ===========================================================================
HDC,int,int,int,int,
BLENDFUNCTION);
- // bitmaps can be drawn only from GUI thread so there is no need to
- // protect this static variable from multiple threads
- static bool s_triedToLoad = false;
- static AlphaBlend_t pfnAlphaBlend = NULL;
- if ( !s_triedToLoad )
- {
- s_triedToLoad = true;
-
- // don't give errors about the DLL being unavailable, we're
- // prepared to handle this
- wxLogNull nolog;
-
- wxDynamicLibrary dll(_T("msimg32.dll"));
- if ( dll.IsLoaded() )
- {
- pfnAlphaBlend = (AlphaBlend_t)dll.GetSymbol(_T("AlphaBlend"));
- if ( pfnAlphaBlend )
- {
- // we must keep the DLL loaded if we want to be able to
- // call AlphaBlend() so just never unload it at all, not a
- // big deal
- dll.Detach();
- }
- }
- }
-
+ static AlphaBlend_t pfnAlphaBlend = wxMSIMG32_SYMBOL(AlphaBlend);
if ( pfnAlphaBlend )
{
BLENDFUNCTION bf;
}
#endif // #ifdef wxHAVE_RAW_BITMAP
+
+void wxDC::DoGradientFillLinear (const wxRect& rect,
+ const wxColour& initialColour,
+ const wxColour& destColour,
+ wxDirection nDirection)
+{
+ // use native function if we have compile-time support it and can load it
+ // during run-time (linking to it statically would make the program
+ // unusable on earlier Windows versions)
+#if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
+ typedef BOOL
+ (WINAPI *GradientFill_t)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG);
+ static GradientFill_t pfnGradientFill = wxMSIMG32_SYMBOL(GradientFill);
+
+ if ( pfnGradientFill )
+ {
+ GRADIENT_RECT grect;
+ grect.UpperLeft = 0;
+ grect.LowerRight = 1;
+
+ // invert colours direction if not filling from left-to-right or
+ // top-to-bottom
+ int firstVertex = nDirection == wxNORTH || nDirection == wxWEST ? 1 : 0;
+
+ // one vertex for upper left and one for upper-right
+ TRIVERTEX vertices[2];
+
+ vertices[0].x = rect.GetLeft();
+ vertices[0].y = rect.GetTop();
+ vertices[1].x = rect.GetRight();
+ vertices[1].y = rect.GetBottom();
+
+ vertices[firstVertex].Red = initialColour.Red() << 8;
+ vertices[firstVertex].Green = initialColour.Green() << 8;
+ vertices[firstVertex].Blue = initialColour.Blue() << 8;
+ vertices[firstVertex].Alpha = 0;
+ vertices[1 - firstVertex].Red = destColour.Red() << 8;
+ vertices[1 - firstVertex].Green = destColour.Green() << 8;
+ vertices[1 - firstVertex].Blue = destColour.Blue() << 8;
+ vertices[1 - firstVertex].Alpha = 0;
+
+ if (nDirection == wxWEST ||
+ nDirection == wxEAST)
+ if ( (*pfnGradientFill)
+ (
+ GetHdc(),
+ vertices,
+ WXSIZEOF(vertices),
+ &grect,
+ 1,
+ nDirection == wxWEST || nDirection == wxEAST
+ ? GRADIENT_FILL_RECT_H
+ : GRADIENT_FILL_RECT_V
+ ) )
+ {
+ // skip call of the base class version below
+ return;
+ }
+
+ wxLogLastError(_T("GradientFill"));
+ }
+#endif // wxUSE_DYNLIB_CLASS
+
+ wxDCBase::DoGradientFillLinear(rect, initialColour, destColour, nDirection);
+}