///////////////////////////////////////////////////////////////////////////// // Name: src/propgrid/manager.cpp // Purpose: wxPropertyGridManager // Author: Jaakko Salli // Modified by: // Created: 2005-01-14 // Copyright: (c) Jaakko Salli // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #if wxUSE_PROPGRID #ifndef WX_PRECOMP #include "wx/settings.h" #include "wx/stattext.h" #include "wx/textctrl.h" #include "wx/toolbar.h" #endif #include "wx/dcbuffer.h" // for wxALWAYS_NATIVE_DOUBLE_BUFFER #include "wx/headerctrl.h" // for wxPGHeaderCtrl // This define is necessary to prevent macro clearing #define __wxPG_SOURCE_FILE__ #include "wx/propgrid/manager.h" #define wxPG_MAN_ALTERNATE_BASE_ID 11249 // Needed for wxID_ANY madness // ----------------------------------------------------------------------- // For wxMSW cursor consistency, we must do mouse capturing even // when using custom controls #define BEGIN_MOUSE_CAPTURE \ if ( !(m_iFlags & wxPG_FL_MOUSE_CAPTURED) ) \ { \ CaptureMouse(); \ m_iFlags |= wxPG_FL_MOUSE_CAPTURED; \ } #define END_MOUSE_CAPTURE \ if ( m_iFlags & wxPG_FL_MOUSE_CAPTURED ) \ { \ ReleaseMouse(); \ m_iFlags &= ~(wxPG_FL_MOUSE_CAPTURED); \ } // ----------------------------------------------------------------------- // wxPropertyGridManager // ----------------------------------------------------------------------- const char wxPropertyGridManagerNameStr[] = "wxPropertyGridManager"; // Categoric Mode Icon static const char* const gs_xpm_catmode[] = { "16 16 5 1", ". c none", "B c black", "D c #868686", "L c #CACACA", "W c #FFFFFF", ".DDD............", ".DLD.BBBBBB.....", ".DDD............", ".....DDDDD.DDD..", "................", ".....DDDDD.DDD..", "................", ".....DDDDD.DDD..", "................", ".....DDDDD.DDD..", "................", ".DDD............", ".DLD.BBBBBB.....", ".DDD............", ".....DDDDD.DDD..", "................" }; // Alphabetic Mode Icon static const char* const gs_xpm_noncatmode[] = { "16 16 5 1", ". c none", "B c black", "D c #868686", "L c #000080", "W c #FFFFFF", "..DBD...DDD.DDD.", ".DB.BD..........", ".BBBBB..DDD.DDD.", ".B...B..........", "...L....DDD.DDD.", "...L............", ".L.L.L..DDD.DDD.", "..LLL...........", "...L....DDD.DDD.", "................", ".BBBBB..DDD.DDD.", "....BD..........", "...BD...DDD.DDD.", "..BD............", ".BBBBB..DDD.DDD.", "................" }; // Default Page Icon. static const char* const gs_xpm_defpage[] = { "16 16 5 1", ". c none", "B c black", "D c #868686", "L c #000080", "W c #FFFFFF", "................", "................", "..BBBBBBBBBBBB..", "..B..........B..", "..B.BB.LLLLL.B..", "..B..........B..", "..B.BB.LLLLL.B..", "..B..........B..", "..B.BB.LLLLL.B..", "..B..........B..", "..B.BB.LLLLL.B..", "..B..........B..", "..BBBBBBBBBBBB..", "................", "................", "................" }; // ----------------------------------------------------------------------- // wxPropertyGridPage // ----------------------------------------------------------------------- wxIMPLEMENT_CLASS(wxPropertyGridPage, wxEvtHandler); wxBEGIN_EVENT_TABLE(wxPropertyGridPage, wxEvtHandler) wxEND_EVENT_TABLE() wxPropertyGridPage::wxPropertyGridPage() : wxEvtHandler(), wxPropertyGridInterface(), wxPropertyGridPageState() { m_pState = this; // wxPropertyGridInterface to point to State m_manager = NULL; m_isDefault = false; } wxPropertyGridPage::~wxPropertyGridPage() { } void wxPropertyGridPage::Clear() { GetStatePtr()->DoClear(); } wxSize wxPropertyGridPage::FitColumns() { wxSize sz = DoFitColumns(); return sz; } void wxPropertyGridPage::RefreshProperty( wxPGProperty* p ) { if ( m_manager ) m_manager->RefreshProperty(p); } void wxPropertyGridPage::OnShow() { } void wxPropertyGridPage::SetSplitterPosition( int splitterPos, int col ) { wxPropertyGrid* pg = GetGrid(); if ( pg->GetState() == this ) pg->SetSplitterPosition(splitterPos); else DoSetSplitterPosition(splitterPos, col, false); } void wxPropertyGridPage::DoSetSplitterPosition( int pos, int splitterColumn, int flags ) { if ( (flags & wxPG_SPLITTER_ALL_PAGES) && m_manager->GetPageCount() ) m_manager->SetSplitterPosition( pos, splitterColumn ); else wxPropertyGridPageState::DoSetSplitterPosition( pos, splitterColumn, flags ); } // ----------------------------------------------------------------------- // wxPGHeaderCtrl // ----------------------------------------------------------------------- #if wxUSE_HEADERCTRL class wxPGHeaderCtrl : public wxHeaderCtrl { public: wxPGHeaderCtrl(wxPropertyGridManager* manager, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : wxHeaderCtrl(manager, id, pos, size, style) { m_manager = manager; EnsureColumnCount(2); // Seed titles with defaults m_columns[0]->SetTitle(_("Property")); m_columns[1]->SetTitle(_("Value")); Bind(wxEVT_HEADER_RESIZING, &wxPGHeaderCtrl::OnResizing, this); Bind(wxEVT_HEADER_BEGIN_RESIZE, &wxPGHeaderCtrl::OnBeginResize, this); Bind(wxEVT_HEADER_END_RESIZE, &wxPGHeaderCtrl::OnEndResize, this); } virtual ~wxPGHeaderCtrl() { for (wxVector::const_iterator it = m_columns.begin(); it != m_columns.end(); ++it) { delete *it; } } virtual void OnColumnCountChanging(unsigned int count) wxOVERRIDE { EnsureColumnCount(count); } void OnPageChanged(const wxPropertyGridPage* page) { m_page = page; SetColumnCount(m_page->GetColumnCount()); DetermineAllColumnWidths(); UpdateAllColumns(); } void OnColumWidthsChanged() { DetermineAllColumnWidths(); UpdateAllColumns(); } virtual const wxHeaderColumn& GetColumn(unsigned int idx) const wxOVERRIDE { return *m_columns[idx]; } void SetColumnTitle(unsigned int idx, const wxString& title) { EnsureColumnCount(idx+1); m_columns[idx]->SetTitle(title); } private: void UpdateAllColumns() { unsigned int colCount = GetColumnCount(); for ( unsigned int i = 0; i < colCount; i++ ) { UpdateColumn(i); } } void EnsureColumnCount(unsigned int count) { while ( m_columns.size() < count ) { wxHeaderColumnSimple* colInfo = new wxHeaderColumnSimple(wxEmptyString); m_columns.push_back(colInfo); } } void DetermineAllColumnWidths() const { wxPropertyGrid* pg = m_manager->GetGrid(); // Internal border width int borderWidth = pg->GetWindowBorderSize().x / 2; const unsigned int colCount = m_page->GetColumnCount(); for ( unsigned int i = 0; i < colCount; i++ ) { wxHeaderColumnSimple* colInfo = m_columns[i]; int colWidth = m_page->GetColumnWidth(i); int colMinWidth = m_page->GetColumnMinWidth(i); if ( i == 0 ) { // Compensate for the internal border int margin = pg->GetMarginWidth() + borderWidth; colWidth += margin; colMinWidth += margin; } else if ( i == colCount-1 ) { // Compensate for the internal border and scrollbar int margin = borderWidth; colWidth += margin; colMinWidth += margin; } colInfo->SetWidth(colWidth); colInfo->SetMinWidth(colMinWidth); } } void OnSetColumnWidth(int col, int colWidth) { wxPropertyGrid* pg = m_manager->GetGrid(); // Internal border width int borderWidth = pg->GetWindowBorderSize().x / 2; // Compensate for the internal border int x = -borderWidth; for ( int i=0; iGetWidth(); x += colWidth; pg->DoSetSplitterPosition(x, col, wxPG_SPLITTER_REFRESH | wxPG_SPLITTER_FROM_EVENT); } void OnResizing(wxHeaderCtrlEvent& evt) { int col = evt.GetColumn(); int colWidth = evt.GetWidth(); OnSetColumnWidth(col, colWidth); OnColumWidthsChanged(); wxPropertyGrid* pg = m_manager->GetGrid(); pg->SendEvent(wxEVT_PG_COL_DRAGGING, NULL, NULL, 0, (unsigned int)col); } void OnBeginResize(wxHeaderCtrlEvent& evt) { int col = evt.GetColumn(); wxPropertyGrid* pg = m_manager->GetGrid(); // Don't allow resizing the rightmost column // (like it's not allowed for the rightmost wxPropertyGrid splitter) if ( col == (int)m_page->GetColumnCount() - 1 ) evt.Veto(); // Never allow column resize if layout is static else if ( m_manager->HasFlag(wxPG_STATIC_SPLITTER) ) evt.Veto(); // Allow application to veto dragging else if ( pg->SendEvent(wxEVT_PG_COL_BEGIN_DRAG, NULL, NULL, 0, (unsigned int)col) ) evt.Veto(); } void OnEndResize(wxHeaderCtrlEvent& evt) { int col = evt.GetColumn(); wxPropertyGrid* pg = m_manager->GetGrid(); pg->SendEvent(wxEVT_PG_COL_END_DRAG, NULL, NULL, 0, (unsigned int)col); } wxPropertyGridManager* m_manager; const wxPropertyGridPage* m_page; wxVector m_columns; }; #endif // wxUSE_HEADERCTRL // ----------------------------------------------------------------------- // wxPropertyGridManager // ----------------------------------------------------------------------- // Final default splitter y is client height minus this. #define wxPGMAN_DEFAULT_NEGATIVE_SPLITTER_Y 100 // ----------------------------------------------------------------------- wxIMPLEMENT_CLASS(wxPropertyGridManager, wxPanel); // ----------------------------------------------------------------------- wxBEGIN_EVENT_TABLE(wxPropertyGridManager, wxPanel) EVT_MOTION(wxPropertyGridManager::OnMouseMove) EVT_SIZE(wxPropertyGridManager::OnResize) EVT_PAINT(wxPropertyGridManager::OnPaint) EVT_LEFT_DOWN(wxPropertyGridManager::OnMouseClick) EVT_LEFT_UP(wxPropertyGridManager::OnMouseUp) EVT_LEAVE_WINDOW(wxPropertyGridManager::OnMouseEntry) //EVT_ENTER_WINDOW(wxPropertyGridManager::OnMouseEntry) wxEND_EVENT_TABLE() // ----------------------------------------------------------------------- wxPropertyGridManager::wxPropertyGridManager() : wxPanel() { Init1(); } // ----------------------------------------------------------------------- wxPropertyGridManager::wxPropertyGridManager( wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : wxPanel() { Init1(); Create(parent,id,pos,size,style,name); } // ----------------------------------------------------------------------- bool wxPropertyGridManager::Create( wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) { if ( !m_pPropGrid ) m_pPropGrid = CreatePropertyGrid(); bool res = wxPanel::Create( parent, id, pos, size, (style & wxWINDOW_STYLE_MASK)|wxWANTS_CHARS, name ); Init2(style); SetInitialSize(size); return res; } // ----------------------------------------------------------------------- // // Initialize values to defaults // void wxPropertyGridManager::Init1() { m_pPropGrid = NULL; #if wxUSE_TOOLBAR m_pToolbar = NULL; #endif #if wxUSE_HEADERCTRL m_pHeaderCtrl = NULL; m_showHeader = false; #endif m_pTxtHelpCaption = NULL; m_pTxtHelpContent = NULL; m_emptyPage = NULL; m_selPage = -1; m_width = m_height = 0; m_splitterHeight = 5; m_splitterY = -1; // -1 causes default to be set. m_nextDescBoxSize = -1; m_categorizedModeToolId = -1; m_alphabeticModeToolId = -1; m_extraHeight = 0; m_dragStatus = 0; m_onSplitter = false; m_iFlags = 0; } // ----------------------------------------------------------------------- // These flags are always used in wxPropertyGrid integrated in wxPropertyGridManager. #define wxPG_MAN_PROPGRID_FORCED_FLAGS ( wxBORDER_THEME | \ wxCLIP_CHILDREN) // Which flags can be passed to underlying wxPropertyGrid. #define wxPG_MAN_PASS_FLAGS_MASK (wxPG_WINDOW_STYLE_MASK|wxTAB_TRAVERSAL) // // Initialize after parent etc. set // void wxPropertyGridManager::Init2( int style ) { if ( m_iFlags & wxPG_FL_INITIALIZED ) return; m_windowStyle |= (style & wxPG_WINDOW_STYLE_MASK); wxSize csz = GetClientSize(); m_cursorSizeNS = wxCursor(wxCURSOR_SIZENS); // Prepare the first page // NB: But just prepare - you still need to call Add/InsertPage // to actually add properties on it. wxPropertyGridPage* pd = new wxPropertyGridPage(); pd->m_isDefault = true; pd->m_manager = this; wxPropertyGridPageState* state = pd->GetStatePtr(); state->m_pPropGrid = m_pPropGrid; m_arrPages.push_back( pd ); m_pPropGrid->m_pState = state; wxWindowID baseId = GetId(); wxWindowID useId = baseId; if ( baseId < 0 ) baseId = wxPG_MAN_ALTERNATE_BASE_ID; #ifdef __WXMAC__ // Smaller controls on Mac SetWindowVariant(wxWINDOW_VARIANT_SMALL); #endif long propGridFlags = (m_windowStyle&wxPG_MAN_PASS_FLAGS_MASK) |wxPG_MAN_PROPGRID_FORCED_FLAGS; propGridFlags &= ~wxBORDER_MASK; long pgManExStyle = 0; if ((style & wxPG_NO_INTERNAL_BORDER) == 0) { propGridFlags |= wxBORDER_THEME; } else { propGridFlags |= wxBORDER_NONE; pgManExStyle |= wxPG_EX_TOOLBAR_SEPARATOR; } // Create propertygrid. m_pPropGrid->Create(this,baseId,wxPoint(0,0),csz, propGridFlags); m_pPropGrid->m_eventObject = this; m_pPropGrid->SetId(useId); m_pPropGrid->SetInternalFlag(wxPG_FL_IN_MANAGER); m_pState = m_pPropGrid->m_pState; // Rely on native double-buffering by default. long pgExStyle = wxPG_EX_INIT_NOCAT; #if wxALWAYS_NATIVE_DOUBLE_BUFFER pgExStyle |= wxPG_EX_NATIVE_DOUBLE_BUFFERING; #endif // wxALWAYS_NATIVE_DOUBLE_BUFFER m_pPropGrid->SetExtraStyle(pgExStyle); wxWindow::SetExtraStyle(pgManExStyle | pgExStyle); // Connect to property grid onselect event. // NB: Even if wxID_ANY is used, this doesn't connect properly in wxPython // (see wxPropertyGridManager::ProcessEvent). ReconnectEventHandlers(wxID_NONE, m_pPropGrid->GetId()); // Optional initial controls. m_width = -12345; m_iFlags |= wxPG_FL_INITIALIZED; } // ----------------------------------------------------------------------- wxPropertyGridManager::~wxPropertyGridManager() { END_MOUSE_CAPTURE //m_pPropGrid->ClearSelection(); wxDELETE(m_pPropGrid); for ( size_t i = 0; i < m_arrPages.size(); i++ ) { delete m_arrPages[i]; } delete m_emptyPage; } // ----------------------------------------------------------------------- wxPropertyGrid* wxPropertyGridManager::CreatePropertyGrid() const { return new wxPropertyGrid(); } // ----------------------------------------------------------------------- void wxPropertyGridManager::SetId( wxWindowID winid ) { wxWindow::SetId(winid); // Reconnect propgrid event handlers. ReconnectEventHandlers(m_pPropGrid->GetId(), winid); m_pPropGrid->SetId(winid); } // ----------------------------------------------------------------------- wxSize wxPropertyGridManager::DoGetBestSize() const { // Width: margin=15 + columns=2*40 + scroll bar return wxSize(15+2*40+wxSystemSettings::GetMetric(wxSYS_VSCROLL_X, m_pPropGrid), 150); } // ----------------------------------------------------------------------- bool wxPropertyGridManager::SetFont( const wxFont& font ) { bool res = wxWindow::SetFont(font); m_pPropGrid->SetFont(font); // TODO: Need to do caption recalculations for other pages as well. for ( unsigned int i = 0; i < m_arrPages.size(); i++ ) { wxPropertyGridPage* page = GetPage(i); if ( page != m_pPropGrid->GetState() ) page->CalculateFontAndBitmapStuff(-1); } return res; } // ----------------------------------------------------------------------- // Which flags can affect the toolbar #define wxPG_EX_WINDOW_TOOLBAR_STYLE_MASK (wxPG_EX_NO_FLAT_TOOLBAR|wxPG_EX_MODE_BUTTONS|wxPG_EX_NO_TOOLBAR_DIVIDER) void wxPropertyGridManager::SetExtraStyle( long exStyle ) { // Pass only relevant flags to wxPropertyGrid. m_pPropGrid->SetExtraStyle(exStyle & wxPG_EX_WINDOW_PG_STYLE_MASK); // Because it can happen that not all flags are actually changed // by call to SetExtraStyle() (e.g. wxPG_EX_NATIVE_DOUBLE_BUFFERING), // we have to get the actual style flags prior to storing them. exStyle &= ~wxPG_EX_WINDOW_PG_STYLE_MASK; exStyle |= m_pPropGrid->GetExtraStyle() & wxPG_EX_WINDOW_PG_STYLE_MASK; #if wxUSE_TOOLBAR bool toolbarStyleChanged = (GetExtraStyle() & wxPG_EX_WINDOW_TOOLBAR_STYLE_MASK) != (exStyle & wxPG_EX_WINDOW_TOOLBAR_STYLE_MASK); #endif // wxUSE_TOOLBAR wxWindow::SetExtraStyle( exStyle ); #if wxUSE_TOOLBAR if ( toolbarStyleChanged && m_pToolbar ) RecreateControls(); #endif } // ----------------------------------------------------------------------- void wxPropertyGridManager::DoFreeze() { m_pPropGrid->Freeze(); wxWindow::DoFreeze(); } // ----------------------------------------------------------------------- void wxPropertyGridManager::DoThaw() { wxWindow::DoThaw(); m_pPropGrid->Thaw(); } // ----------------------------------------------------------------------- void wxPropertyGridManager::SetWindowStyleFlag( long style ) { long oldWindowStyle = GetWindowStyleFlag(); wxWindow::SetWindowStyleFlag( style ); m_pPropGrid->SetWindowStyleFlag( (m_pPropGrid->GetWindowStyleFlag()&~(wxPG_MAN_PASS_FLAGS_MASK)) | (style&wxPG_MAN_PASS_FLAGS_MASK) ); // Need to re-position windows? if ( (oldWindowStyle & (wxPG_TOOLBAR|wxPG_DESCRIPTION)) != (style & (wxPG_TOOLBAR|wxPG_DESCRIPTION)) ) { RecreateControls(); } } // ----------------------------------------------------------------------- bool wxPropertyGridManager::Reparent( wxWindowBase *newParent ) { if ( m_pPropGrid ) m_pPropGrid->OnTLPChanging((wxWindow*)newParent); bool res = wxPanel::Reparent(newParent); return res; } // ----------------------------------------------------------------------- // Actually shows given page. bool wxPropertyGridManager::DoSelectPage( int index ) { // -1 means no page was selected //wxASSERT( m_selPage >= 0 ); wxCHECK_MSG( index >= -1 && index < (int)GetPageCount(), false, wxS("invalid page index") ); if ( m_selPage == index ) return true; if ( m_pPropGrid->GetSelection() ) { if ( !m_pPropGrid->ClearSelection() ) return false; } #if wxUSE_TOOLBAR wxPropertyGridPage* prevPage; if ( m_selPage >= 0 ) prevPage = GetPage(m_selPage); else prevPage = m_emptyPage; #endif wxPropertyGridPage* nextPage; if ( index >= 0 ) { nextPage = m_arrPages[index]; nextPage->OnShow(); } else { if ( !m_emptyPage ) { m_emptyPage = new wxPropertyGridPage(); m_emptyPage->m_pPropGrid = m_pPropGrid; } nextPage = m_emptyPage; } m_iFlags |= wxPG_FL_DESC_REFRESH_REQUIRED; m_pPropGrid->SwitchState( nextPage->GetStatePtr() ); m_pState = m_pPropGrid->m_pState; m_selPage = index; #if wxUSE_TOOLBAR if ( m_pToolbar ) { if ( index >= 0 ) m_pToolbar->ToggleTool( nextPage->GetToolId(), true ); else m_pToolbar->ToggleTool( prevPage->GetToolId(), false ); } #endif #if wxUSE_HEADERCTRL if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() ) m_pHeaderCtrl->OnPageChanged(nextPage); #endif return true; } // ----------------------------------------------------------------------- // Changes page *and* set the target page for insertion operations. void wxPropertyGridManager::SelectPage( int index ) { DoSelectPage(index); } // ----------------------------------------------------------------------- int wxPropertyGridManager::GetPageByName( const wxString& name ) const { for ( size_t i = 0; i < GetPageCount(); i++ ) { if ( m_arrPages[i]->m_label == name ) return i; } return wxNOT_FOUND; } // ----------------------------------------------------------------------- int wxPropertyGridManager::GetPageByState( const wxPropertyGridPageState* pState ) const { wxASSERT( pState ); for ( size_t i = 0; i < GetPageCount(); i++ ) { if ( pState == m_arrPages[i]->GetStatePtr() ) return i; } return wxNOT_FOUND; } // ----------------------------------------------------------------------- const wxString& wxPropertyGridManager::GetPageName( int index ) const { wxASSERT( index >= 0 && index < (int)GetPageCount() ); return m_arrPages[index]->m_label; } // ----------------------------------------------------------------------- wxPropertyGridPageState* wxPropertyGridManager::GetPageState( int page ) const { // Do not change this into wxCHECK because returning NULL is important // for wxPropertyGridInterface page enumeration mechanics. if ( page >= (int)GetPageCount() ) return NULL; if ( page == -1 ) return m_pState; return m_arrPages[page]; } // ----------------------------------------------------------------------- void wxPropertyGridManager::Clear() { m_pPropGrid->ClearSelection(false); m_pPropGrid->Freeze(); for ( int i=(int)GetPageCount()-1; i>=0; i-- ) RemovePage(i); m_pPropGrid->Thaw(); } // ----------------------------------------------------------------------- void wxPropertyGridManager::ClearPage( int page ) { wxASSERT( page >= 0 ); wxASSERT( page < (int)GetPageCount() ); if ( page >= 0 && page < (int)GetPageCount() ) { wxPropertyGridPageState* state = m_arrPages[page]; if ( state == m_pPropGrid->GetState() ) m_pPropGrid->Clear(); else state->DoClear(); } } // ----------------------------------------------------------------------- int wxPropertyGridManager::GetColumnCount( int page ) const { wxASSERT( page >= -1 ); wxASSERT( page < (int)GetPageCount() ); return GetPageState(page)->GetColumnCount(); } // ----------------------------------------------------------------------- void wxPropertyGridManager::SetColumnCount( int colCount, int page ) { wxASSERT( page >= -1 ); wxASSERT( page < (int)GetPageCount() ); wxPropertyGridPageState* state = GetPageState(page); #if wxUSE_HEADERCTRL // Update header only if column count is set for the currently visible page if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() && state == m_pState ) { m_pHeaderCtrl->SetColumnCount(colCount); } #endif // wxUSE_HEADERCTRL state->SetColumnCount( colCount ); GetGrid()->Refresh(); #if wxUSE_HEADERCTRL // Update header only if column count is set for the currently visible page if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() && state == m_pState ) { m_pHeaderCtrl->OnColumWidthsChanged(); } #endif // wxUSE_HEADERCTRL } // ----------------------------------------------------------------------- size_t wxPropertyGridManager::GetPageCount() const { if ( !(m_iFlags & wxPG_MAN_FL_PAGE_INSERTED) ) return 0; return m_arrPages.size(); } // ----------------------------------------------------------------------- wxPropertyGridPage* wxPropertyGridManager::InsertPage( int index, const wxString& label, const wxBitmap& bmp, wxPropertyGridPage* pageObj ) { if ( index < 0 ) index = GetPageCount(); wxCHECK_MSG( (size_t)index == GetPageCount(), NULL, wxS("wxPropertyGridManager currently only supports appending pages (due to wxToolBar limitation).")); bool needInit = true; bool isPageInserted = m_iFlags & wxPG_MAN_FL_PAGE_INSERTED ? true : false; wxASSERT( index == 0 || isPageInserted ); if ( !pageObj ) { // No custom page object was given, so we will either re-use the default base // page (if index==0), or create a new default page object. if ( !isPageInserted ) { pageObj = GetPage(0); // Of course, if the base page was custom, we need to delete and // re-create it. if ( !pageObj->m_isDefault ) { delete pageObj; pageObj = new wxPropertyGridPage(); m_arrPages[0] = pageObj; } needInit = false; } else { pageObj = new wxPropertyGridPage(); } pageObj->m_isDefault = true; } else { if ( !isPageInserted ) { // Initial page needs to be deleted and replaced delete GetPage(0); m_arrPages[0] = pageObj; m_pPropGrid->m_pState = pageObj->GetStatePtr(); } } wxPropertyGridPageState* state = pageObj->GetStatePtr(); pageObj->m_manager = this; if ( needInit ) { state->m_pPropGrid = m_pPropGrid; state->InitNonCatMode(); if ( !isPageInserted ) { state->EnableCategories(m_pPropGrid->HasFlag(wxPG_HIDE_CATEGORIES) ? false : true); } } if ( !label.empty() ) { wxASSERT_MSG( pageObj->m_label.empty(), wxS("If page label is given in constructor, empty label must be given in AddPage")); pageObj->m_label = label; } pageObj->m_toolId = -1; if ( !HasFlag(wxPG_SPLITTER_AUTO_CENTER) ) pageObj->m_dontCenterSplitter = true; if ( isPageInserted ) m_arrPages.push_back( pageObj ); #if wxUSE_TOOLBAR if ( m_windowStyle & wxPG_TOOLBAR ) { if ( !m_pToolbar ) RecreateControls(); if ( !HasExtraStyle(wxPG_EX_HIDE_PAGE_BUTTONS) ) { wxASSERT( m_pToolbar ); // Add separator before first page. if ( GetPageCount() < 2 && HasExtraStyle(wxPG_EX_MODE_BUTTONS) && m_pToolbar->GetToolsCount() < 3 ) m_pToolbar->AddSeparator(); wxToolBarToolBase* tool; if ( bmp.IsOk() ) tool = m_pToolbar->AddTool(wxID_ANY, label, bmp, label, wxITEM_RADIO); else tool = m_pToolbar->AddTool(wxID_ANY, label, wxBitmap(gs_xpm_defpage), label, wxITEM_RADIO); pageObj->m_toolId = tool->GetId(); // Connect to toolbar button events. Bind(wxEVT_TOOL, &wxPropertyGridManager::OnToolbarClick, this, pageObj->GetToolId()); m_pToolbar->Realize(); } } #else wxUnusedVar(bmp); #endif // If selected page was above the point of insertion, fix the current page index if ( isPageInserted ) { if ( m_selPage >= index ) { m_selPage += 1; } } else { // Set this value only when adding the first page m_selPage = 0; } pageObj->Init(); m_iFlags |= wxPG_MAN_FL_PAGE_INSERTED; wxASSERT( pageObj->GetGrid() ); return pageObj; } // ----------------------------------------------------------------------- bool wxPropertyGridManager::IsAnyModified() const { for ( size_t i = 0; i < GetPageCount(); i++ ) { if ( m_arrPages[i]->GetStatePtr()->m_anyModified ) return true; } return false; } // ----------------------------------------------------------------------- bool wxPropertyGridManager::IsPageModified( size_t index ) const { wxCHECK_MSG( index < GetPageCount(), false, wxS("Invalid page index") ); #if WXWIN_COMPATIBILITY_3_0 return m_arrPages[index]->GetStatePtr()->m_anyModified != (unsigned char)false; #else return m_arrPages[index]->GetStatePtr()->m_anyModified; #endif } // ----------------------------------------------------------------------- #if wxUSE_HEADERCTRL void wxPropertyGridManager::ShowHeader(bool show) { if ( show != m_showHeader) { m_showHeader = show; RecreateControls(); } } #endif // ----------------------------------------------------------------------- #if wxUSE_HEADERCTRL void wxPropertyGridManager::SetColumnTitle( int idx, const wxString& title ) { if ( !m_pHeaderCtrl ) ShowHeader(); m_pHeaderCtrl->SetColumnTitle(idx, title); } #endif // ----------------------------------------------------------------------- bool wxPropertyGridManager::IsPropertySelected( wxPGPropArg id ) const { wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) for ( unsigned int i=0; iDoIsPropertySelected(p) ) return true; } return false; } // ----------------------------------------------------------------------- wxPGProperty* wxPropertyGridManager::GetPageRoot( int index ) const { wxCHECK_MSG( (index >= 0) && (index < (int)m_arrPages.size()), NULL, wxS("invalid page index") ); return m_arrPages[index]->GetRoot(); } // ----------------------------------------------------------------------- bool wxPropertyGridManager::RemovePage( int page ) { wxCHECK_MSG( (page >= 0) && (page < (int)GetPageCount()), false, wxS("invalid page index") ); wxPropertyGridPage* pd = m_arrPages[page]; if ( m_arrPages.size() == 1 ) { // Last page: do not remove page entry m_pPropGrid->Clear(); m_selPage = -1; m_iFlags &= ~wxPG_MAN_FL_PAGE_INSERTED; pd->m_label.clear(); } // Change selection if current is page else if ( page == m_selPage ) { if ( !m_pPropGrid->ClearSelection() ) return false; // Substitute page to select int substitute = page - 1; if ( substitute < 0 ) substitute = page + 1; SelectPage(substitute); } // Remove toolbar icon #if wxUSE_TOOLBAR if ( HasFlag(wxPG_TOOLBAR) ) { wxASSERT( m_pToolbar ); int toolPos = HasExtraStyle(wxPG_EX_MODE_BUTTONS) ? 3 : 0; toolPos += page; // Delete separator as well, for consistency if ( HasExtraStyle(wxPG_EX_MODE_BUTTONS) && GetPageCount() == 1 ) m_pToolbar->DeleteToolByPos(2); m_pToolbar->DeleteToolByPos(toolPos); } #endif if ( m_arrPages.size() > 1 ) { m_arrPages.erase(m_arrPages.begin() + page); delete pd; } // Adjust indexes that were above removed if ( m_selPage > page ) m_selPage--; return true; } // ----------------------------------------------------------------------- bool wxPropertyGridManager::ProcessEvent( wxEvent& event ) { const wxEventType evtType = event.GetEventType(); // NB: For some reason, under wxPython, Connect in Init doesn't work properly, // so we'll need to call OnPropertyGridSelect manually. Multiple calls // don't really matter. if ( evtType == wxEVT_PG_SELECTED ) OnPropertyGridSelect((wxPropertyGridEvent&)event); // Property grid events get special attention if ( evtType >= wxPG_BASE_EVT_TYPE && evtType < (wxPG_MAX_EVT_TYPE) && m_selPage >= 0 ) { wxPropertyGridPage* page = GetPage(m_selPage); wxPropertyGridEvent* pgEvent = wxDynamicCast(&event, wxPropertyGridEvent); // Add property grid events to appropriate custom pages // but stop propagating to parent if page says it is // handling everything. if ( pgEvent && !page->m_isDefault ) { /*if ( pgEvent->IsPending() ) page->AddPendingEvent(event); else*/ page->ProcessEvent(event); if ( page->IsHandlingAllEvents() ) event.StopPropagation(); } } return wxPanel::ProcessEvent(event); } // ----------------------------------------------------------------------- void wxPropertyGridManager::RepaintDescBoxDecorations( wxDC& dc, int newSplitterY, int newWidth, int newHeight ) { // Draw background wxColour bgcol = GetBackgroundColour(); dc.SetBrush(bgcol); dc.SetPen(bgcol); int rectHeight = m_splitterHeight; dc.DrawRectangle(0, newSplitterY, newWidth, rectHeight); dc.SetPen( wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW) ); int splitterBottom = newSplitterY + m_splitterHeight - 1; int boxHeight = newHeight - splitterBottom; if ( boxHeight > 1 ) dc.DrawRectangle(0, splitterBottom, newWidth, boxHeight); else dc.DrawLine(0, splitterBottom, newWidth, splitterBottom); } // ----------------------------------------------------------------------- void wxPropertyGridManager::UpdateDescriptionBox( int new_splittery, int new_width, int new_height ) { int use_hei = new_height-1; int use_width = new_width-6; // Fix help control positions. int cap_y = new_splittery+m_splitterHeight+5; m_pTxtHelpCaption->SetSize(3, cap_y, use_width, wxDefaultCoord, wxSIZE_AUTO_HEIGHT); int cap_hei = m_pTxtHelpCaption->GetSize().GetHeight(); int cnt_y = cap_y+cap_hei+3; int sub_cap_hei = cap_y+cap_hei-use_hei; int cnt_hei = use_hei-cnt_y; if ( sub_cap_hei > 0 ) { cap_hei -= sub_cap_hei; cnt_hei = 0; } if ( cap_hei <= 2 ) { m_pTxtHelpCaption->Show( false ); m_pTxtHelpContent->Show( false ); } else { m_pTxtHelpCaption->Wrap(-1); m_pTxtHelpCaption->Show( true ); if ( cnt_hei <= 2 ) { m_pTxtHelpContent->Show( false ); } else { m_pTxtHelpContent->SetSize(3,cnt_y,use_width,cnt_hei); m_pTxtHelpContent->Wrap(use_width); m_pTxtHelpContent->Show( true ); } } wxRect r(0, new_splittery, new_width, new_height-new_splittery); RefreshRect(r); m_splitterY = new_splittery; m_iFlags &= ~(wxPG_FL_DESC_REFRESH_REQUIRED); } // ----------------------------------------------------------------------- void wxPropertyGridManager::RecalculatePositions( int width, int height ) { int propgridY = 0; int propgridBottomY = height; // Toolbar at the top. #if wxUSE_TOOLBAR if ( m_pToolbar ) { m_pToolbar->SetSize(0, 0, width, wxDefaultCoord); propgridY += m_pToolbar->GetSize().y; if ( HasExtraStyle(wxPG_EX_TOOLBAR_SEPARATOR) ) propgridY += 1; } #endif // Header comes after the tool bar #if wxUSE_HEADERCTRL if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() ) { m_pHeaderCtrl->SetSize(0, propgridY, width, wxDefaultCoord); // Sync horizontal scroll position with grid int x; m_pPropGrid->CalcScrolledPosition(0, 0, &x, NULL); m_pHeaderCtrl->ScrollWindow(x, 0); propgridY += m_pHeaderCtrl->GetSize().y; } #endif // Help box. if ( m_pTxtHelpCaption ) { int new_splittery = m_splitterY; // Move m_splitterY if ( ( m_splitterY >= 0 || m_nextDescBoxSize ) && m_height > 32 ) { if ( m_nextDescBoxSize >= 0 ) { new_splittery = m_height - m_nextDescBoxSize - m_splitterHeight; m_nextDescBoxSize = -1; } new_splittery += (height-m_height); } else { new_splittery = height - wxPGMAN_DEFAULT_NEGATIVE_SPLITTER_Y; if ( new_splittery < 32 ) new_splittery = 32; } // Check if beyond minimum. int nspy_min = propgridY + m_pPropGrid->GetRowHeight(); if ( new_splittery < nspy_min ) new_splittery = nspy_min; propgridBottomY = new_splittery; UpdateDescriptionBox( new_splittery, width, height ); } if ( m_iFlags & wxPG_FL_INITIALIZED ) { int pgh = propgridBottomY - propgridY; if ( pgh < 0 ) pgh = 0; m_pPropGrid->SetSize( 0, propgridY, width, pgh ); m_extraHeight = height - pgh; m_width = width; m_height = height; } } // ----------------------------------------------------------------------- void wxPropertyGridManager::SetDescBoxHeight( int ht, bool refresh ) { if ( m_windowStyle & wxPG_DESCRIPTION ) { if ( ht != GetDescBoxHeight() ) { m_nextDescBoxSize = ht; if ( refresh ) RecalculatePositions(m_width, m_height); } } } // ----------------------------------------------------------------------- int wxPropertyGridManager::GetDescBoxHeight() const { return GetClientSize().y - m_splitterY - m_splitterHeight; } // ----------------------------------------------------------------------- void wxPropertyGridManager::OnPaint( wxPaintEvent& WXUNUSED(event) ) { wxPaintDC dc(this); // Update everything inside the box wxRect r = GetUpdateRegion().GetBox(); if ( HasExtraStyle(wxPG_EX_TOOLBAR_SEPARATOR) ) { #if wxUSE_TOOLBAR if (m_pToolbar && m_pPropGrid) { wxPen marginPen(m_pPropGrid->GetMarginColour()); dc.SetPen(marginPen); int y = m_pPropGrid->GetPosition().y-1; dc.DrawLine(0, y, GetClientSize().x, y); } #endif // wxUSE_TOOLBAR } // Repaint splitter and any other description box decorations if ( (r.y + r.height) >= m_splitterY && m_splitterY != -1) RepaintDescBoxDecorations( dc, m_splitterY, m_width, m_height ); } // ----------------------------------------------------------------------- void wxPropertyGridManager::Refresh(bool eraseBackground, const wxRect* rect ) { wxPanel::Refresh(eraseBackground, rect); } // ----------------------------------------------------------------------- void wxPropertyGridManager::RefreshProperty( wxPGProperty* p ) { wxASSERT( p->IsRoot() || p->GetParentState() == p->GetParent()->GetParentState() ); if ( GetPage(m_selPage)->GetStatePtr() == p->GetParentState() ) { wxPropertyGrid* grid = p->GetGrid(); grid->RefreshProperty(p); } } // ----------------------------------------------------------------------- void wxPropertyGridManager::RecreateControls() { bool was_shown = IsShown(); if ( was_shown ) Show ( false ); #if wxUSE_TOOLBAR if ( m_windowStyle & wxPG_TOOLBAR ) { bool tbModified = false; long toolBarFlags = HasExtraStyle(wxPG_EX_NO_FLAT_TOOLBAR) ? 0 : wxTB_FLAT; if ( HasExtraStyle(wxPG_EX_NO_TOOLBAR_DIVIDER) ) toolBarFlags |= wxTB_NODIVIDER; // Has toolbar. if ( !m_pToolbar ) { m_pToolbar = new wxToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, toolBarFlags); m_pToolbar->SetToolBitmapSize(wxSize(16, 15)); #if defined(__WXMSW__) // Eliminate toolbar flicker on XP // NOTE: Not enabled since it corrupts drawing somewhat. /* #ifndef WS_EX_COMPOSITED #define WS_EX_COMPOSITED 0x02000000L #endif wxMSWWinExStyleUpdater(GetHwndOf(m_pToolbar)) .TurnOn(WS_EX_COMPOSITED); */ #endif m_pToolbar->SetCursor ( *wxSTANDARD_CURSOR ); tbModified = true; m_categorizedModeToolId = -1; m_alphabeticModeToolId = -1; } else { m_pToolbar->SetWindowStyle(toolBarFlags); tbModified = true; } if ( HasExtraStyle(wxPG_EX_MODE_BUTTONS) ) { // Add buttons if they don't already exist. if (m_categorizedModeToolId == -1) { wxString desc(_("Categorized Mode")); wxToolBarToolBase* tool = m_pToolbar->InsertTool(0, wxID_ANY, desc, wxBitmap(gs_xpm_catmode), wxNullBitmap, wxITEM_RADIO, desc); m_categorizedModeToolId = tool->GetId(); tbModified = true; Bind(wxEVT_TOOL, &wxPropertyGridManager::OnToolbarClick, this, m_categorizedModeToolId); } if (m_alphabeticModeToolId == -1) { wxString desc(_("Alphabetic Mode")); wxToolBarToolBase* tool = m_pToolbar->InsertTool(1, wxID_ANY, desc, wxBitmap(gs_xpm_noncatmode), wxNullBitmap, wxITEM_RADIO, desc); m_alphabeticModeToolId = tool->GetId(); tbModified = true; Bind(wxEVT_TOOL, &wxPropertyGridManager::OnToolbarClick, this, m_alphabeticModeToolId); } // Both buttons should exist here. wxASSERT( m_categorizedModeToolId != -1 && m_alphabeticModeToolId != -1); } else { // Remove buttons if they exist. if (m_categorizedModeToolId != -1) { Unbind(wxEVT_TOOL, &wxPropertyGridManager::OnToolbarClick, this, m_categorizedModeToolId); m_pToolbar->DeleteTool(m_categorizedModeToolId); m_categorizedModeToolId = -1; tbModified = true; } if (m_alphabeticModeToolId != -1) { Unbind(wxEVT_TOOL, &wxPropertyGridManager::OnToolbarClick, this, m_alphabeticModeToolId); m_pToolbar->DeleteTool(m_alphabeticModeToolId); m_alphabeticModeToolId = -1; tbModified = true; } // No button should exist here. wxASSERT( m_categorizedModeToolId == -1 && m_alphabeticModeToolId == -1); } // Rebuild toolbar if any changes were applied. if (tbModified) { m_pToolbar->Realize(); } if ( HasExtraStyle(wxPG_EX_MODE_BUTTONS) ) { // Toggle correct mode button. // TODO: This doesn't work in wxMSW (when changing, // both items will get toggled). int toggle_but_on_ind; int toggle_but_off_ind; if ( m_pPropGrid->m_pState->IsInNonCatMode() ) { toggle_but_on_ind = m_alphabeticModeToolId; toggle_but_off_ind = m_categorizedModeToolId; } else { toggle_but_on_ind = m_categorizedModeToolId; toggle_but_off_ind = m_alphabeticModeToolId; } m_pToolbar->ToggleTool(toggle_but_on_ind, true); m_pToolbar->ToggleTool(toggle_but_off_ind, false); } } else { // No toolbar. if ( m_pToolbar ) m_pToolbar->Destroy(); m_pToolbar = NULL; } #endif #if wxUSE_HEADERCTRL if ( m_showHeader ) { if ( !m_pHeaderCtrl ) { m_pHeaderCtrl = new wxPGHeaderCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0); } else { m_pHeaderCtrl->Show(); } m_pHeaderCtrl->OnPageChanged(GetCurrentPage()); } else { if ( m_pHeaderCtrl ) m_pHeaderCtrl->Hide(); } #endif if ( m_windowStyle & wxPG_DESCRIPTION ) { // Has help box. m_pPropGrid->SetInternalFlag(wxPG_FL_NOSTATUSBARHELP); if ( !m_pTxtHelpCaption ) { m_pTxtHelpCaption = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT|wxST_NO_AUTORESIZE); m_pTxtHelpCaption->SetFont(m_pPropGrid->GetCaptionFont()); m_pTxtHelpCaption->SetCursor( *wxSTANDARD_CURSOR ); } if ( !m_pTxtHelpContent ) { m_pTxtHelpContent = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT|wxST_NO_AUTORESIZE); m_pTxtHelpContent->SetCursor( *wxSTANDARD_CURSOR ); } SetDescribedProperty(GetSelection()); } else { // No help box. m_pPropGrid->ClearInternalFlag(wxPG_FL_NOSTATUSBARHELP); if ( m_pTxtHelpCaption ) m_pTxtHelpCaption->Destroy(); m_pTxtHelpCaption = NULL; if ( m_pTxtHelpContent ) m_pTxtHelpContent->Destroy(); m_pTxtHelpContent = NULL; } int width, height; GetClientSize(&width,&height); RecalculatePositions(width,height); if ( was_shown ) Show ( true ); } // ----------------------------------------------------------------------- wxPGProperty* wxPropertyGridManager::DoGetPropertyByName( const wxString& name ) const { for ( size_t i = 0; i < GetPageCount(); i++ ) { wxPropertyGridPageState* pState = m_arrPages[i]->GetStatePtr(); wxPGProperty* p = pState->BaseGetPropertyByName(name); if ( p ) { return p; } } return NULL; } // ----------------------------------------------------------------------- bool wxPropertyGridManager::EnsureVisible( wxPGPropArg id ) { wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) wxPropertyGridPageState* parentState = p->GetParentState(); // Select correct page. if ( m_pPropGrid->m_pState != parentState ) DoSelectPage( GetPageByState(parentState) ); return m_pPropGrid->EnsureVisible(id); } // ----------------------------------------------------------------------- #if wxUSE_TOOLBAR void wxPropertyGridManager::OnToolbarClick( wxCommandEvent &event ) { int id = event.GetId(); if ( id == m_categorizedModeToolId ) { // Categorized mode. if ( m_pPropGrid->HasFlag(wxPG_HIDE_CATEGORIES) ) { if ( !m_pPropGrid->HasInternalFlag(wxPG_FL_CATMODE_AUTO_SORT) ) m_pPropGrid->m_windowStyle &= ~wxPG_AUTO_SORT; m_pPropGrid->EnableCategories( true ); } } else if ( id == m_alphabeticModeToolId ) { // Alphabetic mode. if ( !m_pPropGrid->HasFlag(wxPG_HIDE_CATEGORIES) ) { if ( m_pPropGrid->HasFlag(wxPG_AUTO_SORT) ) m_pPropGrid->SetInternalFlag(wxPG_FL_CATMODE_AUTO_SORT); else m_pPropGrid->ClearInternalFlag(wxPG_FL_CATMODE_AUTO_SORT); m_pPropGrid->m_windowStyle |= wxPG_AUTO_SORT; m_pPropGrid->EnableCategories( false ); } } else { // Page Switching. int index = -1; // Find page with given id. for ( size_t i = 0; i < GetPageCount(); i++ ) { wxPropertyGridPage* pdc = m_arrPages[i]; if ( pdc->GetToolId() == id ) { index = i; break; } } wxASSERT( index >= 0 ); if ( DoSelectPage(index) ) { // Event dispatching must be last. m_pPropGrid->SendEvent( wxEVT_PG_PAGE_CHANGED, (wxPGProperty*)NULL ); } else { // Restore button state on toolbar. wxToolBar* tb = wxDynamicCast(event.GetEventObject(), wxToolBar); wxASSERT( tb ); // Release the current button. tb->ToggleTool(id, false); // Depress the old button. if ( m_selPage >= 0 ) { wxPropertyGridPage* prevPage = m_arrPages[m_selPage]; tb->ToggleTool(prevPage->GetToolId(), true); } } } } #endif // ----------------------------------------------------------------------- bool wxPropertyGridManager::SetEditableStateItem( const wxString& name, wxVariant value ) { if ( name == wxS("descboxheight") ) { SetDescBoxHeight(value.GetLong(), true); return true; } return false; } // ----------------------------------------------------------------------- wxVariant wxPropertyGridManager::GetEditableStateItem( const wxString& name ) const { if ( name == wxS("descboxheight") ) { return (long) GetDescBoxHeight(); } return wxNullVariant; } // ----------------------------------------------------------------------- void wxPropertyGridManager::SetDescription( const wxString& label, const wxString& content ) { if ( m_pTxtHelpCaption ) { wxSize osz1 = m_pTxtHelpCaption->GetSize(); wxSize osz2 = m_pTxtHelpContent->GetSize(); m_pTxtHelpCaption->SetLabel(label); m_pTxtHelpContent->SetLabel(content); m_pTxtHelpCaption->SetSize(wxDefaultCoord, osz1.y); m_pTxtHelpContent->SetSize(wxDefaultCoord, osz2.y); UpdateDescriptionBox( m_splitterY, m_width, m_height ); } } // ----------------------------------------------------------------------- void wxPropertyGridManager::SetDescribedProperty( wxPGProperty* p ) { if ( m_pTxtHelpCaption ) { if ( p ) { SetDescription( p->GetLabel(), p->GetHelpString() ); } else { SetDescription( wxEmptyString, wxEmptyString ); } } } // ----------------------------------------------------------------------- void wxPropertyGridManager::SetSplitterLeft( bool subProps, bool allPages ) { if ( !allPages ) { m_pPropGrid->SetSplitterLeft(subProps); } else { wxClientDC dc(this); dc.SetFont(m_pPropGrid->GetFont()); int highest = 0; for ( size_t i = 0; i < GetPageCount(); i++ ) { int maxW = m_pState->GetColumnFitWidth(dc, m_arrPages[i]->DoGetRoot(), 0, subProps ); maxW += m_pPropGrid->GetMarginWidth(); if ( maxW > highest ) highest = maxW; m_pState->m_dontCenterSplitter = true; } if ( highest > 0 ) SetSplitterPosition( highest ); } #if wxUSE_HEADERCTRL if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() ) m_pHeaderCtrl->OnColumWidthsChanged(); #endif } void wxPropertyGridManager::SetPageSplitterLeft(int page, bool subProps) { wxASSERT_MSG( (page < (int) GetPageCount()), wxS("SetPageSplitterLeft() has no effect until pages have been added") ); if (page < (int) GetPageCount()) { wxClientDC dc(this); dc.SetFont(m_pPropGrid->GetFont()); int maxW = m_pState->GetColumnFitWidth(dc, m_arrPages[page]->DoGetRoot(), 0, subProps ); maxW += m_pPropGrid->GetMarginWidth(); SetPageSplitterPosition( page, maxW ); #if wxUSE_HEADERCTRL if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() ) m_pHeaderCtrl->OnColumWidthsChanged(); #endif } } void wxPropertyGridManager::ReconnectEventHandlers(wxWindowID oldId, wxWindowID newId) { wxCHECK_RET( oldId != newId, wxS("Attempting to reconnect event handlers to the same window")); if (oldId != wxID_NONE) { Unbind(wxEVT_PG_SELECTED, &wxPropertyGridManager::OnPropertyGridSelect, this, oldId); Unbind(wxEVT_PG_HSCROLL, &wxPropertyGridManager::OnPGScrollH, this, oldId); Unbind(wxEVT_PG_COLS_RESIZED, &wxPropertyGridManager::OnColWidthsChanged, this, oldId); } if (newId != wxID_NONE) { Bind(wxEVT_PG_SELECTED, &wxPropertyGridManager::OnPropertyGridSelect, this, newId); Bind(wxEVT_PG_HSCROLL, &wxPropertyGridManager::OnPGScrollH, this, newId); Bind(wxEVT_PG_COLS_RESIZED, &wxPropertyGridManager::OnColWidthsChanged, this, newId); } } // ----------------------------------------------------------------------- void wxPropertyGridManager::OnPropertyGridSelect( wxPropertyGridEvent& event ) { // Check id. wxASSERT_MSG( GetId() == m_pPropGrid->GetId(), wxS("wxPropertyGridManager id must be set with wxPropertyGridManager::SetId (not wxWindow::SetId).") ); SetDescribedProperty(event.GetProperty()); event.Skip(); } // ----------------------------------------------------------------------- void wxPropertyGridManager::OnPGScrollH(wxPropertyGridEvent& evt) { #if wxUSE_HEADERCTRL if ( m_pHeaderCtrl ) { m_pHeaderCtrl->ScrollWindow(evt.GetInt(), 0); } #endif // wxUSE_HEADERCTRL } void wxPropertyGridManager::OnColWidthsChanged(wxPropertyGridEvent& WXUNUSED(evt)) { #if wxUSE_HEADERCTRL if ( m_pHeaderCtrl ) m_pHeaderCtrl->OnColumWidthsChanged(); #endif } // ----------------------------------------------------------------------- void wxPropertyGridManager::OnResize( wxSizeEvent& WXUNUSED(event) ) { int width, height; GetClientSize(&width, &height); if ( m_width == -12345 ) RecreateControls(); RecalculatePositions(width, height); if ( m_pPropGrid && m_pPropGrid->GetParent() ) { int pgWidth, pgHeight; m_pPropGrid->GetClientSize(&pgWidth, &pgHeight); // Regenerate splitter positions for non-current pages for ( unsigned int i=0; iGetState() ) { page->OnClientWidthChange(pgWidth, pgWidth - page->GetVirtualWidth(), true); } } } #if wxUSE_HEADERCTRL if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() ) m_pHeaderCtrl->OnColumWidthsChanged(); #endif } // ----------------------------------------------------------------------- void wxPropertyGridManager::OnMouseEntry( wxMouseEvent& WXUNUSED(event) ) { // Correct cursor. This is required at least for wxGTK, for which // setting button's cursor to *wxSTANDARD_CURSOR does not work. SetCursor( wxNullCursor ); m_onSplitter = false; } // ----------------------------------------------------------------------- void wxPropertyGridManager::OnMouseMove( wxMouseEvent &event ) { if ( !m_pTxtHelpCaption ) return; int y = event.m_y; if ( m_dragStatus > 0 ) { int sy = y - m_dragOffset; // Calculate drag limits int bottom_limit = m_height - m_splitterHeight + 1; int top_limit = m_pPropGrid->GetRowHeight(); #if wxUSE_TOOLBAR if ( m_pToolbar ) top_limit += m_pToolbar->GetSize().y; #endif if ( sy >= top_limit && sy < bottom_limit ) { int change = sy - m_splitterY; if ( change ) { m_splitterY = sy; m_pPropGrid->SetSize( m_width, m_splitterY - m_pPropGrid->GetPosition().y ); UpdateDescriptionBox( m_splitterY, m_width, m_height ); m_extraHeight -= change; InvalidateBestSize(); } } } else { if ( y >= m_splitterY && y < (m_splitterY+m_splitterHeight+2) ) { SetCursor ( m_cursorSizeNS ); m_onSplitter = true; } else { if ( m_onSplitter ) { SetCursor ( wxNullCursor ); } m_onSplitter = false; } } } // ----------------------------------------------------------------------- void wxPropertyGridManager::OnMouseClick( wxMouseEvent &event ) { int y = event.m_y; // Click on splitter. if ( y >= m_splitterY && y < (m_splitterY+m_splitterHeight+2) ) { if ( m_dragStatus == 0 ) { // // Begin dragging the splitter // BEGIN_MOUSE_CAPTURE m_dragStatus = 1; m_dragOffset = y - m_splitterY; } } } // ----------------------------------------------------------------------- void wxPropertyGridManager::OnMouseUp( wxMouseEvent &event ) { // No event type check - basically calling this method should // just stop dragging. if ( m_dragStatus >= 1 ) { // // End Splitter Dragging // int y = event.m_y; // DO NOT ENABLE FOLLOWING LINE! // (it is only here as a reminder to not to do it) //m_splitterY = y; // This is necessary to return cursor END_MOUSE_CAPTURE // Set back the default cursor, if necessary if ( y < m_splitterY || y >= (m_splitterY+m_splitterHeight+2) ) { SetCursor ( wxNullCursor ); } m_dragStatus = 0; } } // ----------------------------------------------------------------------- void wxPropertyGridManager::SetSplitterPosition( int pos, int splitterColumn ) { wxASSERT_MSG( GetPageCount(), wxS("SetSplitterPosition() has no effect until pages have been added") ); for ( size_t i = 0; i < GetPageCount(); i++ ) { wxPropertyGridPage* page = GetPage(i); page->DoSetSplitterPosition( pos, splitterColumn, wxPG_SPLITTER_REFRESH ); } #if wxUSE_HEADERCTRL if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() ) m_pHeaderCtrl->OnColumWidthsChanged(); #endif } // ----------------------------------------------------------------------- void wxPropertyGridManager::SetPageSplitterPosition( int page, int pos, int column ) { GetPage(page)->DoSetSplitterPosition( pos, column ); #if wxUSE_HEADERCTRL if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() ) m_pHeaderCtrl->OnColumWidthsChanged(); #endif } // ----------------------------------------------------------------------- // wxPGVIterator_Manager // ----------------------------------------------------------------------- // Default returned by wxPropertyGridInterface::CreateVIterator(). class wxPGVIteratorBase_Manager : public wxPGVIteratorBase { public: wxPGVIteratorBase_Manager( wxPropertyGridManager* manager, int flags ) : m_manager(manager), m_flags(flags), m_curPage(0) { m_it.Init(manager->GetPage(0), flags); } virtual ~wxPGVIteratorBase_Manager() { } virtual void Next() wxOVERRIDE { m_it.Next(); // Next page? if ( m_it.AtEnd() ) { m_curPage++; if ( m_curPage < m_manager->GetPageCount() ) m_it.Init( m_manager->GetPage(m_curPage), m_flags ); } } private: wxPropertyGridManager* m_manager; int m_flags; unsigned int m_curPage; }; wxPGVIterator wxPropertyGridManager::GetVIterator( int flags ) const { return wxPGVIterator(new wxPGVIteratorBase_Manager(const_cast(this), flags)); } #endif // wxUSE_PROPGRID