From 4488a1d33266555c47bd3ca72cca6e20c67ab509 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 22 Oct 2007 21:15:04 +0000 Subject: [PATCH] added wxBG_STYLE_TRANSPARENT and implemented it for wxMac; documented various transparency-related functions git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@49341 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + docs/latex/wx/window.tex | 65 ++++++++++---- include/wx/defs.h | 3 +- include/wx/mac/carbon/toplevel.h | 1 + samples/shaped/shaped.cpp | 142 +++++++++++++++++++++++++++++-- src/mac/carbon/toplevel.cpp | 49 +++++++++++ src/mac/carbon/window.cpp | 17 +++- 7 files changed, 250 insertions(+), 28 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 18ae1e73d0..7eabf9bc39 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -181,6 +181,7 @@ All (GUI): - Added support for drop down toolbar buttons (Tim Kosse). - Added support for labels for toolbar controls (Vince Harron). - Added wxMessageDialog::SetMessage() and SetExtendedMessage(). +- Added wxBG_STYLE_TRANSPARENT background style (Julian Scheid) - Added XRCSIZERITEM() macro for obtaining sizers from XRC (Brian Vanderburg II) - New and improved wxFileCtrl (Diaa Sami and Marcin Wojdyr) - Added wxEventBlocker class (Francesco Montorsi). diff --git a/docs/latex/wx/window.tex b/docs/latex/wx/window.tex index d19f545197..ef908b33d0 100644 --- a/docs/latex/wx/window.tex +++ b/docs/latex/wx/window.tex @@ -226,6 +226,16 @@ called by the user code. Sets the cached best size value. +\membersection{wxWindow::CanSetTransparent}\label{wxwindowcansettransparent} + +\func{bool}{CanSetTransparent}{\void} + +Returns \true if the system supports transparent windows and calling +\helpref{SetTransparent}{wxwindowsettransparent} may succeed. If this function +returns \false, transparent windows are definitely not supported by the current +system. + + \membersection{wxWindow::CaptureMouse}\label{wxwindowcapturemouse} \func{virtual void}{CaptureMouse}{\void} @@ -775,19 +785,32 @@ Returns the background colour of the window. \constfunc{virtual wxBackgroundStyle}{GetBackgroundStyle}{\void} -Returns the background style of the window. The background style indicates -whether background colour should be determined by the system (wxBG\_STYLE\_SYSTEM), -be set to a specific colour (wxBG\_STYLE\_COLOUR), or should be left to the -application to implement (wxBG\_STYLE\_CUSTOM). - -On GTK+, use of wxBG\_STYLE\_CUSTOM allows the flicker-free drawing of a custom -background, such as a tiled bitmap. Currently the style has no effect on other platforms. +Returns the background style of the window. The background style can be one of: +\begin{twocollist}\itemsep=0pt +\twocolitem{wxBG\_STYLE\_SYSTEM}{Use the default background, as determined by +the system or the current theme.} +\twocolitem{wxBG\_STYLE\_COLOUR}{Use a solid colour for the background, this +style is set automatically if you call +\helpref{SetBackgroundColour}{wxwindowsetbackgroundcolour} so you only need to +set it explicitly if you had changed the background style to something else +before.} +\twocolitem{wxBG\_STYLE\_CUSTOM}{Don't draw the background at all, it's +supposed that it is drawn by the user-defined erase background event handler. +This style should be used to avoid flicker when the background is entirely +custom-drawn.} +\twocolitem{wxBG\_STYLE\_TRANSPARET}{The background is (partially) transparent, +this style is automatically set if you call +\helpref{SetTransparent}{wxwindowsettransparent} which is used to set the +transparency level.} +\end{twocollist} \wxheading{See also} \helpref{wxWindow::SetBackgroundColour}{wxwindowsetbackgroundcolour},\rtfsp \helpref{wxWindow::GetForegroundColour}{wxwindowgetforegroundcolour},\rtfsp -\helpref{wxWindow::SetBackgroundStyle}{wxwindowsetbackgroundstyle} +\helpref{wxWindow::SetBackgroundStyle}{wxwindowsetbackgroundstyle},\rtfsp +\helpref{wxWindow::SetTransparent}{wxwindowsettransparent} + \membersection{wxWindow::GetEffectiveMinSize}\label{wxwindowgeteffectiveminsize} @@ -2793,19 +2816,15 @@ applications on the system. \func{virtual void}{SetBackgroundStyle}{\param{wxBackgroundStyle}{ style}} -Sets the background style of the window. The background style indicates -whether background colour should be determined by the system (wxBG\_STYLE\_SYSTEM), -be set to a specific colour (wxBG\_STYLE\_COLOUR), or should be left to the -application to implement (wxBG\_STYLE\_CUSTOM). - -On GTK+, use of wxBG\_STYLE\_CUSTOM allows the flicker-free drawing of a custom -background, such as a tiled bitmap. Currently the style has no effect on other platforms. +Sets the background style of the window. see +\helpref{GetBackgroundStyle()}{wxwindowgetbackgroundstyle} for the description +of the possible style values. \wxheading{See also} \helpref{wxWindow::SetBackgroundColour}{wxwindowsetbackgroundcolour},\rtfsp \helpref{wxWindow::GetForegroundColour}{wxwindowgetforegroundcolour},\rtfsp -\helpref{wxWindow::GetBackgroundStyle}{wxwindowgetbackgroundstyle} +\helpref{wxWindow::SetTransparent}{wxwindowsettransparent} @@ -3545,6 +3564,20 @@ See also: \helpref{GetToolTip}{wxwindowgettooltip}, \helpref{wxToolTip}{wxtooltip} +\membersection{wxWindow::SetTransparent}\label{wxwindowsettransparent} + +\func{bool}{SetTransparent}{\param{wxByte }{alpha}} + +Set the transparency of the window. If the system supports transparent windows, +returns \true, otherwise returns \false and the window remains fully opaque. +See also \helpref{CanSetTransparent}{wxwindowcansettransparent}. + +The parameter \arg{alpha} is in the range $0..255$ where $0$ corresponds to a +fully transparent window and $255$ to the fully opaque one. The constants +\texttt{wxIMAGE\_ALPHA\_TRANSPARENT} and \texttt{wxIMAGE\_ALPHA\_OPAQUE} can be +used. + + \membersection{wxWindow::SetValidator}\label{wxwindowsetvalidator} \func{virtual void}{SetValidator}{\param{const wxValidator\&}{ validator}} diff --git a/include/wx/defs.h b/include/wx/defs.h index 8e387b61ed..66263a007c 100644 --- a/include/wx/defs.h +++ b/include/wx/defs.h @@ -1751,7 +1751,8 @@ enum wxBackgroundStyle { wxBG_STYLE_SYSTEM, wxBG_STYLE_COLOUR, - wxBG_STYLE_CUSTOM + wxBG_STYLE_CUSTOM, + wxBG_STYLE_TRANSPARENT }; /* diff --git a/include/wx/mac/carbon/toplevel.h b/include/wx/mac/carbon/toplevel.h index b123748caa..71a5f1937c 100644 --- a/include/wx/mac/carbon/toplevel.h +++ b/include/wx/mac/carbon/toplevel.h @@ -70,6 +70,7 @@ public: virtual bool SetTransparent(wxByte alpha); virtual bool CanSetTransparent(); + virtual bool SetBackgroundStyle(wxBackgroundStyle style); // implementation from now on // -------------------------- diff --git a/samples/shaped/shaped.cpp b/samples/shaped/shaped.cpp index cc8ed4a232..1a9efa8132 100644 --- a/samples/shaped/shaped.cpp +++ b/samples/shaped/shaped.cpp @@ -58,12 +58,13 @@ public: }; -// Define a new frame type: this is going to be our main frame +// Define a new frame type: this is going to the frame showing the +// effect of wxFRAME_SHAPED class ShapedFrame : public wxFrame { public: // ctor(s) - ShapedFrame(); + ShapedFrame(wxFrame *parent); void SetWindowShape(); // event handlers (these functions should _not_ be virtual) @@ -84,6 +85,35 @@ private: DECLARE_EVENT_TABLE() }; +// Define a new frame type: this is going to the frame showing the +// effect of wxWindow::SetTransparent and of +// wxWindow::SetBackgroundStyle(wxBG_STYLE_TRANSPARENT) +class SeeThroughFrame : public wxFrame +{ +public: + // ctor(s) + SeeThroughFrame(); + + // event handlers (these functions should _not_ be virtual) + void OnDoubleClick(wxMouseEvent& evt); + void OnPaint(wxPaintEvent& evt); + void OnSize(wxSizeEvent& evt); + +private: + enum State + { + STATE_SEETHROUGH, + STATE_TRANSPARENT, + STATE_OPAQUE, + STATE_MAX + }; + + State m_currentState; + + // any class wishing to process wxWidgets events must use this macro + DECLARE_EVENT_TABLE() +}; + // ---------------------------------------------------------------------------- // event tables and other macros for wxWidgets @@ -130,10 +160,14 @@ bool MyApp::OnInit() wxInitAllImageHandlers(); - // Create the main application window - ShapedFrame *frame = new ShapedFrame(); - frame->Show(true); - SetTopWindow(frame); + // Create the transparent window + SeeThroughFrame *seeThroughFrame = new SeeThroughFrame(); + seeThroughFrame->Show(true); + SetTopWindow(seeThroughFrame); + + // Create the shaped window + ShapedFrame *shapedFrame = new ShapedFrame(seeThroughFrame); + shapedFrame->Show(true); // success: wxApp::OnRun() will be called which will enter the main message // loop and the application will run. If we returned false here, the @@ -142,12 +176,12 @@ bool MyApp::OnInit() } // ---------------------------------------------------------------------------- -// main frame +// shaped frame // ---------------------------------------------------------------------------- // frame constructor -ShapedFrame::ShapedFrame() - : wxFrame((wxFrame *)NULL, wxID_ANY, wxEmptyString, +ShapedFrame::ShapedFrame(wxFrame *parent) + : wxFrame(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(100, 100), //wxDefaultSize, 0 | wxFRAME_SHAPED @@ -235,3 +269,93 @@ void ShapedFrame::OnWindowCreate(wxWindowCreateEvent& WXUNUSED(evt)) SetWindowShape(); } +// ---------------------------------------------------------------------------- +// see-through frame +// ---------------------------------------------------------------------------- + +// frame constructor +SeeThroughFrame::SeeThroughFrame() + : wxFrame(NULL, wxID_ANY, "Transparency test: double click here", + wxPoint(100, 30), wxSize(300, 300), + wxDEFAULT_FRAME_STYLE | wxSTAY_ON_TOP), + m_currentState(STATE_SEETHROUGH) +{ + SetBackgroundColour(wxColour(255, 255, 255, 255)); + SetBackgroundStyle(wxBG_STYLE_TRANSPARENT); +} + +// Redraws the whole window on resize +void SeeThroughFrame::OnSize(wxSizeEvent& WXUNUSED(evt)) +{ + Refresh(); +} + +// Paints a grid of varying hue and alpha +void SeeThroughFrame::OnPaint(wxPaintEvent& WXUNUSED(evt)) +{ + wxPaintDC dc(this); + dc.SetPen(wxNullPen); + + int xcount = 8; + int ycount = 8; + + float xstep = 1. / xcount; + float ystep = 1. / ycount; + + int width = GetClientSize().GetWidth(); + int height = GetClientSize().GetHeight(); + + for ( float x = 0.; x < 1.; x += xstep ) + { + for ( float 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); + } + } +} + +// Switches between colour and transparent background on doubleclick +void SeeThroughFrame::OnDoubleClick(wxMouseEvent& WXUNUSED(evt)) +{ + m_currentState = (State)((m_currentState + 1) % STATE_MAX); + + switch ( m_currentState ) + { + case STATE_OPAQUE: + SetBackgroundStyle(wxBG_STYLE_COLOUR); + SetTransparent(255); + SetTitle("Opaque"); + break; + + case STATE_SEETHROUGH: + SetBackgroundStyle(wxBG_STYLE_TRANSPARENT); + SetTransparent(255); + SetTitle("See through"); + break; + + case STATE_TRANSPARENT: + SetBackgroundStyle(wxBG_STYLE_COLOUR); + SetTransparent(128); + SetTitle("Semi-transparent"); + break; + + case STATE_MAX: + wxFAIL_MSG( "unreachable" ); + } + + Refresh(); +} + +BEGIN_EVENT_TABLE(SeeThroughFrame, wxFrame) + EVT_LEFT_DCLICK(SeeThroughFrame::OnDoubleClick) + EVT_PAINT(SeeThroughFrame::OnPaint) + EVT_SIZE(SeeThroughFrame::OnSize) +END_EVENT_TABLE() + diff --git a/src/mac/carbon/toplevel.cpp b/src/mac/carbon/toplevel.cpp index d45476496a..dec6597956 100644 --- a/src/mac/carbon/toplevel.cpp +++ b/src/mac/carbon/toplevel.cpp @@ -102,6 +102,7 @@ static const EventTypeSpec eventList[] = { kEventClassWindow , kEventWindowBoundsChanging } , { kEventClassWindow , kEventWindowBoundsChanged } , { kEventClassWindow , kEventWindowClose } , + { kEventClassWindow , kEventWindowGetRegion } , // we have to catch these events on the toplevel window level, // as controls don't get the raw mouse events anymore @@ -804,6 +805,36 @@ static pascal OSStatus wxMacTopLevelWindowEventHandler( EventHandlerCallRef hand } break ; + case kEventWindowGetRegion : + { + if ( toplevelWindow->GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT ) + { + WindowRegionCode windowRegionCode ; + + // Fetch the region code that is being queried + GetEventParameter( event, + kEventParamWindowRegionCode, + typeWindowRegionCode, NULL, + sizeof windowRegionCode, NULL, + &windowRegionCode ) ; + + // If it is the opaque region code then set the + // region to empty and return noErr to stop event + // propagation + if ( windowRegionCode == kWindowOpaqueRgn ) { + RgnHandle region; + GetEventParameter( event, + kEventParamRgnHandle, + typeQDRgnHandle, NULL, + sizeof region, NULL, + ®ion) ; + SetEmptyRgn(region) ; + result = noErr ; + } + } + } + break ; + default : break ; } @@ -1482,6 +1513,24 @@ void wxTopLevelWindowMac::SetExtraStyle(long exStyle) #endif } +bool wxTopLevelWindowMac::SetBackgroundStyle(wxBackgroundStyle style) +{ + if ( !wxTopLevelWindowBase::SetBackgroundStyle(style) ) + return false ; + + WindowRef windowRef = HIViewGetWindow( (HIViewRef)GetHandle() ); + + if ( GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT ) + { + OSStatus err = HIWindowChangeFeatures( windowRef, 0, kWindowIsOpaque ); + verify_noerr( err ); + err = ReshapeCustomWindow( windowRef ); + verify_noerr( err ); + } + + return true ; +} + // TODO: switch to structure bounds - // we are still using coordinates of the content view // diff --git a/src/mac/carbon/window.cpp b/src/mac/carbon/window.cpp index 9d32605485..bd25da73e0 100644 --- a/src/mac/carbon/window.cpp +++ b/src/mac/carbon/window.cpp @@ -278,6 +278,15 @@ static pascal OSStatus wxMacWindowControlEventHandler( EventHandlerCallRef handl } } CGContextSetAlpha( cgContext , alpha ) ; + + if ( thisWindow->GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT ) + { + HIRect bounds; + HIViewGetBounds( controlRef, &bounds ); + CGContextClearRect( cgContext, bounds ); + } + + #endif if ( thisWindow->MacDoRedraw( updateRgn , cEvent.GetTicks() ) ) result = noErr ; @@ -2363,7 +2372,8 @@ void wxWindowMac::OnEraseBackground(wxEraseEvent& event) return ; #if TARGET_API_MAC_OSX - if ( !m_macBackgroundBrush.Ok() || m_macBackgroundBrush.GetStyle() == wxTRANSPARENT ) + if ( !m_macBackgroundBrush.Ok() || m_macBackgroundBrush.GetStyle() == wxTRANSPARENT + || GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT ) { event.Skip() ; } @@ -3343,7 +3353,8 @@ void wxWindowMac::OnMouseEvent( wxMouseEvent &event ) void wxWindowMac::OnPaint( wxPaintEvent & event ) { - if ( wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL ) + if ( wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL + && GetBackgroundStyle() != wxBG_STYLE_TRANSPARENT ) CallNextEventHandler( (EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() , (EventRef) wxTheApp->MacGetCurrentEvent() ) ; @@ -3387,6 +3398,8 @@ bool wxWindowMac::Reparent(wxWindowBase *newParentBase) bool wxWindowMac::SetTransparent(wxByte alpha) { #if wxMAC_USE_CORE_GRAPHICS + SetBackgroundStyle(wxBG_STYLE_TRANSPARENT); + if ( alpha != m_macAlpha ) { m_macAlpha = alpha ; -- 2.45.2