1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/manager.cpp
3 // Purpose: wxPropertyGridManager
4 // Author: Jaakko Salli
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
21 #include "wx/object.h"
23 #include "wx/string.h"
26 #include "wx/window.h"
31 #include "wx/cursor.h"
32 #include "wx/dialog.h"
33 #include "wx/settings.h"
34 #include "wx/msgdlg.h"
35 #include "wx/choice.h"
36 #include "wx/textctrl.h"
37 #include "wx/dirdlg.h"
38 #include "wx/combobox.h"
39 #include "wx/layout.h"
41 #include "wx/textdlg.h"
42 #include "wx/filedlg.h"
43 #include "wx/statusbr.h"
47 // This define is necessary to prevent macro clearing
48 #define __wxPG_SOURCE_FILE__
50 #include <wx/propgrid/propgrid.h>
52 #include <wx/propgrid/manager.h>
55 #define wxPG_MAN_ALTERNATE_BASE_ID 11249 // Needed for wxID_ANY madnesss
58 // -----------------------------------------------------------------------
60 // For wxMSW cursor consistency, we must do mouse capturing even
61 // when using custom controls
63 #define BEGIN_MOUSE_CAPTURE \
64 if ( !(m_iFlags & wxPG_FL_MOUSE_CAPTURED) ) \
67 m_iFlags |= wxPG_FL_MOUSE_CAPTURED; \
70 #define END_MOUSE_CAPTURE \
71 if ( m_iFlags & wxPG_FL_MOUSE_CAPTURED ) \
74 m_iFlags &= ~(wxPG_FL_MOUSE_CAPTURED); \
77 // -----------------------------------------------------------------------
78 // wxPropertyGridManager
79 // -----------------------------------------------------------------------
81 const wxChar
*wxPropertyGridManagerNameStr
= wxT("wxPropertyGridManager");
84 // Categoric Mode Icon
85 static const char* gs_xpm_catmode
[] = {
110 // Alphabetic Mode Icon
111 static const char* gs_xpm_noncatmode
[] = {
136 // Default Page Icon.
137 static const char* gs_xpm_defpage
[] = {
162 #define GETPAGESTATE(page) ((wxPropertyGridPage*)m_arrPages.Item(page))->GetStatePtr()
164 // -----------------------------------------------------------------------
165 // wxPropertyGridPage
166 // -----------------------------------------------------------------------
169 IMPLEMENT_CLASS(wxPropertyGridPage
, wxEvtHandler
)
172 BEGIN_EVENT_TABLE(wxPropertyGridPage
, wxEvtHandler
)
176 wxPropertyGridPage::wxPropertyGridPage()
177 : wxEvtHandler(), wxPropertyGridInterface(), wxPropertyGridPageState()
179 m_pState
= this; // wxPropertyGridInterface to point to State
184 wxPropertyGridPage::~wxPropertyGridPage()
188 void wxPropertyGridPage::Clear()
190 GetStatePtr()->DoClear();
193 wxSize
wxPropertyGridPage::FitColumns()
195 wxSize sz
= DoFitColumns();
199 void wxPropertyGridPage::RefreshProperty( wxPGProperty
* p
)
202 m_manager
->RefreshProperty(p
);
205 void wxPropertyGridPage::OnShow()
209 void wxPropertyGridPage::SetSplitterPosition( int splitterPos
, int col
)
211 wxPropertyGrid
* pg
= GetGrid();
212 if ( pg
->GetState() == this )
213 pg
->SetSplitterPosition(splitterPos
);
215 DoSetSplitterPosition(splitterPos
, col
, false);
218 void wxPropertyGridPage::DoSetSplitterPosition( int pos
, int splitterColumn
, bool allPages
)
220 if ( allPages
&& m_manager
->GetPageCount() )
221 m_manager
->SetSplitterPosition( pos
, splitterColumn
);
223 DoSetSplitterPositionThisPage( pos
, splitterColumn
);
226 // -----------------------------------------------------------------------
227 // wxPropertyGridManager
228 // -----------------------------------------------------------------------
230 // Final default splitter y is client height minus this.
231 #define wxPGMAN_DEFAULT_NEGATIVE_SPLITTER_Y 100
233 // -----------------------------------------------------------------------
235 IMPLEMENT_CLASS(wxPropertyGridManager
, wxPanel
)
237 #define ID_ADVTOOLBAR_OFFSET 1
238 #define ID_ADVHELPCAPTION_OFFSET 2
239 #define ID_ADVHELPCONTENT_OFFSET 3
240 #define ID_ADVBUTTON_OFFSET 4
241 #define ID_ADVTBITEMSBASE_OFFSET 5 // Must be last.
243 // -----------------------------------------------------------------------
245 BEGIN_EVENT_TABLE(wxPropertyGridManager
, wxPanel
)
246 EVT_MOTION(wxPropertyGridManager::OnMouseMove
)
247 EVT_SIZE(wxPropertyGridManager::OnResize
)
248 EVT_PAINT(wxPropertyGridManager::OnPaint
)
249 EVT_LEFT_DOWN(wxPropertyGridManager::OnMouseClick
)
250 EVT_LEFT_UP(wxPropertyGridManager::OnMouseUp
)
251 EVT_LEAVE_WINDOW(wxPropertyGridManager::OnMouseEntry
)
252 //EVT_ENTER_WINDOW(wxPropertyGridManager::OnMouseEntry)
255 // -----------------------------------------------------------------------
257 wxPropertyGridManager::wxPropertyGridManager()
263 // -----------------------------------------------------------------------
265 wxPropertyGridManager::wxPropertyGridManager( wxWindow
*parent
,
274 Create(parent
,id
,pos
,size
,style
,name
);
277 // -----------------------------------------------------------------------
279 bool wxPropertyGridManager::Create( wxWindow
*parent
,
287 bool res
= wxPanel::Create( parent
, id
, pos
, size
,
288 (style
&0xFFFF0000)|wxWANTS_CHARS
,
295 // -----------------------------------------------------------------------
298 // Initialize values to defaults
300 void wxPropertyGridManager::Init1()
303 //m_pPropGrid = (wxPropertyGrid*) NULL;
304 m_pPropGrid
= CreatePropertyGrid();
307 m_pToolbar
= (wxToolBar
*) NULL
;
309 m_pTxtHelpCaption
= (wxStaticText
*) NULL
;
310 m_pTxtHelpContent
= (wxStaticText
*) NULL
;
312 m_emptyPage
= (wxPropertyGridPage
*) NULL
;
316 m_width
= m_height
= 0;
318 m_splitterHeight
= 5;
320 m_splitterY
= -1; // -1 causes default to be set.
322 m_nextDescBoxSize
= -1;
330 // -----------------------------------------------------------------------
332 // These flags are always used in wxPropertyGrid integrated in wxPropertyGridManager.
334 #define wxPG_MAN_PROPGRID_FORCED_FLAGS (wxSIMPLE_BORDER| \
335 wxNO_FULL_REPAINT_ON_RESIZE| \
338 #define wxPG_MAN_PROPGRID_FORCED_FLAGS (wxNO_BORDER| \
339 wxNO_FULL_REPAINT_ON_RESIZE| \
343 // Which flags can be passed to underlying wxPropertyGrid.
344 #define wxPG_MAN_PASS_FLAGS_MASK (0xFFF0|wxTAB_TRAVERSAL)
347 // Initialize after parent etc. set
349 void wxPropertyGridManager::Init2( int style
)
352 if ( m_iFlags
& wxPG_FL_INITIALIZED
)
355 m_windowStyle
|= (style
&0x0000FFFF);
357 wxSize csz
= GetClientSize();
359 m_cursorSizeNS
= wxCursor(wxCURSOR_SIZENS
);
361 // Prepare the first page
362 // NB: But just prepare - you still need to call Add/InsertPage
363 // to actually add properties on it.
364 wxPropertyGridPage
* pd
= new wxPropertyGridPage();
365 pd
->m_isDefault
= true;
366 pd
->m_manager
= this;
367 wxPropertyGridPageState
* state
= pd
->GetStatePtr();
368 state
->m_pPropGrid
= m_pPropGrid
;
369 m_arrPages
.Add( (void*)pd
);
370 m_pPropGrid
->m_pState
= state
;
372 wxWindowID baseId
= GetId();
373 wxWindowID useId
= baseId
;
375 baseId
= wxPG_MAN_ALTERNATE_BASE_ID
;
380 // Smaller controls on Mac
381 SetWindowVariant(wxWINDOW_VARIANT_SMALL
);
384 // Create propertygrid.
385 m_pPropGrid
->Create(this,baseId
,wxPoint(0,0),csz
,
386 (m_windowStyle
&wxPG_MAN_PASS_FLAGS_MASK
)
387 |wxPG_MAN_PROPGRID_FORCED_FLAGS
);
389 m_pPropGrid
->m_eventObject
= this;
391 m_pPropGrid
->SetId(useId
);
393 m_pPropGrid
->m_iFlags
|= wxPG_FL_IN_MANAGER
;
395 m_pState
= m_pPropGrid
->m_pState
;
397 m_pPropGrid
->SetExtraStyle(wxPG_EX_INIT_NOCAT
);
399 m_nextTbInd
= baseId
+ID_ADVTBITEMSBASE_OFFSET
+ 2;
402 // Connect to property grid onselect event.
403 // NB: Even if wxID_ANY is used, this doesn't connect properly in wxPython
404 // (see wxPropertyGridManager::ProcessEvent).
405 Connect(m_pPropGrid
->GetId()/*wxID_ANY*/,
407 wxPropertyGridEventHandler(wxPropertyGridManager::OnPropertyGridSelect
) );
409 // Connect to toolbar button events.
410 Connect(baseId
+ID_ADVTBITEMSBASE_OFFSET
,baseId
+ID_ADVTBITEMSBASE_OFFSET
+50,
411 wxEVT_COMMAND_TOOL_CLICKED
,
412 wxCommandEventHandler(wxPropertyGridManager::OnToolbarClick
) );
414 // Optional initial controls.
417 m_iFlags
|= wxPG_FL_INITIALIZED
;
421 // -----------------------------------------------------------------------
423 wxPropertyGridManager::~wxPropertyGridManager()
427 m_pPropGrid
->DoSelectProperty(NULL
);
428 m_pPropGrid
->m_pState
= NULL
;
431 for ( i
=0; i
<m_arrPages
.GetCount(); i
++ )
433 delete (wxPropertyGridPage
*)m_arrPages
.Item(i
);
439 // -----------------------------------------------------------------------
441 wxPropertyGrid
* wxPropertyGridManager::CreatePropertyGrid() const
443 return new wxPropertyGrid();
446 // -----------------------------------------------------------------------
448 void wxPropertyGridManager::SetId( wxWindowID winid
)
450 wxWindow::SetId(winid
);
452 // TODO: Reconnect propgrid event handler(s).
454 m_pPropGrid
->SetId(winid
);
457 // -----------------------------------------------------------------------
459 wxSize
wxPropertyGridManager::DoGetBestSize() const
461 return wxSize(60,150);
464 // -----------------------------------------------------------------------
466 bool wxPropertyGridManager::SetFont( const wxFont
& font
)
468 bool res
= wxWindow::SetFont(font
);
469 m_pPropGrid
->SetFont(font
);
471 // TODO: Need to do caption recacalculations for other pages as well.
473 for ( i
=0; i
<m_arrPages
.GetCount(); i
++ )
475 wxPropertyGridPage
* page
= GetPage(i
);
477 if ( page
!= m_pPropGrid
->GetState() )
478 page
->CalculateFontAndBitmapStuff(-1);
484 // -----------------------------------------------------------------------
486 void wxPropertyGridManager::SetExtraStyle( long exStyle
)
488 wxWindow::SetExtraStyle( exStyle
);
489 m_pPropGrid
->SetExtraStyle( exStyle
& 0xFFFFF000 );
491 if ( (exStyle
& wxPG_EX_NO_FLAT_TOOLBAR
) && m_pToolbar
)
496 // -----------------------------------------------------------------------
498 void wxPropertyGridManager::Freeze()
500 m_pPropGrid
->Freeze();
504 // -----------------------------------------------------------------------
506 void wxPropertyGridManager::Thaw()
512 // -----------------------------------------------------------------------
514 void wxPropertyGridManager::SetWindowStyleFlag( long style
)
516 wxWindow::SetWindowStyleFlag( style
);
517 m_pPropGrid
->SetWindowStyleFlag( (m_pPropGrid
->GetWindowStyleFlag()&~(wxPG_MAN_PASS_FLAGS_MASK
)) |
518 (style
&wxPG_MAN_PASS_FLAGS_MASK
) );
521 // -----------------------------------------------------------------------
523 // Actually shows given page.
524 bool wxPropertyGridManager::DoSelectPage( int index
)
526 // -1 means no page was selected
527 //wxASSERT( m_selPage >= 0 );
529 wxCHECK_MSG( index
>= -1 && index
< (int)GetPageCount(),
531 wxT("invalid page index") );
533 if ( m_selPage
== index
)
536 if ( m_pPropGrid
->m_selected
)
538 if ( !m_pPropGrid
->ClearSelection() )
542 wxPropertyGridPage
* prevPage
;
544 if ( m_selPage
>= 0 )
545 prevPage
= GetPage(m_selPage
);
547 prevPage
= m_emptyPage
;
549 wxPropertyGridPage
* nextPage
;
553 nextPage
= (wxPropertyGridPage
*)m_arrPages
.Item(index
);
561 m_emptyPage
= new wxPropertyGridPage();
562 m_emptyPage
->m_pPropGrid
= m_pPropGrid
;
565 nextPage
= m_emptyPage
;
568 m_iFlags
|= wxPG_FL_DESC_REFRESH_REQUIRED
;
570 m_pPropGrid
->SwitchState( nextPage
->GetStatePtr() );
572 m_pState
= m_pPropGrid
->m_pState
;
580 m_pToolbar
->ToggleTool( nextPage
->m_id
, true );
582 m_pToolbar
->ToggleTool( prevPage
->m_id
, false );
589 // -----------------------------------------------------------------------
591 // Changes page *and* set the target page for insertion operations.
592 void wxPropertyGridManager::SelectPage( int index
)
597 // -----------------------------------------------------------------------
599 int wxPropertyGridManager::GetPageByName( const wxString
& name
) const
602 for ( i
=0; i
<GetPageCount(); i
++ )
604 if ( ((wxPropertyGridPage
*)m_arrPages
.Item(i
))->m_label
== name
)
610 // -----------------------------------------------------------------------
612 int wxPropertyGridManager::GetPageByState( const wxPropertyGridPageState
* pState
) const
617 for ( i
=0; i
<GetPageCount(); i
++ )
619 if ( pState
== ((wxPropertyGridPage
*)m_arrPages
.Item(i
))->GetStatePtr() )
626 // -----------------------------------------------------------------------
628 const wxString
& wxPropertyGridManager::GetPageName( int index
) const
630 wxASSERT( index
>= 0 && index
< (int)GetPageCount() );
631 return ((wxPropertyGridPage
*)m_arrPages
.Item(index
))->m_label
;
634 // -----------------------------------------------------------------------
636 wxPropertyGridPageState
* wxPropertyGridManager::GetPageState( int page
) const
638 // Do not change this into wxCHECK because returning NULL is important
639 // for wxPropertyGridInterface page enumeration mechanics.
640 if ( page
>= (int)GetPageCount() )
645 return GETPAGESTATE(page
);
648 // -----------------------------------------------------------------------
650 void wxPropertyGridManager::Clear()
652 m_pPropGrid
->Freeze();
655 for ( i
=(int)GetPageCount()-1; i
>=0; i
-- )
659 m_nextTbInd
= m_baseId
+ID_ADVTBITEMSBASE_OFFSET
+ 2;
664 // -----------------------------------------------------------------------
666 void wxPropertyGridManager::ClearPage( int page
)
668 wxASSERT( page
>= 0 );
669 wxASSERT( page
< (int)GetPageCount() );
671 if ( page
>= 0 && page
< (int)GetPageCount() )
673 wxPropertyGridPageState
* state
= GETPAGESTATE(page
);
675 if ( state
== m_pPropGrid
->GetState() )
676 m_pPropGrid
->Clear();
682 // -----------------------------------------------------------------------
684 int wxPropertyGridManager::GetColumnCount( int page
) const
686 wxASSERT( page
>= -1 );
687 wxASSERT( page
< (int)GetPageCount() );
689 return GetPageState(page
)->GetColumnCount();
692 // -----------------------------------------------------------------------
694 void wxPropertyGridManager::SetColumnCount( int colCount
, int page
)
696 wxASSERT( page
>= -1 );
697 wxASSERT( page
< (int)GetPageCount() );
699 GetPageState(page
)->SetColumnCount( colCount
);
700 GetGrid()->Refresh();
702 // -----------------------------------------------------------------------
704 void wxPropertyGridManager::SetPropertyAttributeAll( const wxString
& attrName
, wxVariant value
)
707 for ( i
=0; i
<GetPageCount(); i
++ )
709 wxPropertyGridPage
* page
= (wxPropertyGridPage
*)m_arrPages
.Item(i
);
711 DoSetPropertyAttribute(page
->GetStatePtr()->m_properties
, attrName
, value
, wxPG_RECURSE
);
715 // -----------------------------------------------------------------------
717 size_t wxPropertyGridManager::GetPageCount() const
719 if ( !(m_iFlags
& wxPG_MAN_FL_PAGE_INSERTED
) )
722 return m_arrPages
.GetCount();
725 // -----------------------------------------------------------------------
727 int wxPropertyGridManager::InsertPage( int index
, const wxString
& label
,
728 const wxBitmap
& bmp
, wxPropertyGridPage
* pageObj
)
731 index
= GetPageCount();
733 wxCHECK_MSG( (size_t)index
== GetPageCount(), -1,
734 wxT("wxPropertyGridManager currently only supports appending pages (due to wxToolBar limitation)."));
736 bool needInit
= true;
737 bool isPageInserted
= m_iFlags
& wxPG_MAN_FL_PAGE_INSERTED
? true : false;
739 wxASSERT( index
== 0 || isPageInserted
);
743 // No custom page object was given, so we will either re-use the default base
744 // page (if index==0), or create a new default page object.
745 if ( !isPageInserted
)
747 pageObj
= GetPage(0);
748 // Of course, if the base page was custom, we need to delete and
750 if ( !pageObj
->m_isDefault
)
753 pageObj
= new wxPropertyGridPage();
754 m_arrPages
[0] = pageObj
;
760 pageObj
= new wxPropertyGridPage();
762 pageObj
->m_isDefault
= true;
766 if ( !isPageInserted
)
768 // Initial page needs to be deleted and replaced
770 m_arrPages
[0] = pageObj
;
771 m_pPropGrid
->m_pState
= pageObj
->GetStatePtr();
775 wxPropertyGridPageState
* state
= pageObj
->GetStatePtr();
777 pageObj
->m_manager
= this;
781 state
->m_pPropGrid
= m_pPropGrid
;
782 state
->InitNonCatMode();
785 if ( label
.length() )
787 wxASSERT_MSG( !pageObj
->m_label
.length(),
788 wxT("If page label is given in constructor, empty label must be given in AddPage"));
789 pageObj
->m_label
= label
;
792 pageObj
->m_id
= m_nextTbInd
;
794 if ( isPageInserted
)
795 m_arrPages
.Add( (void*)pageObj
);
798 if ( m_windowStyle
& wxPG_TOOLBAR
)
803 if ( !(GetExtraStyle()&wxPG_EX_HIDE_PAGE_BUTTONS
) )
805 wxASSERT( m_pToolbar
);
807 // Add separator before first page.
808 if ( GetPageCount() < 2 && (GetExtraStyle()&wxPG_EX_MODE_BUTTONS
) &&
809 m_pToolbar
->GetToolsCount() < 3 )
810 m_pToolbar
->AddSeparator();
812 if ( &bmp
!= &wxNullBitmap
)
813 m_pToolbar
->AddTool(m_nextTbInd
,label
,bmp
,label
,wxITEM_RADIO
);
814 //m_pToolbar->InsertTool(index+3,m_nextTbInd,bmp);
816 m_pToolbar
->AddTool(m_nextTbInd
,label
,wxBitmap( (const char**)gs_xpm_defpage
),
821 m_pToolbar
->Realize();
828 // If selected page was above the point of insertion, fix the current page index
829 if ( isPageInserted
)
831 if ( m_selPage
>= index
)
838 // Set this value only when adding the first page
844 m_iFlags
|= wxPG_MAN_FL_PAGE_INSERTED
;
846 wxASSERT( pageObj
->GetGrid() );
851 // -----------------------------------------------------------------------
853 bool wxPropertyGridManager::IsAnyModified() const
856 for ( i
=0; i
<GetPageCount(); i
++ )
858 if ( ((wxPropertyGridPage
*)m_arrPages
.Item(i
))->GetStatePtr()->m_anyModified
)
864 // -----------------------------------------------------------------------
866 bool wxPropertyGridManager::IsPageModified( size_t index
) const
868 if ( ((wxPropertyGridPage
*)m_arrPages
.Item(index
))->GetStatePtr()->m_anyModified
)
873 // -----------------------------------------------------------------------
875 wxPGProperty
* wxPropertyGridManager::GetPageRoot( int index
) const
877 wxASSERT( index
>= 0 );
878 wxASSERT( index
< (int)m_arrPages
.GetCount() );
880 return ((wxPropertyGridPage
*)m_arrPages
.Item(index
))->GetStatePtr()->m_properties
;
883 // -----------------------------------------------------------------------
885 bool wxPropertyGridManager::RemovePage( int page
)
887 wxCHECK_MSG( (page
>= 0) && (page
< (int)GetPageCount()),
889 wxT("invalid page index") );
891 wxPropertyGridPage
* pd
= (wxPropertyGridPage
*)m_arrPages
.Item(page
);
893 if ( m_arrPages
.GetCount() == 1 )
895 // Last page: do not remove page entry
896 m_pPropGrid
->Clear();
898 m_iFlags
&= ~wxPG_MAN_FL_PAGE_INSERTED
;
901 // Change selection if current is page
902 else if ( page
== m_selPage
)
904 if ( !m_pPropGrid
->ClearSelection() )
907 // Substitute page to select
908 int substitute
= page
- 1;
909 if ( substitute
< 0 )
910 substitute
= page
+ 1;
912 SelectPage(substitute
);
915 // Remove toolbar icon
917 if ( HasFlag(wxPG_TOOLBAR
) )
919 wxASSERT( m_pToolbar
);
921 int toolPos
= GetExtraStyle() & wxPG_EX_MODE_BUTTONS
? 3 : 0;
924 // Delete separator as well, for consistency
925 if ( (GetExtraStyle() & wxPG_EX_MODE_BUTTONS
) &&
926 GetPageCount() == 1 )
927 m_pToolbar
->DeleteToolByPos(2);
929 m_pToolbar
->DeleteToolByPos(toolPos
);
933 if ( m_arrPages
.GetCount() > 1 )
935 m_arrPages
.RemoveAt(page
);
939 // Adjust indexes that were above removed
940 if ( m_selPage
> page
)
946 // -----------------------------------------------------------------------
948 bool wxPropertyGridManager::ProcessEvent( wxEvent
& event
)
950 int evtType
= event
.GetEventType();
952 // NB: For some reason, under wxPython, Connect in Init doesn't work properly,
953 // so we'll need to call OnPropertyGridSelect manually. Multiple call's
954 // don't really matter.
955 if ( evtType
== wxEVT_PG_SELECTED
)
956 OnPropertyGridSelect((wxPropertyGridEvent
&)event
);
958 // Property grid events get special attention
959 if ( evtType
>= wxPG_BASE_EVT_TYPE
&&
960 evtType
< (wxPG_MAX_EVT_TYPE
) &&
963 wxPropertyGridPage
* page
= GetPage(m_selPage
);
964 wxPropertyGridEvent
* pgEvent
= wxDynamicCast(&event
, wxPropertyGridEvent
);
966 // Add property grid events to appropriate custom pages
967 // but stop propagating to parent if page says it is
968 // handling everything.
969 if ( pgEvent
&& !page
->m_isDefault
)
971 /*if ( pgEvent->IsPending() )
972 page->AddPendingEvent(event);
974 page
->ProcessEvent(event
);
976 if ( page
->IsHandlingAllEvents() )
977 event
.StopPropagation();
981 return wxPanel::ProcessEvent(event
);
984 // -----------------------------------------------------------------------
986 void wxPropertyGridManager::RepaintSplitter( wxDC
& dc
, int new_splittery
, int new_width
,
987 int new_height
, bool desc_too
)
989 int use_hei
= new_height
;
992 wxColour bgcol
= GetBackgroundColour();
993 dc
.SetBrush( bgcol
);
995 int rect_hei
= use_hei
-new_splittery
;
997 rect_hei
= m_splitterHeight
;
998 dc
.DrawRectangle(0,new_splittery
,new_width
,rect_hei
);
999 dc
.SetPen ( wxSystemSettings::GetColour ( wxSYS_COLOUR_3DDKSHADOW
) );
1000 int splitter_bottom
= new_splittery
+m_splitterHeight
- 1;
1001 int box_height
= use_hei
-splitter_bottom
;
1002 if ( box_height
> 1 )
1003 dc
.DrawRectangle(0,splitter_bottom
,new_width
,box_height
);
1005 dc
.DrawLine(0,splitter_bottom
,new_width
,splitter_bottom
);
1008 // -----------------------------------------------------------------------
1010 void wxPropertyGridManager::RefreshHelpBox( int new_splittery
, int new_width
, int new_height
)
1012 //if ( new_splittery == m_splitterY && new_width == m_width )
1015 int use_hei
= new_height
;
1018 //wxRendererNative::Get().DrawSplitterSash(this,dc,
1019 //wxSize(width,m_splitterHeight),new_splittery,wxHORIZONTAL);
1021 //wxRendererNative::Get().DrawSplitterBorder(this,dc,
1022 // wxRect(0,new_splittery,new_width,m_splitterHeight));
1024 // Fix help control positions.
1025 int cap_hei
= m_pPropGrid
->m_fontHeight
;
1026 int cap_y
= new_splittery
+m_splitterHeight
+5;
1027 int cnt_y
= cap_y
+cap_hei
+3;
1028 int sub_cap_hei
= cap_y
+cap_hei
-use_hei
;
1029 int cnt_hei
= use_hei
-cnt_y
;
1030 if ( sub_cap_hei
> 0 )
1032 cap_hei
-= sub_cap_hei
;
1037 m_pTxtHelpCaption
->Show( false );
1038 m_pTxtHelpContent
->Show( false );
1042 m_pTxtHelpCaption
->SetSize(3,cap_y
,new_width
-6,cap_hei
);
1043 m_pTxtHelpCaption
->Wrap(-1);
1044 m_pTxtHelpCaption
->Show( true );
1047 m_pTxtHelpContent
->Show( false );
1051 m_pTxtHelpContent
->SetSize(3,cnt_y
,new_width
-6,cnt_hei
);
1052 m_pTxtHelpContent
->Show( true );
1056 wxClientDC
dc(this);
1057 RepaintSplitter( dc
, new_splittery
, new_width
, new_height
, true );
1059 m_splitterY
= new_splittery
;
1061 m_iFlags
&= ~(wxPG_FL_DESC_REFRESH_REQUIRED
);
1064 // -----------------------------------------------------------------------
1066 void wxPropertyGridManager::RecalculatePositions( int width
, int height
)
1069 int propgridBottomY
= height
;
1071 // Toolbar at the top.
1077 #if ( wxMINOR_VERSION < 6 || (wxMINOR_VERSION == 6 && wxRELEASE_NUMBER < 2) )
1080 // In wxWidgets 2.6.2+, Toolbar default height may be broken
1081 #if defined(__WXMSW__)
1083 #elif defined(__WXGTK__)
1084 tbHeight
= -1; // 22;
1085 #elif defined(__WXMAC__)
1092 m_pToolbar
->SetSize(0,0,width
,tbHeight
);
1093 propgridY
+= m_pToolbar
->GetSize().y
;
1098 if ( m_pTxtHelpCaption
)
1100 int new_splittery
= m_splitterY
;
1103 if ( ( m_splitterY
>= 0 || m_nextDescBoxSize
) && m_height
> 32 )
1105 if ( m_nextDescBoxSize
>= 0 )
1107 new_splittery
= m_height
- m_nextDescBoxSize
- m_splitterHeight
;
1108 m_nextDescBoxSize
= -1;
1110 new_splittery
+= (height
-m_height
);
1114 new_splittery
= height
- wxPGMAN_DEFAULT_NEGATIVE_SPLITTER_Y
;
1115 if ( new_splittery
< 32 )
1119 // Check if beyond minimum.
1120 int nspy_min
= propgridY
+ m_pPropGrid
->m_lineHeight
;
1121 if ( new_splittery
< nspy_min
)
1122 new_splittery
= nspy_min
;
1124 propgridBottomY
= new_splittery
;
1126 RefreshHelpBox( new_splittery
, width
, height
);
1129 if ( m_iFlags
& wxPG_FL_INITIALIZED
)
1131 int pgh
= propgridBottomY
- propgridY
;
1132 m_pPropGrid
->SetSize( 0, propgridY
, width
, pgh
);
1134 m_extraHeight
= height
- pgh
;
1141 // -----------------------------------------------------------------------
1143 void wxPropertyGridManager::SetDescBoxHeight( int ht
, bool refresh
)
1145 if ( m_windowStyle
& wxPG_DESCRIPTION
)
1147 m_nextDescBoxSize
= ht
;
1149 RecalculatePositions(m_width
, m_height
);
1153 // -----------------------------------------------------------------------
1155 int wxPropertyGridManager::GetDescBoxHeight() const
1157 return GetClientSize().y
- m_splitterY
;
1160 // -----------------------------------------------------------------------
1162 void wxPropertyGridManager::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
1166 // Update everything inside the box
1167 wxRect r
= GetUpdateRegion().GetBox();
1169 // Repaint splitter?
1170 int r_bottom
= r
.y
+ r
.height
;
1171 int splitter_bottom
= m_splitterY
+ m_splitterHeight
;
1172 if ( r
.y
< splitter_bottom
&& r_bottom
>= m_splitterY
)
1173 RepaintSplitter( dc
, m_splitterY
, m_width
, m_height
, false );
1176 // -----------------------------------------------------------------------
1178 void wxPropertyGridManager::Refresh(bool eraseBackground
, const wxRect
* rect
)
1180 m_pPropGrid
->Refresh(eraseBackground
);
1181 wxWindow::Refresh(eraseBackground
,rect
);
1184 // -----------------------------------------------------------------------
1186 void wxPropertyGridManager::RefreshProperty( wxPGProperty
* p
)
1188 wxPropertyGrid
* grid
= p
->GetGrid();
1190 if ( GetPage(m_selPage
)->GetStatePtr() == p
->GetParent()->GetParentState() )
1191 grid
->RefreshProperty(p
);
1194 // -----------------------------------------------------------------------
1196 void wxPropertyGridManager::RecreateControls()
1199 bool was_shown
= IsShown();
1203 wxWindowID baseId
= m_pPropGrid
->GetId();
1205 baseId
= wxPG_MAN_ALTERNATE_BASE_ID
;
1208 if ( m_windowStyle
& wxPG_TOOLBAR
)
1213 m_pToolbar
= new wxToolBar(this,baseId
+ID_ADVTOOLBAR_OFFSET
,
1214 wxDefaultPosition
,wxDefaultSize
,
1215 ((GetExtraStyle()&wxPG_EX_NO_FLAT_TOOLBAR
)?0:wxTB_FLAT
)
1216 /*| wxTB_HORIZONTAL | wxNO_BORDER*/ );
1218 #if defined(__WXMSW__)
1219 // Eliminate toolbar flicker on XP
1220 // NOTE: Not enabled since it corrupts drawing somewhat.
1223 #ifndef WS_EX_COMPOSITED
1224 #define WS_EX_COMPOSITED 0x02000000L
1227 HWND hWnd = (HWND)m_pToolbar->GetHWND();
1229 ::SetWindowLong( hWnd, GWL_EXSTYLE,
1230 ::GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_COMPOSITED );
1235 m_pToolbar
->SetCursor ( *wxSTANDARD_CURSOR
);
1237 if ( (GetExtraStyle()&wxPG_EX_MODE_BUTTONS
) )
1239 wxString
desc1(_("Categorized Mode"));
1240 wxString
desc2(_("Alphabetic Mode"));
1241 m_pToolbar
->AddTool(baseId
+ID_ADVTBITEMSBASE_OFFSET
+0,
1242 desc1
,wxBitmap ( (const char**)gs_xpm_catmode
),
1243 desc1
,wxITEM_RADIO
);
1244 m_pToolbar
->AddTool(baseId
+ID_ADVTBITEMSBASE_OFFSET
+1,
1245 desc2
,wxBitmap ( (const char**)gs_xpm_noncatmode
),
1246 desc2
,wxITEM_RADIO
);
1247 m_pToolbar
->Realize();
1252 if ( (GetExtraStyle()&wxPG_EX_MODE_BUTTONS
) )
1254 // Toggle correct mode button.
1255 // TODO: This doesn't work in wxMSW (when changing,
1256 // both items will get toggled).
1257 int toggle_but_on_ind
= ID_ADVTBITEMSBASE_OFFSET
+0;
1258 int toggle_but_off_ind
= ID_ADVTBITEMSBASE_OFFSET
+1;
1259 if ( m_pPropGrid
->m_pState
->IsInNonCatMode() )
1261 toggle_but_on_ind
++;
1262 toggle_but_off_ind
--;
1265 m_pToolbar
->ToggleTool(baseId
+toggle_but_on_ind
,true);
1266 m_pToolbar
->ToggleTool(baseId
+toggle_but_off_ind
,false);
1274 m_pToolbar
->Destroy();
1275 m_pToolbar
= (wxToolBar
*) NULL
;
1279 if ( m_windowStyle
& wxPG_DESCRIPTION
)
1282 m_pPropGrid
->m_iFlags
|= (wxPG_FL_NOSTATUSBARHELP
);
1284 if ( !m_pTxtHelpCaption
)
1286 m_pTxtHelpCaption
= new wxStaticText (this,baseId
+ID_ADVHELPCAPTION_OFFSET
,wxEmptyString
);
1287 m_pTxtHelpCaption
->SetFont( m_pPropGrid
->m_captionFont
);
1288 m_pTxtHelpCaption
->SetCursor ( *wxSTANDARD_CURSOR
);
1290 if ( !m_pTxtHelpContent
)
1292 m_pTxtHelpContent
= new wxStaticText (this,baseId
+ID_ADVHELPCONTENT_OFFSET
,
1293 wxEmptyString
,wxDefaultPosition
,wxDefaultSize
,wxALIGN_LEFT
|wxST_NO_AUTORESIZE
);
1294 m_pTxtHelpContent
->SetCursor ( *wxSTANDARD_CURSOR
);
1300 m_pPropGrid
->m_iFlags
&= ~(wxPG_FL_NOSTATUSBARHELP
);
1302 if ( m_pTxtHelpCaption
)
1303 m_pTxtHelpCaption
->Destroy();
1305 m_pTxtHelpCaption
= (wxStaticText
*) NULL
;
1307 if ( m_pTxtHelpContent
)
1308 m_pTxtHelpContent
->Destroy();
1310 m_pTxtHelpContent
= (wxStaticText
*) NULL
;
1315 GetClientSize(&width
,&height
);
1317 RecalculatePositions(width
,height
);
1323 // -----------------------------------------------------------------------
1325 wxPGProperty
* wxPropertyGridManager::DoGetPropertyByName( const wxString
& name
) const
1328 for ( i
=0; i
<GetPageCount(); i
++ )
1330 wxPropertyGridPageState
* pState
= ((wxPropertyGridPage
*)m_arrPages
.Item(i
))->GetStatePtr();
1331 wxPGProperty
* p
= pState
->BaseGetPropertyByName(name
);
1340 // -----------------------------------------------------------------------
1342 bool wxPropertyGridManager::EnsureVisible( wxPGPropArg id
)
1344 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
1346 wxPropertyGridPageState
* parentState
= p
->GetParentState();
1348 // Select correct page.
1349 if ( m_pPropGrid
->m_pState
!= parentState
)
1350 DoSelectPage( GetPageByState(parentState
) );
1352 return m_pPropGrid
->EnsureVisible(id
);
1355 // -----------------------------------------------------------------------
1357 size_t wxPropertyGridManager::GetChildrenCount( int page_index
)
1359 return GetChildrenCount( GetPage(page_index
)->GetStatePtr()->m_properties
);
1362 // -----------------------------------------------------------------------
1364 void wxPropertyGridManager::OnToolbarClick( wxCommandEvent
&event
)
1366 int id
= event
.GetId();
1369 int baseId
= m_pPropGrid
->GetId();
1371 baseId
= wxPG_MAN_ALTERNATE_BASE_ID
;
1373 if ( id
== ( baseId
+ ID_ADVTBITEMSBASE_OFFSET
+ 0 ) )
1375 // Categorized mode.
1376 if ( m_pPropGrid
->m_windowStyle
& wxPG_HIDE_CATEGORIES
)
1377 m_pPropGrid
->EnableCategories( true );
1379 else if ( id
== ( baseId
+ ID_ADVTBITEMSBASE_OFFSET
+ 1 ) )
1382 if ( !(m_pPropGrid
->m_windowStyle
& wxPG_HIDE_CATEGORIES
) )
1383 m_pPropGrid
->EnableCategories( false );
1391 wxPropertyGridPage
* pdc
;
1393 // Find page with given id.
1394 for ( i
=0; i
<GetPageCount(); i
++ )
1396 pdc
= (wxPropertyGridPage
*)m_arrPages
.Item(i
);
1397 if ( pdc
->m_id
== id
)
1404 wxASSERT( index
>= 0 );
1406 if ( DoSelectPage( index
) )
1409 // Event dispatching must be last.
1410 m_pPropGrid
->SendEvent( wxEVT_PG_PAGE_CHANGED
, (wxPGProperty
*) NULL
);
1415 // TODO: Depress the old button on toolbar.
1422 // -----------------------------------------------------------------------
1424 void wxPropertyGridManager::SetDescription( const wxString
& label
, const wxString
& content
)
1426 if ( m_pTxtHelpCaption
)
1428 wxSize osz1
= m_pTxtHelpCaption
->GetSize();
1429 wxSize osz2
= m_pTxtHelpContent
->GetSize();
1431 m_pTxtHelpCaption
->SetLabel(label
);
1432 m_pTxtHelpContent
->SetLabel(content
);
1434 m_pTxtHelpCaption
->SetSize(-1,osz1
.y
);
1435 m_pTxtHelpContent
->SetSize(-1,osz2
.y
);
1437 if ( (m_iFlags
& wxPG_FL_DESC_REFRESH_REQUIRED
) || (osz2
.x
<(m_width
-10)) )
1438 RefreshHelpBox( m_splitterY
, m_width
, m_height
);
1442 // -----------------------------------------------------------------------
1444 void wxPropertyGridManager::SetDescribedProperty( wxPGProperty
* p
)
1446 if ( m_pTxtHelpCaption
)
1450 SetDescription( p
->GetLabel(), p
->GetHelpString() );
1454 m_pTxtHelpCaption
->SetLabel(wxEmptyString
);
1455 m_pTxtHelpContent
->SetLabel(wxEmptyString
);
1460 // -----------------------------------------------------------------------
1462 void wxPropertyGridManager::SetSplitterLeft( bool subProps
, bool allPages
)
1466 m_pPropGrid
->SetSplitterLeft(subProps
);
1470 wxClientDC
dc(this);
1471 dc
.SetFont(m_pPropGrid
->m_font
);
1476 for ( i
=0; i
<GetPageCount(); i
++ )
1478 int maxW
= m_pState
->GetColumnFitWidth(dc
, GETPAGESTATE(i
)->m_properties
, 0, subProps
);
1479 maxW
+= m_pPropGrid
->m_marginWidth
;
1480 if ( maxW
> highest
)
1485 m_pPropGrid
->SetSplitterPosition( highest
);
1487 m_pPropGrid
->m_iFlags
|= wxPG_FL_DONT_CENTER_SPLITTER
;
1491 // -----------------------------------------------------------------------
1493 void wxPropertyGridManager::OnPropertyGridSelect( wxPropertyGridEvent
& event
)
1496 wxASSERT_MSG( GetId() == m_pPropGrid
->GetId(),
1497 wxT("wxPropertyGridManager id must be set with wxPropertyGridManager::SetId (not wxWindow::SetId).") );
1499 SetDescribedProperty(event
.GetProperty());
1503 // -----------------------------------------------------------------------
1505 void wxPropertyGridManager::OnResize( wxSizeEvent
& WXUNUSED(event
) )
1509 GetClientSize(&width
,&height
);
1511 if ( m_width
== -12345 )
1514 RecalculatePositions(width
,height
);
1517 // -----------------------------------------------------------------------
1519 void wxPropertyGridManager::OnMouseEntry( wxMouseEvent
& WXUNUSED(event
) )
1521 // Correct cursor. This is required atleast for wxGTK, for which
1522 // setting button's cursor to *wxSTANDARD_CURSOR does not work.
1523 SetCursor( wxNullCursor
);
1527 // -----------------------------------------------------------------------
1529 void wxPropertyGridManager::OnMouseMove( wxMouseEvent
&event
)
1531 if ( !m_pTxtHelpCaption
)
1536 if ( m_dragStatus
> 0 )
1538 int sy
= y
- m_dragOffset
;
1540 // Calculate drag limits
1541 int bottom_limit
= m_height
- m_splitterHeight
+ 1;
1542 int top_limit
= m_pPropGrid
->m_lineHeight
;
1544 if ( m_pToolbar
) top_limit
+= m_pToolbar
->GetSize().y
;
1547 if ( sy
>= top_limit
&& sy
< bottom_limit
)
1550 int change
= sy
- m_splitterY
;
1555 m_pPropGrid
->SetSize( m_width
, m_splitterY
- m_pPropGrid
->GetPosition().y
);
1556 RefreshHelpBox( m_splitterY
, m_width
, m_height
);
1558 m_extraHeight
-= change
;
1559 InvalidateBestSize();
1567 if ( y
>= m_splitterY
&& y
< (m_splitterY
+m_splitterHeight
+2) )
1569 SetCursor ( m_cursorSizeNS
);
1576 SetCursor ( wxNullCursor
);
1583 // -----------------------------------------------------------------------
1585 void wxPropertyGridManager::OnMouseClick( wxMouseEvent
&event
)
1589 // Click on splitter.
1590 if ( y
>= m_splitterY
&& y
< (m_splitterY
+m_splitterHeight
+2) )
1592 if ( m_dragStatus
== 0 )
1595 // Begin draggin the splitter
1602 m_dragOffset
= y
- m_splitterY
;
1608 // -----------------------------------------------------------------------
1610 void wxPropertyGridManager::OnMouseUp( wxMouseEvent
&event
)
1612 // No event type check - basicly calling this method should
1613 // just stop dragging.
1615 if ( m_dragStatus
>= 1 )
1618 // End Splitter Dragging
1623 // DO NOT ENABLE FOLLOWING LINE!
1624 // (it is only here as a reminder to not to do it)
1627 // This is necessary to return cursor
1630 // Set back the default cursor, if necessary
1631 if ( y
< m_splitterY
|| y
>= (m_splitterY
+m_splitterHeight
+2) )
1633 SetCursor ( wxNullCursor
);
1640 // -----------------------------------------------------------------------
1642 void wxPropertyGridManager::SetSplitterPosition( int pos
, int splitterColumn
)
1644 wxASSERT_MSG( GetPageCount(),
1645 wxT("SetSplitterPosition() has no effect until pages have been added") );
1648 for ( i
=0; i
<GetPageCount(); i
++ )
1650 wxPropertyGridPage
* page
= GetPage(i
);
1651 page
->DoSetSplitterPositionThisPage( pos
, splitterColumn
);
1654 m_pPropGrid
->SetInternalFlag(wxPG_FL_SPLITTER_PRE_SET
);
1657 // -----------------------------------------------------------------------
1658 // wxPGVIterator_Manager
1659 // -----------------------------------------------------------------------
1661 // Default returned by wxPropertyGridInterface::CreateVIterator().
1662 class wxPGVIteratorBase_Manager
: public wxPGVIteratorBase
1665 wxPGVIteratorBase_Manager( wxPropertyGridManager
* manager
, int flags
)
1666 : m_manager(manager
), m_flags(flags
), m_curPage(0)
1668 m_it
.Init(manager
->GetPage(0), flags
);
1670 virtual ~wxPGVIteratorBase_Manager() { }
1679 if ( m_curPage
< m_manager
->GetPageCount() )
1680 m_it
.Init( m_manager
->GetPage(m_curPage
), m_flags
);
1684 wxPropertyGridManager
* m_manager
;
1686 unsigned int m_curPage
;
1689 wxPGVIterator
wxPropertyGridManager::GetVIterator( int flags
) const
1691 return wxPGVIterator( new wxPGVIteratorBase_Manager( (wxPropertyGridManager
*)this, flags
) );