diff --git a/docs/doxygen/mainpages/samples.h b/docs/doxygen/mainpages/samples.h index 0b5c3b576a..9dd572587e 100644 --- a/docs/doxygen/mainpages/samples.h +++ b/docs/doxygen/mainpages/samples.h @@ -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} diff --git a/interface/wx/toplevel.h b/interface/wx/toplevel.h index 68ba34827e..64cc29a233 100644 --- a/interface/wx/toplevel.h +++ b/interface/wx/toplevel.h @@ -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 diff --git a/interface/wx/window.h b/interface/wx/window.h index 1688fd5ed8..4dfebe1fef 100644 --- a/interface/wx/window.h +++ b/interface/wx/window.h @@ -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 diff --git a/samples/shaped/shaped.cpp b/samples/shaped/shaped.cpp index 95011739ed..f5aadf1dab 100644 --- a/samples/shaped/shaped.cpp +++ b/samples/shaped/shaped.cpp @@ -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) { - wxString reason; - if (IsTransparentBackgroundSupported(&reason)) + SeeThroughFrame *seeThroughFrame = new SeeThroughFrame; + + if ( event.GetId() == Show_TransparentBg ) { - SeeThroughFrame *seeThroughFrame = new SeeThroughFrame; - seeThroughFrame->Create(); - seeThroughFrame->Show(true); - } - else - { - wxLogError("%s, can't create transparent window.", reason); + wxString reason; + if (IsTransparentBackgroundSupported(&reason)) + { + seeThroughFrame->SetBackgroundStyle(wxBG_STYLE_TRANSPARENT); + } + else + { + 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 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()); }