Hello,
I'm working with wxWidgets 3.1.5 and would like to have some gradient text in my app similar to:
I'm certain there's a way to do this, but I could use some pointers in the right direction. I'm not exactly sure what pieces in the library to put together to accomplish this, so any tips or insight would be greatly appreciated. Apologies if this has been asked before and I've missed the post. Thanks!
Gradient Text
Re: Gradient Text
This could (and should) be very easy, unfortunately the option to set a brush for a font was "forgotten" in wxGraphicsContext.
The documentation for wxGraphicsContext::DrawText() is wrong, the brush you can pass here is not used to fill the text, it's used to fill the background.
So i only came up with this complicated way: You first draw the text into a wxBitmap, then you create a wxRegion from that bitmap, which you can then use as a clipping mask for any drawing operation.
The documentation for wxGraphicsContext::DrawText() is wrong, the brush you can pass here is not used to fill the text, it's used to fill the background.
So i only came up with this complicated way: You first draw the text into a wxBitmap, then you create a wxRegion from that bitmap, which you can then use as a clipping mask for any drawing operation.
Code: Select all
#include "wx/graphics.h"
#include "wx/dcgraph.h"
#include "wx/dcbuffer.h"
class MyPanel : public wxPanel
{
public:
MyPanel( wxWindow *parent, wxWindowID id)
: wxPanel(parent, id)
{
SetBackgroundStyle(wxBG_STYLE_PAINT);
Bind(wxEVT_PAINT, &MyPanel::OnPaint, this);
}
void OnPaint( wxPaintEvent &event )
{
wxBufferedPaintDC dc(this);
const wxSize &size = GetClientSize();
wxGraphicsContext *gc = wxGraphicsContext::Create(dc);
// clear background of the window with black
gc->SetBrush(*wxBLACK_BRUSH);
gc->DrawRectangle( 0, 0, size.x, size.y);
// create a mask by drawing the text into a wxBitmap and then creating a wxRegion from that wxBitmap
wxFont font(48, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, "Tahoma");
wxString s("SOME TEXT");
dc.SetFont( font );
// calculate size needed for text
wxSize textSize = dc.GetTextExtent( s );
wxBitmap bmp(textSize.x, textSize.y);
{
wxMemoryDC mdc(bmp);
mdc.SetBrush(*wxWHITE_BRUSH);
mdc.Clear();
mdc.SetTextForeground(*wxBLACK);
mdc.SetFont( font );
mdc.DrawText( s, 0, 0 );
}
// bitmap now contains the outline of the text
// use it as clipping region
wxRegion rgn(bmp, *wxWHITE );
gc->Clip(rgn);
wxGraphicsBrush brush = gc->CreateLinearGradientBrush(0, 0, textSize.x, 0, wxColor(255,0,0), wxColor(0,255,0) );
gc->SetBrush( brush );
// draw rectangle using the gradient brush
gc->DrawRectangle(0, 0, textSize.x, textSize.y);
delete gc;
}
};
Use the source, Luke!
-
- In need of some credit
- Posts: 4
- Joined: Thu Apr 29, 2021 3:29 pm
Re: Gradient Text
Thank you! This is great. I was thinking along the same lines, but didn't know what pieces I needed. I'll give this a try. Thanks again!doublemax wrote: ↑Fri Apr 30, 2021 12:01 am This could (and should) be very easy, unfortunately the option to set a brush for a font was "forgotten" in wxGraphicsContext.
The documentation for wxGraphicsContext::DrawText() is wrong, the brush you can pass here is not used to fill the text, it's used to fill the background.
So i only came up with this complicated way: You first draw the text into a wxBitmap, then you create a wxRegion from that bitmap, which you can then use as a clipping mask for any drawing operation.
-
- In need of some credit
- Posts: 4
- Joined: Thu Apr 29, 2021 3:29 pm
Re: Gradient Text
Thank you again for the code snippet. It worked perfectly. There does appear to be some aliasing on the drawn text, which isn't a huge deal, but wondering if there's anything that can be done about it. Here's a snap of what I'm getting:
BTW, I'm on MacOS 10.15.7, wxWidgets 3.1.5.
Any ideas?BTW, I'm on MacOS 10.15.7, wxWidgets 3.1.5.
Re: Gradient Text
As the region is effectively just a 1 bit mask, you can't get antialiasing. It's a little strange though that the edges on the image are 2x2 pixels. I guess it's somehow related to Retina displays, but i don't understand how.
Another idea:
draw the text into a bitmap (black on white background)
draw the gradient into another bitmap of the same size.
do the compositing yourself, pixel-by-pixel (the greyvalue of the first bitmap will be the blending factor)
The last step would be slow, but still reasonably fast when using wxPixelData:
https://docs.wxwidgets.org/trunk/classw ... _data.html
Or, you could make a feature request at https://groups.google.com/g/wx-users
I would suspect that all underlying native APIs for wxGraphicsContext support brushes for fonts. At least the GDI+ renderer already supports it internally, it's just not exposed through the public API. I haven't checked the renderers for GTK and OSX.
Another idea:
draw the text into a bitmap (black on white background)
draw the gradient into another bitmap of the same size.
do the compositing yourself, pixel-by-pixel (the greyvalue of the first bitmap will be the blending factor)
The last step would be slow, but still reasonably fast when using wxPixelData:
https://docs.wxwidgets.org/trunk/classw ... _data.html
Or, you could make a feature request at https://groups.google.com/g/wx-users
I would suspect that all underlying native APIs for wxGraphicsContext support brushes for fonts. At least the GDI+ renderer already supports it internally, it's just not exposed through the public API. I haven't checked the renderers for GTK and OSX.
Use the source, Luke!
-
- In need of some credit
- Posts: 4
- Joined: Thu Apr 29, 2021 3:29 pm
Re: Gradient Text
Thanks again doublemax! I appreciate your help!