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