delay setting the window shape until it is realized (slightly modified patch 1935497)
[wxWidgets.git] / samples / shaped / shaped.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: shaped.cpp
3 // Purpose: Shaped Window sample
4 // Author: Robin Dunn
5 // Modified by:
6 // Created: 28-Mar-2003
7 // RCS-ID: $Id$
8 // Copyright: (c) Robin Dunn
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx/wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 // for all others, include the necessary headers
28 #ifndef WX_PRECOMP
29 #include "wx/app.h"
30 #include "wx/log.h"
31 #include "wx/frame.h"
32 #include "wx/panel.h"
33 #include "wx/stattext.h"
34 #include "wx/menu.h"
35 #include "wx/layout.h"
36 #include "wx/msgdlg.h"
37 #include "wx/image.h"
38 #endif
39
40 #include "wx/dcclient.h"
41 #include "wx/image.h"
42
43 // ----------------------------------------------------------------------------
44 // constants
45 // ----------------------------------------------------------------------------
46
47 // menu ids
48 enum
49 {
50 Show_Shaped = 100,
51 Show_Transparent,
52
53 // must be consecutive and in the same order as wxShowEffect enum elements
54 Show_Effect_First,
55 Show_Effect_Roll = Show_Effect_First,
56 Show_Effect_Slide,
57 Show_Effect_Blend,
58 Show_Effect_Expand,
59 Show_Effect_Last = Show_Effect_Expand
60 };
61
62 // ----------------------------------------------------------------------------
63 // private classes
64 // ----------------------------------------------------------------------------
65
66 // Define a new application type, each program should derive a class from wxApp
67 class MyApp : public wxApp
68 {
69 public:
70 // override base class virtuals
71 // ----------------------------
72
73 // this one is called on application startup and is a good place for the app
74 // initialization (doing it here and not in the ctor allows to have an error
75 // return: if OnInit() returns false, the application terminates)
76 virtual bool OnInit();
77 };
78
79
80 // Main frame just contains the menu items invoking the other tests
81 class MainFrame : public wxFrame
82 {
83 public:
84 MainFrame();
85
86 private:
87 void OnShowShaped(wxCommandEvent& event);
88 void OnShowTransparent(wxCommandEvent& event);
89 void OnShowEffect(wxCommandEvent& event);
90
91 DECLARE_EVENT_TABLE()
92 };
93
94 // Define a new frame type: this is going to the frame showing the
95 // effect of wxFRAME_SHAPED
96 class ShapedFrame : public wxFrame
97 {
98 public:
99 // ctor(s)
100 ShapedFrame(wxFrame *parent);
101 void SetWindowShape();
102
103 // event handlers (these functions should _not_ be virtual)
104 void OnDoubleClick(wxMouseEvent& evt);
105 void OnLeftDown(wxMouseEvent& evt);
106 void OnLeftUp(wxMouseEvent& evt);
107 void OnMouseMove(wxMouseEvent& evt);
108 void OnExit(wxMouseEvent& evt);
109 void OnPaint(wxPaintEvent& evt);
110
111 private:
112 bool m_hasShape;
113 wxBitmap m_bmp;
114 wxPoint m_delta;
115
116 // any class wishing to process wxWidgets events must use this macro
117 DECLARE_EVENT_TABLE()
118 };
119
120 // Define a new frame type: this is going to the frame showing the
121 // effect of wxWindow::SetTransparent and of
122 // wxWindow::SetBackgroundStyle(wxBG_STYLE_TRANSPARENT)
123 class SeeThroughFrame : public wxFrame
124 {
125 public:
126 // ctor(s)
127 SeeThroughFrame();
128
129 // event handlers (these functions should _not_ be virtual)
130 void OnDoubleClick(wxMouseEvent& evt);
131 void OnPaint(wxPaintEvent& evt);
132
133 private:
134 enum State
135 {
136 STATE_SEETHROUGH,
137 STATE_TRANSPARENT,
138 STATE_OPAQUE,
139 STATE_MAX
140 };
141
142 State m_currentState;
143
144 // any class wishing to process wxWidgets events must use this macro
145 DECLARE_EVENT_TABLE()
146 };
147
148 class EffectFrame : public wxFrame
149 {
150 public:
151 EffectFrame(wxWindow *parent,
152 wxShowEffect effect,
153 // TODO: add menu command to the main frame to allow changing
154 // these parameters
155 unsigned timeout = 1000,
156 wxDirection dir = wxBOTTOM)
157 : wxFrame(parent, wxID_ANY,
158 wxString::Format("Frame shown with %s effect",
159 GetEffectName(effect)),
160 wxDefaultPosition, wxSize(450, 300)),
161 m_effect(effect),
162 m_timeout(timeout),
163 m_dir(dir)
164 {
165 new wxStaticText(this, wxID_ANY,
166 wxString::Format("Effect: %s", GetEffectName(effect)),
167 wxPoint(20, 20));
168 new wxStaticText(this, wxID_ANY,
169 wxString::Format("Timeout: %ums", m_timeout),
170 wxPoint(20, 60));
171
172 ShowWithEffect(m_effect, m_timeout, m_dir);
173
174 Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(EffectFrame::OnClose));
175 }
176
177 private:
178 static const char *GetEffectName(wxShowEffect effect)
179 {
180 static const char *names[] =
181 {
182 "roll", "slide", "fade", "expand",
183 };
184 wxCOMPILE_TIME_ASSERT( WXSIZEOF(names) == wxSHOW_EFFECT_MAX,
185 EffectNamesMismatch );
186
187 return names[effect];
188 }
189
190 void OnClose(wxCloseEvent& event)
191 {
192 HideWithEffect(m_effect, m_timeout, m_dir);
193
194 event.Skip();
195 }
196
197 wxShowEffect m_effect;
198 unsigned m_timeout;
199 wxDirection m_dir;
200 };
201
202 // ============================================================================
203 // implementation
204 // ============================================================================
205
206 // ----------------------------------------------------------------------------
207 // the application class
208 // ----------------------------------------------------------------------------
209
210 IMPLEMENT_APP(MyApp)
211
212 // `Main program' equivalent: the program execution "starts" here
213 bool MyApp::OnInit()
214 {
215 if ( !wxApp::OnInit() )
216 return false;
217
218 wxInitAllImageHandlers();
219
220 new MainFrame;
221
222 // success: wxApp::OnRun() will be called which will enter the main message
223 // loop and the application will run. If we returned false here, the
224 // application would exit immediately.
225 return true;
226 }
227
228 // ----------------------------------------------------------------------------
229 // main frame
230 // ----------------------------------------------------------------------------
231
232 BEGIN_EVENT_TABLE(MainFrame, wxFrame)
233 EVT_MENU(Show_Shaped, MainFrame::OnShowShaped)
234 EVT_MENU(Show_Transparent, MainFrame::OnShowTransparent)
235 EVT_MENU_RANGE(Show_Effect_First, Show_Effect_Last, MainFrame::OnShowEffect)
236 END_EVENT_TABLE()
237
238 MainFrame::MainFrame()
239 : wxFrame(NULL, wxID_ANY, "wxWidgets Shaped Sample",
240 wxDefaultPosition, wxSize(200, 100))
241 {
242 wxMenuBar * const mbar = new wxMenuBar;
243 wxMenu * const menuFrames = new wxMenu;
244 menuFrames->Append(Show_Shaped, "Show &shaped window\tCtrl-S");
245 menuFrames->Append(Show_Transparent, "Show &transparent window\tCtrl-T");
246 menuFrames->AppendSeparator();
247 menuFrames->Append(Show_Effect_Roll, "Show &rolled effect\tCtrl-R");
248 menuFrames->Append(Show_Effect_Slide, "Show s&lide effect\tCtrl-L");
249 menuFrames->Append(Show_Effect_Blend, "Show &fade effect\tCtrl-F");
250 menuFrames->Append(Show_Effect_Expand, "Show &expand effect\tCtrl-E");
251 menuFrames->AppendSeparator();
252 menuFrames->Append(wxID_EXIT, "E&xit");
253
254 mbar->Append(menuFrames, "&Show");
255 SetMenuBar(mbar);
256
257 Show();
258 }
259
260 void MainFrame::OnShowShaped(wxCommandEvent& WXUNUSED(event))
261 {
262 ShapedFrame *shapedFrame = new ShapedFrame(this);
263 shapedFrame->Show(true);
264 }
265
266 void MainFrame::OnShowTransparent(wxCommandEvent& WXUNUSED(event))
267 {
268 SeeThroughFrame *seeThroughFrame = new SeeThroughFrame();
269 seeThroughFrame->Show(true);
270 }
271
272 void MainFrame::OnShowEffect(wxCommandEvent& event)
273 {
274 int effect = wxSHOW_EFFECT_ROLL + event.GetId() - Show_Effect_Roll;
275 static wxDirection direction = wxLEFT;
276 direction = (wxDirection)(((int)direction)<< 1);
277 if ( direction > wxDOWN )
278 direction = wxLEFT ;
279 new EffectFrame(this, wx_static_cast(wxShowEffect, effect),1000,direction);
280 }
281
282 // ----------------------------------------------------------------------------
283 // shaped frame
284 // ----------------------------------------------------------------------------
285
286 BEGIN_EVENT_TABLE(ShapedFrame, wxFrame)
287 EVT_LEFT_DCLICK(ShapedFrame::OnDoubleClick)
288 EVT_LEFT_DOWN(ShapedFrame::OnLeftDown)
289 EVT_LEFT_UP(ShapedFrame::OnLeftUp)
290 EVT_MOTION(ShapedFrame::OnMouseMove)
291 EVT_RIGHT_UP(ShapedFrame::OnExit)
292 EVT_PAINT(ShapedFrame::OnPaint)
293 END_EVENT_TABLE()
294
295
296 // frame constructor
297 ShapedFrame::ShapedFrame(wxFrame *parent)
298 : wxFrame(parent, wxID_ANY, wxEmptyString,
299 wxDefaultPosition, wxSize(100, 100),
300 0
301 | wxFRAME_SHAPED
302 | wxSIMPLE_BORDER
303 | wxFRAME_NO_TASKBAR
304 | wxSTAY_ON_TOP
305 )
306 {
307 m_hasShape = false;
308 m_bmp = wxBitmap(_T("star.png"), wxBITMAP_TYPE_PNG);
309 SetSize(wxSize(m_bmp.GetWidth(), m_bmp.GetHeight()));
310 SetToolTip(wxT("Right-click to close"));
311 SetWindowShape();
312 }
313
314 void ShapedFrame::SetWindowShape()
315 {
316 wxRegion region(m_bmp, *wxWHITE);
317 m_hasShape = SetShape(region);
318 }
319
320 void ShapedFrame::OnDoubleClick(wxMouseEvent& WXUNUSED(evt))
321 {
322 if (m_hasShape)
323 {
324 wxRegion region;
325 SetShape(region);
326 m_hasShape = false;
327 }
328 else
329 SetWindowShape();
330 }
331
332 void ShapedFrame::OnLeftDown(wxMouseEvent& evt)
333 {
334 CaptureMouse();
335 wxPoint pos = ClientToScreen(evt.GetPosition());
336 wxPoint origin = GetPosition();
337 int dx = pos.x - origin.x;
338 int dy = pos.y - origin.y;
339 m_delta = wxPoint(dx, dy);
340 }
341
342 void ShapedFrame::OnLeftUp(wxMouseEvent& WXUNUSED(evt))
343 {
344 if (HasCapture())
345 {
346 ReleaseMouse();
347 }
348 }
349
350 void ShapedFrame::OnMouseMove(wxMouseEvent& evt)
351 {
352 wxPoint pt = evt.GetPosition();
353 if (evt.Dragging() && evt.LeftIsDown())
354 {
355 wxPoint pos = ClientToScreen(pt);
356 Move(wxPoint(pos.x - m_delta.x, pos.y - m_delta.y));
357 }
358 }
359
360 void ShapedFrame::OnExit(wxMouseEvent& WXUNUSED(evt))
361 {
362 Close();
363 }
364
365 void ShapedFrame::OnPaint(wxPaintEvent& WXUNUSED(evt))
366 {
367 wxPaintDC dc(this);
368 dc.DrawBitmap(m_bmp, 0, 0, true);
369 }
370
371 // ----------------------------------------------------------------------------
372 // see-through frame
373 // ----------------------------------------------------------------------------
374
375 BEGIN_EVENT_TABLE(SeeThroughFrame, wxFrame)
376 EVT_LEFT_DCLICK(SeeThroughFrame::OnDoubleClick)
377 EVT_PAINT(SeeThroughFrame::OnPaint)
378 END_EVENT_TABLE()
379
380 SeeThroughFrame::SeeThroughFrame()
381 : wxFrame(NULL, wxID_ANY, "Transparency test: double click here",
382 wxPoint(100, 30), wxSize(300, 300),
383 wxDEFAULT_FRAME_STYLE |
384 wxFULL_REPAINT_ON_RESIZE |
385 wxSTAY_ON_TOP),
386 m_currentState(STATE_SEETHROUGH)
387 {
388 SetBackgroundColour(wxColour(255, 255, 255, 255));
389 SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
390 }
391
392 // Paints a grid of varying hue and alpha
393 void SeeThroughFrame::OnPaint(wxPaintEvent& WXUNUSED(evt))
394 {
395 wxPaintDC dc(this);
396 dc.SetPen(wxNullPen);
397
398 int xcount = 8;
399 int ycount = 8;
400
401 float xstep = 1. / xcount;
402 float ystep = 1. / ycount;
403
404 int width = GetClientSize().GetWidth();
405 int height = GetClientSize().GetHeight();
406
407 for ( float x = 0.; x < 1.; x += xstep )
408 {
409 for ( float y = 0.; y < 1.; y += ystep )
410 {
411 wxImage::RGBValue v = wxImage::HSVtoRGB(wxImage::HSVValue(x, 1., 1.));
412 dc.SetBrush(wxBrush(wxColour(v.red, v.green, v.blue,
413 (int)(255*(1. - y)))));
414 int x1 = (int)(x * width);
415 int y1 = (int)(y * height);
416 int x2 = (int)((x + xstep) * width);
417 int y2 = (int)((y + ystep) * height);
418 dc.DrawRectangle(x1, y1, x2 - x1, y2 - y1);
419 }
420 }
421 }
422
423 // Switches between colour and transparent background on doubleclick
424 void SeeThroughFrame::OnDoubleClick(wxMouseEvent& WXUNUSED(evt))
425 {
426 m_currentState = (State)((m_currentState + 1) % STATE_MAX);
427
428 switch ( m_currentState )
429 {
430 case STATE_OPAQUE:
431 SetBackgroundStyle(wxBG_STYLE_COLOUR);
432 SetTransparent(255);
433 SetTitle("Opaque");
434 break;
435
436 case STATE_SEETHROUGH:
437 SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
438 SetTransparent(255);
439 SetTitle("See through");
440 break;
441
442 case STATE_TRANSPARENT:
443 SetBackgroundStyle(wxBG_STYLE_COLOUR);
444 SetTransparent(128);
445 SetTitle("Semi-transparent");
446 break;
447
448 case STATE_MAX:
449 wxFAIL_MSG( "unreachable" );
450 }
451
452 Refresh();
453 }
454