]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/propgrid/manager.cpp
missing commit
[wxWidgets.git] / src / propgrid / manager.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/propgrid/manager.cpp
3// Purpose: wxPropertyGridManager
4// Author: Jaakko Salli
5// Modified by:
6// Created: 2005-01-14
7// RCS-ID: $Id$
8// Copyright: (c) Jaakko Salli
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx/wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16 #pragma hdrstop
17#endif
18
19#if wxUSE_PROPGRID
20
21#ifndef WX_PRECOMP
22 #include "wx/defs.h"
23 #include "wx/object.h"
24 #include "wx/hash.h"
25 #include "wx/string.h"
26 #include "wx/log.h"
27 #include "wx/event.h"
28 #include "wx/window.h"
29 #include "wx/panel.h"
30 #include "wx/dc.h"
31 #include "wx/pen.h"
32 #include "wx/brush.h"
33 #include "wx/cursor.h"
34 #include "wx/settings.h"
35 #include "wx/textctrl.h"
36 #include "wx/sizer.h"
37 #include "wx/statusbr.h"
38 #include "wx/intl.h"
39#endif
40
41// This define is necessary to prevent macro clearing
42#define __wxPG_SOURCE_FILE__
43
44#include "wx/propgrid/propgrid.h"
45
46#include "wx/propgrid/manager.h"
47
48
49#define wxPG_MAN_ALTERNATE_BASE_ID 11249 // Needed for wxID_ANY madnesss
50
51
52// -----------------------------------------------------------------------
53
54// For wxMSW cursor consistency, we must do mouse capturing even
55// when using custom controls
56
57#define BEGIN_MOUSE_CAPTURE \
58 if ( !(m_iFlags & wxPG_FL_MOUSE_CAPTURED) ) \
59 { \
60 CaptureMouse(); \
61 m_iFlags |= wxPG_FL_MOUSE_CAPTURED; \
62 }
63
64#define END_MOUSE_CAPTURE \
65 if ( m_iFlags & wxPG_FL_MOUSE_CAPTURED ) \
66 { \
67 ReleaseMouse(); \
68 m_iFlags &= ~(wxPG_FL_MOUSE_CAPTURED); \
69 }
70
71// -----------------------------------------------------------------------
72// wxPropertyGridManager
73// -----------------------------------------------------------------------
74
75const char wxPropertyGridManagerNameStr[] = "wxPropertyGridManager";
76
77
78// Categoric Mode Icon
79static const char* const gs_xpm_catmode[] = {
80"16 16 5 1",
81". c none",
82"B c black",
83"D c #868686",
84"L c #CACACA",
85"W c #FFFFFF",
86".DDD............",
87".DLD.BBBBBB.....",
88".DDD............",
89".....DDDDD.DDD..",
90"................",
91".....DDDDD.DDD..",
92"................",
93".....DDDDD.DDD..",
94"................",
95".....DDDDD.DDD..",
96"................",
97".DDD............",
98".DLD.BBBBBB.....",
99".DDD............",
100".....DDDDD.DDD..",
101"................"
102};
103
104// Alphabetic Mode Icon
105static const char* const gs_xpm_noncatmode[] = {
106"16 16 5 1",
107". c none",
108"B c black",
109"D c #868686",
110"L c #000080",
111"W c #FFFFFF",
112"..DBD...DDD.DDD.",
113".DB.BD..........",
114".BBBBB..DDD.DDD.",
115".B...B..........",
116"...L....DDD.DDD.",
117"...L............",
118".L.L.L..DDD.DDD.",
119"..LLL...........",
120"...L....DDD.DDD.",
121"................",
122".BBBBB..DDD.DDD.",
123"....BD..........",
124"...BD...DDD.DDD.",
125"..BD............",
126".BBBBB..DDD.DDD.",
127"................"
128};
129
130// Default Page Icon.
131static const char* const gs_xpm_defpage[] = {
132"16 16 5 1",
133". c none",
134"B c black",
135"D c #868686",
136"L c #000080",
137"W c #FFFFFF",
138"................",
139"................",
140"..BBBBBBBBBBBB..",
141"..B..........B..",
142"..B.BB.LLLLL.B..",
143"..B..........B..",
144"..B.BB.LLLLL.B..",
145"..B..........B..",
146"..B.BB.LLLLL.B..",
147"..B..........B..",
148"..B.BB.LLLLL.B..",
149"..B..........B..",
150"..BBBBBBBBBBBB..",
151"................",
152"................",
153"................"
154};
155
156// -----------------------------------------------------------------------
157// wxPropertyGridPage
158// -----------------------------------------------------------------------
159
160
161IMPLEMENT_CLASS(wxPropertyGridPage, wxEvtHandler)
162
163
164BEGIN_EVENT_TABLE(wxPropertyGridPage, wxEvtHandler)
165END_EVENT_TABLE()
166
167
168wxPropertyGridPage::wxPropertyGridPage()
169 : wxEvtHandler(), wxPropertyGridInterface(), wxPropertyGridPageState()
170{
171 m_pState = this; // wxPropertyGridInterface to point to State
172 m_manager = NULL;
173 m_isDefault = false;
174}
175
176wxPropertyGridPage::~wxPropertyGridPage()
177{
178}
179
180void wxPropertyGridPage::Clear()
181{
182 GetStatePtr()->DoClear();
183}
184
185wxSize wxPropertyGridPage::FitColumns()
186{
187 wxSize sz = DoFitColumns();
188 return sz;
189}
190
191void wxPropertyGridPage::RefreshProperty( wxPGProperty* p )
192{
193 if ( m_manager )
194 m_manager->RefreshProperty(p);
195}
196
197void wxPropertyGridPage::OnShow()
198{
199}
200
201void wxPropertyGridPage::SetSplitterPosition( int splitterPos, int col )
202{
203 wxPropertyGrid* pg = GetGrid();
204 if ( pg->GetState() == this )
205 pg->SetSplitterPosition(splitterPos);
206 else
207 DoSetSplitterPosition(splitterPos, col, false);
208}
209
210void wxPropertyGridPage::DoSetSplitterPosition( int pos,
211 int splitterColumn,
212 int flags )
213{
214 if ( (flags & wxPG_SPLITTER_ALL_PAGES) && m_manager->GetPageCount() )
215 m_manager->SetSplitterPosition( pos, splitterColumn );
216 else
217 wxPropertyGridPageState::DoSetSplitterPosition( pos,
218 splitterColumn,
219 flags );
220}
221
222// -----------------------------------------------------------------------
223// wxPGHeaderCtrl
224// -----------------------------------------------------------------------
225
226#if wxUSE_HEADERCTRL
227
228class wxPGHeaderCtrl : public wxHeaderCtrl
229{
230public:
231 wxPGHeaderCtrl(wxPropertyGridManager* manager) :
232 wxHeaderCtrl()
233 {
234 m_manager = manager;
235 EnsureColumnCount(2);
236
237 // Seed titles with defaults
238 m_columns[0]->SetTitle(_("Property"));
239 m_columns[1]->SetTitle(_("Value"));
240 }
241
242 virtual ~wxPGHeaderCtrl()
243 {
244 for (unsigned int i=0; i<m_columns.size(); i++ )
245 delete m_columns[i];
246 }
247
248 int DetermineColumnWidth(unsigned int idx, int* pMinWidth) const
249 {
250 const wxPropertyGridPage* page = m_page;
251 int colWidth = page->GetColumnWidth(idx);
252 int colMinWidth = page->GetColumnMinWidth(idx);
253 if ( idx == 0 )
254 {
255 wxPropertyGrid* pg = m_manager->GetGrid();
256 int margin = pg->GetMarginWidth();
257
258 // Compensate for the internal border
259 margin += (pg->GetSize().x - pg->GetClientSize().x) / 2;
260
261 colWidth += margin;
262 colMinWidth += margin;
263 }
264 *pMinWidth = colMinWidth;
265 return colWidth;
266 }
267
268 void OnPageChanged(const wxPropertyGridPage* page)
269 {
270 m_page = page;
271 OnPageUpdated();
272 }
273
274 void OnPageUpdated()
275 {
276 // Get column info from the page
277 const wxPropertyGridPage* page = m_page;
278 unsigned int colCount = page->GetColumnCount();
279 EnsureColumnCount(colCount);
280
281 for ( unsigned int i=0; i<colCount; i++ )
282 {
283 wxHeaderColumnSimple* colInfo = m_columns[i];
284 int colMinWidth = 0;
285 int colWidth = DetermineColumnWidth(i, &colMinWidth);
286 colInfo->SetWidth(colWidth);
287 colInfo->SetMinWidth(colMinWidth);
288 }
289
290 SetColumnCount(colCount);
291 }
292
293 void OnColumWidthsChanged()
294 {
295 const wxPropertyGridPage* page = m_page;
296 unsigned int colCount = page->GetColumnCount();
297
298 for ( unsigned int i=0; i<colCount; i++ )
299 {
300 wxHeaderColumnSimple* colInfo = m_columns[i];
301 int colMinWidth = 0;
302 int colWidth = DetermineColumnWidth(i, &colMinWidth);
303 colInfo->SetWidth(colWidth);
304 colInfo->SetMinWidth(colMinWidth);
305 UpdateColumn(i);
306 }
307 }
308
309 virtual const wxHeaderColumn& GetColumn(unsigned int idx) const
310 {
311 return *m_columns[idx];
312 }
313
314 void SetColumnTitle(unsigned int idx, const wxString& title)
315 {
316 EnsureColumnCount(idx+1);
317 m_columns[idx]->SetTitle(title);
318 }
319
320private:
321 void EnsureColumnCount(unsigned int count)
322 {
323 while ( m_columns.size() < count )
324 {
325 wxHeaderColumnSimple* colInfo = new wxHeaderColumnSimple("");
326 m_columns.push_back(colInfo);
327 }
328 }
329
330 void OnSetColumnWidth(int col, int colWidth)
331 {
332 wxPropertyGrid* pg = m_manager->GetGrid();
333
334 // Compensate for the internal border
335 int x = -((pg->GetSize().x - pg->GetClientSize().x) / 2);
336
337 for ( int i=0; i<col; i++ )
338 x += m_columns[i]->GetWidth();
339
340 x += colWidth;
341
342 pg->DoSetSplitterPosition(x, col,
343 wxPG_SPLITTER_REFRESH |
344 wxPG_SPLITTER_FROM_EVENT);
345 }
346
347 virtual bool ProcessEvent( wxEvent& event )
348 {
349 if ( event.IsKindOf(wxCLASSINFO(wxHeaderCtrlEvent)) )
350 {
351 wxHeaderCtrlEvent& hcEvent =
352 static_cast<wxHeaderCtrlEvent&>(event);
353
354 wxPropertyGrid* pg = m_manager->GetGrid();
355 int col = hcEvent.GetColumn();
356 int evtType = event.GetEventType();
357
358 if ( evtType == wxEVT_HEADER_RESIZING )
359 {
360 int colWidth = hcEvent.GetWidth();
361
362 OnSetColumnWidth(col, colWidth);
363
364 pg->SendEvent(wxEVT_PG_COL_DRAGGING,
365 NULL, NULL, 0,
366 (unsigned int)col);
367
368 return true;
369 }
370 else if ( evtType == wxEVT_HEADER_BEGIN_RESIZE )
371 {
372 // Never allow column resize if layout is static
373 if ( m_manager->HasFlag(wxPG_STATIC_SPLITTER) )
374 hcEvent.Veto();
375 // Allow application to veto dragging
376 else if ( pg->SendEvent(wxEVT_PG_COL_BEGIN_DRAG,
377 NULL, NULL, 0,
378 (unsigned int)col) )
379 hcEvent.Veto();
380
381 return true;
382 }
383 else if ( evtType == wxEVT_HEADER_END_RESIZE )
384 {
385 pg->SendEvent(wxEVT_PG_COL_END_DRAG,
386 NULL, NULL, 0,
387 (unsigned int)col);
388
389 return true;
390 }
391 }
392
393 return wxHeaderCtrl::ProcessEvent(event);
394 }
395
396 wxPropertyGridManager* m_manager;
397 const wxPropertyGridPage* m_page;
398 wxVector<wxHeaderColumnSimple*> m_columns;
399};
400
401#endif // wxUSE_HEADERCTRL
402
403// -----------------------------------------------------------------------
404// wxPropertyGridManager
405// -----------------------------------------------------------------------
406
407// Final default splitter y is client height minus this.
408#define wxPGMAN_DEFAULT_NEGATIVE_SPLITTER_Y 100
409
410// -----------------------------------------------------------------------
411
412IMPLEMENT_CLASS(wxPropertyGridManager, wxPanel)
413
414// -----------------------------------------------------------------------
415
416BEGIN_EVENT_TABLE(wxPropertyGridManager, wxPanel)
417 EVT_MOTION(wxPropertyGridManager::OnMouseMove)
418 EVT_SIZE(wxPropertyGridManager::OnResize)
419 EVT_PAINT(wxPropertyGridManager::OnPaint)
420 EVT_LEFT_DOWN(wxPropertyGridManager::OnMouseClick)
421 EVT_LEFT_UP(wxPropertyGridManager::OnMouseUp)
422 EVT_LEAVE_WINDOW(wxPropertyGridManager::OnMouseEntry)
423 //EVT_ENTER_WINDOW(wxPropertyGridManager::OnMouseEntry)
424END_EVENT_TABLE()
425
426// -----------------------------------------------------------------------
427
428wxPropertyGridManager::wxPropertyGridManager()
429 : wxPanel()
430{
431 Init1();
432}
433
434// -----------------------------------------------------------------------
435
436wxPropertyGridManager::wxPropertyGridManager( wxWindow *parent,
437 wxWindowID id,
438 const wxPoint& pos,
439 const wxSize& size,
440 long style,
441 const wxString& name )
442 : wxPanel()
443{
444 Init1();
445 Create(parent,id,pos,size,style,name);
446}
447
448// -----------------------------------------------------------------------
449
450bool wxPropertyGridManager::Create( wxWindow *parent,
451 wxWindowID id,
452 const wxPoint& pos,
453 const wxSize& size,
454 long style,
455 const wxString& name )
456{
457 if ( !m_pPropGrid )
458 m_pPropGrid = CreatePropertyGrid();
459
460 bool res = wxPanel::Create( parent, id, pos, size,
461 (style&0xFFFF0000)|wxWANTS_CHARS,
462 name );
463 Init2(style);
464
465 // FIXME: this changes call ordering so wxPropertyGrid is created
466 // immediately, before SetExtraStyle has a chance to be called. However,
467 // without it, we may get assertions if size is wxDefaultSize.
468 //SetInitialSize(size);
469
470 return res;
471}
472
473// -----------------------------------------------------------------------
474
475//
476// Initialize values to defaults
477//
478void wxPropertyGridManager::Init1()
479{
480
481 m_pPropGrid = NULL;
482
483#if wxUSE_TOOLBAR
484 m_pToolbar = NULL;
485#endif
486#if wxUSE_HEADERCTRL
487 m_pHeaderCtrl = NULL;
488 m_showHeader = false;
489#endif
490 m_pTxtHelpCaption = NULL;
491 m_pTxtHelpContent = NULL;
492
493 m_emptyPage = NULL;
494
495 m_selPage = -1;
496
497 m_width = m_height = 0;
498
499 m_splitterHeight = 5;
500
501 m_splitterY = -1; // -1 causes default to be set.
502
503 m_nextDescBoxSize = -1;
504
505 m_categorizedModeToolId = -1;
506 m_alphabeticModeToolId = -1;
507
508 m_extraHeight = 0;
509 m_dragStatus = 0;
510 m_onSplitter = 0;
511 m_iFlags = 0;
512}
513
514// -----------------------------------------------------------------------
515
516// These flags are always used in wxPropertyGrid integrated in wxPropertyGridManager.
517#define wxPG_MAN_PROPGRID_FORCED_FLAGS ( wxBORDER_THEME | \
518 wxNO_FULL_REPAINT_ON_RESIZE| \
519 wxCLIP_CHILDREN)
520
521// Which flags can be passed to underlying wxPropertyGrid.
522#define wxPG_MAN_PASS_FLAGS_MASK (0xFFF0|wxTAB_TRAVERSAL)
523
524//
525// Initialize after parent etc. set
526//
527void wxPropertyGridManager::Init2( int style )
528{
529
530 if ( m_iFlags & wxPG_FL_INITIALIZED )
531 return;
532
533 m_windowStyle |= (style&0x0000FFFF);
534
535 wxSize csz = GetClientSize();
536
537 m_cursorSizeNS = wxCursor(wxCURSOR_SIZENS);
538
539 // Prepare the first page
540 // NB: But just prepare - you still need to call Add/InsertPage
541 // to actually add properties on it.
542 wxPropertyGridPage* pd = new wxPropertyGridPage();
543 pd->m_isDefault = true;
544 pd->m_manager = this;
545 wxPropertyGridPageState* state = pd->GetStatePtr();
546 state->m_pPropGrid = m_pPropGrid;
547 m_arrPages.push_back( pd );
548 m_pPropGrid->m_pState = state;
549
550 wxWindowID baseId = GetId();
551 wxWindowID useId = baseId;
552 if ( baseId < 0 )
553 baseId = wxPG_MAN_ALTERNATE_BASE_ID;
554
555#ifdef __WXMAC__
556 // Smaller controls on Mac
557 SetWindowVariant(wxWINDOW_VARIANT_SMALL);
558#endif
559
560 long propGridFlags = (m_windowStyle&wxPG_MAN_PASS_FLAGS_MASK)
561 |wxPG_MAN_PROPGRID_FORCED_FLAGS;
562
563 propGridFlags &= ~wxBORDER_MASK;
564
565 if ((style & wxPG_NO_INTERNAL_BORDER) == 0)
566 {
567 propGridFlags |= wxBORDER_THEME;
568 }
569 else
570 {
571 propGridFlags |= wxBORDER_NONE;
572 wxWindow::SetExtraStyle(wxPG_EX_TOOLBAR_SEPARATOR);
573 }
574
575 // Create propertygrid.
576 m_pPropGrid->Create(this,baseId,wxPoint(0,0),csz, propGridFlags);
577
578 m_pPropGrid->m_eventObject = this;
579
580 m_pPropGrid->SetId(useId);
581
582 m_pPropGrid->m_iFlags |= wxPG_FL_IN_MANAGER;
583
584 m_pState = m_pPropGrid->m_pState;
585
586 m_pPropGrid->SetExtraStyle(wxPG_EX_INIT_NOCAT);
587
588 // Connect to property grid onselect event.
589 // NB: Even if wxID_ANY is used, this doesn't connect properly in wxPython
590 // (see wxPropertyGridManager::ProcessEvent).
591 Connect(m_pPropGrid->GetId(),
592 wxEVT_PG_SELECTED,
593 wxPropertyGridEventHandler(wxPropertyGridManager::OnPropertyGridSelect));
594
595 Connect(m_pPropGrid->GetId(),
596 wxEVT_PG_COL_DRAGGING,
597 wxPropertyGridEventHandler(wxPropertyGridManager::OnPGColDrag));
598
599 // Optional initial controls.
600 m_width = -12345;
601
602 m_iFlags |= wxPG_FL_INITIALIZED;
603
604}
605
606// -----------------------------------------------------------------------
607
608wxPropertyGridManager::~wxPropertyGridManager()
609{
610 END_MOUSE_CAPTURE
611
612 //m_pPropGrid->ClearSelection();
613 wxDELETE(m_pPropGrid);
614
615 size_t i;
616 for ( i=0; i<m_arrPages.size(); i++ )
617 {
618 delete m_arrPages[i];
619 }
620
621 delete m_emptyPage;
622}
623
624// -----------------------------------------------------------------------
625
626wxPropertyGrid* wxPropertyGridManager::CreatePropertyGrid() const
627{
628 return new wxPropertyGrid();
629}
630
631// -----------------------------------------------------------------------
632
633void wxPropertyGridManager::SetId( wxWindowID winid )
634{
635 wxWindow::SetId(winid);
636
637 // TODO: Reconnect propgrid event handler(s).
638
639 m_pPropGrid->SetId(winid);
640}
641
642// -----------------------------------------------------------------------
643
644wxSize wxPropertyGridManager::DoGetBestSize() const
645{
646 return wxSize(60,150);
647}
648
649// -----------------------------------------------------------------------
650
651bool wxPropertyGridManager::SetFont( const wxFont& font )
652{
653 bool res = wxWindow::SetFont(font);
654 m_pPropGrid->SetFont(font);
655
656 // TODO: Need to do caption recacalculations for other pages as well.
657 unsigned int i;
658 for ( i=0; i<m_arrPages.size(); i++ )
659 {
660 wxPropertyGridPage* page = GetPage(i);
661
662 if ( page != m_pPropGrid->GetState() )
663 page->CalculateFontAndBitmapStuff(-1);
664 }
665
666 return res;
667}
668
669// -----------------------------------------------------------------------
670
671void wxPropertyGridManager::SetExtraStyle( long exStyle )
672{
673 wxWindow::SetExtraStyle( exStyle );
674 m_pPropGrid->SetExtraStyle( exStyle & 0xFFFFF000 );
675#if wxUSE_TOOLBAR
676 if ( (exStyle & wxPG_EX_NO_FLAT_TOOLBAR) && m_pToolbar )
677 RecreateControls();
678#endif
679}
680
681// -----------------------------------------------------------------------
682
683void wxPropertyGridManager::Freeze()
684{
685 m_pPropGrid->Freeze();
686 wxWindow::Freeze();
687}
688
689// -----------------------------------------------------------------------
690
691void wxPropertyGridManager::Thaw()
692{
693 wxWindow::Thaw();
694 m_pPropGrid->Thaw();
695}
696
697// -----------------------------------------------------------------------
698
699void wxPropertyGridManager::SetWindowStyleFlag( long style )
700{
701 int oldWindowStyle = GetWindowStyleFlag();
702
703 wxWindow::SetWindowStyleFlag( style );
704 m_pPropGrid->SetWindowStyleFlag( (m_pPropGrid->GetWindowStyleFlag()&~(wxPG_MAN_PASS_FLAGS_MASK)) |
705 (style&wxPG_MAN_PASS_FLAGS_MASK) );
706
707 // Need to re-position windows?
708 if ( (oldWindowStyle & (wxPG_TOOLBAR|wxPG_DESCRIPTION)) !=
709 (style & (wxPG_TOOLBAR|wxPG_DESCRIPTION)) )
710 {
711 RecreateControls();
712 }
713}
714
715// -----------------------------------------------------------------------
716
717bool wxPropertyGridManager::Reparent( wxWindowBase *newParent )
718{
719 if ( m_pPropGrid )
720 m_pPropGrid->OnTLPChanging((wxWindow*)newParent);
721
722 bool res = wxPanel::Reparent(newParent);
723
724 return res;
725}
726
727// -----------------------------------------------------------------------
728
729// Actually shows given page.
730bool wxPropertyGridManager::DoSelectPage( int index )
731{
732 // -1 means no page was selected
733 //wxASSERT( m_selPage >= 0 );
734
735 wxCHECK_MSG( index >= -1 && index < (int)GetPageCount(),
736 false,
737 wxT("invalid page index") );
738
739 if ( m_selPage == index )
740 return true;
741
742 if ( m_pPropGrid->GetSelection() )
743 {
744 if ( !m_pPropGrid->ClearSelection() )
745 return false;
746 }
747
748#if wxUSE_TOOLBAR
749 wxPropertyGridPage* prevPage;
750
751 if ( m_selPage >= 0 )
752 prevPage = GetPage(m_selPage);
753 else
754 prevPage = m_emptyPage;
755#endif
756
757 wxPropertyGridPage* nextPage;
758
759 if ( index >= 0 )
760 {
761 nextPage = m_arrPages[index];
762
763 nextPage->OnShow();
764 }
765 else
766 {
767 if ( !m_emptyPage )
768 {
769 m_emptyPage = new wxPropertyGridPage();
770 m_emptyPage->m_pPropGrid = m_pPropGrid;
771 }
772
773 nextPage = m_emptyPage;
774 }
775
776 m_iFlags |= wxPG_FL_DESC_REFRESH_REQUIRED;
777
778 m_pPropGrid->SwitchState( nextPage->GetStatePtr() );
779
780 m_pState = m_pPropGrid->m_pState;
781
782 m_selPage = index;
783
784#if wxUSE_TOOLBAR
785 if ( m_pToolbar )
786 {
787 if ( index >= 0 )
788 m_pToolbar->ToggleTool( nextPage->m_toolId, true );
789 else
790 m_pToolbar->ToggleTool( prevPage->m_toolId, false );
791 }
792#endif
793
794#if wxUSE_HEADERCTRL
795 if ( m_showHeader )
796 m_pHeaderCtrl->OnPageChanged(nextPage);
797#endif
798
799 return true;
800}
801
802// -----------------------------------------------------------------------
803
804// Changes page *and* set the target page for insertion operations.
805void wxPropertyGridManager::SelectPage( int index )
806{
807 DoSelectPage(index);
808}
809
810// -----------------------------------------------------------------------
811
812int wxPropertyGridManager::GetPageByName( const wxString& name ) const
813{
814 size_t i;
815 for ( i=0; i<GetPageCount(); i++ )
816 {
817 if ( m_arrPages[i]->m_label == name )
818 return i;
819 }
820 return wxNOT_FOUND;
821}
822
823// -----------------------------------------------------------------------
824
825int wxPropertyGridManager::GetPageByState( const wxPropertyGridPageState* pState ) const
826{
827 wxASSERT( pState );
828
829 size_t i;
830 for ( i=0; i<GetPageCount(); i++ )
831 {
832 if ( pState == m_arrPages[i]->GetStatePtr() )
833 return i;
834 }
835
836 return wxNOT_FOUND;
837}
838
839// -----------------------------------------------------------------------
840
841const wxString& wxPropertyGridManager::GetPageName( int index ) const
842{
843 wxASSERT( index >= 0 && index < (int)GetPageCount() );
844 return m_arrPages[index]->m_label;
845}
846
847// -----------------------------------------------------------------------
848
849wxPropertyGridPageState* wxPropertyGridManager::GetPageState( int page ) const
850{
851 // Do not change this into wxCHECK because returning NULL is important
852 // for wxPropertyGridInterface page enumeration mechanics.
853 if ( page >= (int)GetPageCount() )
854 return NULL;
855
856 if ( page == -1 )
857 return m_pState;
858 return m_arrPages[page];
859}
860
861// -----------------------------------------------------------------------
862
863void wxPropertyGridManager::Clear()
864{
865 m_pPropGrid->ClearSelection(false);
866
867 m_pPropGrid->Freeze();
868
869 int i;
870 for ( i=(int)GetPageCount()-1; i>=0; i-- )
871 RemovePage(i);
872
873 m_pPropGrid->Thaw();
874}
875
876// -----------------------------------------------------------------------
877
878void wxPropertyGridManager::ClearPage( int page )
879{
880 wxASSERT( page >= 0 );
881 wxASSERT( page < (int)GetPageCount() );
882
883 if ( page >= 0 && page < (int)GetPageCount() )
884 {
885 wxPropertyGridPageState* state = m_arrPages[page];
886
887 if ( state == m_pPropGrid->GetState() )
888 m_pPropGrid->Clear();
889 else
890 state->DoClear();
891 }
892}
893
894// -----------------------------------------------------------------------
895
896int wxPropertyGridManager::GetColumnCount( int page ) const
897{
898 wxASSERT( page >= -1 );
899 wxASSERT( page < (int)GetPageCount() );
900
901 return GetPageState(page)->GetColumnCount();
902}
903
904// -----------------------------------------------------------------------
905
906void wxPropertyGridManager::SetColumnCount( int colCount, int page )
907{
908 wxASSERT( page >= -1 );
909 wxASSERT( page < (int)GetPageCount() );
910
911 GetPageState(page)->SetColumnCount( colCount );
912 GetGrid()->Refresh();
913
914#if wxUSE_HEADERCTRL
915 if ( m_showHeader )
916 m_pHeaderCtrl->OnPageUpdated();
917#endif
918}
919// -----------------------------------------------------------------------
920
921size_t wxPropertyGridManager::GetPageCount() const
922{
923 if ( !(m_iFlags & wxPG_MAN_FL_PAGE_INSERTED) )
924 return 0;
925
926 return m_arrPages.size();
927}
928
929// -----------------------------------------------------------------------
930
931wxPropertyGridPage* wxPropertyGridManager::InsertPage( int index,
932 const wxString& label,
933 const wxBitmap& bmp,
934 wxPropertyGridPage* pageObj )
935{
936 if ( index < 0 )
937 index = GetPageCount();
938
939 wxCHECK_MSG( (size_t)index == GetPageCount(), NULL,
940 wxT("wxPropertyGridManager currently only supports appending pages (due to wxToolBar limitation)."));
941
942 bool needInit = true;
943 bool isPageInserted = m_iFlags & wxPG_MAN_FL_PAGE_INSERTED ? true : false;
944
945 wxASSERT( index == 0 || isPageInserted );
946
947 if ( !pageObj )
948 {
949 // No custom page object was given, so we will either re-use the default base
950 // page (if index==0), or create a new default page object.
951 if ( !isPageInserted )
952 {
953 pageObj = GetPage(0);
954 // Of course, if the base page was custom, we need to delete and
955 // re-create it.
956 if ( !pageObj->m_isDefault )
957 {
958 delete pageObj;
959 pageObj = new wxPropertyGridPage();
960 m_arrPages[0] = pageObj;
961 }
962 needInit = false;
963 }
964 else
965 {
966 pageObj = new wxPropertyGridPage();
967 }
968 pageObj->m_isDefault = true;
969 }
970 else
971 {
972 if ( !isPageInserted )
973 {
974 // Initial page needs to be deleted and replaced
975 delete GetPage(0);
976 m_arrPages[0] = pageObj;
977 m_pPropGrid->m_pState = pageObj->GetStatePtr();
978 }
979 }
980
981 wxPropertyGridPageState* state = pageObj->GetStatePtr();
982
983 pageObj->m_manager = this;
984
985 if ( needInit )
986 {
987 state->m_pPropGrid = m_pPropGrid;
988 state->InitNonCatMode();
989 }
990
991 if ( !label.empty() )
992 {
993 wxASSERT_MSG( !pageObj->m_label.length(),
994 wxT("If page label is given in constructor, empty label must be given in AddPage"));
995 pageObj->m_label = label;
996 }
997
998 pageObj->m_toolId = -1;
999
1000 if ( !HasFlag(wxPG_SPLITTER_AUTO_CENTER) )
1001 pageObj->m_dontCenterSplitter = true;
1002
1003 if ( isPageInserted )
1004 m_arrPages.push_back( pageObj );
1005
1006#if wxUSE_TOOLBAR
1007 if ( m_windowStyle & wxPG_TOOLBAR )
1008 {
1009 if ( !m_pToolbar )
1010 RecreateControls();
1011
1012 if ( !(GetExtraStyle()&wxPG_EX_HIDE_PAGE_BUTTONS) )
1013 {
1014 wxASSERT( m_pToolbar );
1015
1016 // Add separator before first page.
1017 if ( GetPageCount() < 2 && (GetExtraStyle()&wxPG_EX_MODE_BUTTONS) &&
1018 m_pToolbar->GetToolsCount() < 3 )
1019 m_pToolbar->AddSeparator();
1020
1021 wxToolBarToolBase* tool;
1022
1023 if ( &bmp != &wxNullBitmap )
1024 tool = m_pToolbar->AddTool(wxID_ANY, label, bmp,
1025 label, wxITEM_RADIO);
1026 else
1027 tool = m_pToolbar->AddTool(wxID_ANY, label,
1028 wxBitmap(gs_xpm_defpage),
1029 label, wxITEM_RADIO);
1030
1031 pageObj->m_toolId = tool->GetId();
1032
1033 // Connect to toolbar button events.
1034 Connect(pageObj->m_toolId,
1035 wxEVT_TOOL,
1036 wxCommandEventHandler(
1037 wxPropertyGridManager::OnToolbarClick));
1038
1039 m_pToolbar->Realize();
1040 }
1041 }
1042#else
1043 wxUnusedVar(bmp);
1044#endif
1045
1046 // If selected page was above the point of insertion, fix the current page index
1047 if ( isPageInserted )
1048 {
1049 if ( m_selPage >= index )
1050 {
1051 m_selPage += 1;
1052 }
1053 }
1054 else
1055 {
1056 // Set this value only when adding the first page
1057 m_selPage = 0;
1058 }
1059
1060 pageObj->Init();
1061
1062 m_iFlags |= wxPG_MAN_FL_PAGE_INSERTED;
1063
1064 wxASSERT( pageObj->GetGrid() );
1065
1066 return pageObj;
1067}
1068
1069// -----------------------------------------------------------------------
1070
1071bool wxPropertyGridManager::IsAnyModified() const
1072{
1073 size_t i;
1074 for ( i=0; i<GetPageCount(); i++ )
1075 {
1076 if ( m_arrPages[i]->GetStatePtr()->m_anyModified )
1077 return true;
1078 }
1079 return false;
1080}
1081
1082// -----------------------------------------------------------------------
1083
1084bool wxPropertyGridManager::IsPageModified( size_t index ) const
1085{
1086 if ( m_arrPages[index]->GetStatePtr()->m_anyModified )
1087 return true;
1088 return false;
1089}
1090
1091// -----------------------------------------------------------------------
1092
1093#if wxUSE_HEADERCTRL
1094void wxPropertyGridManager::ShowHeader(bool show)
1095{
1096 if ( show != m_showHeader)
1097 {
1098 m_showHeader = show;
1099 RecreateControls();
1100 }
1101}
1102#endif
1103
1104// -----------------------------------------------------------------------
1105
1106#if wxUSE_HEADERCTRL
1107void wxPropertyGridManager::SetColumnTitle( int idx, const wxString& title )
1108{
1109 if ( !m_pHeaderCtrl )
1110 ShowHeader();
1111
1112 m_pHeaderCtrl->SetColumnTitle(idx, title);
1113}
1114#endif
1115
1116// -----------------------------------------------------------------------
1117
1118bool wxPropertyGridManager::IsPropertySelected( wxPGPropArg id ) const
1119{
1120 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
1121 for ( unsigned int i=0; i<GetPageCount(); i++ )
1122 {
1123 if ( GetPageState(i)->DoIsPropertySelected(p) )
1124 return true;
1125 }
1126 return false;
1127}
1128
1129// -----------------------------------------------------------------------
1130
1131wxPGProperty* wxPropertyGridManager::GetPageRoot( int index ) const
1132{
1133 wxASSERT( index >= 0 );
1134 wxASSERT( index < (int)m_arrPages.size() );
1135
1136 return m_arrPages[index]->GetStatePtr()->m_properties;
1137}
1138
1139// -----------------------------------------------------------------------
1140
1141bool wxPropertyGridManager::RemovePage( int page )
1142{
1143 wxCHECK_MSG( (page >= 0) && (page < (int)GetPageCount()),
1144 false,
1145 wxT("invalid page index") );
1146
1147 wxPropertyGridPage* pd = m_arrPages[page];
1148
1149 if ( m_arrPages.size() == 1 )
1150 {
1151 // Last page: do not remove page entry
1152 m_pPropGrid->Clear();
1153 m_selPage = -1;
1154 m_iFlags &= ~wxPG_MAN_FL_PAGE_INSERTED;
1155 pd->m_label.clear();
1156 }
1157
1158 // Change selection if current is page
1159 else if ( page == m_selPage )
1160 {
1161 if ( !m_pPropGrid->ClearSelection() )
1162 return false;
1163
1164 // Substitute page to select
1165 int substitute = page - 1;
1166 if ( substitute < 0 )
1167 substitute = page + 1;
1168
1169 SelectPage(substitute);
1170 }
1171
1172 // Remove toolbar icon
1173#if wxUSE_TOOLBAR
1174 if ( HasFlag(wxPG_TOOLBAR) )
1175 {
1176 wxASSERT( m_pToolbar );
1177
1178 int toolPos = GetExtraStyle() & wxPG_EX_MODE_BUTTONS ? 3 : 0;
1179 toolPos += page;
1180
1181 // Delete separator as well, for consistency
1182 if ( (GetExtraStyle() & wxPG_EX_MODE_BUTTONS) &&
1183 GetPageCount() == 1 )
1184 m_pToolbar->DeleteToolByPos(2);
1185
1186 m_pToolbar->DeleteToolByPos(toolPos);
1187 }
1188#endif
1189
1190 if ( m_arrPages.size() > 1 )
1191 {
1192 m_arrPages.erase(m_arrPages.begin() + page);
1193 delete pd;
1194 }
1195
1196 // Adjust indexes that were above removed
1197 if ( m_selPage > page )
1198 m_selPage--;
1199
1200 return true;
1201}
1202
1203// -----------------------------------------------------------------------
1204
1205bool wxPropertyGridManager::ProcessEvent( wxEvent& event )
1206{
1207 int evtType = event.GetEventType();
1208
1209 // NB: For some reason, under wxPython, Connect in Init doesn't work properly,
1210 // so we'll need to call OnPropertyGridSelect manually. Multiple call's
1211 // don't really matter.
1212 if ( evtType == wxEVT_PG_SELECTED )
1213 OnPropertyGridSelect((wxPropertyGridEvent&)event);
1214
1215 // Property grid events get special attention
1216 if ( evtType >= wxPG_BASE_EVT_TYPE &&
1217 evtType < (wxPG_MAX_EVT_TYPE) &&
1218 m_selPage >= 0 )
1219 {
1220 wxPropertyGridPage* page = GetPage(m_selPage);
1221 wxPropertyGridEvent* pgEvent = wxDynamicCast(&event, wxPropertyGridEvent);
1222
1223 // Add property grid events to appropriate custom pages
1224 // but stop propagating to parent if page says it is
1225 // handling everything.
1226 if ( pgEvent && !page->m_isDefault )
1227 {
1228 /*if ( pgEvent->IsPending() )
1229 page->AddPendingEvent(event);
1230 else*/
1231 page->ProcessEvent(event);
1232
1233 if ( page->IsHandlingAllEvents() )
1234 event.StopPropagation();
1235 }
1236 }
1237
1238 return wxPanel::ProcessEvent(event);
1239}
1240
1241// -----------------------------------------------------------------------
1242
1243void wxPropertyGridManager::RepaintDescBoxDecorations( wxDC& dc,
1244 int newSplitterY,
1245 int newWidth,
1246 int newHeight )
1247{
1248 // Draw background
1249 wxColour bgcol = GetBackgroundColour();
1250 dc.SetBrush(bgcol);
1251 dc.SetPen(bgcol);
1252 int rectHeight = m_splitterHeight;
1253 dc.DrawRectangle(0, newSplitterY, newWidth, rectHeight);
1254 dc.SetPen( wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW) );
1255 int splitterBottom = newSplitterY + m_splitterHeight - 1;
1256 int boxHeight = newHeight - splitterBottom;
1257 if ( boxHeight > 1 )
1258 dc.DrawRectangle(0, splitterBottom, newWidth, boxHeight);
1259 else
1260 dc.DrawLine(0, splitterBottom, newWidth, splitterBottom);
1261}
1262
1263// -----------------------------------------------------------------------
1264
1265void wxPropertyGridManager::UpdateDescriptionBox( int new_splittery, int new_width, int new_height )
1266{
1267 int use_hei = new_height;
1268 use_hei--;
1269
1270 // Fix help control positions.
1271 int cap_hei = m_pPropGrid->m_fontHeight;
1272 int cap_y = new_splittery+m_splitterHeight+5;
1273 int cnt_y = cap_y+cap_hei+3;
1274 int sub_cap_hei = cap_y+cap_hei-use_hei;
1275 int cnt_hei = use_hei-cnt_y;
1276 if ( sub_cap_hei > 0 )
1277 {
1278 cap_hei -= sub_cap_hei;
1279 cnt_hei = 0;
1280 }
1281 if ( cap_hei <= 2 )
1282 {
1283 m_pTxtHelpCaption->Show( false );
1284 m_pTxtHelpContent->Show( false );
1285 }
1286 else
1287 {
1288 m_pTxtHelpCaption->SetSize(3,cap_y,new_width-6,cap_hei);
1289 m_pTxtHelpCaption->Wrap(-1);
1290 m_pTxtHelpCaption->Show( true );
1291 if ( cnt_hei <= 2 )
1292 {
1293 m_pTxtHelpContent->Show( false );
1294 }
1295 else
1296 {
1297 m_pTxtHelpContent->SetSize(3,cnt_y,new_width-6,cnt_hei);
1298 m_pTxtHelpContent->Show( true );
1299 }
1300 }
1301
1302 wxRect r(0, new_splittery, new_width, new_height-new_splittery);
1303 RefreshRect(r);
1304
1305 m_splitterY = new_splittery;
1306
1307 m_iFlags &= ~(wxPG_FL_DESC_REFRESH_REQUIRED);
1308}
1309
1310// -----------------------------------------------------------------------
1311
1312void wxPropertyGridManager::RecalculatePositions( int width, int height )
1313{
1314 int propgridY = 0;
1315 int propgridBottomY = height;
1316
1317 // Toolbar at the top.
1318#if wxUSE_TOOLBAR
1319 if ( m_pToolbar )
1320 {
1321 m_pToolbar->SetSize(0, 0, width, -1);
1322 propgridY += m_pToolbar->GetSize().y;
1323
1324 if (GetExtraStyle() & wxPG_EX_TOOLBAR_SEPARATOR)
1325 propgridY += 1;
1326 }
1327#endif
1328
1329 // Header comes after the tool bar
1330#if wxUSE_HEADERCTRL
1331 if ( m_showHeader )
1332 {
1333 m_pHeaderCtrl->SetSize(0, propgridY, width, -1);
1334 propgridY += m_pHeaderCtrl->GetSize().y;
1335 }
1336#endif
1337
1338 // Help box.
1339 if ( m_pTxtHelpCaption )
1340 {
1341 int new_splittery = m_splitterY;
1342
1343 // Move m_splitterY
1344 if ( ( m_splitterY >= 0 || m_nextDescBoxSize ) && m_height > 32 )
1345 {
1346 if ( m_nextDescBoxSize >= 0 )
1347 {
1348 new_splittery = m_height - m_nextDescBoxSize - m_splitterHeight;
1349 m_nextDescBoxSize = -1;
1350 }
1351 new_splittery += (height-m_height);
1352 }
1353 else
1354 {
1355 new_splittery = height - wxPGMAN_DEFAULT_NEGATIVE_SPLITTER_Y;
1356 if ( new_splittery < 32 )
1357 new_splittery = 32;
1358 }
1359
1360 // Check if beyond minimum.
1361 int nspy_min = propgridY + m_pPropGrid->m_lineHeight;
1362 if ( new_splittery < nspy_min )
1363 new_splittery = nspy_min;
1364
1365 propgridBottomY = new_splittery;
1366
1367 UpdateDescriptionBox( new_splittery, width, height );
1368 }
1369
1370 if ( m_iFlags & wxPG_FL_INITIALIZED )
1371 {
1372 int pgh = propgridBottomY - propgridY;
1373 if ( pgh < 0 )
1374 pgh = 0;
1375 m_pPropGrid->SetSize( 0, propgridY, width, pgh );
1376
1377 m_extraHeight = height - pgh;
1378
1379 m_width = width;
1380 m_height = height;
1381 }
1382}
1383
1384// -----------------------------------------------------------------------
1385
1386void wxPropertyGridManager::SetDescBoxHeight( int ht, bool refresh )
1387{
1388 if ( m_windowStyle & wxPG_DESCRIPTION )
1389 {
1390 if ( ht != GetDescBoxHeight() )
1391 {
1392 m_nextDescBoxSize = ht;
1393 if ( refresh )
1394 RecalculatePositions(m_width, m_height);
1395 }
1396 }
1397}
1398
1399// -----------------------------------------------------------------------
1400
1401int wxPropertyGridManager::GetDescBoxHeight() const
1402{
1403 return GetClientSize().y - m_splitterY - m_splitterHeight;
1404}
1405
1406// -----------------------------------------------------------------------
1407
1408void wxPropertyGridManager::OnPaint( wxPaintEvent& WXUNUSED(event) )
1409{
1410 wxPaintDC dc(this);
1411
1412 // Update everything inside the box
1413 wxRect r = GetUpdateRegion().GetBox();
1414
1415 if (GetExtraStyle() & wxPG_EX_TOOLBAR_SEPARATOR)
1416 {
1417 if (m_pToolbar && m_pPropGrid)
1418 {
1419 wxPen marginPen(m_pPropGrid->GetMarginColour());
1420 dc.SetPen(marginPen);
1421
1422 int y = m_pPropGrid->GetPosition().y-1;
1423 dc.DrawLine(0, y, GetClientSize().x, y);
1424 }
1425 }
1426
1427 // Repaint splitter and any other description box decorations
1428 if ( (r.y + r.height) >= m_splitterY && m_splitterY != -1)
1429 RepaintDescBoxDecorations( dc, m_splitterY, m_width, m_height );
1430}
1431
1432// -----------------------------------------------------------------------
1433
1434void wxPropertyGridManager::Refresh(bool eraseBackground, const wxRect* rect )
1435{
1436 m_pPropGrid->Refresh(eraseBackground);
1437 wxWindow::Refresh(eraseBackground,rect);
1438}
1439
1440// -----------------------------------------------------------------------
1441
1442void wxPropertyGridManager::RefreshProperty( wxPGProperty* p )
1443{
1444 wxPropertyGrid* grid = p->GetGrid();
1445
1446 if ( GetPage(m_selPage)->GetStatePtr() == p->GetParent()->GetParentState() )
1447 grid->RefreshProperty(p);
1448}
1449
1450// -----------------------------------------------------------------------
1451
1452void wxPropertyGridManager::RecreateControls()
1453{
1454
1455 bool was_shown = IsShown();
1456 if ( was_shown )
1457 Show ( false );
1458
1459#if wxUSE_TOOLBAR
1460 if ( m_windowStyle & wxPG_TOOLBAR )
1461 {
1462 // Has toolbar.
1463 if ( !m_pToolbar )
1464 {
1465 long toolBarFlags = ((GetExtraStyle()&wxPG_EX_NO_FLAT_TOOLBAR)?0:wxTB_FLAT);
1466 if (GetExtraStyle() & wxPG_EX_NO_TOOLBAR_DIVIDER)
1467 toolBarFlags |= wxTB_NODIVIDER;
1468
1469 m_pToolbar = new wxToolBar(this, wxID_ANY,
1470 wxDefaultPosition,
1471 wxDefaultSize,
1472 toolBarFlags);
1473 m_pToolbar->SetToolBitmapSize(wxSize(16, 15));
1474
1475 #if defined(__WXMSW__)
1476 // Eliminate toolbar flicker on XP
1477 // NOTE: Not enabled since it corrupts drawing somewhat.
1478
1479 /*
1480 #ifndef WS_EX_COMPOSITED
1481 #define WS_EX_COMPOSITED 0x02000000L
1482 #endif
1483
1484 HWND hWnd = (HWND)m_pToolbar->GetHWND();
1485
1486 ::SetWindowLong( hWnd, GWL_EXSTYLE,
1487 ::GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_COMPOSITED );
1488 */
1489
1490 #endif
1491
1492 m_pToolbar->SetCursor ( *wxSTANDARD_CURSOR );
1493
1494 if ( (GetExtraStyle()&wxPG_EX_MODE_BUTTONS) )
1495 {
1496 wxString desc1(_("Categorized Mode"));
1497 wxString desc2(_("Alphabetic Mode"));
1498
1499 wxToolBarToolBase* tool;
1500
1501 tool = m_pToolbar->AddTool(wxID_ANY,
1502 desc1,
1503 wxBitmap(gs_xpm_catmode),
1504 desc1,
1505 wxITEM_RADIO);
1506 m_categorizedModeToolId = tool->GetId();
1507
1508 tool = m_pToolbar->AddTool(wxID_ANY,
1509 desc2,
1510 wxBitmap(gs_xpm_noncatmode),
1511 desc2,
1512 wxITEM_RADIO);
1513 m_alphabeticModeToolId = tool->GetId();
1514
1515 m_pToolbar->Realize();
1516
1517 Connect(m_categorizedModeToolId,
1518 wxEVT_TOOL,
1519 wxCommandEventHandler(
1520 wxPropertyGridManager::OnToolbarClick));
1521 Connect(m_alphabeticModeToolId,
1522 wxEVT_TOOL,
1523 wxCommandEventHandler(
1524 wxPropertyGridManager::OnToolbarClick));
1525 }
1526 else
1527 {
1528 m_categorizedModeToolId = -1;
1529 m_alphabeticModeToolId = -1;
1530 }
1531
1532 }
1533
1534 if ( (GetExtraStyle() & wxPG_EX_MODE_BUTTONS) )
1535 {
1536 // Toggle correct mode button.
1537 // TODO: This doesn't work in wxMSW (when changing,
1538 // both items will get toggled).
1539 int toggle_but_on_ind;
1540 int toggle_but_off_ind;
1541 if ( m_pPropGrid->m_pState->IsInNonCatMode() )
1542 {
1543 toggle_but_on_ind = m_alphabeticModeToolId;
1544 toggle_but_off_ind = m_categorizedModeToolId;
1545 }
1546 else
1547 {
1548 toggle_but_on_ind = m_categorizedModeToolId;
1549 toggle_but_off_ind = m_alphabeticModeToolId;
1550 }
1551
1552 m_pToolbar->ToggleTool(toggle_but_on_ind, true);
1553 m_pToolbar->ToggleTool(toggle_but_off_ind, false);
1554 }
1555
1556 }
1557 else
1558 {
1559 // No toolbar.
1560 if ( m_pToolbar )
1561 m_pToolbar->Destroy();
1562 m_pToolbar = NULL;
1563 }
1564#endif
1565
1566#if wxUSE_HEADERCTRL
1567 if ( m_showHeader )
1568 {
1569 wxPGHeaderCtrl* hc;
1570
1571 if ( !m_pHeaderCtrl )
1572 {
1573 hc = new wxPGHeaderCtrl(this);
1574 hc->Create(this, wxID_ANY);
1575 m_pHeaderCtrl = hc;
1576 }
1577 else
1578 {
1579 m_pHeaderCtrl->Show();
1580 }
1581
1582 m_pHeaderCtrl->OnPageChanged(GetCurrentPage());
1583 }
1584 else
1585 {
1586 if ( m_pHeaderCtrl )
1587 m_pHeaderCtrl->Hide();
1588 }
1589#endif
1590
1591 if ( m_windowStyle & wxPG_DESCRIPTION )
1592 {
1593 // Has help box.
1594 m_pPropGrid->m_iFlags |= (wxPG_FL_NOSTATUSBARHELP);
1595
1596 if ( !m_pTxtHelpCaption )
1597 {
1598 m_pTxtHelpCaption = new wxStaticText(this,
1599 wxID_ANY,
1600 wxT(""),
1601 wxDefaultPosition,
1602 wxDefaultSize,
1603 wxALIGN_LEFT|wxST_NO_AUTORESIZE);
1604 m_pTxtHelpCaption->SetFont( m_pPropGrid->m_captionFont );
1605 m_pTxtHelpCaption->SetCursor( *wxSTANDARD_CURSOR );
1606 }
1607 if ( !m_pTxtHelpContent )
1608 {
1609 m_pTxtHelpContent = new wxStaticText(this,
1610 wxID_ANY,
1611 wxT(""),
1612 wxDefaultPosition,
1613 wxDefaultSize,
1614 wxALIGN_LEFT|wxST_NO_AUTORESIZE);
1615 m_pTxtHelpContent->SetCursor( *wxSTANDARD_CURSOR );
1616 }
1617
1618 SetDescribedProperty(GetSelection());
1619 }
1620 else
1621 {
1622 // No help box.
1623 m_pPropGrid->m_iFlags &= ~(wxPG_FL_NOSTATUSBARHELP);
1624
1625 if ( m_pTxtHelpCaption )
1626 m_pTxtHelpCaption->Destroy();
1627
1628 m_pTxtHelpCaption = NULL;
1629
1630 if ( m_pTxtHelpContent )
1631 m_pTxtHelpContent->Destroy();
1632
1633 m_pTxtHelpContent = NULL;
1634 }
1635
1636 int width, height;
1637
1638 GetClientSize(&width,&height);
1639
1640 RecalculatePositions(width,height);
1641
1642 if ( was_shown )
1643 Show ( true );
1644}
1645
1646// -----------------------------------------------------------------------
1647
1648wxPGProperty* wxPropertyGridManager::DoGetPropertyByName( const wxString& name ) const
1649{
1650 size_t i;
1651 for ( i=0; i<GetPageCount(); i++ )
1652 {
1653 wxPropertyGridPageState* pState = m_arrPages[i]->GetStatePtr();
1654 wxPGProperty* p = pState->BaseGetPropertyByName(name);
1655 if ( p )
1656 {
1657 return p;
1658 }
1659 }
1660 return NULL;
1661}
1662
1663// -----------------------------------------------------------------------
1664
1665bool wxPropertyGridManager::EnsureVisible( wxPGPropArg id )
1666{
1667 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
1668
1669 wxPropertyGridPageState* parentState = p->GetParentState();
1670
1671 // Select correct page.
1672 if ( m_pPropGrid->m_pState != parentState )
1673 DoSelectPage( GetPageByState(parentState) );
1674
1675 return m_pPropGrid->EnsureVisible(id);
1676}
1677
1678// -----------------------------------------------------------------------
1679
1680void wxPropertyGridManager::OnToolbarClick( wxCommandEvent &event )
1681{
1682 int id = event.GetId();
1683
1684 if ( id == m_categorizedModeToolId )
1685 {
1686 // Categorized mode.
1687 if ( m_pPropGrid->m_windowStyle & wxPG_HIDE_CATEGORIES )
1688 {
1689 if ( !m_pPropGrid->HasInternalFlag(wxPG_FL_CATMODE_AUTO_SORT) )
1690 m_pPropGrid->m_windowStyle &= ~wxPG_AUTO_SORT;
1691 m_pPropGrid->EnableCategories( true );
1692 }
1693 }
1694 else if ( id == m_alphabeticModeToolId )
1695 {
1696 // Alphabetic mode.
1697 if ( !(m_pPropGrid->m_windowStyle & wxPG_HIDE_CATEGORIES) )
1698 {
1699 if ( m_pPropGrid->HasFlag(wxPG_AUTO_SORT) )
1700 m_pPropGrid->SetInternalFlag(wxPG_FL_CATMODE_AUTO_SORT);
1701 else
1702 m_pPropGrid->ClearInternalFlag(wxPG_FL_CATMODE_AUTO_SORT);
1703
1704 m_pPropGrid->m_windowStyle |= wxPG_AUTO_SORT;
1705 m_pPropGrid->EnableCategories( false );
1706 }
1707 }
1708 else
1709 {
1710 // Page Switching.
1711
1712 int index = -1;
1713 size_t i;
1714 wxPropertyGridPage* pdc;
1715
1716 // Find page with given id.
1717 for ( i=0; i<GetPageCount(); i++ )
1718 {
1719 pdc = m_arrPages[i];
1720 if ( pdc->m_toolId == id )
1721 {
1722 index = i;
1723 break;
1724 }
1725 }
1726
1727 wxASSERT( index >= 0 );
1728
1729 if ( DoSelectPage( index ) )
1730 {
1731 // Event dispatching must be last.
1732 m_pPropGrid->SendEvent( wxEVT_PG_PAGE_CHANGED, NULL );
1733 }
1734 else
1735 {
1736 // TODO: Depress the old button on toolbar.
1737 }
1738 }
1739}
1740
1741// -----------------------------------------------------------------------
1742
1743bool wxPropertyGridManager::SetEditableStateItem( const wxString& name, wxVariant value )
1744{
1745 if ( name == wxS("descboxheight") )
1746 {
1747 SetDescBoxHeight(value.GetLong(), true);
1748 return true;
1749 }
1750 return false;
1751}
1752
1753// -----------------------------------------------------------------------
1754
1755wxVariant wxPropertyGridManager::GetEditableStateItem( const wxString& name ) const
1756{
1757 if ( name == wxS("descboxheight") )
1758 {
1759 return (long) GetDescBoxHeight();
1760 }
1761 return wxNullVariant;
1762}
1763
1764// -----------------------------------------------------------------------
1765
1766void wxPropertyGridManager::SetDescription( const wxString& label, const wxString& content )
1767{
1768 if ( m_pTxtHelpCaption )
1769 {
1770 wxSize osz1 = m_pTxtHelpCaption->GetSize();
1771 wxSize osz2 = m_pTxtHelpContent->GetSize();
1772
1773 m_pTxtHelpCaption->SetLabel(label);
1774 m_pTxtHelpContent->SetLabel(content);
1775
1776 m_pTxtHelpCaption->SetSize(-1,osz1.y);
1777 m_pTxtHelpContent->SetSize(-1,osz2.y);
1778
1779 UpdateDescriptionBox( m_splitterY, m_width, m_height );
1780 }
1781}
1782
1783// -----------------------------------------------------------------------
1784
1785void wxPropertyGridManager::SetDescribedProperty( wxPGProperty* p )
1786{
1787 if ( m_pTxtHelpCaption )
1788 {
1789 if ( p )
1790 {
1791 SetDescription( p->GetLabel(), p->GetHelpString() );
1792 }
1793 else
1794 {
1795 SetDescription( wxEmptyString, wxEmptyString );
1796 }
1797 }
1798}
1799
1800// -----------------------------------------------------------------------
1801
1802void wxPropertyGridManager::SetSplitterLeft( bool subProps, bool allPages )
1803{
1804 if ( !allPages )
1805 {
1806 m_pPropGrid->SetSplitterLeft(subProps);
1807 }
1808 else
1809 {
1810 wxClientDC dc(this);
1811 dc.SetFont(m_pPropGrid->GetFont());
1812
1813 int highest = 0;
1814 unsigned int i;
1815
1816 for ( i=0; i<GetPageCount(); i++ )
1817 {
1818 int maxW = m_pState->GetColumnFitWidth(dc, m_arrPages[i]->m_properties, 0, subProps );
1819 maxW += m_pPropGrid->m_marginWidth;
1820 if ( maxW > highest )
1821 highest = maxW;
1822 m_pState->m_dontCenterSplitter = true;
1823 }
1824
1825 if ( highest > 0 )
1826 SetSplitterPosition( highest );
1827 }
1828
1829#if wxUSE_HEADERCTRL
1830 if ( m_showHeader )
1831 m_pHeaderCtrl->OnColumWidthsChanged();
1832#endif
1833}
1834
1835void wxPropertyGridManager::SetPageSplitterLeft(int page, bool subProps)
1836{
1837 wxASSERT_MSG( (page < (int) GetPageCount()),
1838 wxT("SetPageSplitterLeft() has no effect until pages have been added") );
1839
1840 if (page < (int) GetPageCount())
1841 {
1842 wxClientDC dc(this);
1843 dc.SetFont(m_pPropGrid->GetFont());
1844
1845 int maxW = m_pState->GetColumnFitWidth(dc, m_arrPages[page]->m_properties, 0, subProps );
1846 maxW += m_pPropGrid->m_marginWidth;
1847 SetPageSplitterPosition( page, maxW );
1848
1849#if wxUSE_HEADERCTRL
1850 if ( m_showHeader )
1851 m_pHeaderCtrl->OnColumWidthsChanged();
1852#endif
1853 }
1854}
1855
1856// -----------------------------------------------------------------------
1857
1858void wxPropertyGridManager::OnPropertyGridSelect( wxPropertyGridEvent& event )
1859{
1860 // Check id.
1861 wxASSERT_MSG( GetId() == m_pPropGrid->GetId(),
1862 wxT("wxPropertyGridManager id must be set with wxPropertyGridManager::SetId (not wxWindow::SetId).") );
1863
1864 SetDescribedProperty(event.GetProperty());
1865 event.Skip();
1866}
1867
1868// -----------------------------------------------------------------------
1869
1870void
1871wxPropertyGridManager::OnPGColDrag( wxPropertyGridEvent& WXUNUSED(event) )
1872{
1873#if wxUSE_HEADERCTRL
1874 if ( !m_showHeader )
1875 return;
1876
1877 m_pHeaderCtrl->OnColumWidthsChanged();
1878#endif
1879}
1880
1881// -----------------------------------------------------------------------
1882
1883void wxPropertyGridManager::OnResize( wxSizeEvent& WXUNUSED(event) )
1884{
1885 int width, height;
1886
1887 GetClientSize(&width, &height);
1888
1889 if ( m_width == -12345 )
1890 RecreateControls();
1891
1892 RecalculatePositions(width, height);
1893
1894 if ( m_pPropGrid && m_pPropGrid->m_parent )
1895 {
1896 int pgWidth, pgHeight;
1897 m_pPropGrid->GetClientSize(&pgWidth, &pgHeight);
1898
1899 // Regenerate splitter positions for non-current pages
1900 for ( unsigned int i=0; i<GetPageCount(); i++ )
1901 {
1902 wxPropertyGridPage* page = GetPage(i);
1903 if ( page != m_pPropGrid->GetState() )
1904 {
1905 page->OnClientWidthChange(pgWidth,
1906 pgWidth - page->m_width,
1907 true);
1908 }
1909 }
1910 }
1911
1912#if wxUSE_HEADERCTRL
1913 if ( m_showHeader )
1914 m_pHeaderCtrl->OnColumWidthsChanged();
1915#endif
1916}
1917
1918// -----------------------------------------------------------------------
1919
1920void wxPropertyGridManager::OnMouseEntry( wxMouseEvent& WXUNUSED(event) )
1921{
1922 // Correct cursor. This is required atleast for wxGTK, for which
1923 // setting button's cursor to *wxSTANDARD_CURSOR does not work.
1924 SetCursor( wxNullCursor );
1925 m_onSplitter = 0;
1926}
1927
1928// -----------------------------------------------------------------------
1929
1930void wxPropertyGridManager::OnMouseMove( wxMouseEvent &event )
1931{
1932 if ( !m_pTxtHelpCaption )
1933 return;
1934
1935 int y = event.m_y;
1936
1937 if ( m_dragStatus > 0 )
1938 {
1939 int sy = y - m_dragOffset;
1940
1941 // Calculate drag limits
1942 int bottom_limit = m_height - m_splitterHeight + 1;
1943 int top_limit = m_pPropGrid->m_lineHeight;
1944#if wxUSE_TOOLBAR
1945 if ( m_pToolbar ) top_limit += m_pToolbar->GetSize().y;
1946#endif
1947
1948 if ( sy >= top_limit && sy < bottom_limit )
1949 {
1950
1951 int change = sy - m_splitterY;
1952 if ( change )
1953 {
1954 m_splitterY = sy;
1955
1956 m_pPropGrid->SetSize( m_width, m_splitterY - m_pPropGrid->GetPosition().y );
1957 UpdateDescriptionBox( m_splitterY, m_width, m_height );
1958
1959 m_extraHeight -= change;
1960 InvalidateBestSize();
1961 }
1962
1963 }
1964
1965 }
1966 else
1967 {
1968 if ( y >= m_splitterY && y < (m_splitterY+m_splitterHeight+2) )
1969 {
1970 SetCursor ( m_cursorSizeNS );
1971 m_onSplitter = 1;
1972 }
1973 else
1974 {
1975 if ( m_onSplitter )
1976 {
1977 SetCursor ( wxNullCursor );
1978 }
1979 m_onSplitter = 0;
1980 }
1981 }
1982}
1983
1984// -----------------------------------------------------------------------
1985
1986void wxPropertyGridManager::OnMouseClick( wxMouseEvent &event )
1987{
1988 int y = event.m_y;
1989
1990 // Click on splitter.
1991 if ( y >= m_splitterY && y < (m_splitterY+m_splitterHeight+2) )
1992 {
1993 if ( m_dragStatus == 0 )
1994 {
1995 //
1996 // Begin draggin the splitter
1997 //
1998
1999 BEGIN_MOUSE_CAPTURE
2000
2001 m_dragStatus = 1;
2002
2003 m_dragOffset = y - m_splitterY;
2004
2005 }
2006 }
2007}
2008
2009// -----------------------------------------------------------------------
2010
2011void wxPropertyGridManager::OnMouseUp( wxMouseEvent &event )
2012{
2013 // No event type check - basically calling this method should
2014 // just stop dragging.
2015
2016 if ( m_dragStatus >= 1 )
2017 {
2018 //
2019 // End Splitter Dragging
2020 //
2021
2022 int y = event.m_y;
2023
2024 // DO NOT ENABLE FOLLOWING LINE!
2025 // (it is only here as a reminder to not to do it)
2026 //m_splitterY = y;
2027
2028 // This is necessary to return cursor
2029 END_MOUSE_CAPTURE
2030
2031 // Set back the default cursor, if necessary
2032 if ( y < m_splitterY || y >= (m_splitterY+m_splitterHeight+2) )
2033 {
2034 SetCursor ( wxNullCursor );
2035 }
2036
2037 m_dragStatus = 0;
2038 }
2039}
2040
2041// -----------------------------------------------------------------------
2042
2043void wxPropertyGridManager::SetSplitterPosition( int pos, int splitterColumn )
2044{
2045 wxASSERT_MSG( GetPageCount(),
2046 wxT("SetSplitterPosition() has no effect until pages have been added") );
2047
2048 size_t i;
2049 for ( i=0; i<GetPageCount(); i++ )
2050 {
2051 wxPropertyGridPage* page = GetPage(i);
2052 page->DoSetSplitterPosition( pos, splitterColumn,
2053 wxPG_SPLITTER_REFRESH );
2054 }
2055
2056#if wxUSE_HEADERCTRL
2057 if ( m_showHeader )
2058 m_pHeaderCtrl->OnColumWidthsChanged();
2059#endif
2060}
2061
2062// -----------------------------------------------------------------------
2063
2064void wxPropertyGridManager::SetPageSplitterPosition( int page,
2065 int pos,
2066 int column )
2067{
2068 GetPage(page)->DoSetSplitterPosition( pos, column );
2069
2070#if wxUSE_HEADERCTRL
2071 if ( m_showHeader )
2072 m_pHeaderCtrl->OnColumWidthsChanged();
2073#endif
2074}
2075
2076// -----------------------------------------------------------------------
2077// wxPGVIterator_Manager
2078// -----------------------------------------------------------------------
2079
2080// Default returned by wxPropertyGridInterface::CreateVIterator().
2081class wxPGVIteratorBase_Manager : public wxPGVIteratorBase
2082{
2083public:
2084 wxPGVIteratorBase_Manager( wxPropertyGridManager* manager, int flags )
2085 : m_manager(manager), m_flags(flags), m_curPage(0)
2086 {
2087 m_it.Init(manager->GetPage(0), flags);
2088 }
2089 virtual ~wxPGVIteratorBase_Manager() { }
2090 virtual void Next()
2091 {
2092 m_it.Next();
2093
2094 // Next page?
2095 if ( m_it.AtEnd() )
2096 {
2097 m_curPage++;
2098 if ( m_curPage < m_manager->GetPageCount() )
2099 m_it.Init( m_manager->GetPage(m_curPage), m_flags );
2100 }
2101 }
2102private:
2103 wxPropertyGridManager* m_manager;
2104 int m_flags;
2105 unsigned int m_curPage;
2106};
2107
2108wxPGVIterator wxPropertyGridManager::GetVIterator( int flags ) const
2109{
2110 return wxPGVIterator( new wxPGVIteratorBase_Manager( (wxPropertyGridManager*)this, flags ) );
2111}
2112
2113#endif // wxUSE_PROPGRID