added linear and concentric gradient fill functions (modified/fixed patch from Ryan Norton)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@37512 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
d6bf7254f4
commit
213ad8e72c
@ -47,6 +47,7 @@ All:
|
||||
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,
|
||||
|
@ -786,6 +786,35 @@ Gets the current user scale factor (set by \helpref{SetUserScale}{wxdcsetusersca
|
||||
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}}
|
||||
|
@ -158,6 +158,27 @@ public:
|
||||
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
|
||||
@ -645,6 +666,11 @@ protected:
|
||||
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;
|
||||
|
@ -164,6 +164,11 @@ protected:
|
||||
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);
|
||||
|
@ -60,7 +60,9 @@ enum ScreenToShow
|
||||
Show_Ops,
|
||||
Show_Regions,
|
||||
Show_Circles,
|
||||
Show_Splines
|
||||
Show_Splines,
|
||||
Show_Gradient,
|
||||
Show_Max
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -164,6 +166,7 @@ protected:
|
||||
void DrawCircles(wxDC& dc);
|
||||
void DrawSplines(wxDC& dc);
|
||||
void DrawDefault(wxDC& dc);
|
||||
void DrawGradients(wxDC& dc);
|
||||
|
||||
void DrawRegionsHelper(wxDC& dc, wxCoord x, bool firstTime);
|
||||
|
||||
@ -200,7 +203,8 @@ enum
|
||||
File_ShowRegions,
|
||||
File_ShowCircles,
|
||||
File_ShowSplines,
|
||||
MenuShow_Last = File_ShowSplines,
|
||||
File_ShowGradients,
|
||||
MenuShow_Last = File_ShowGradients,
|
||||
|
||||
File_Clip,
|
||||
|
||||
@ -971,6 +975,36 @@ void MyCanvas::DrawSplines(wxDC& dc)
|
||||
#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 ")
|
||||
@ -1105,6 +1139,10 @@ void MyCanvas::OnPaint(wxPaintEvent &WXUNUSED(event))
|
||||
case Show_Ops:
|
||||
DrawWithLogicalOps(dc);
|
||||
break;
|
||||
|
||||
case Show_Gradient:
|
||||
DrawGradients(dc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1161,7 +1199,8 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
|
||||
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();
|
||||
|
@ -680,6 +680,165 @@ void wxDCBase::DrawLabel(const wxString& text,
|
||||
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(...)
|
||||
|
||||
|
123
src/msw/dc.cpp
123
src/msw/dc.cpp
@ -196,6 +196,37 @@ private:
|
||||
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
|
||||
// ===========================================================================
|
||||
@ -2483,32 +2514,7 @@ static bool AlphaBlt(HDC hdcDst,
|
||||
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;
|
||||
@ -2609,3 +2615,68 @@ wxAlphaBlend(HDC hdcDst, int xDst, int yDst,
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user