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