]> git.saurik.com Git - wxWidgets.git/blob - samples/shaped/shaped.cpp
don't leak events in wxEvtHandler::QueueEvent when there's no event loop
[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 #ifndef __WXMSW__
44 #include "../sample.xpm"
45 #endif
46
47 // ----------------------------------------------------------------------------
48 // constants
49 // ----------------------------------------------------------------------------
50
51 // menu ids
52 enum
53 {
54 Show_Shaped = 100,
55 Show_Transparent,
56
57 // must be consecutive and in the same order as wxShowEffect enum elements
58 Show_Effect_First,
59 Show_Effect_Roll = Show_Effect_First,
60 Show_Effect_Slide,
61 Show_Effect_Blend,
62 Show_Effect_Expand,
63 Show_Effect_Last = Show_Effect_Expand
64 };
65
66 // ----------------------------------------------------------------------------
67 // private classes
68 // ----------------------------------------------------------------------------
69
70 // Define a new application type, each program should derive a class from wxApp
71 class MyApp : public wxApp
72 {
73 public:
74 // override base class virtuals
75 // ----------------------------
76
77 // this one is called on application startup and is a good place for the app
78 // initialization (doing it here and not in the ctor allows to have an error
79 // return: if OnInit() returns false, the application terminates)
80 virtual bool OnInit();
81 };
82
83
84 // Main frame just contains the menu items invoking the other tests
85 class MainFrame : public wxFrame
86 {
87 public:
88 MainFrame();
89
90 private:
91 void OnShowShaped(wxCommandEvent& event);
92 void OnShowTransparent(wxCommandEvent& event);
93 void OnShowEffect(wxCommandEvent& event);
94
95 DECLARE_EVENT_TABLE()
96 };
97
98 // Define a new frame type: this is going to the frame showing the
99 // effect of wxFRAME_SHAPED
100 class ShapedFrame : public wxFrame
101 {
102 public:
103 // ctor(s)
104 ShapedFrame(wxFrame *parent);
105 void SetWindowShape();
106
107 // event handlers (these functions should _not_ be virtual)
108 void OnDoubleClick(wxMouseEvent& evt);
109 void OnLeftDown(wxMouseEvent& evt);
110 void OnLeftUp(wxMouseEvent& evt);
111 void OnMouseMove(wxMouseEvent& evt);
112 void OnExit(wxMouseEvent& evt);
113 void OnPaint(wxPaintEvent& evt);
114
115 private:
116 bool m_hasShape;
117 wxBitmap m_bmp;
118 wxPoint m_delta;
119
120 // any class wishing to process wxWidgets events must use this macro
121 DECLARE_EVENT_TABLE()
122 };
123
124 // Define a new frame type: this is going to the frame showing the
125 // effect of wxWindow::SetTransparent and of
126 // wxWindow::SetBackgroundStyle(wxBG_STYLE_TRANSPARENT)
127 class SeeThroughFrame : public wxFrame
128 {
129 public:
130 // ctor(s)
131 SeeThroughFrame();
132
133 // event handlers (these functions should _not_ be virtual)
134 void OnDoubleClick(wxMouseEvent& evt);
135 void OnPaint(wxPaintEvent& evt);
136
137 private:
138 enum State
139 {
140 STATE_SEETHROUGH,
141 STATE_TRANSPARENT,
142 STATE_OPAQUE,
143 STATE_MAX
144 };
145
146 State m_currentState;
147
148 // any class wishing to process wxWidgets events must use this macro
149 DECLARE_EVENT_TABLE()
150 };
151
152 class EffectFrame : public wxFrame
153 {
154 public:
155 EffectFrame(wxWindow *parent,
156 wxShowEffect effect,
157 // TODO: add menu command to the main frame to allow changing
158 // these parameters
159 unsigned timeout = 1000)
160 : wxFrame(parent, wxID_ANY,
161 wxString::Format("Frame shown with %s effect",
162 GetEffectName(effect)),
163 wxDefaultPosition, wxSize(450, 300)),
164 m_effect(effect),
165 m_timeout(timeout)
166 {
167 new wxStaticText(this, wxID_ANY,
168 wxString::Format("Effect: %s", GetEffectName(effect)),
169 wxPoint(20, 20));
170 new wxStaticText(this, wxID_ANY,
171 wxString::Format("Timeout: %ums", m_timeout),
172 wxPoint(20, 60));
173
174 ShowWithEffect(m_effect, m_timeout);
175
176 Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(EffectFrame::OnClose));
177 }
178
179 private:
180 static const char *GetEffectName(wxShowEffect effect)
181 {
182 static const char *names[] =
183 {
184 "roll to left",
185 "roll to right",
186 "roll to top",
187 "roll to bottom",
188 "slide to left",
189 "slide to right",
190 "slide to top",
191 "slide to bottom",
192 "fade",
193 "expand",
194 };
195 wxCOMPILE_TIME_ASSERT( WXSIZEOF(names) == wxSHOW_EFFECT_MAX,
196 EffectNamesMismatch );
197
198 return names[effect];
199 }
200
201 void OnClose(wxCloseEvent& event)
202 {
203 HideWithEffect(m_effect, m_timeout);
204
205 event.Skip();
206 }
207
208 wxShowEffect m_effect;
209 unsigned m_timeout;
210 };
211
212 // ============================================================================
213 // implementation
214 // ============================================================================
215
216 // ----------------------------------------------------------------------------
217 // the application class
218 // ----------------------------------------------------------------------------
219
220 IMPLEMENT_APP(MyApp)
221
222 // `Main program' equivalent: the program execution "starts" here
223 bool MyApp::OnInit()
224 {
225 if ( !wxApp::OnInit() )
226 return false;
227
228 wxInitAllImageHandlers();
229
230 new MainFrame;
231
232 // success: wxApp::OnRun() will be called which will enter the main message
233 // loop and the application will run. If we returned false here, the
234 // application would exit immediately.
235 return true;
236 }
237
238 // ----------------------------------------------------------------------------
239 // main frame
240 // ----------------------------------------------------------------------------
241
242 BEGIN_EVENT_TABLE(MainFrame, wxFrame)
243 EVT_MENU(Show_Shaped, MainFrame::OnShowShaped)
244 EVT_MENU(Show_Transparent, MainFrame::OnShowTransparent)
245 EVT_MENU_RANGE(Show_Effect_First, Show_Effect_Last, MainFrame::OnShowEffect)
246 END_EVENT_TABLE()
247
248 MainFrame::MainFrame()
249 : wxFrame(NULL, wxID_ANY, "wxWidgets Shaped Sample",
250 wxDefaultPosition, wxSize(200, 100))
251 {
252 SetIcon(wxICON(sample));
253
254 wxMenuBar * const mbar = new wxMenuBar;
255 wxMenu * const menuFrames = new wxMenu;
256 menuFrames->Append(Show_Shaped, "Show &shaped window\tCtrl-S");
257 menuFrames->Append(Show_Transparent, "Show &transparent window\tCtrl-T");
258 menuFrames->AppendSeparator();
259 menuFrames->Append(Show_Effect_Roll, "Show &rolled effect\tCtrl-R");
260 menuFrames->Append(Show_Effect_Slide, "Show s&lide effect\tCtrl-L");
261 menuFrames->Append(Show_Effect_Blend, "Show &fade effect\tCtrl-F");
262 menuFrames->Append(Show_Effect_Expand, "Show &expand effect\tCtrl-E");
263 menuFrames->AppendSeparator();
264 menuFrames->Append(wxID_EXIT, "E&xit");
265
266 mbar->Append(menuFrames, "&Show");
267 SetMenuBar(mbar);
268
269 Show();
270 }
271
272 void MainFrame::OnShowShaped(wxCommandEvent& WXUNUSED(event))
273 {
274 ShapedFrame *shapedFrame = new ShapedFrame(this);
275 shapedFrame->Show(true);
276 }
277
278 void MainFrame::OnShowTransparent(wxCommandEvent& WXUNUSED(event))
279 {
280 SeeThroughFrame *seeThroughFrame = new SeeThroughFrame();
281 seeThroughFrame->Show(true);
282 }
283
284 void MainFrame::OnShowEffect(wxCommandEvent& event)
285 {
286 int effect = event.GetId();
287 static wxDirection direction = wxLEFT;
288 direction = (wxDirection)(((int)direction)<< 1);
289 if ( direction > wxDOWN )
290 direction = wxLEFT ;
291
292 wxShowEffect eff;
293 switch ( effect )
294 {
295 case Show_Effect_Roll:
296 switch ( direction )
297 {
298 case wxLEFT:
299 eff = wxSHOW_EFFECT_ROLL_TO_LEFT;
300 break;
301 case wxRIGHT:
302 eff = wxSHOW_EFFECT_ROLL_TO_RIGHT;
303 break;
304 case wxTOP:
305 eff = wxSHOW_EFFECT_ROLL_TO_TOP;
306 break;
307 case wxBOTTOM:
308 eff = wxSHOW_EFFECT_ROLL_TO_BOTTOM;
309 break;
310 default:
311 wxFAIL_MSG( "invalid direction" );
312 return;
313 }
314 break;
315 case Show_Effect_Slide:
316 switch ( direction )
317 {
318 case wxLEFT:
319 eff = wxSHOW_EFFECT_SLIDE_TO_LEFT;
320 break;
321 case wxRIGHT:
322 eff = wxSHOW_EFFECT_SLIDE_TO_RIGHT;
323 break;
324 case wxTOP:
325 eff = wxSHOW_EFFECT_SLIDE_TO_TOP;
326 break;
327 case wxBOTTOM:
328 eff = wxSHOW_EFFECT_SLIDE_TO_BOTTOM;
329 break;
330 default:
331 wxFAIL_MSG( "invalid direction" );
332 return;
333 }
334 break;
335
336 case Show_Effect_Blend:
337 eff = wxSHOW_EFFECT_BLEND;
338 break;
339
340 case Show_Effect_Expand:
341 eff = wxSHOW_EFFECT_EXPAND;
342 break;
343
344 default:
345 wxFAIL_MSG( "invalid effect" );
346 return;
347 }
348
349 new EffectFrame(this, eff,1000);
350 }
351
352 // ----------------------------------------------------------------------------
353 // shaped frame
354 // ----------------------------------------------------------------------------
355
356 BEGIN_EVENT_TABLE(ShapedFrame, wxFrame)
357 EVT_LEFT_DCLICK(ShapedFrame::OnDoubleClick)
358 EVT_LEFT_DOWN(ShapedFrame::OnLeftDown)
359 EVT_LEFT_UP(ShapedFrame::OnLeftUp)
360 EVT_MOTION(ShapedFrame::OnMouseMove)
361 EVT_RIGHT_UP(ShapedFrame::OnExit)
362 EVT_PAINT(ShapedFrame::OnPaint)
363 END_EVENT_TABLE()
364
365
366 // frame constructor
367 ShapedFrame::ShapedFrame(wxFrame *parent)
368 : wxFrame(parent, wxID_ANY, wxEmptyString,
369 wxDefaultPosition, wxSize(100, 100),
370 0
371 | wxFRAME_SHAPED
372 | wxSIMPLE_BORDER
373 | wxFRAME_NO_TASKBAR
374 | wxSTAY_ON_TOP
375 )
376 {
377 m_hasShape = false;
378 m_bmp = wxBitmap(_T("star.png"), wxBITMAP_TYPE_PNG);
379 SetSize(wxSize(m_bmp.GetWidth(), m_bmp.GetHeight()));
380 SetToolTip(wxT("Right-click to close"));
381 SetWindowShape();
382 }
383
384 void ShapedFrame::SetWindowShape()
385 {
386 wxRegion region(m_bmp, *wxWHITE);
387 m_hasShape = SetShape(region);
388 }
389
390 void ShapedFrame::OnDoubleClick(wxMouseEvent& WXUNUSED(evt))
391 {
392 if (m_hasShape)
393 {
394 wxRegion region;
395 SetShape(region);
396 m_hasShape = false;
397 }
398 else
399 SetWindowShape();
400 }
401
402 void ShapedFrame::OnLeftDown(wxMouseEvent& evt)
403 {
404 CaptureMouse();
405 wxPoint pos = ClientToScreen(evt.GetPosition());
406 wxPoint origin = GetPosition();
407 int dx = pos.x - origin.x;
408 int dy = pos.y - origin.y;
409 m_delta = wxPoint(dx, dy);
410 }
411
412 void ShapedFrame::OnLeftUp(wxMouseEvent& WXUNUSED(evt))
413 {
414 if (HasCapture())
415 {
416 ReleaseMouse();
417 }
418 }
419
420 void ShapedFrame::OnMouseMove(wxMouseEvent& evt)
421 {
422 wxPoint pt = evt.GetPosition();
423 if (evt.Dragging() && evt.LeftIsDown())
424 {
425 wxPoint pos = ClientToScreen(pt);
426 Move(wxPoint(pos.x - m_delta.x, pos.y - m_delta.y));
427 }
428 }
429
430 void ShapedFrame::OnExit(wxMouseEvent& WXUNUSED(evt))
431 {
432 Close();
433 }
434
435 void ShapedFrame::OnPaint(wxPaintEvent& WXUNUSED(evt))
436 {
437 wxPaintDC dc(this);
438 dc.DrawBitmap(m_bmp, 0, 0, true);
439 }
440
441 // ----------------------------------------------------------------------------
442 // see-through frame
443 // ----------------------------------------------------------------------------
444
445 BEGIN_EVENT_TABLE(SeeThroughFrame, wxFrame)
446 EVT_LEFT_DCLICK(SeeThroughFrame::OnDoubleClick)
447 EVT_PAINT(SeeThroughFrame::OnPaint)
448 END_EVENT_TABLE()
449
450 SeeThroughFrame::SeeThroughFrame()
451 : wxFrame(NULL, wxID_ANY, "Transparency test: double click here",
452 wxPoint(100, 30), wxSize(300, 300),
453 wxDEFAULT_FRAME_STYLE |
454 wxFULL_REPAINT_ON_RESIZE |
455 wxSTAY_ON_TOP),
456 m_currentState(STATE_SEETHROUGH)
457 {
458 SetBackgroundColour(wxColour(255, 255, 255, 255));
459 SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
460 }
461
462 // Paints a grid of varying hue and alpha
463 void SeeThroughFrame::OnPaint(wxPaintEvent& WXUNUSED(evt))
464 {
465 wxPaintDC dc(this);
466 dc.SetPen(wxNullPen);
467
468 int xcount = 8;
469 int ycount = 8;
470
471 float xstep = 1. / xcount;
472 float ystep = 1. / ycount;
473
474 int width = GetClientSize().GetWidth();
475 int height = GetClientSize().GetHeight();
476
477 for ( float x = 0.; x < 1.; x += xstep )
478 {
479 for ( float y = 0.; y < 1.; y += ystep )
480 {
481 wxImage::RGBValue v = wxImage::HSVtoRGB(wxImage::HSVValue(x, 1., 1.));
482 dc.SetBrush(wxBrush(wxColour(v.red, v.green, v.blue,
483 (int)(255*(1. - y)))));
484 int x1 = (int)(x * width);
485 int y1 = (int)(y * height);
486 int x2 = (int)((x + xstep) * width);
487 int y2 = (int)((y + ystep) * height);
488 dc.DrawRectangle(x1, y1, x2 - x1, y2 - y1);
489 }
490 }
491 }
492
493 // Switches between colour and transparent background on doubleclick
494 void SeeThroughFrame::OnDoubleClick(wxMouseEvent& WXUNUSED(evt))
495 {
496 m_currentState = (State)((m_currentState + 1) % STATE_MAX);
497
498 switch ( m_currentState )
499 {
500 case STATE_OPAQUE:
501 SetBackgroundStyle(wxBG_STYLE_COLOUR);
502 SetTransparent(255);
503 SetTitle("Opaque");
504 break;
505
506 case STATE_SEETHROUGH:
507 SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
508 SetTransparent(255);
509 SetTitle("See through");
510 break;
511
512 case STATE_TRANSPARENT:
513 SetBackgroundStyle(wxBG_STYLE_COLOUR);
514 SetTransparent(128);
515 SetTitle("Semi-transparent");
516 break;
517
518 case STATE_MAX:
519 wxFAIL_MSG( "unreachable" );
520 }
521
522 Refresh();
523 }
524