Provide shorter synonyms for wxEVT_XXX constants.
[wxWidgets.git] / src / osx / cocoa / preferences.mm
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/osx/cocoa/preferences.cpp
3 // Purpose:     Native OS X implementation of wxPreferencesEditor.
4 // Author:      Vaclav Slavik
5 // Created:     2013-02-19
6 // RCS-ID:      $Id$
7 // Copyright:   (c) 2013 Vaclav Slavik <vslavik@fastmail.fm>
8 // Licence:     wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23     #pragma hdrstop
24 #endif
25
26 #include "wx/private/preferences.h"
27
28 #ifdef wxHAS_PREF_EDITOR_NATIVE
29
30 #include "wx/frame.h"
31 #include "wx/sharedptr.h"
32 #include "wx/toolbar.h"
33 #include "wx/vector.h"
34 #include "wx/weakref.h"
35 #include "wx/windowid.h"
36 #include "wx/osx/private.h"
37
38 #import <AppKit/NSWindow.h>
39
40
41 wxBitmap wxStockPreferencesPage::GetLargeIcon() const
42 {
43     switch ( m_kind )
44     {
45         case Kind_General:
46             return wxBitmap([NSImage imageNamed:NSImageNamePreferencesGeneral]);
47         case Kind_Advanced:
48             return wxBitmap([NSImage imageNamed:NSImageNameAdvanced]);
49     }
50     return wxBitmap(); // silence compiler warning
51 }
52
53
54 class wxCocoaPrefsWindow : public wxFrame
55 {
56 public:
57     wxCocoaPrefsWindow()
58         : wxFrame(NULL, wxID_ANY, _("Preferences"),
59                   wxDefaultPosition, wxDefaultSize,
60                   wxDEFAULT_FRAME_STYLE & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX)),
61           m_toolbarRealized(false),
62           m_visiblePage(NULL)
63     {
64         m_toolbar = new wxToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
65                                   wxTB_FLAT | wxTB_TEXT);
66         m_toolbar->SetToolBitmapSize(wxSize(32,32));
67         m_toolbar->OSXSetSelectableTools(true);
68         SetToolBar(m_toolbar);
69
70         m_toolbar->Bind(wxEVT_TOOL,
71                         &wxCocoaPrefsWindow::OnPageChanged, this);
72         Bind(wxEVT_CLOSE_WINDOW, &wxCocoaPrefsWindow::OnClose, this);
73     }
74
75     void AddPage(wxPreferencesPage *page)
76     {
77         wxASSERT_MSG( !m_toolbarRealized,
78                       "can't add more preferences pages after showing the window" );
79
80         const wxString title = page->GetName();
81         wxBitmap bmp(page->GetLargeIcon());
82         wxASSERT_MSG( bmp.IsOk(), "OS X requires valid bitmap for preference page" );
83
84         int toolId = wxIdManager::ReserveId();
85         wxToolBarToolBase *tool = m_toolbar->AddTool(toolId, title, bmp);
86
87         wxSharedPtr<PageInfo> info(new PageInfo(page));
88         m_pages.push_back(info);
89
90         tool->SetClientData(info.get());
91     }
92
93     virtual bool Show(bool show)
94     {
95         if ( show && !m_toolbarRealized )
96         {
97             m_toolbar->Realize();
98             m_toolbarRealized = true;
99
100             const wxToolBarToolBase *first = m_toolbar->GetToolByPos(0);
101             wxCHECK_MSG( first, false, "no preferences panels" );
102             OnSelectPageForTool(first);
103             m_toolbar->OSXSelectTool(first->GetId());
104         }
105
106         return wxFrame::Show(show);
107     }
108
109     virtual bool ShouldPreventAppExit() const { return false; }
110
111 protected:
112     // Native preferences windows resize when the selected panel changes and
113     // the resizing is animated, so we need to override DoMoveWindow.
114     virtual void DoMoveWindow(int x, int y, int width, int height)
115     {
116         NSRect r = wxToNSRect(NULL, wxRect(x, y, width, height));
117         NSWindow *win = (NSWindow*)GetWXWindow();
118         [win setFrame:r display:YES animate:YES];
119     }
120
121
122 private:
123     void OnSelectPageForTool(const wxToolBarToolBase *tool)
124     {
125         PageInfo *info = static_cast<PageInfo*>(tool->GetClientData());
126         wxCHECK_RET( info, "toolbar item lacks client data" );
127
128         if ( !info->win )
129         {
130             info->win = info->page->CreateWindow(this);
131             info->win->Hide();
132             // fill the page with data using wxEVT_INIT_DIALOG/TransferDataToWindow:
133             info->win->InitDialog();
134         }
135
136         // When the page changes in a native preferences dialog, the sequence
137         // of events is thus:
138
139         // 1. the old page is hidden, only gray background remains
140         if ( m_visiblePage )
141             m_visiblePage->Hide();
142         m_visiblePage = info->win;
143
144         //   2. window is resized to fix the new page, with animation
145         //      (in our case, using overriden DoMoveWindow())
146         SetClientSize(info->win->GetSize());
147
148         //   3. new page is shown and the title updated.
149         info->win->Show();
150         SetTitle(info->page->GetName());
151
152         // TODO: Preferences window may have some pages resizeable and some
153         //       non-resizable on OS X; the whole window is or is not resizable
154         //       depending on which page is selected.
155         //
156         //       We'll need to add wxPreferencesPage::IsResizable() virtual
157         //       method to implement this.
158     }
159
160     void OnPageChanged(wxCommandEvent& event)
161     {
162         wxToolBarToolBase *tool = m_toolbar->FindById(event.GetId());
163         wxCHECK_RET( tool, "invalid tool ID" );
164         OnSelectPageForTool(tool);
165     }
166
167     void OnClose(wxCloseEvent& e)
168     {
169         // Instead of destroying the window, just hide it, it could be
170         // reused again by another invocation of the editor.
171         Hide();
172     }
173
174 private:
175     struct PageInfo : public wxObject
176     {
177         PageInfo(wxPreferencesPage *p) : page(p), win(NULL) {}
178
179         wxSharedPtr<wxPreferencesPage> page;
180         wxWindow *win;
181     };
182     // All pages. Use shared pointer to be able to get pointers to PageInfo structs
183     wxVector< wxSharedPtr<PageInfo> > m_pages;
184
185     wxToolBar *m_toolbar;
186     bool       m_toolbarRealized;
187     wxWindow  *m_visiblePage;
188 };
189
190
191 class wxCocoaPreferencesEditorImpl : public wxPreferencesEditorImpl
192 {
193 public:
194     wxCocoaPreferencesEditorImpl() : m_win(NULL)
195     {
196     }
197
198     virtual ~wxCocoaPreferencesEditorImpl()
199     {
200         // m_win may already be destroyed if this destructor is called from
201         // wxApp's destructor. In that case, all windows -- including this
202         // one -- would already be destroyed by now.
203         if ( m_win )
204             m_win->Destroy();
205     }
206
207     virtual void AddPage(wxPreferencesPage* page)
208     {
209         GetWin()->AddPage(page);
210     }
211
212     virtual void Show(wxWindow* WXUNUSED(parent))
213     {
214         // OS X preferences windows don't have parents, they are independent
215         // windows, so we just ignore the 'parent' argument.
216         wxWindow *win = GetWin();
217         win->Show();
218         win->Raise();
219     }
220
221     virtual void Dismiss()
222     {
223         // Don't destroy the window, only hide it, because OS X preferences
224         // window typically remember their state even when closed. Reopening
225         // the window should show it in the exact same state the user left it.
226         GetWin()->Hide();
227     }
228
229 private:
230     // Use this function to access m_win, so that the window is only created on
231     // demand when actually needed.
232     wxCocoaPrefsWindow* GetWin()
233     {
234         if ( !m_win )
235             m_win = new wxCocoaPrefsWindow();
236         return m_win;
237     }
238
239     wxWeakRef<wxCocoaPrefsWindow> m_win;
240 };
241
242 /*static*/
243 wxPreferencesEditorImpl* wxPreferencesEditorImpl::Create()
244 {
245     return new wxCocoaPreferencesEditorImpl();
246 }
247
248 #endif // wxHAS_PREF_EDITOR_NATIVE