Fix wrong configure test for abi::__forced_unwind in previous commit.
[wxWidgets.git] / samples / shaped / shaped.cpp
index dee29b4788dfccd2a7aa69e44e5e1bcc7711b1b3..e1e3afc17abff8bfe6f3d382a9ec742721545de9 100644 (file)
 // headers
 // ----------------------------------------------------------------------------
 
-#if defined(__GNUG__) && !defined(__APPLE__)
-    #pragma implementation "shaped.cpp"
-    #pragma interface "shaped.cpp"
-#endif
-
 // For compilers that support precompilation, includes "wx/wx.h".
 #include "wx/wxprec.h"
 
     #include "wx/menu.h"
     #include "wx/layout.h"
     #include "wx/msgdlg.h"
+    #include "wx/image.h"
 #endif
 
 #include "wx/dcclient.h"
+#include "wx/graphics.h"
 #include "wx/image.h"
 
+#ifndef wxHAS_IMAGES_IN_RESOURCES
+    #include "../sample.xpm"
+#endif
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+// menu ids
+enum
+{
+    Show_Shaped = 100,
+    Show_Transparent,
+
+    // must be consecutive and in the same order as wxShowEffect enum elements
+    Show_Effect_First,
+    Show_Effect_Roll = Show_Effect_First,
+    Show_Effect_Slide,
+    Show_Effect_Blend,
+    Show_Effect_Expand,
+    Show_Effect_Last = Show_Effect_Expand
+};
+
 // ----------------------------------------------------------------------------
 // private classes
 // ----------------------------------------------------------------------------
@@ -62,12 +82,28 @@ public:
 };
 
 
-// Define a new frame type: this is going to be our main frame
+// Main frame just contains the menu items invoking the other tests
+class MainFrame : public wxFrame
+{
+public:
+    MainFrame();
+
+private:
+    void OnShowShaped(wxCommandEvent& event);
+    void OnShowTransparent(wxCommandEvent& event);
+    void OnShowEffect(wxCommandEvent& event);
+    void OnExit(wxCommandEvent& event);
+
+    DECLARE_EVENT_TABLE()
+};
+
+// 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)
@@ -77,46 +113,113 @@ public:
     void OnMouseMove(wxMouseEvent& evt);
     void OnExit(wxMouseEvent& evt);
     void OnPaint(wxPaintEvent& evt);
-    void OnWindowCreate(wxWindowCreateEvent& evt);
 
 private:
-    bool     m_hasShape;
+    enum ShapeKind
+    {
+        Shape_None,
+        Shape_Star,
+#if wxUSE_GRAPHICS_CONTEXT
+        Shape_Circle,
+#endif // wxUSE_GRAPHICS_CONTEXT
+        Shape_Max
+    } m_shapeKind;
+
     wxBitmap m_bmp;
     wxPoint  m_delta;
 
-    // any class wishing to process wxWindows events must use this macro
+    // any class wishing to process wxWidgets events must use this macro
     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 tables and other macros for wxWindows
-// ----------------------------------------------------------------------------
+    // event handlers (these functions should _not_ be virtual)
+    void OnDoubleClick(wxMouseEvent& evt);
+    void OnPaint(wxPaintEvent& evt);
 
-// the event tables connect the wxWindows events with the functions (event
-// handlers) which process them. It can be also done at run-time, but for the
-// simple menu events like this the static method is much simpler.
-BEGIN_EVENT_TABLE(ShapedFrame, wxFrame)
-    EVT_LEFT_DCLICK(ShapedFrame::OnDoubleClick)
-    EVT_LEFT_DOWN(ShapedFrame::OnLeftDown)
-    EVT_LEFT_UP(ShapedFrame::OnLeftUp)
-    EVT_MOTION(ShapedFrame::OnMouseMove)
-    EVT_RIGHT_UP(ShapedFrame::OnExit)
+private:
+    enum State
+    {
+        STATE_SEETHROUGH,
+        STATE_TRANSPARENT,
+        STATE_OPAQUE,
+        STATE_MAX
+    };
 
-    EVT_PAINT(ShapedFrame::OnPaint)
+    State m_currentState;
 
-#ifdef __WXGTK__
-    EVT_WINDOW_CREATE(ShapedFrame::OnWindowCreate)
-#endif
-END_EVENT_TABLE()
+    // any class wishing to process wxWidgets events must use this macro
+    DECLARE_EVENT_TABLE()
+};
+
+class EffectFrame : public wxFrame
+{
+public:
+    EffectFrame(wxWindow *parent,
+                wxShowEffect effect,
+                // TODO: add menu command to the main frame to allow changing
+                //       these parameters
+                unsigned timeout = 1000)
+        : wxFrame(parent, wxID_ANY,
+                  wxString::Format("Frame shown with %s effect",
+                                   GetEffectName(effect)),
+                  wxDefaultPosition, wxSize(450, 300)),
+          m_effect(effect),
+          m_timeout(timeout)
+    {
+        new wxStaticText(this, wxID_ANY,
+                         wxString::Format("Effect: %s", GetEffectName(effect)),
+                         wxPoint(20, 20));
+        new wxStaticText(this, wxID_ANY,
+                         wxString::Format("Timeout: %ums", m_timeout),
+                         wxPoint(20, 60));
 
+        ShowWithEffect(m_effect, m_timeout);
 
-// Create a new application object: this macro will allow wxWindows to create
-// the application object during program execution (it's better than using a
-// static object for many reasons) and also declares the accessor function
-// wxGetApp() which will return the reference of the right type (i.e. MyApp and
-// not wxApp)
-IMPLEMENT_APP(MyApp)
+        Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(EffectFrame::OnClose));
+    }
+
+private:
+    static const char *GetEffectName(wxShowEffect effect)
+    {
+        static const char *names[] =
+        {
+            "none",
+            "roll to left",
+            "roll to right",
+            "roll to top",
+            "roll to bottom",
+            "slide to left",
+            "slide to right",
+            "slide to top",
+            "slide to bottom",
+            "fade",
+            "expand",
+        };
+        wxCOMPILE_TIME_ASSERT( WXSIZEOF(names) == wxSHOW_EFFECT_MAX,
+                                EffectNamesMismatch );
+
+        return names[effect];
+    }
+
+    void OnClose(wxCloseEvent& event)
+    {
+        HideWithEffect(m_effect, m_timeout);
+
+        event.Skip();
+    }
+
+    wxShowEffect m_effect;
+    unsigned m_timeout;
+};
 
 // ============================================================================
 // implementation
@@ -126,61 +229,209 @@ IMPLEMENT_APP(MyApp)
 // the application class
 // ----------------------------------------------------------------------------
 
+IMPLEMENT_APP(MyApp)
+
 // `Main program' equivalent: the program execution "starts" here
 bool MyApp::OnInit()
 {
+    if ( !wxApp::OnInit() )
+        return false;
+
     wxInitAllImageHandlers();
 
-    // Create the main application window
-    ShapedFrame *frame = new ShapedFrame();
-    frame->Show(TRUE);
+    new MainFrame;
 
     // success: wxApp::OnRun() will be called which will enter the main message
-    // loop and the application will run. If we returned FALSE here, the
+    // loop and the application will run. If we returned false here, the
     // application would exit immediately.
-    return TRUE;
+    return true;
 }
 
 // ----------------------------------------------------------------------------
 // main frame
 // ----------------------------------------------------------------------------
 
+BEGIN_EVENT_TABLE(MainFrame, wxFrame)
+    EVT_MENU(Show_Shaped, MainFrame::OnShowShaped)
+    EVT_MENU(Show_Transparent, MainFrame::OnShowTransparent)
+    EVT_MENU_RANGE(Show_Effect_First, Show_Effect_Last, MainFrame::OnShowEffect)
+    EVT_MENU(wxID_EXIT, MainFrame::OnExit)
+END_EVENT_TABLE()
+
+MainFrame::MainFrame()
+         : wxFrame(NULL, wxID_ANY, "wxWidgets Shaped Sample",
+                   wxDefaultPosition, wxSize(200, 100))
+{
+    SetIcon(wxICON(sample));
+
+    wxMenuBar * const mbar = new wxMenuBar;
+    wxMenu * const menuFrames = new wxMenu;
+    menuFrames->Append(Show_Shaped, "Show &shaped window\tCtrl-S");
+    menuFrames->Append(Show_Transparent, "Show &transparent window\tCtrl-T");
+    menuFrames->AppendSeparator();
+    menuFrames->Append(Show_Effect_Roll, "Show &rolled effect\tCtrl-R");
+    menuFrames->Append(Show_Effect_Slide, "Show s&lide effect\tCtrl-L");
+    menuFrames->Append(Show_Effect_Blend, "Show &fade effect\tCtrl-F");
+    menuFrames->Append(Show_Effect_Expand, "Show &expand effect\tCtrl-E");
+    menuFrames->AppendSeparator();
+    menuFrames->Append(wxID_EXIT, "E&xit");
+
+    mbar->Append(menuFrames, "&Show");
+    SetMenuBar(mbar);
+
+    Show();
+}
+
+void MainFrame::OnShowShaped(wxCommandEvent& WXUNUSED(event))
+{
+    ShapedFrame *shapedFrame = new ShapedFrame(this);
+    shapedFrame->Show(true);
+}
+
+void MainFrame::OnShowTransparent(wxCommandEvent& WXUNUSED(event))
+{
+    SeeThroughFrame *seeThroughFrame = new SeeThroughFrame();
+    seeThroughFrame->Show(true);
+}
+
+void MainFrame::OnShowEffect(wxCommandEvent& event)
+{
+    int effect = event.GetId();
+    static wxDirection direction = wxLEFT;
+    direction = (wxDirection)(((int)direction)<< 1);
+    if ( direction > wxDOWN )
+        direction = wxLEFT ;
+
+    wxShowEffect eff;
+    switch ( effect )
+    {
+        case Show_Effect_Roll:
+            switch ( direction )
+            {
+                case wxLEFT:
+                    eff = wxSHOW_EFFECT_ROLL_TO_LEFT;
+                    break;
+                case wxRIGHT:
+                    eff = wxSHOW_EFFECT_ROLL_TO_RIGHT;
+                    break;
+                case wxTOP:
+                    eff = wxSHOW_EFFECT_ROLL_TO_TOP;
+                    break;
+                case wxBOTTOM:
+                    eff = wxSHOW_EFFECT_ROLL_TO_BOTTOM;
+                    break;
+                default:
+                    wxFAIL_MSG( "invalid direction" );
+                    return;
+            }
+            break;
+        case Show_Effect_Slide:
+            switch ( direction )
+            {
+                case wxLEFT:
+                    eff = wxSHOW_EFFECT_SLIDE_TO_LEFT;
+                    break;
+                case wxRIGHT:
+                    eff = wxSHOW_EFFECT_SLIDE_TO_RIGHT;
+                    break;
+                case wxTOP:
+                    eff = wxSHOW_EFFECT_SLIDE_TO_TOP;
+                    break;
+                case wxBOTTOM:
+                    eff = wxSHOW_EFFECT_SLIDE_TO_BOTTOM;
+                    break;
+                default:
+                    wxFAIL_MSG( "invalid direction" );
+                    return;
+            }
+            break;
+
+        case Show_Effect_Blend:
+            eff = wxSHOW_EFFECT_BLEND;
+            break;
+
+        case Show_Effect_Expand:
+            eff = wxSHOW_EFFECT_EXPAND;
+            break;
+
+        default:
+            wxFAIL_MSG( "invalid effect" );
+            return;
+    }
+
+    new EffectFrame(this,  eff, 1000);
+}
+
+void MainFrame::OnExit(wxCommandEvent& WXUNUSED(event))
+{
+    Close();
+}
+
+// ----------------------------------------------------------------------------
+// shaped frame
+// ----------------------------------------------------------------------------
+
+BEGIN_EVENT_TABLE(ShapedFrame, wxFrame)
+    EVT_LEFT_DCLICK(ShapedFrame::OnDoubleClick)
+    EVT_LEFT_DOWN(ShapedFrame::OnLeftDown)
+    EVT_LEFT_UP(ShapedFrame::OnLeftUp)
+    EVT_MOTION(ShapedFrame::OnMouseMove)
+    EVT_RIGHT_UP(ShapedFrame::OnExit)
+    EVT_PAINT(ShapedFrame::OnPaint)
+END_EVENT_TABLE()
+
+
 // frame constructor
-ShapedFrame::ShapedFrame()
-       : wxFrame((wxFrame *)NULL, -1, wxEmptyString,
-                 wxDefaultPosition, wxDefaultSize,
-                 wxSIMPLE_BORDER | wxFRAME_NO_TASKBAR)
+ShapedFrame::ShapedFrame(wxFrame *parent)
+       : wxFrame(parent, wxID_ANY, wxEmptyString,
+                  wxDefaultPosition, wxSize(100, 100),
+                  0
+                  | wxFRAME_SHAPED
+                  | wxSIMPLE_BORDER
+                  | wxFRAME_NO_TASKBAR
+                  | wxSTAY_ON_TOP
+            )
 {
-    m_hasShape = FALSE;
-    m_bmp = wxBitmap("star.png", wxBITMAP_TYPE_PNG);
+    m_shapeKind = Shape_None;
+    m_bmp = wxBitmap(wxT("star.png"), wxBITMAP_TYPE_PNG);
     SetSize(wxSize(m_bmp.GetWidth(), m_bmp.GetHeight()));
-#if wxUSE_TOOLTIP
-    SetToolTip(wxT("Right-click to exit"));
-#endif
-#ifdef __WXMSW__
-    // On wxGTK we can't do this yet because the window hasn't been created
-    // yet so we wait until the EVT_WINDOW_CREATE event happens.  On wxMSW it
-    // has been created so we set the shape now.
+    SetToolTip(wxT("Right-click to close, double click to cycle shape"));
     SetWindowShape();
-#endif
 }
 
 void ShapedFrame::SetWindowShape()
 {
-    wxRegion region(m_bmp, *wxWHITE);
-    m_hasShape = SetShape(region);
+    switch ( m_shapeKind )
+    {
+        case Shape_None:
+            SetShape(wxRegion());
+            break;
+
+        case Shape_Star:
+            SetShape(wxRegion(m_bmp, *wxWHITE));
+            break;
+
+#if wxUSE_GRAPHICS_CONTEXT
+        case Shape_Circle:
+            {
+                wxGraphicsPath
+                    path = wxGraphicsRenderer::GetDefaultRenderer()->CreatePath();
+                path.AddCircle(m_bmp.GetWidth()/2, m_bmp.GetHeight()/2, 30);
+                SetShape(path);
+            }
+            break;
+#endif // wxUSE_GRAPHICS_CONTEXT
+
+        case Shape_Max:
+            wxFAIL_MSG( "invalid shape kind" );
+            break;
+    }
 }
 
-void ShapedFrame::OnDoubleClick(wxMouseEvent& evt)
+void ShapedFrame::OnDoubleClick(wxMouseEvent& WXUNUSED(evt))
 {
-    if (m_hasShape)
-    {
-        wxRegion region;
-        SetShape(region);
-        m_hasShape = FALSE;
-    }
-    else
-        SetWindowShape();
+    m_shapeKind = static_cast<ShapeKind>((m_shapeKind + 1) % Shape_Max);
+    SetWindowShape();
 }
 
 void ShapedFrame::OnLeftDown(wxMouseEvent& evt)
@@ -193,34 +444,116 @@ void ShapedFrame::OnLeftDown(wxMouseEvent& evt)
     m_delta = wxPoint(dx, dy);
 }
 
-void ShapedFrame::OnLeftUp(wxMouseEvent& evt)
+void ShapedFrame::OnLeftUp(wxMouseEvent& WXUNUSED(evt))
 {
     if (HasCapture())
+    {
         ReleaseMouse();
+    }
 }
 
 void ShapedFrame::OnMouseMove(wxMouseEvent& evt)
 {
+    wxPoint pt = evt.GetPosition();
     if (evt.Dragging() && evt.LeftIsDown())
     {
-        wxPoint pos = ClientToScreen(evt.GetPosition());
+        wxPoint pos = ClientToScreen(pt);
         Move(wxPoint(pos.x - m_delta.x, pos.y - m_delta.y));
     }
 }
 
-void ShapedFrame::OnExit(wxMouseEvent& evt)
+void ShapedFrame::OnExit(wxMouseEvent& WXUNUSED(evt))
 {
     Close();
 }
 
-void ShapedFrame::OnPaint(wxPaintEvent& evt)
+void ShapedFrame::OnPaint(wxPaintEvent& WXUNUSED(evt))
 {
     wxPaintDC dc(this);
-    dc.DrawBitmap(m_bmp, 0, 0, TRUE);
+    dc.DrawBitmap(m_bmp, 0, 0, true);
 }
 
-void ShapedFrame::OnWindowCreate(wxWindowCreateEvent& evt)
+// ----------------------------------------------------------------------------
+// see-through frame
+// ----------------------------------------------------------------------------
+
+BEGIN_EVENT_TABLE(SeeThroughFrame, wxFrame)
+    EVT_LEFT_DCLICK(SeeThroughFrame::OnDoubleClick)
+    EVT_PAINT(SeeThroughFrame::OnPaint)
+END_EVENT_TABLE()
+
+SeeThroughFrame::SeeThroughFrame()
+       : wxFrame(NULL, wxID_ANY, "Transparency test: double click here",
+                  wxPoint(100, 30), wxSize(300, 300),
+                  wxDEFAULT_FRAME_STYLE |
+                  wxFULL_REPAINT_ON_RESIZE |
+                  wxSTAY_ON_TOP),
+         m_currentState(STATE_SEETHROUGH)
 {
-    SetWindowShape();
+    SetBackgroundColour(wxColour(255, 255, 255, 255));
+    SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
+}
+
+// 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();
 }