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