1 ///////////////////////////////////////////////////////////////////////////////
 
   2 // Name:        src/osx/cocoa/preferences.cpp
 
   3 // Purpose:     Native OS X implementation of wxPreferencesEditor.
 
   4 // Author:      Vaclav Slavik
 
   6 // Copyright:   (c) 2013 Vaclav Slavik <vslavik@fastmail.fm>
 
   7 // Licence:     wxWindows licence
 
   8 ///////////////////////////////////////////////////////////////////////////////
 
  10 // ============================================================================
 
  12 // ============================================================================
 
  14 // ----------------------------------------------------------------------------
 
  16 // ----------------------------------------------------------------------------
 
  18 // for compilers that support precompilation, includes "wx.h".
 
  19 #include "wx/wxprec.h"
 
  25 #if wxUSE_PREFERENCES_EDITOR
 
  27 #include "wx/private/preferences.h"
 
  29 #ifdef wxHAS_PREF_EDITOR_NATIVE
 
  32 #include "wx/sharedptr.h"
 
  33 #include "wx/toolbar.h"
 
  34 #include "wx/vector.h"
 
  35 #include "wx/weakref.h"
 
  36 #include "wx/windowid.h"
 
  37 #include "wx/osx/private.h"
 
  39 #import <AppKit/NSWindow.h>
 
  42 wxBitmap wxStockPreferencesPage::GetLargeIcon() const
 
  47             return wxBitmap([NSImage imageNamed:NSImageNamePreferencesGeneral]);
 
  49             return wxBitmap([NSImage imageNamed:NSImageNameAdvanced]);
 
  51     return wxBitmap(); // silence compiler warning
 
  55 class wxCocoaPrefsWindow : public wxFrame
 
  58     wxCocoaPrefsWindow(const wxString& title)
 
  59         : wxFrame(NULL, wxID_ANY, title,
 
  60                   wxDefaultPosition, wxDefaultSize,
 
  61                   wxDEFAULT_FRAME_STYLE & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX)),
 
  62           m_toolbarRealized(false),
 
  65         m_toolbar = new wxToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
 
  66                                   wxTB_FLAT | wxTB_TEXT);
 
  67         m_toolbar->SetToolBitmapSize(wxSize(32,32));
 
  68         m_toolbar->OSXSetSelectableTools(true);
 
  69         SetToolBar(m_toolbar);
 
  71         m_toolbar->Bind(wxEVT_TOOL,
 
  72                         &wxCocoaPrefsWindow::OnPageChanged, this);
 
  73         Bind(wxEVT_CLOSE_WINDOW, &wxCocoaPrefsWindow::OnClose, this);
 
  76     void AddPage(wxPreferencesPage *page)
 
  78         wxASSERT_MSG( !m_toolbarRealized,
 
  79                       "can't add more preferences pages after showing the window" );
 
  81         const wxString title = page->GetName();
 
  82         wxBitmap bmp(page->GetLargeIcon());
 
  83         wxASSERT_MSG( bmp.IsOk(), "OS X requires valid bitmap for preference page" );
 
  85         int toolId = wxIdManager::ReserveId();
 
  86         wxToolBarToolBase *tool = m_toolbar->AddTool(toolId, title, bmp);
 
  88         wxSharedPtr<PageInfo> info(new PageInfo(page));
 
  89         m_pages.push_back(info);
 
  91         tool->SetClientData(info.get());
 
  94     virtual bool Show(bool show)
 
  96         if ( show && !m_toolbarRealized )
 
  99             m_toolbarRealized = true;
 
 101             const wxToolBarToolBase *first = m_toolbar->GetToolByPos(0);
 
 102             wxCHECK_MSG( first, false, "no preferences panels" );
 
 103             OnSelectPageForTool(first);
 
 104             m_toolbar->OSXSelectTool(first->GetId());
 
 107         return wxFrame::Show(show);
 
 110     virtual bool ShouldPreventAppExit() const { return false; }
 
 113     // Native preferences windows resize when the selected panel changes and
 
 114     // the resizing is animated, so we need to override DoMoveWindow.
 
 115     virtual void DoMoveWindow(int x, int y, int width, int height)
 
 117         NSRect r = wxToNSRect(NULL, wxRect(x, y, width, height));
 
 118         NSWindow *win = (NSWindow*)GetWXWindow();
 
 119         [win setFrame:r display:YES animate:YES];
 
 124     void OnSelectPageForTool(const wxToolBarToolBase *tool)
 
 126         PageInfo *info = static_cast<PageInfo*>(tool->GetClientData());
 
 127         wxCHECK_RET( info, "toolbar item lacks client data" );
 
 131             info->win = info->page->CreateWindow(this);
 
 134             // fill the page with data using wxEVT_INIT_DIALOG/TransferDataToWindow:
 
 135             info->win->InitDialog();
 
 138         // When the page changes in a native preferences dialog, the sequence
 
 139         // of events is thus:
 
 141         // 1. the old page is hidden, only gray background remains
 
 143             m_visiblePage->Hide();
 
 144         m_visiblePage = info->win;
 
 146         //   2. window is resized to fix the new page, with animation
 
 147         //      (in our case, using overriden DoMoveWindow())
 
 148         SetClientSize(info->win->GetSize());
 
 150         //   3. new page is shown and the title updated.
 
 152         SetTitle(info->page->GetName());
 
 154         // TODO: Preferences window may have some pages resizeable and some
 
 155         //       non-resizable on OS X; the whole window is or is not resizable
 
 156         //       depending on which page is selected.
 
 158         //       We'll need to add wxPreferencesPage::IsResizable() virtual
 
 159         //       method to implement this.
 
 162     void OnPageChanged(wxCommandEvent& event)
 
 164         wxToolBarToolBase *tool = m_toolbar->FindById(event.GetId());
 
 165         wxCHECK_RET( tool, "invalid tool ID" );
 
 166         OnSelectPageForTool(tool);
 
 169     void OnClose(wxCloseEvent& e)
 
 171         // Instead of destroying the window, just hide it, it could be
 
 172         // reused again by another invocation of the editor.
 
 177     struct PageInfo : public wxObject
 
 179         PageInfo(wxPreferencesPage *p) : page(p), win(NULL) {}
 
 181         wxSharedPtr<wxPreferencesPage> page;
 
 184     // All pages. Use shared pointer to be able to get pointers to PageInfo structs
 
 185     wxVector< wxSharedPtr<PageInfo> > m_pages;
 
 187     wxToolBar *m_toolbar;
 
 188     bool       m_toolbarRealized;
 
 189     wxWindow  *m_visiblePage;
 
 193 class wxCocoaPreferencesEditorImpl : public wxPreferencesEditorImpl
 
 196     wxCocoaPreferencesEditorImpl(const wxString& title)
 
 197         : m_win(NULL), m_title(title)
 
 201     virtual ~wxCocoaPreferencesEditorImpl()
 
 203         // m_win may already be destroyed if this destructor is called from
 
 204         // wxApp's destructor. In that case, all windows -- including this
 
 205         // one -- would already be destroyed by now.
 
 210     virtual void AddPage(wxPreferencesPage* page)
 
 212         GetWin()->AddPage(page);
 
 215     virtual void Show(wxWindow* WXUNUSED(parent))
 
 217         // OS X preferences windows don't have parents, they are independent
 
 218         // windows, so we just ignore the 'parent' argument.
 
 219         wxWindow *win = GetWin();
 
 224     virtual void Dismiss()
 
 226         // Don't destroy the window, only hide it, because OS X preferences
 
 227         // window typically remember their state even when closed. Reopening
 
 228         // the window should show it in the exact same state the user left it.
 
 233     // Use this function to access m_win, so that the window is only created on
 
 234     // demand when actually needed.
 
 235     wxCocoaPrefsWindow* GetWin()
 
 239             if ( m_title.empty() )
 
 240                 m_title = _("Preferences");
 
 242             m_win = new wxCocoaPrefsWindow(m_title);
 
 248     wxWeakRef<wxCocoaPrefsWindow> m_win;
 
 254 wxPreferencesEditorImpl* wxPreferencesEditorImpl::Create(const wxString& title)
 
 256     return new wxCocoaPreferencesEditorImpl(title);
 
 259 #endif // wxHAS_PREF_EDITOR_NATIVE
 
 261 #endif // wxUSE_PREFERENCES_EDITOR