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"
23 #include "wx/object.h"
25 #include "wx/string.h"
28 #include "wx/window.h"
33 #include "wx/cursor.h"
34 #include "wx/dialog.h"
35 #include "wx/settings.h"
36 #include "wx/msgdlg.h"
37 #include "wx/choice.h"
38 #include "wx/textctrl.h"
39 #include "wx/dirdlg.h"
40 #include "wx/combobox.h"
41 #include "wx/layout.h"
43 #include "wx/textdlg.h"
44 #include "wx/filedlg.h"
45 #include "wx/statusbr.h"
49 // This define is necessary to prevent macro clearing
50 #define __wxPG_SOURCE_FILE__
52 #include <wx/propgrid/propgrid.h>
54 #include <wx/propgrid/manager.h>
57 #define wxPG_MAN_ALTERNATE_BASE_ID 11249 // Needed for wxID_ANY madnesss
60 // -----------------------------------------------------------------------
62 // For wxMSW cursor consistency, we must do mouse capturing even
63 // when using custom controls
65 #define BEGIN_MOUSE_CAPTURE \
66 if ( !(m_iFlags & wxPG_FL_MOUSE_CAPTURED) ) \
69 m_iFlags |= wxPG_FL_MOUSE_CAPTURED; \
72 #define END_MOUSE_CAPTURE \
73 if ( m_iFlags & wxPG_FL_MOUSE_CAPTURED ) \
76 m_iFlags &= ~(wxPG_FL_MOUSE_CAPTURED); \
79 // -----------------------------------------------------------------------
80 // wxPropertyGridManager
81 // -----------------------------------------------------------------------
83 const wxChar
*wxPropertyGridManagerNameStr
= wxT("wxPropertyGridManager");
86 // Categoric Mode Icon
87 static const char* gs_xpm_catmode
[] = {
112 // Alphabetic Mode Icon
113 static const char* gs_xpm_noncatmode
[] = {
138 // Default Page Icon.
139 static const char* gs_xpm_defpage
[] = {
164 #define GETPAGESTATE(page) ((wxPropertyGridPage*)m_arrPages.Item(page))->GetStatePtr()
166 // -----------------------------------------------------------------------
167 // wxPropertyGridPage
168 // -----------------------------------------------------------------------
171 IMPLEMENT_CLASS(wxPropertyGridPage
, wxEvtHandler
)
174 BEGIN_EVENT_TABLE(wxPropertyGridPage
, wxEvtHandler
)
178 wxPropertyGridPage
::wxPropertyGridPage()
179 : wxEvtHandler(), wxPropertyGridInterface(), wxPropertyGridPageState()
181 m_pState
= this; // wxPropertyGridInterface to point to State
186 wxPropertyGridPage
::~wxPropertyGridPage()
190 void wxPropertyGridPage
::Clear()
192 GetStatePtr()->DoClear();
195 wxSize wxPropertyGridPage
::FitColumns()
197 wxSize sz
= DoFitColumns();
201 void wxPropertyGridPage
::RefreshProperty( wxPGProperty
* p
)
204 m_manager
->RefreshProperty(p
);
207 void wxPropertyGridPage
::OnShow()
211 void wxPropertyGridPage
::SetSplitterPosition( int splitterPos
, int col
)
213 wxPropertyGrid
* pg
= GetGrid();
214 if ( pg
->GetState() == this )
215 pg
->SetSplitterPosition(splitterPos
);
217 DoSetSplitterPosition(splitterPos
, col
, false);
220 void wxPropertyGridPage
::DoSetSplitterPosition( int pos
, int splitterColumn
, bool allPages
)
222 if ( allPages
&& m_manager
->GetPageCount() )
223 m_manager
->SetSplitterPosition( pos
, splitterColumn
);
225 DoSetSplitterPositionThisPage( pos
, splitterColumn
);
228 // -----------------------------------------------------------------------
229 // wxPropertyGridManager
230 // -----------------------------------------------------------------------
232 // Final default splitter y is client height minus this.
233 #define wxPGMAN_DEFAULT_NEGATIVE_SPLITTER_Y 100
235 // -----------------------------------------------------------------------
237 IMPLEMENT_CLASS(wxPropertyGridManager
, wxPanel
)
239 #define ID_ADVTOOLBAR_OFFSET 1
240 #define ID_ADVHELPCAPTION_OFFSET 2
241 #define ID_ADVHELPCONTENT_OFFSET 3
242 #define ID_ADVBUTTON_OFFSET 4
243 #define ID_ADVTBITEMSBASE_OFFSET 5 // Must be last.
245 // -----------------------------------------------------------------------
247 BEGIN_EVENT_TABLE(wxPropertyGridManager
, wxPanel
)
248 EVT_MOTION(wxPropertyGridManager
::OnMouseMove
)
249 EVT_SIZE(wxPropertyGridManager
::OnResize
)
250 EVT_PAINT(wxPropertyGridManager
::OnPaint
)
251 EVT_LEFT_DOWN(wxPropertyGridManager
::OnMouseClick
)
252 EVT_LEFT_UP(wxPropertyGridManager
::OnMouseUp
)
253 EVT_LEAVE_WINDOW(wxPropertyGridManager
::OnMouseEntry
)
254 //EVT_ENTER_WINDOW(wxPropertyGridManager::OnMouseEntry)
257 // -----------------------------------------------------------------------
259 wxPropertyGridManager
::wxPropertyGridManager()
265 // -----------------------------------------------------------------------
267 wxPropertyGridManager
::wxPropertyGridManager( wxWindow
*parent
,
276 Create(parent
,id
,pos
,size
,style
,name
);
279 // -----------------------------------------------------------------------
281 bool wxPropertyGridManager
::Create( wxWindow
*parent
,
289 bool res
= wxPanel
::Create( parent
, id
, pos
, size
,
290 (style
&0xFFFF0000)|wxWANTS_CHARS
,
297 // -----------------------------------------------------------------------
300 // Initialize values to defaults
302 void wxPropertyGridManager
::Init1()
305 //m_pPropGrid = (wxPropertyGrid*) NULL;
306 m_pPropGrid
= CreatePropertyGrid();
309 m_pToolbar
= (wxToolBar
*) NULL
;
311 m_pTxtHelpCaption
= (wxStaticText
*) NULL
;
312 m_pTxtHelpContent
= (wxStaticText
*) NULL
;
314 m_emptyPage
= (wxPropertyGridPage
*) NULL
;
318 m_width
= m_height
= 0;
320 m_splitterHeight
= 5;
322 m_splitterY
= -1; // -1 causes default to be set.
324 m_nextDescBoxSize
= -1;
332 // -----------------------------------------------------------------------
334 // These flags are always used in wxPropertyGrid integrated in wxPropertyGridManager.
336 #define wxPG_MAN_PROPGRID_FORCED_FLAGS (wxSIMPLE_BORDER| \
337 wxNO_FULL_REPAINT_ON_RESIZE| \
340 #define wxPG_MAN_PROPGRID_FORCED_FLAGS (wxNO_BORDER| \
341 wxNO_FULL_REPAINT_ON_RESIZE| \
345 // Which flags can be passed to underlying wxPropertyGrid.
346 #define wxPG_MAN_PASS_FLAGS_MASK (0xFFF0|wxTAB_TRAVERSAL)
349 // Initialize after parent etc. set
351 void wxPropertyGridManager
::Init2( int style
)
354 if ( m_iFlags
& wxPG_FL_INITIALIZED
)
357 m_windowStyle
|= (style
&0x0000FFFF);
359 wxSize csz
= GetClientSize();
361 m_cursorSizeNS
= wxCursor(wxCURSOR_SIZENS
);
363 // Prepare the first page
364 // NB: But just prepare - you still need to call Add/InsertPage
365 // to actually add properties on it.
366 wxPropertyGridPage
* pd
= new wxPropertyGridPage();
367 pd
->m_isDefault
= true;
368 pd
->m_manager
= this;
369 wxPropertyGridPageState
* state
= pd
->GetStatePtr();
370 state
->m_pPropGrid
= m_pPropGrid
;
371 m_arrPages
.Add( (void*)pd
);
372 m_pPropGrid
->m_pState
= state
;
374 wxWindowID baseId
= GetId();
375 wxWindowID useId
= baseId
;
377 baseId
= wxPG_MAN_ALTERNATE_BASE_ID
;
382 // Smaller controls on Mac
383 SetWindowVariant(wxWINDOW_VARIANT_SMALL
);
386 // Create propertygrid.
387 m_pPropGrid
->Create(this,baseId
,wxPoint(0,0),csz
,
388 (m_windowStyle
&wxPG_MAN_PASS_FLAGS_MASK
)
389 |wxPG_MAN_PROPGRID_FORCED_FLAGS
);
391 m_pPropGrid
->m_eventObject
= this;
393 m_pPropGrid
->SetId(useId
);
395 m_pPropGrid
->m_iFlags
|= wxPG_FL_IN_MANAGER
;
397 m_pState
= m_pPropGrid
->m_pState
;
399 m_pPropGrid
->SetExtraStyle(wxPG_EX_INIT_NOCAT
);
401 m_nextTbInd
= baseId
+ID_ADVTBITEMSBASE_OFFSET
+ 2;
404 // Connect to property grid onselect event.
405 // NB: Even if wxID_ANY is used, this doesn't connect properly in wxPython
406 // (see wxPropertyGridManager::ProcessEvent).
407 Connect(m_pPropGrid
->GetId()/*wxID_ANY*/,
409 wxPropertyGridEventHandler(wxPropertyGridManager
::OnPropertyGridSelect
) );
411 // Connect to toolbar button events.
412 Connect(baseId
+ID_ADVTBITEMSBASE_OFFSET
,baseId
+ID_ADVTBITEMSBASE_OFFSET
+50,
413 wxEVT_COMMAND_TOOL_CLICKED
,
414 wxCommandEventHandler(wxPropertyGridManager
::OnToolbarClick
) );
416 // Optional initial controls.
419 m_iFlags
|= wxPG_FL_INITIALIZED
;
423 // -----------------------------------------------------------------------
425 wxPropertyGridManager
::~wxPropertyGridManager()
429 m_pPropGrid
->DoSelectProperty(NULL
);
430 m_pPropGrid
->m_pState
= NULL
;
433 for ( i
=0; i
<m_arrPages
.GetCount(); i
++ )
435 delete (wxPropertyGridPage
*)m_arrPages
.Item(i
);
441 // -----------------------------------------------------------------------
443 wxPropertyGrid
* wxPropertyGridManager
::CreatePropertyGrid() const
445 return new wxPropertyGrid();
448 // -----------------------------------------------------------------------
450 void wxPropertyGridManager
::SetId( wxWindowID winid
)
452 wxWindow
::SetId(winid
);
454 // TODO: Reconnect propgrid event handler(s).
456 m_pPropGrid
->SetId(winid
);
459 // -----------------------------------------------------------------------
461 wxSize wxPropertyGridManager
::DoGetBestSize() const
463 return wxSize(60,150);
466 // -----------------------------------------------------------------------
468 bool wxPropertyGridManager
::SetFont( const wxFont
& font
)
470 bool res
= wxWindow
::SetFont(font
);
471 m_pPropGrid
->SetFont(font
);
473 // TODO: Need to do caption recacalculations for other pages as well.
475 for ( i
=0; i
<m_arrPages
.GetCount(); i
++ )
477 wxPropertyGridPage
* page
= GetPage(i
);
479 if ( page
!= m_pPropGrid
->GetState() )
480 page
->CalculateFontAndBitmapStuff(-1);
486 // -----------------------------------------------------------------------
488 void wxPropertyGridManager
::SetExtraStyle( long exStyle
)
490 wxWindow
::SetExtraStyle( exStyle
);
491 m_pPropGrid
->SetExtraStyle( exStyle
& 0xFFFFF000 );
493 if ( (exStyle
& wxPG_EX_NO_FLAT_TOOLBAR
) && m_pToolbar
)
498 // -----------------------------------------------------------------------
500 void wxPropertyGridManager
::Freeze()
502 m_pPropGrid
->Freeze();
506 // -----------------------------------------------------------------------
508 void wxPropertyGridManager
::Thaw()
514 // -----------------------------------------------------------------------
516 void wxPropertyGridManager
::SetWindowStyleFlag( long style
)
518 wxWindow
::SetWindowStyleFlag( style
);
519 m_pPropGrid
->SetWindowStyleFlag( (m_pPropGrid
->GetWindowStyleFlag()&~(wxPG_MAN_PASS_FLAGS_MASK
)) |
520 (style
&wxPG_MAN_PASS_FLAGS_MASK
) );
523 // -----------------------------------------------------------------------
525 // Actually shows given page.
526 bool wxPropertyGridManager
::DoSelectPage( int index
)
528 // -1 means no page was selected
529 //wxASSERT( m_selPage >= 0 );
531 wxCHECK_MSG( index
>= -1 && index
< (int)GetPageCount(),
533 wxT("invalid page index") );
535 if ( m_selPage
== index
)
538 if ( m_pPropGrid
->m_selected
)
540 if ( !m_pPropGrid
->ClearSelection() )
544 wxPropertyGridPage
* prevPage
;
546 if ( m_selPage
>= 0 )
547 prevPage
= GetPage(m_selPage
);
549 prevPage
= m_emptyPage
;
551 wxPropertyGridPage
* nextPage
;
555 nextPage
= (wxPropertyGridPage
*)m_arrPages
.Item(index
);
563 m_emptyPage
= new wxPropertyGridPage();
564 m_emptyPage
->m_pPropGrid
= m_pPropGrid
;
567 nextPage
= m_emptyPage
;
570 m_iFlags
|= wxPG_FL_DESC_REFRESH_REQUIRED
;
572 m_pPropGrid
->SwitchState( nextPage
->GetStatePtr() );
574 m_pState
= m_pPropGrid
->m_pState
;
582 m_pToolbar
->ToggleTool( nextPage
->m_id
, true );
584 m_pToolbar
->ToggleTool( prevPage
->m_id
, false );
591 // -----------------------------------------------------------------------
593 // Changes page *and* set the target page for insertion operations.
594 void wxPropertyGridManager
::SelectPage( int index
)
599 // -----------------------------------------------------------------------
601 int wxPropertyGridManager
::GetPageByName( const wxString
& name
) const
604 for ( i
=0; i
<GetPageCount(); i
++ )
606 if ( ((wxPropertyGridPage
*)m_arrPages
.Item(i
))->m_label
== name
)
612 // -----------------------------------------------------------------------
614 int wxPropertyGridManager
::GetPageByState( const wxPropertyGridPageState
* pState
) const
619 for ( i
=0; i
<GetPageCount(); i
++ )
621 if ( pState
== ((wxPropertyGridPage
*)m_arrPages
.Item(i
))->GetStatePtr() )
628 // -----------------------------------------------------------------------
630 const wxString
& wxPropertyGridManager
::GetPageName( int index
) const
632 wxASSERT( index
>= 0 && index
< (int)GetPageCount() );
633 return ((wxPropertyGridPage
*)m_arrPages
.Item(index
))->m_label
;
636 // -----------------------------------------------------------------------
638 wxPropertyGridPageState
* wxPropertyGridManager
::GetPageState( int page
) const
640 // Do not change this into wxCHECK because returning NULL is important
641 // for wxPropertyGridInterface page enumeration mechanics.
642 if ( page
>= (int)GetPageCount() )
647 return GETPAGESTATE(page
);
650 // -----------------------------------------------------------------------
652 void wxPropertyGridManager
::Clear()
654 m_pPropGrid
->Freeze();
657 for ( i
=(int)GetPageCount()-1; i
>=0; i
-- )
661 m_nextTbInd
= m_baseId
+ID_ADVTBITEMSBASE_OFFSET
+ 2;
666 // -----------------------------------------------------------------------
668 void wxPropertyGridManager
::ClearPage( int page
)
670 wxASSERT( page
>= 0 );
671 wxASSERT( page
< (int)GetPageCount() );
673 if ( page
>= 0 && page
< (int)GetPageCount() )
675 wxPropertyGridPageState
* state
= GETPAGESTATE(page
);
677 if ( state
== m_pPropGrid
->GetState() )
678 m_pPropGrid
->Clear();
684 // -----------------------------------------------------------------------
686 int wxPropertyGridManager
::GetColumnCount( int page
) const
688 wxASSERT( page
>= -1 );
689 wxASSERT( page
< (int)GetPageCount() );
691 return GetPageState(page
)->GetColumnCount();
694 // -----------------------------------------------------------------------
696 void wxPropertyGridManager
::SetColumnCount( int colCount
, int page
)
698 wxASSERT( page
>= -1 );
699 wxASSERT( page
< (int)GetPageCount() );
701 GetPageState(page
)->SetColumnCount( colCount
);
702 GetGrid()->Refresh();
704 // -----------------------------------------------------------------------
706 size_t wxPropertyGridManager
::GetPageCount() const
708 if ( !(m_iFlags
& wxPG_MAN_FL_PAGE_INSERTED
) )
711 return m_arrPages
.GetCount();
714 // -----------------------------------------------------------------------
716 int wxPropertyGridManager
::InsertPage( int index
, const wxString
& label
,
717 const wxBitmap
& bmp
, wxPropertyGridPage
* pageObj
)
720 index
= GetPageCount();
722 wxCHECK_MSG( (size_t)index
== GetPageCount(), -1,
723 wxT("wxPropertyGridManager currently only supports appending pages (due to wxToolBar limitation)."));
725 bool needInit
= true;
726 bool isPageInserted
= m_iFlags
& wxPG_MAN_FL_PAGE_INSERTED ?
true : false;
728 wxASSERT( index
== 0 || isPageInserted
);
732 // No custom page object was given, so we will either re-use the default base
733 // page (if index==0), or create a new default page object.
734 if ( !isPageInserted
)
736 pageObj
= GetPage(0);
737 // Of course, if the base page was custom, we need to delete and
739 if ( !pageObj
->m_isDefault
)
742 pageObj
= new wxPropertyGridPage();
743 m_arrPages
[0] = pageObj
;
749 pageObj
= new wxPropertyGridPage();
751 pageObj
->m_isDefault
= true;
755 if ( !isPageInserted
)
757 // Initial page needs to be deleted and replaced
759 m_arrPages
[0] = pageObj
;
760 m_pPropGrid
->m_pState
= pageObj
->GetStatePtr();
764 wxPropertyGridPageState
* state
= pageObj
->GetStatePtr();
766 pageObj
->m_manager
= this;
770 state
->m_pPropGrid
= m_pPropGrid
;
771 state
->InitNonCatMode();
774 if ( label
.length() )
776 wxASSERT_MSG( !pageObj
->m_label
.length(),
777 wxT("If page label is given in constructor, empty label must be given in AddPage"));
778 pageObj
->m_label
= label
;
781 pageObj
->m_id
= m_nextTbInd
;
783 if ( isPageInserted
)
784 m_arrPages
.Add( (void*)pageObj
);
787 if ( m_windowStyle
& wxPG_TOOLBAR
)
792 if ( !(GetExtraStyle()&wxPG_EX_HIDE_PAGE_BUTTONS
) )
794 wxASSERT( m_pToolbar
);
796 // Add separator before first page.
797 if ( GetPageCount() < 2 && (GetExtraStyle()&wxPG_EX_MODE_BUTTONS
) &&
798 m_pToolbar
->GetToolsCount() < 3 )
799 m_pToolbar
->AddSeparator();
801 if ( &bmp
!= &wxNullBitmap
)
802 m_pToolbar
->AddTool(m_nextTbInd
,label
,bmp
,label
,wxITEM_RADIO
);
803 //m_pToolbar->InsertTool(index+3,m_nextTbInd,bmp);
805 m_pToolbar
->AddTool(m_nextTbInd
,label
,wxBitmap( (const char**)gs_xpm_defpage
),
810 m_pToolbar
->Realize();
817 // If selected page was above the point of insertion, fix the current page index
818 if ( isPageInserted
)
820 if ( m_selPage
>= index
)
827 // Set this value only when adding the first page
833 m_iFlags
|= wxPG_MAN_FL_PAGE_INSERTED
;
835 wxASSERT( pageObj
->GetGrid() );
840 // -----------------------------------------------------------------------
842 bool wxPropertyGridManager
::IsAnyModified() const
845 for ( i
=0; i
<GetPageCount(); i
++ )
847 if ( ((wxPropertyGridPage
*)m_arrPages
.Item(i
))->GetStatePtr()->m_anyModified
)
853 // -----------------------------------------------------------------------
855 bool wxPropertyGridManager
::IsPageModified( size_t index
) const
857 if ( ((wxPropertyGridPage
*)m_arrPages
.Item(index
))->GetStatePtr()->m_anyModified
)
862 // -----------------------------------------------------------------------
864 wxPGProperty
* wxPropertyGridManager
::GetPageRoot( int index
) const
866 wxASSERT( index
>= 0 );
867 wxASSERT( index
< (int)m_arrPages
.GetCount() );
869 return ((wxPropertyGridPage
*)m_arrPages
.Item(index
))->GetStatePtr()->m_properties
;
872 // -----------------------------------------------------------------------
874 bool wxPropertyGridManager
::RemovePage( int page
)
876 wxCHECK_MSG( (page
>= 0) && (page
< (int)GetPageCount()),
878 wxT("invalid page index") );
880 wxPropertyGridPage
* pd
= (wxPropertyGridPage
*)m_arrPages
.Item(page
);
882 if ( m_arrPages
.GetCount() == 1 )
884 // Last page: do not remove page entry
885 m_pPropGrid
->Clear();
887 m_iFlags
&= ~wxPG_MAN_FL_PAGE_INSERTED
;
890 // Change selection if current is page
891 else if ( page
== m_selPage
)
893 if ( !m_pPropGrid
->ClearSelection() )
896 // Substitute page to select
897 int substitute
= page
- 1;
898 if ( substitute
< 0 )
899 substitute
= page
+ 1;
901 SelectPage(substitute
);
904 // Remove toolbar icon
906 if ( HasFlag(wxPG_TOOLBAR
) )
908 wxASSERT( m_pToolbar
);
910 int toolPos
= GetExtraStyle() & wxPG_EX_MODE_BUTTONS ?
3 : 0;
913 // Delete separator as well, for consistency
914 if ( (GetExtraStyle() & wxPG_EX_MODE_BUTTONS
) &&
915 GetPageCount() == 1 )
916 m_pToolbar
->DeleteToolByPos(2);
918 m_pToolbar
->DeleteToolByPos(toolPos
);
922 if ( m_arrPages
.GetCount() > 1 )
924 m_arrPages
.RemoveAt(page
);
928 // Adjust indexes that were above removed
929 if ( m_selPage
> page
)
935 // -----------------------------------------------------------------------
937 bool wxPropertyGridManager
::ProcessEvent( wxEvent
& event
)
939 int evtType
= event
.GetEventType();
941 // NB: For some reason, under wxPython, Connect in Init doesn't work properly,
942 // so we'll need to call OnPropertyGridSelect manually. Multiple call's
943 // don't really matter.
944 if ( evtType
== wxEVT_PG_SELECTED
)
945 OnPropertyGridSelect((wxPropertyGridEvent
&)event
);
947 // Property grid events get special attention
948 if ( evtType
>= wxPG_BASE_EVT_TYPE
&&
949 evtType
< (wxPG_MAX_EVT_TYPE
) &&
952 wxPropertyGridPage
* page
= GetPage(m_selPage
);
953 wxPropertyGridEvent
* pgEvent
= wxDynamicCast(&event
, wxPropertyGridEvent
);
955 // Add property grid events to appropriate custom pages
956 // but stop propagating to parent if page says it is
957 // handling everything.
958 if ( pgEvent
&& !page
->m_isDefault
)
960 /*if ( pgEvent->IsPending() )
961 page->AddPendingEvent(event);
963 page
->ProcessEvent(event
);
965 if ( page
->IsHandlingAllEvents() )
966 event
.StopPropagation();
970 return wxPanel
::ProcessEvent(event
);
973 // -----------------------------------------------------------------------
975 void wxPropertyGridManager
::RepaintSplitter( wxDC
& dc
, int new_splittery
, int new_width
,
976 int new_height
, bool desc_too
)
978 int use_hei
= new_height
;
981 wxColour bgcol
= GetBackgroundColour();
982 dc
.SetBrush( bgcol
);
984 int rect_hei
= use_hei
-new_splittery
;
986 rect_hei
= m_splitterHeight
;
987 dc
.DrawRectangle(0,new_splittery
,new_width
,rect_hei
);
988 dc
.SetPen ( wxSystemSettings
::GetColour ( wxSYS_COLOUR_3DDKSHADOW
) );
989 int splitter_bottom
= new_splittery
+m_splitterHeight
- 1;
990 int box_height
= use_hei
-splitter_bottom
;
991 if ( box_height
> 1 )
992 dc
.DrawRectangle(0,splitter_bottom
,new_width
,box_height
);
994 dc
.DrawLine(0,splitter_bottom
,new_width
,splitter_bottom
);
997 // -----------------------------------------------------------------------
999 void wxPropertyGridManager
::RefreshHelpBox( int new_splittery
, int new_width
, int new_height
)
1001 //if ( new_splittery == m_splitterY && new_width == m_width )
1004 int use_hei
= new_height
;
1007 //wxRendererNative::Get().DrawSplitterSash(this,dc,
1008 //wxSize(width,m_splitterHeight),new_splittery,wxHORIZONTAL);
1010 //wxRendererNative::Get().DrawSplitterBorder(this,dc,
1011 // wxRect(0,new_splittery,new_width,m_splitterHeight));
1013 // Fix help control positions.
1014 int cap_hei
= m_pPropGrid
->m_fontHeight
;
1015 int cap_y
= new_splittery
+m_splitterHeight
+5;
1016 int cnt_y
= cap_y
+cap_hei
+3;
1017 int sub_cap_hei
= cap_y
+cap_hei
-use_hei
;
1018 int cnt_hei
= use_hei
-cnt_y
;
1019 if ( sub_cap_hei
> 0 )
1021 cap_hei
-= sub_cap_hei
;
1026 m_pTxtHelpCaption
->Show( false );
1027 m_pTxtHelpContent
->Show( false );
1031 m_pTxtHelpCaption
->SetSize(3,cap_y
,new_width
-6,cap_hei
);
1032 m_pTxtHelpCaption
->Wrap(-1);
1033 m_pTxtHelpCaption
->Show( true );
1036 m_pTxtHelpContent
->Show( false );
1040 m_pTxtHelpContent
->SetSize(3,cnt_y
,new_width
-6,cnt_hei
);
1041 m_pTxtHelpContent
->Show( true );
1045 wxClientDC
dc(this);
1046 RepaintSplitter( dc
, new_splittery
, new_width
, new_height
, true );
1048 m_splitterY
= new_splittery
;
1050 m_iFlags
&= ~(wxPG_FL_DESC_REFRESH_REQUIRED
);
1053 // -----------------------------------------------------------------------
1055 void wxPropertyGridManager
::RecalculatePositions( int width
, int height
)
1058 int propgridBottomY
= height
;
1060 // Toolbar at the top.
1066 #if ( wxMINOR_VERSION < 6 || (wxMINOR_VERSION == 6 && wxRELEASE_NUMBER < 2) )
1069 // In wxWidgets 2.6.2+, Toolbar default height may be broken
1070 #if defined(__WXMSW__)
1072 #elif defined(__WXGTK__)
1073 tbHeight
= -1; // 22;
1074 #elif defined(__WXMAC__)
1081 m_pToolbar
->SetSize(0,0,width
,tbHeight
);
1082 propgridY
+= m_pToolbar
->GetSize().y
;
1087 if ( m_pTxtHelpCaption
)
1089 int new_splittery
= m_splitterY
;
1092 if ( ( m_splitterY
>= 0 || m_nextDescBoxSize
) && m_height
> 32 )
1094 if ( m_nextDescBoxSize
>= 0 )
1096 new_splittery
= m_height
- m_nextDescBoxSize
- m_splitterHeight
;
1097 m_nextDescBoxSize
= -1;
1099 new_splittery
+= (height
-m_height
);
1103 new_splittery
= height
- wxPGMAN_DEFAULT_NEGATIVE_SPLITTER_Y
;
1104 if ( new_splittery
< 32 )
1108 // Check if beyond minimum.
1109 int nspy_min
= propgridY
+ m_pPropGrid
->m_lineHeight
;
1110 if ( new_splittery
< nspy_min
)
1111 new_splittery
= nspy_min
;
1113 propgridBottomY
= new_splittery
;
1115 RefreshHelpBox( new_splittery
, width
, height
);
1118 if ( m_iFlags
& wxPG_FL_INITIALIZED
)
1120 int pgh
= propgridBottomY
- propgridY
;
1121 m_pPropGrid
->SetSize( 0, propgridY
, width
, pgh
);
1123 m_extraHeight
= height
- pgh
;
1130 // -----------------------------------------------------------------------
1132 void wxPropertyGridManager
::SetDescBoxHeight( int ht
, bool refresh
)
1134 if ( m_windowStyle
& wxPG_DESCRIPTION
)
1136 m_nextDescBoxSize
= ht
;
1138 RecalculatePositions(m_width
, m_height
);
1142 // -----------------------------------------------------------------------
1144 int wxPropertyGridManager
::GetDescBoxHeight() const
1146 return GetClientSize().y
- m_splitterY
;
1149 // -----------------------------------------------------------------------
1151 void wxPropertyGridManager
::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
1155 // Update everything inside the box
1156 wxRect r
= GetUpdateRegion().GetBox();
1158 // Repaint splitter?
1159 int r_bottom
= r
.y
+ r
.height
;
1160 int splitter_bottom
= m_splitterY
+ m_splitterHeight
;
1161 if ( r
.y
< splitter_bottom
&& r_bottom
>= m_splitterY
)
1162 RepaintSplitter( dc
, m_splitterY
, m_width
, m_height
, false );
1165 // -----------------------------------------------------------------------
1167 void wxPropertyGridManager
::Refresh(bool eraseBackground
, const wxRect
* rect
)
1169 m_pPropGrid
->Refresh(eraseBackground
);
1170 wxWindow
::Refresh(eraseBackground
,rect
);
1173 // -----------------------------------------------------------------------
1175 void wxPropertyGridManager
::RefreshProperty( wxPGProperty
* p
)
1177 wxPropertyGrid
* grid
= p
->GetGrid();
1179 if ( GetPage(m_selPage
)->GetStatePtr() == p
->GetParent()->GetParentState() )
1180 grid
->RefreshProperty(p
);
1183 // -----------------------------------------------------------------------
1185 void wxPropertyGridManager
::RecreateControls()
1188 bool was_shown
= IsShown();
1192 wxWindowID baseId
= m_pPropGrid
->GetId();
1194 baseId
= wxPG_MAN_ALTERNATE_BASE_ID
;
1197 if ( m_windowStyle
& wxPG_TOOLBAR
)
1202 m_pToolbar
= new wxToolBar(this,baseId
+ID_ADVTOOLBAR_OFFSET
,
1203 wxDefaultPosition
,wxDefaultSize
,
1204 ((GetExtraStyle()&wxPG_EX_NO_FLAT_TOOLBAR
)?
0:wxTB_FLAT
)
1205 /*| wxTB_HORIZONTAL | wxNO_BORDER*/ );
1207 #if defined(__WXMSW__)
1208 // Eliminate toolbar flicker on XP
1209 // NOTE: Not enabled since it corrupts drawing somewhat.
1212 #ifndef WS_EX_COMPOSITED
1213 #define WS_EX_COMPOSITED 0x02000000L
1216 HWND hWnd = (HWND)m_pToolbar->GetHWND();
1218 ::SetWindowLong( hWnd, GWL_EXSTYLE,
1219 ::GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_COMPOSITED );
1224 m_pToolbar
->SetCursor ( *wxSTANDARD_CURSOR
);
1226 if ( (GetExtraStyle()&wxPG_EX_MODE_BUTTONS
) )
1228 wxString
desc1(_("Categorized Mode"));
1229 wxString
desc2(_("Alphabetic Mode"));
1230 m_pToolbar
->AddTool(baseId
+ID_ADVTBITEMSBASE_OFFSET
+0,
1231 desc1
,wxBitmap ( (const char**)gs_xpm_catmode
),
1232 desc1
,wxITEM_RADIO
);
1233 m_pToolbar
->AddTool(baseId
+ID_ADVTBITEMSBASE_OFFSET
+1,
1234 desc2
,wxBitmap ( (const char**)gs_xpm_noncatmode
),
1235 desc2
,wxITEM_RADIO
);
1236 m_pToolbar
->Realize();
1241 if ( (GetExtraStyle()&wxPG_EX_MODE_BUTTONS
) )
1243 // Toggle correct mode button.
1244 // TODO: This doesn't work in wxMSW (when changing,
1245 // both items will get toggled).
1246 int toggle_but_on_ind
= ID_ADVTBITEMSBASE_OFFSET
+0;
1247 int toggle_but_off_ind
= ID_ADVTBITEMSBASE_OFFSET
+1;
1248 if ( m_pPropGrid
->m_pState
->IsInNonCatMode() )
1250 toggle_but_on_ind
++;
1251 toggle_but_off_ind
--;
1254 m_pToolbar
->ToggleTool(baseId
+toggle_but_on_ind
,true);
1255 m_pToolbar
->ToggleTool(baseId
+toggle_but_off_ind
,false);
1263 m_pToolbar
->Destroy();
1264 m_pToolbar
= (wxToolBar
*) NULL
;
1268 if ( m_windowStyle
& wxPG_DESCRIPTION
)
1271 m_pPropGrid
->m_iFlags
|= (wxPG_FL_NOSTATUSBARHELP
);
1273 if ( !m_pTxtHelpCaption
)
1275 m_pTxtHelpCaption
= new wxStaticText (this,baseId
+ID_ADVHELPCAPTION_OFFSET
,wxEmptyString
);
1276 m_pTxtHelpCaption
->SetFont( m_pPropGrid
->m_captionFont
);
1277 m_pTxtHelpCaption
->SetCursor ( *wxSTANDARD_CURSOR
);
1279 if ( !m_pTxtHelpContent
)
1281 m_pTxtHelpContent
= new wxStaticText (this,baseId
+ID_ADVHELPCONTENT_OFFSET
,
1282 wxEmptyString
,wxDefaultPosition
,wxDefaultSize
,wxALIGN_LEFT
|wxST_NO_AUTORESIZE
);
1283 m_pTxtHelpContent
->SetCursor ( *wxSTANDARD_CURSOR
);
1289 m_pPropGrid
->m_iFlags
&= ~(wxPG_FL_NOSTATUSBARHELP
);
1291 if ( m_pTxtHelpCaption
)
1292 m_pTxtHelpCaption
->Destroy();
1294 m_pTxtHelpCaption
= (wxStaticText
*) NULL
;
1296 if ( m_pTxtHelpContent
)
1297 m_pTxtHelpContent
->Destroy();
1299 m_pTxtHelpContent
= (wxStaticText
*) NULL
;
1304 GetClientSize(&width
,&height
);
1306 RecalculatePositions(width
,height
);
1312 // -----------------------------------------------------------------------
1314 wxPGProperty
* wxPropertyGridManager
::DoGetPropertyByName( const wxString
& name
) const
1317 for ( i
=0; i
<GetPageCount(); i
++ )
1319 wxPropertyGridPageState
* pState
= ((wxPropertyGridPage
*)m_arrPages
.Item(i
))->GetStatePtr();
1320 wxPGProperty
* p
= pState
->BaseGetPropertyByName(name
);
1329 // -----------------------------------------------------------------------
1331 bool wxPropertyGridManager
::EnsureVisible( wxPGPropArg id
)
1333 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
1335 wxPropertyGridPageState
* parentState
= p
->GetParentState();
1337 // Select correct page.
1338 if ( m_pPropGrid
->m_pState
!= parentState
)
1339 DoSelectPage( GetPageByState(parentState
) );
1341 return m_pPropGrid
->EnsureVisible(id
);
1344 // -----------------------------------------------------------------------
1346 size_t wxPropertyGridManager
::GetChildrenCount( int page_index
)
1348 return GetChildrenCount( GetPage(page_index
)->GetStatePtr()->m_properties
);
1351 // -----------------------------------------------------------------------
1353 void wxPropertyGridManager
::OnToolbarClick( wxCommandEvent
&event
)
1355 int id
= event
.GetId();
1358 int baseId
= m_pPropGrid
->GetId();
1360 baseId
= wxPG_MAN_ALTERNATE_BASE_ID
;
1362 if ( id
== ( baseId
+ ID_ADVTBITEMSBASE_OFFSET
+ 0 ) )
1364 // Categorized mode.
1365 if ( m_pPropGrid
->m_windowStyle
& wxPG_HIDE_CATEGORIES
)
1366 m_pPropGrid
->EnableCategories( true );
1368 else if ( id
== ( baseId
+ ID_ADVTBITEMSBASE_OFFSET
+ 1 ) )
1371 if ( !(m_pPropGrid
->m_windowStyle
& wxPG_HIDE_CATEGORIES
) )
1372 m_pPropGrid
->EnableCategories( false );
1380 wxPropertyGridPage
* pdc
;
1382 // Find page with given id.
1383 for ( i
=0; i
<GetPageCount(); i
++ )
1385 pdc
= (wxPropertyGridPage
*)m_arrPages
.Item(i
);
1386 if ( pdc
->m_id
== id
)
1393 wxASSERT( index
>= 0 );
1395 if ( DoSelectPage( index
) )
1398 // Event dispatching must be last.
1399 m_pPropGrid
->SendEvent( wxEVT_PG_PAGE_CHANGED
, (wxPGProperty
*) NULL
);
1404 // TODO: Depress the old button on toolbar.
1411 // -----------------------------------------------------------------------
1413 void wxPropertyGridManager
::SetDescription( const wxString
& label
, const wxString
& content
)
1415 if ( m_pTxtHelpCaption
)
1417 wxSize osz1
= m_pTxtHelpCaption
->GetSize();
1418 wxSize osz2
= m_pTxtHelpContent
->GetSize();
1420 m_pTxtHelpCaption
->SetLabel(label
);
1421 m_pTxtHelpContent
->SetLabel(content
);
1423 m_pTxtHelpCaption
->SetSize(-1,osz1
.y
);
1424 m_pTxtHelpContent
->SetSize(-1,osz2
.y
);
1426 if ( (m_iFlags
& wxPG_FL_DESC_REFRESH_REQUIRED
) || (osz2
.x
<(m_width
-10)) )
1427 RefreshHelpBox( m_splitterY
, m_width
, m_height
);
1431 // -----------------------------------------------------------------------
1433 void wxPropertyGridManager
::SetDescribedProperty( wxPGProperty
* p
)
1435 if ( m_pTxtHelpCaption
)
1439 SetDescription( p
->GetLabel(), p
->GetHelpString() );
1443 m_pTxtHelpCaption
->SetLabel(wxEmptyString
);
1444 m_pTxtHelpContent
->SetLabel(wxEmptyString
);
1449 // -----------------------------------------------------------------------
1451 void wxPropertyGridManager
::SetSplitterLeft( bool subProps
, bool allPages
)
1455 m_pPropGrid
->SetSplitterLeft(subProps
);
1459 wxClientDC
dc(this);
1460 dc
.SetFont(m_pPropGrid
->m_font
);
1465 for ( i
=0; i
<GetPageCount(); i
++ )
1467 int maxW
= m_pState
->GetColumnFitWidth(dc
, GETPAGESTATE(i
)->m_properties
, 0, subProps
);
1468 maxW
+= m_pPropGrid
->m_marginWidth
;
1469 if ( maxW
> highest
)
1474 m_pPropGrid
->SetSplitterPosition( highest
);
1476 m_pPropGrid
->m_iFlags
|= wxPG_FL_DONT_CENTER_SPLITTER
;
1480 // -----------------------------------------------------------------------
1482 void wxPropertyGridManager
::OnPropertyGridSelect( wxPropertyGridEvent
& event
)
1485 wxASSERT_MSG( GetId() == m_pPropGrid
->GetId(),
1486 wxT("wxPropertyGridManager id must be set with wxPropertyGridManager::SetId (not wxWindow::SetId).") );
1488 SetDescribedProperty(event
.GetProperty());
1492 // -----------------------------------------------------------------------
1494 void wxPropertyGridManager
::OnResize( wxSizeEvent
& WXUNUSED(event
) )
1498 GetClientSize(&width
,&height
);
1500 if ( m_width
== -12345 )
1503 RecalculatePositions(width
,height
);
1506 // -----------------------------------------------------------------------
1508 void wxPropertyGridManager
::OnMouseEntry( wxMouseEvent
& WXUNUSED(event
) )
1510 // Correct cursor. This is required atleast for wxGTK, for which
1511 // setting button's cursor to *wxSTANDARD_CURSOR does not work.
1512 SetCursor( wxNullCursor
);
1516 // -----------------------------------------------------------------------
1518 void wxPropertyGridManager
::OnMouseMove( wxMouseEvent
&event
)
1520 if ( !m_pTxtHelpCaption
)
1525 if ( m_dragStatus
> 0 )
1527 int sy
= y
- m_dragOffset
;
1529 // Calculate drag limits
1530 int bottom_limit
= m_height
- m_splitterHeight
+ 1;
1531 int top_limit
= m_pPropGrid
->m_lineHeight
;
1533 if ( m_pToolbar
) top_limit
+= m_pToolbar
->GetSize().y
;
1536 if ( sy
>= top_limit
&& sy
< bottom_limit
)
1539 int change
= sy
- m_splitterY
;
1544 m_pPropGrid
->SetSize( m_width
, m_splitterY
- m_pPropGrid
->GetPosition().y
);
1545 RefreshHelpBox( m_splitterY
, m_width
, m_height
);
1547 m_extraHeight
-= change
;
1548 InvalidateBestSize();
1556 if ( y
>= m_splitterY
&& y
< (m_splitterY
+m_splitterHeight
+2) )
1558 SetCursor ( m_cursorSizeNS
);
1565 SetCursor ( wxNullCursor
);
1572 // -----------------------------------------------------------------------
1574 void wxPropertyGridManager
::OnMouseClick( wxMouseEvent
&event
)
1578 // Click on splitter.
1579 if ( y
>= m_splitterY
&& y
< (m_splitterY
+m_splitterHeight
+2) )
1581 if ( m_dragStatus
== 0 )
1584 // Begin draggin the splitter
1591 m_dragOffset
= y
- m_splitterY
;
1597 // -----------------------------------------------------------------------
1599 void wxPropertyGridManager
::OnMouseUp( wxMouseEvent
&event
)
1601 // No event type check - basicly calling this method should
1602 // just stop dragging.
1604 if ( m_dragStatus
>= 1 )
1607 // End Splitter Dragging
1612 // DO NOT ENABLE FOLLOWING LINE!
1613 // (it is only here as a reminder to not to do it)
1616 // This is necessary to return cursor
1619 // Set back the default cursor, if necessary
1620 if ( y
< m_splitterY
|| y
>= (m_splitterY
+m_splitterHeight
+2) )
1622 SetCursor ( wxNullCursor
);
1629 // -----------------------------------------------------------------------
1631 void wxPropertyGridManager
::SetSplitterPosition( int pos
, int splitterColumn
)
1633 wxASSERT_MSG( GetPageCount(),
1634 wxT("SetSplitterPosition() has no effect until pages have been added") );
1637 for ( i
=0; i
<GetPageCount(); i
++ )
1639 wxPropertyGridPage
* page
= GetPage(i
);
1640 page
->DoSetSplitterPositionThisPage( pos
, splitterColumn
);
1643 m_pPropGrid
->SetInternalFlag(wxPG_FL_SPLITTER_PRE_SET
);
1646 // -----------------------------------------------------------------------
1647 // wxPGVIterator_Manager
1648 // -----------------------------------------------------------------------
1650 // Default returned by wxPropertyGridInterface::CreateVIterator().
1651 class wxPGVIteratorBase_Manager
: public wxPGVIteratorBase
1654 wxPGVIteratorBase_Manager( wxPropertyGridManager
* manager
, int flags
)
1655 : m_manager(manager
), m_flags(flags
), m_curPage(0)
1657 m_it
.Init(manager
->GetPage(0), flags
);
1659 virtual ~wxPGVIteratorBase_Manager() { }
1668 if ( m_curPage
< m_manager
->GetPageCount() )
1669 m_it
.Init( m_manager
->GetPage(m_curPage
), m_flags
);
1673 wxPropertyGridManager
* m_manager
;
1675 unsigned int m_curPage
;
1678 wxPGVIterator wxPropertyGridManager
::GetVIterator( int flags
) const
1680 return wxPGVIterator( new wxPGVIteratorBase_Manager( (wxPropertyGridManager
*)this, flags
) );
1683 #endif // wxUSE_PROPGRID