Merge branch 'win-transparency'

Improve shaped sample and its documentation.

See #22230.
This commit is contained in:
Vadim Zeitlin
2022-03-28 00:16:31 +01:00
4 changed files with 102 additions and 39 deletions

View File

@@ -690,10 +690,14 @@ utility under macOS).
@section page_samples_shaped Shaped Window Sample
@sampleabout{how to implement a shaped or transparent window\, and a window showing/hiding with effect}
@sampleabout{Showing unusual, e.g. shaped or semi-transparent windows}
This sample shows windows with non-rectangular shapes and non-opaque windows as
well as how the windows can be shown with a special effect.
@see wxTopLevelWindow::SetShape(), wxTopLevelWindow::SetTransparent(),
wxWindow::ShowWithEffect(), wxWindow::HideWithEffect()
wxWindow::ShowWithEffect(), wxWindow::HideWithEffect(),
wxWindow::SetBackgroundStyle()
@sampledir{shaped}

View File

@@ -585,6 +585,13 @@ public:
/**
If the platform supports it will set the window to be translucent.
Note that in wxGTK this function must be called before the window is
shown the first time it's called (but it can be called again after
showing the window too).
See @ref page_samples_shaped "the shaped sample" for an example of
using this function.
@param alpha
Determines how opaque or transparent the window will be, if the
platform supports the operation. A value of 0 sets the window to be

View File

@@ -2395,7 +2395,9 @@ public:
Under wxGTK and wxOSX, you can use ::wxBG_STYLE_TRANSPARENT to obtain
full transparency of the window background. Note that wxGTK supports
this only since GTK 2.12 with a compositing manager enabled, call
IsTransparentBackgroundSupported() to check whether this is the case.
IsTransparentBackgroundSupported() to check whether this is the case,
see the example of doing it in @ref page_samples_shaped "the shaped
sample".
Also, in order for @c SetBackgroundStyle(wxBG_STYLE_TRANSPARENT) to
work, it must be called before Create(). If you're using your own

View File

@@ -36,6 +36,9 @@
#include "wx/dcclient.h"
#include "wx/graphics.h"
#include "wx/image.h"
#include "wx/scopedptr.h"
#include "wx/sizer.h"
#include "wx/slider.h"
#ifndef wxHAS_IMAGES_IN_RESOURCES
#include "../sample.xpm"
@@ -50,6 +53,7 @@ enum
{
Show_Shaped = 100,
Show_Transparent,
Show_TransparentBg,
// must be consecutive and in the same order as wxShowEffect enum elements
Show_Effect_First,
@@ -134,12 +138,14 @@ private:
class SeeThroughFrame : public wxFrame
{
public:
void Create();
void Create(wxWindow* parent);
private:
// event handlers (these functions should _not_ be virtual)
void OnPaint(wxPaintEvent& evt);
void OnAlpha(wxCommandEvent& event);
// any class wishing to process wxWidgets events must use this macro
wxDECLARE_EVENT_TABLE();
};
@@ -238,6 +244,7 @@ bool MyApp::OnInit()
wxBEGIN_EVENT_TABLE(MainFrame, wxFrame)
EVT_MENU(Show_Shaped, MainFrame::OnShowShaped)
EVT_MENU(Show_Transparent, MainFrame::OnShowTransparent)
EVT_MENU(Show_TransparentBg, MainFrame::OnShowTransparent)
EVT_MENU_RANGE(Show_Effect_First, Show_Effect_Last, MainFrame::OnShowEffect)
EVT_MENU(wxID_EXIT, MainFrame::OnExit)
wxEND_EVENT_TABLE()
@@ -252,6 +259,8 @@ MainFrame::MainFrame()
wxMenu * const menuFrames = new wxMenu;
menuFrames->Append(Show_Shaped, "Show &shaped window\tCtrl-S");
menuFrames->Append(Show_Transparent, "Show &transparent window\tCtrl-T");
menuFrames->Append(Show_TransparentBg,
"Show with &transparent background\tShift-Ctrl-T");
menuFrames->AppendSeparator();
menuFrames->Append(Show_Effect_Roll, "Show &rolled effect\tCtrl-R");
menuFrames->Append(Show_Effect_Slide, "Show s&lide effect\tCtrl-L");
@@ -272,19 +281,27 @@ void MainFrame::OnShowShaped(wxCommandEvent& WXUNUSED(event))
shapedFrame->Show(true);
}
void MainFrame::OnShowTransparent(wxCommandEvent& WXUNUSED(event))
void MainFrame::OnShowTransparent(wxCommandEvent& event)
{
SeeThroughFrame *seeThroughFrame = new SeeThroughFrame;
if ( event.GetId() == Show_TransparentBg )
{
wxString reason;
if (IsTransparentBackgroundSupported(&reason))
{
SeeThroughFrame *seeThroughFrame = new SeeThroughFrame;
seeThroughFrame->Create();
seeThroughFrame->Show(true);
seeThroughFrame->SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
}
else
{
wxLogError("%s, can't create transparent window.", reason);
wxLogError("Can't use transparent background: %s", reason);
delete seeThroughFrame;
return;
}
}
seeThroughFrame->Create(this);
seeThroughFrame->Show(true);
}
void MainFrame::OnShowEffect(wxCommandEvent& event)
@@ -474,44 +491,77 @@ wxBEGIN_EVENT_TABLE(SeeThroughFrame, wxFrame)
EVT_PAINT(SeeThroughFrame::OnPaint)
wxEND_EVENT_TABLE()
void SeeThroughFrame::Create()
void
SeeThroughFrame::Create(wxWindow* parent)
{
SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
wxFrame::Create(NULL, wxID_ANY, "Transparency test",
wxPoint(100, 30), wxSize(300, 300),
wxFrame::Create(parent, wxID_ANY, "Transparency test",
wxDefaultPosition, wxWindow::FromDIP(wxSize(300, 300), parent),
wxDEFAULT_FRAME_STYLE |
wxFULL_REPAINT_ON_RESIZE |
wxSTAY_ON_TOP);
SetBackgroundColour(*wxWHITE);
const int initialAlpha = wxALPHA_OPAQUE / 2;
// Create control for choosing alpha and put it in the middle of the window.
wxPanel* panel = new wxPanel(this);
wxSlider* slider = new wxSlider
(
panel,
wxID_ANY,
initialAlpha,
wxALPHA_TRANSPARENT,
wxALPHA_OPAQUE,
wxDefaultPosition,
FromDIP(wxSize(256, -1)),
wxSL_HORIZONTAL | wxSL_LABELS
);
slider->Bind(wxEVT_SLIDER, &SeeThroughFrame::OnAlpha, this);
const wxSizerFlags center = wxSizerFlags().Center().Border();
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(new wxStaticText(panel, wxID_ANY, "Window opacity:"), center);
sizer->Add(slider, center);
panel->SetSizer(sizer);
wxSizer* sizerTop = new wxBoxSizer(wxVERTICAL);
sizerTop->AddStretchSpacer();
sizerTop->Add(panel, center);
sizerTop->AddStretchSpacer();
SetSizer(sizerTop);
// Note that this must be called before the frame is shown.
SetTransparent(initialAlpha);
}
// Paints a grid of varying hue and alpha
void SeeThroughFrame::OnPaint(wxPaintEvent& WXUNUSED(evt))
{
wxPaintDC dc(this);
dc.SetPen(wxNullPen);
wxScopedPtr<wxGraphicsContext> gc(wxGraphicsContext::Create(dc));
int xcount = 8;
int ycount = 8;
// Draw 3 bands: one opaque, one semi-transparent and one transparent.
const wxSize size = GetClientSize();
const double h = size.y / 3.0;
double xstep = 1.0 / xcount;
double ystep = 1.0 / ycount;
wxGraphicsPath path = gc->CreatePath();
path.AddRectangle(0, 0, size.x, h);
gc->SetBrush(wxBrush(wxColour(0, 0, 255, wxALPHA_OPAQUE)));
gc->FillPath(path);
int width = GetClientSize().GetWidth();
int height = GetClientSize().GetHeight();
gc->SetBrush(wxBrush(wxColour(0, 0, 255, wxALPHA_OPAQUE / 2)));
gc->Translate(0, h);
gc->FillPath(path);
for ( double x = 0; x < 1; x += xstep )
{
for ( double y = 0; y < 1; y += ystep )
{
wxImage::RGBValue v = wxImage::HSVtoRGB(wxImage::HSVValue(x, 1., 1.));
dc.SetBrush(wxBrush(wxColour(v.red, v.green, v.blue,
(int)(255*(1. - y)))));
int x1 = (int)(x * width);
int y1 = (int)(y * height);
int x2 = (int)((x + xstep) * width);
int y2 = (int)((y + ystep) * height);
dc.DrawRectangle(x1, y1, x2 - x1, y2 - y1);
}
}
// This blue won't actually be seen and instead the white background will
// be visible, because this brush is fully transparent.
gc->SetBrush(wxBrush(wxColour(0, 0, 255, wxALPHA_TRANSPARENT)));
gc->Translate(0, h);
gc->FillPath(path);
}
void SeeThroughFrame::OnAlpha(wxCommandEvent& event)
{
SetTransparent(event.GetInt());
}