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