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