]> git.saurik.com Git - wxWidgets.git/blame - src/osx/cocoa/preferences.mm
Fit modeless preferences dialog to its contents too.
[wxWidgets.git] / src / osx / cocoa / preferences.mm
CommitLineData
2aab96f5
VS
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
41wxBitmap 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
54class wxCocoaPrefsWindow : public wxFrame
55{
56public:
654c4b7b
VZ
57 wxCocoaPrefsWindow(const wxString& title)
58 : wxFrame(NULL, wxID_ANY, title,
2aab96f5
VS
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
ce7fe42e 70 m_toolbar->Bind(wxEVT_TOOL,
2aab96f5
VS
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
111protected:
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
122private:
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
174private:
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
191class wxCocoaPreferencesEditorImpl : public wxPreferencesEditorImpl
192{
193public:
654c4b7b
VZ
194 wxCocoaPreferencesEditorImpl(const wxString& title)
195 : m_win(NULL), m_title(title)
2aab96f5
VS
196 {
197 }
198
199 virtual ~wxCocoaPreferencesEditorImpl()
200 {
201 // m_win may already be destroyed if this destructor is called from
202 // wxApp's destructor. In that case, all windows -- including this
203 // one -- would already be destroyed by now.
204 if ( m_win )
205 m_win->Destroy();
206 }
207
208 virtual void AddPage(wxPreferencesPage* page)
209 {
210 GetWin()->AddPage(page);
211 }
212
213 virtual void Show(wxWindow* WXUNUSED(parent))
214 {
215 // OS X preferences windows don't have parents, they are independent
216 // windows, so we just ignore the 'parent' argument.
217 wxWindow *win = GetWin();
218 win->Show();
219 win->Raise();
220 }
221
222 virtual void Dismiss()
223 {
224 // Don't destroy the window, only hide it, because OS X preferences
225 // window typically remember their state even when closed. Reopening
226 // the window should show it in the exact same state the user left it.
227 GetWin()->Hide();
228 }
229
230private:
231 // Use this function to access m_win, so that the window is only created on
232 // demand when actually needed.
233 wxCocoaPrefsWindow* GetWin()
234 {
235 if ( !m_win )
654c4b7b
VZ
236 {
237 if ( m_title.empty() )
238 m_title = _("Preferences");
239
240 m_win = new wxCocoaPrefsWindow(m_title);
241 }
242
2aab96f5
VS
243 return m_win;
244 }
245
246 wxWeakRef<wxCocoaPrefsWindow> m_win;
654c4b7b
VZ
247
248 wxString m_title;
2aab96f5
VS
249};
250
251/*static*/
654c4b7b 252wxPreferencesEditorImpl* wxPreferencesEditorImpl::Create(const wxString& title)
2aab96f5 253{
654c4b7b 254 return new wxCocoaPreferencesEditorImpl(title);
2aab96f5
VS
255}
256
257#endif // wxHAS_PREF_EDITOR_NATIVE