Clear grid selection more consistently prior clear operations; improved Clear() tests...
[wxWidgets.git] / src / propgrid / manager.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/manager.cpp
3 // Purpose: wxPropertyGridManager
4 // Author: Jaakko Salli
5 // Modified by:
6 // Created: 2005-01-14
7 // RCS-ID: $Id$
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_PROPGRID
20
21 #ifndef WX_PRECOMP
22 #include "wx/defs.h"
23 #include "wx/object.h"
24 #include "wx/hash.h"
25 #include "wx/string.h"
26 #include "wx/log.h"
27 #include "wx/event.h"
28 #include "wx/window.h"
29 #include "wx/panel.h"
30 #include "wx/dc.h"
31 #include "wx/pen.h"
32 #include "wx/brush.h"
33 #include "wx/cursor.h"
34 #include "wx/settings.h"
35 #include "wx/textctrl.h"
36 #include "wx/sizer.h"
37 #include "wx/statusbr.h"
38 #include "wx/intl.h"
39 #endif
40
41 // This define is necessary to prevent macro clearing
42 #define __wxPG_SOURCE_FILE__
43
44 #include "wx/propgrid/propgrid.h"
45
46 #include "wx/propgrid/manager.h"
47
48
49 #define wxPG_MAN_ALTERNATE_BASE_ID 11249 // Needed for wxID_ANY madnesss
50
51
52 // -----------------------------------------------------------------------
53
54 // For wxMSW cursor consistency, we must do mouse capturing even
55 // when using custom controls
56
57 #define BEGIN_MOUSE_CAPTURE \
58 if ( !(m_iFlags & wxPG_FL_MOUSE_CAPTURED) ) \
59 { \
60 CaptureMouse(); \
61 m_iFlags |= wxPG_FL_MOUSE_CAPTURED; \
62 }
63
64 #define END_MOUSE_CAPTURE \
65 if ( m_iFlags & wxPG_FL_MOUSE_CAPTURED ) \
66 { \
67 ReleaseMouse(); \
68 m_iFlags &= ~(wxPG_FL_MOUSE_CAPTURED); \
69 }
70
71 // -----------------------------------------------------------------------
72 // wxPropertyGridManager
73 // -----------------------------------------------------------------------
74
75 const char wxPropertyGridManagerNameStr[] = "wxPropertyGridManager";
76
77
78 // Categoric Mode Icon
79 static const char* 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* 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* 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 bool allPages,
213 bool fromAutoCenter )
214 {
215 if ( allPages && m_manager->GetPageCount() )
216 m_manager->SetSplitterPosition( pos, splitterColumn );
217 else
218 wxPropertyGridPageState::DoSetSplitterPosition( pos,
219 splitterColumn,
220 allPages,
221 fromAutoCenter );
222 }
223
224 // -----------------------------------------------------------------------
225 // wxPropertyGridManager
226 // -----------------------------------------------------------------------
227
228 // Final default splitter y is client height minus this.
229 #define wxPGMAN_DEFAULT_NEGATIVE_SPLITTER_Y 100
230
231 // -----------------------------------------------------------------------
232
233 IMPLEMENT_CLASS(wxPropertyGridManager, wxPanel)
234
235 #define ID_ADVTOOLBAR_OFFSET 1
236 #define ID_ADVHELPCAPTION_OFFSET 2
237 #define ID_ADVHELPCONTENT_OFFSET 3
238 //#define ID_ADVBUTTON_OFFSET 4
239 #define ID_ADVTBITEMSBASE_OFFSET 5 // Must be last.
240
241 // -----------------------------------------------------------------------
242
243 BEGIN_EVENT_TABLE(wxPropertyGridManager, wxPanel)
244 EVT_MOTION(wxPropertyGridManager::OnMouseMove)
245 EVT_SIZE(wxPropertyGridManager::OnResize)
246 EVT_PAINT(wxPropertyGridManager::OnPaint)
247 EVT_LEFT_DOWN(wxPropertyGridManager::OnMouseClick)
248 EVT_LEFT_UP(wxPropertyGridManager::OnMouseUp)
249 EVT_LEAVE_WINDOW(wxPropertyGridManager::OnMouseEntry)
250 //EVT_ENTER_WINDOW(wxPropertyGridManager::OnMouseEntry)
251 END_EVENT_TABLE()
252
253 // -----------------------------------------------------------------------
254
255 wxPropertyGridManager::wxPropertyGridManager()
256 : wxPanel()
257 {
258 Init1();
259 }
260
261 // -----------------------------------------------------------------------
262
263 wxPropertyGridManager::wxPropertyGridManager( wxWindow *parent,
264 wxWindowID id,
265 const wxPoint& pos,
266 const wxSize& size,
267 long style,
268 const wxString& name )
269 : wxPanel()
270 {
271 Init1();
272 Create(parent,id,pos,size,style,name);
273 }
274
275 // -----------------------------------------------------------------------
276
277 bool wxPropertyGridManager::Create( wxWindow *parent,
278 wxWindowID id,
279 const wxPoint& pos,
280 const wxSize& size,
281 long style,
282 const wxString& name )
283 {
284 if ( !m_pPropGrid )
285 m_pPropGrid = CreatePropertyGrid();
286
287 bool res = wxPanel::Create( parent, id, pos, size,
288 (style&0xFFFF0000)|wxWANTS_CHARS,
289 name );
290 Init2(style);
291
292 return res;
293 }
294
295 // -----------------------------------------------------------------------
296
297 //
298 // Initialize values to defaults
299 //
300 void wxPropertyGridManager::Init1()
301 {
302
303 m_pPropGrid = NULL;
304
305 #if wxUSE_TOOLBAR
306 m_pToolbar = NULL;
307 #endif
308 m_pTxtHelpCaption = NULL;
309 m_pTxtHelpContent = NULL;
310
311 m_emptyPage = NULL;
312
313 m_selPage = -1;
314
315 m_width = m_height = 0;
316
317 m_splitterHeight = 5;
318
319 m_splitterY = -1; // -1 causes default to be set.
320
321 m_nextDescBoxSize = -1;
322
323 m_extraHeight = 0;
324 m_dragStatus = 0;
325 m_onSplitter = 0;
326 m_iFlags = 0;
327 }
328
329 // -----------------------------------------------------------------------
330
331 // These flags are always used in wxPropertyGrid integrated in wxPropertyGridManager.
332 #ifndef __WXMAC__
333 #define wxPG_MAN_PROPGRID_FORCED_FLAGS (wxSIMPLE_BORDER| \
334 wxNO_FULL_REPAINT_ON_RESIZE| \
335 wxCLIP_CHILDREN)
336 #else
337 #define wxPG_MAN_PROPGRID_FORCED_FLAGS (wxNO_BORDER| \
338 wxNO_FULL_REPAINT_ON_RESIZE| \
339 wxCLIP_CHILDREN)
340 #endif
341
342 // Which flags can be passed to underlying wxPropertyGrid.
343 #define wxPG_MAN_PASS_FLAGS_MASK (0xFFF0|wxTAB_TRAVERSAL)
344
345 //
346 // Initialize after parent etc. set
347 //
348 void wxPropertyGridManager::Init2( int style )
349 {
350
351 if ( m_iFlags & wxPG_FL_INITIALIZED )
352 return;
353
354 m_windowStyle |= (style&0x0000FFFF);
355
356 wxSize csz = GetClientSize();
357
358 m_cursorSizeNS = wxCursor(wxCURSOR_SIZENS);
359
360 // Prepare the first page
361 // NB: But just prepare - you still need to call Add/InsertPage
362 // to actually add properties on it.
363 wxPropertyGridPage* pd = new wxPropertyGridPage();
364 pd->m_isDefault = true;
365 pd->m_manager = this;
366 wxPropertyGridPageState* state = pd->GetStatePtr();
367 state->m_pPropGrid = m_pPropGrid;
368 m_arrPages.push_back( pd );
369 m_pPropGrid->m_pState = state;
370
371 wxWindowID baseId = GetId();
372 wxWindowID useId = baseId;
373 if ( baseId < 0 )
374 baseId = wxPG_MAN_ALTERNATE_BASE_ID;
375
376 m_baseId = baseId;
377
378 #ifdef __WXMAC__
379 // Smaller controls on Mac
380 SetWindowVariant(wxWINDOW_VARIANT_SMALL);
381 #endif
382
383 // Create propertygrid.
384 m_pPropGrid->Create(this,baseId,wxPoint(0,0),csz,
385 (m_windowStyle&wxPG_MAN_PASS_FLAGS_MASK)
386 |wxPG_MAN_PROPGRID_FORCED_FLAGS);
387
388 m_pPropGrid->m_eventObject = this;
389
390 m_pPropGrid->SetId(useId);
391
392 m_pPropGrid->m_iFlags |= wxPG_FL_IN_MANAGER;
393
394 m_pState = m_pPropGrid->m_pState;
395
396 m_pPropGrid->SetExtraStyle(wxPG_EX_INIT_NOCAT);
397
398 m_nextTbInd = baseId+ID_ADVTBITEMSBASE_OFFSET + 2;
399
400
401 // Connect to property grid onselect event.
402 // NB: Even if wxID_ANY is used, this doesn't connect properly in wxPython
403 // (see wxPropertyGridManager::ProcessEvent).
404 Connect(m_pPropGrid->GetId()/*wxID_ANY*/,
405 wxEVT_PG_SELECTED,
406 wxPropertyGridEventHandler(wxPropertyGridManager::OnPropertyGridSelect) );
407
408 // Connect to toolbar button events.
409 Connect(baseId+ID_ADVTBITEMSBASE_OFFSET,baseId+ID_ADVTBITEMSBASE_OFFSET+50,
410 wxEVT_COMMAND_TOOL_CLICKED,
411 wxCommandEventHandler(wxPropertyGridManager::OnToolbarClick) );
412
413 // Optional initial controls.
414 m_width = -12345;
415
416 m_iFlags |= wxPG_FL_INITIALIZED;
417
418 }
419
420 // -----------------------------------------------------------------------
421
422 wxPropertyGridManager::~wxPropertyGridManager()
423 {
424 END_MOUSE_CAPTURE
425
426 m_pPropGrid->DoSelectProperty(NULL);
427 m_pPropGrid->m_pState = NULL;
428
429 size_t i;
430 for ( i=0; i<m_arrPages.size(); i++ )
431 {
432 delete m_arrPages[i];
433 }
434
435 delete m_emptyPage;
436 }
437
438 // -----------------------------------------------------------------------
439
440 wxPropertyGrid* wxPropertyGridManager::CreatePropertyGrid() const
441 {
442 return new wxPropertyGrid();
443 }
444
445 // -----------------------------------------------------------------------
446
447 void wxPropertyGridManager::SetId( wxWindowID winid )
448 {
449 wxWindow::SetId(winid);
450
451 // TODO: Reconnect propgrid event handler(s).
452
453 m_pPropGrid->SetId(winid);
454 }
455
456 // -----------------------------------------------------------------------
457
458 wxSize wxPropertyGridManager::DoGetBestSize() const
459 {
460 return wxSize(60,150);
461 }
462
463 // -----------------------------------------------------------------------
464
465 bool wxPropertyGridManager::SetFont( const wxFont& font )
466 {
467 bool res = wxWindow::SetFont(font);
468 m_pPropGrid->SetFont(font);
469
470 // TODO: Need to do caption recacalculations for other pages as well.
471 unsigned int i;
472 for ( i=0; i<m_arrPages.size(); i++ )
473 {
474 wxPropertyGridPage* page = GetPage(i);
475
476 if ( page != m_pPropGrid->GetState() )
477 page->CalculateFontAndBitmapStuff(-1);
478 }
479
480 return res;
481 }
482
483 // -----------------------------------------------------------------------
484
485 void wxPropertyGridManager::SetExtraStyle( long exStyle )
486 {
487 wxWindow::SetExtraStyle( exStyle );
488 m_pPropGrid->SetExtraStyle( exStyle & 0xFFFFF000 );
489 #if wxUSE_TOOLBAR
490 if ( (exStyle & wxPG_EX_NO_FLAT_TOOLBAR) && m_pToolbar )
491 RecreateControls();
492 #endif
493 }
494
495 // -----------------------------------------------------------------------
496
497 void wxPropertyGridManager::Freeze()
498 {
499 m_pPropGrid->Freeze();
500 wxWindow::Freeze();
501 }
502
503 // -----------------------------------------------------------------------
504
505 void wxPropertyGridManager::Thaw()
506 {
507 wxWindow::Thaw();
508 m_pPropGrid->Thaw();
509 }
510
511 // -----------------------------------------------------------------------
512
513 void wxPropertyGridManager::SetWindowStyleFlag( long style )
514 {
515 int oldWindowStyle = GetWindowStyleFlag();
516
517 wxWindow::SetWindowStyleFlag( style );
518 m_pPropGrid->SetWindowStyleFlag( (m_pPropGrid->GetWindowStyleFlag()&~(wxPG_MAN_PASS_FLAGS_MASK)) |
519 (style&wxPG_MAN_PASS_FLAGS_MASK) );
520
521 // Need to re-position windows?
522 if ( (oldWindowStyle & (wxPG_TOOLBAR|wxPG_DESCRIPTION)) !=
523 (style & (wxPG_TOOLBAR|wxPG_DESCRIPTION)) )
524 {
525 RecreateControls();
526 }
527 }
528
529 // -----------------------------------------------------------------------
530
531 // Actually shows given page.
532 bool wxPropertyGridManager::DoSelectPage( int index )
533 {
534 // -1 means no page was selected
535 //wxASSERT( m_selPage >= 0 );
536
537 wxCHECK_MSG( index >= -1 && index < (int)GetPageCount(),
538 false,
539 wxT("invalid page index") );
540
541 if ( m_selPage == index )
542 return true;
543
544 if ( m_pPropGrid->m_selected )
545 {
546 if ( !m_pPropGrid->ClearSelection() )
547 return false;
548 }
549
550 wxPropertyGridPage* prevPage;
551
552 if ( m_selPage >= 0 )
553 prevPage = GetPage(m_selPage);
554 else
555 prevPage = m_emptyPage;
556
557 wxPropertyGridPage* nextPage;
558
559 if ( index >= 0 )
560 {
561 nextPage = m_arrPages[index];
562
563 nextPage->OnShow();
564 }
565 else
566 {
567 if ( !m_emptyPage )
568 {
569 m_emptyPage = new wxPropertyGridPage();
570 m_emptyPage->m_pPropGrid = m_pPropGrid;
571 }
572
573 nextPage = m_emptyPage;
574 }
575
576 m_iFlags |= wxPG_FL_DESC_REFRESH_REQUIRED;
577
578 m_pPropGrid->SwitchState( nextPage->GetStatePtr() );
579
580 m_pState = m_pPropGrid->m_pState;
581
582 m_selPage = index;
583
584 #if wxUSE_TOOLBAR
585 if ( m_pToolbar )
586 {
587 if ( index >= 0 )
588 m_pToolbar->ToggleTool( nextPage->m_id, true );
589 else
590 m_pToolbar->ToggleTool( prevPage->m_id, false );
591 }
592 #endif
593
594 return true;
595 }
596
597 // -----------------------------------------------------------------------
598
599 // Changes page *and* set the target page for insertion operations.
600 void wxPropertyGridManager::SelectPage( int index )
601 {
602 DoSelectPage(index);
603 }
604
605 // -----------------------------------------------------------------------
606
607 int wxPropertyGridManager::GetPageByName( const wxString& name ) const
608 {
609 size_t i;
610 for ( i=0; i<GetPageCount(); i++ )
611 {
612 if ( m_arrPages[i]->m_label == name )
613 return i;
614 }
615 return wxNOT_FOUND;
616 }
617
618 // -----------------------------------------------------------------------
619
620 int wxPropertyGridManager::GetPageByState( const wxPropertyGridPageState* pState ) const
621 {
622 wxASSERT( pState );
623
624 size_t i;
625 for ( i=0; i<GetPageCount(); i++ )
626 {
627 if ( pState == m_arrPages[i]->GetStatePtr() )
628 return i;
629 }
630
631 return wxNOT_FOUND;
632 }
633
634 // -----------------------------------------------------------------------
635
636 const wxString& wxPropertyGridManager::GetPageName( int index ) const
637 {
638 wxASSERT( index >= 0 && index < (int)GetPageCount() );
639 return m_arrPages[index]->m_label;
640 }
641
642 // -----------------------------------------------------------------------
643
644 wxPropertyGridPageState* wxPropertyGridManager::GetPageState( int page ) const
645 {
646 // Do not change this into wxCHECK because returning NULL is important
647 // for wxPropertyGridInterface page enumeration mechanics.
648 if ( page >= (int)GetPageCount() )
649 return NULL;
650
651 if ( page == -1 )
652 return m_pState;
653 return m_arrPages[page];
654 }
655
656 // -----------------------------------------------------------------------
657
658 void wxPropertyGridManager::Clear()
659 {
660 m_pPropGrid->ClearSelection(false);
661
662 m_pPropGrid->Freeze();
663
664 int i;
665 for ( i=(int)GetPageCount()-1; i>=0; i-- )
666 RemovePage(i);
667
668 // Reset toolbar ids
669 m_nextTbInd = m_baseId+ID_ADVTBITEMSBASE_OFFSET + 2;
670
671 m_pPropGrid->Thaw();
672 }
673
674 // -----------------------------------------------------------------------
675
676 void wxPropertyGridManager::ClearPage( int page )
677 {
678 wxASSERT( page >= 0 );
679 wxASSERT( page < (int)GetPageCount() );
680
681 if ( page >= 0 && page < (int)GetPageCount() )
682 {
683 wxPropertyGridPageState* state = m_arrPages[page];
684
685 if ( state == m_pPropGrid->GetState() )
686 m_pPropGrid->Clear();
687 else
688 state->DoClear();
689 }
690 }
691
692 // -----------------------------------------------------------------------
693
694 int wxPropertyGridManager::GetColumnCount( int page ) const
695 {
696 wxASSERT( page >= -1 );
697 wxASSERT( page < (int)GetPageCount() );
698
699 return GetPageState(page)->GetColumnCount();
700 }
701
702 // -----------------------------------------------------------------------
703
704 void wxPropertyGridManager::SetColumnCount( int colCount, int page )
705 {
706 wxASSERT( page >= -1 );
707 wxASSERT( page < (int)GetPageCount() );
708
709 GetPageState(page)->SetColumnCount( colCount );
710 GetGrid()->Refresh();
711 }
712 // -----------------------------------------------------------------------
713
714 size_t wxPropertyGridManager::GetPageCount() const
715 {
716 if ( !(m_iFlags & wxPG_MAN_FL_PAGE_INSERTED) )
717 return 0;
718
719 return m_arrPages.size();
720 }
721
722 // -----------------------------------------------------------------------
723
724 wxPropertyGridPage* wxPropertyGridManager::InsertPage( int index,
725 const wxString& label,
726 const wxBitmap& bmp,
727 wxPropertyGridPage* pageObj )
728 {
729 if ( index < 0 )
730 index = GetPageCount();
731
732 wxCHECK_MSG( (size_t)index == GetPageCount(), NULL,
733 wxT("wxPropertyGridManager currently only supports appending pages (due to wxToolBar limitation)."));
734
735 bool needInit = true;
736 bool isPageInserted = m_iFlags & wxPG_MAN_FL_PAGE_INSERTED ? true : false;
737
738 wxASSERT( index == 0 || isPageInserted );
739
740 if ( !pageObj )
741 {
742 // No custom page object was given, so we will either re-use the default base
743 // page (if index==0), or create a new default page object.
744 if ( !isPageInserted )
745 {
746 pageObj = GetPage(0);
747 // Of course, if the base page was custom, we need to delete and
748 // re-create it.
749 if ( !pageObj->m_isDefault )
750 {
751 delete pageObj;
752 pageObj = new wxPropertyGridPage();
753 m_arrPages[0] = pageObj;
754 }
755 needInit = false;
756 }
757 else
758 {
759 pageObj = new wxPropertyGridPage();
760 }
761 pageObj->m_isDefault = true;
762 }
763 else
764 {
765 if ( !isPageInserted )
766 {
767 // Initial page needs to be deleted and replaced
768 delete GetPage(0);
769 m_arrPages[0] = pageObj;
770 m_pPropGrid->m_pState = pageObj->GetStatePtr();
771 }
772 }
773
774 wxPropertyGridPageState* state = pageObj->GetStatePtr();
775
776 pageObj->m_manager = this;
777
778 if ( needInit )
779 {
780 state->m_pPropGrid = m_pPropGrid;
781 state->InitNonCatMode();
782 }
783
784 if ( label.length() )
785 {
786 wxASSERT_MSG( !pageObj->m_label.length(),
787 wxT("If page label is given in constructor, empty label must be given in AddPage"));
788 pageObj->m_label = label;
789 }
790
791 pageObj->m_id = m_nextTbInd;
792
793 if ( isPageInserted )
794 m_arrPages.push_back( pageObj );
795
796 #if wxUSE_TOOLBAR
797 if ( m_windowStyle & wxPG_TOOLBAR )
798 {
799 if ( !m_pToolbar )
800 RecreateControls();
801
802 if ( !(GetExtraStyle()&wxPG_EX_HIDE_PAGE_BUTTONS) )
803 {
804 wxASSERT( m_pToolbar );
805
806 // Add separator before first page.
807 if ( GetPageCount() < 2 && (GetExtraStyle()&wxPG_EX_MODE_BUTTONS) &&
808 m_pToolbar->GetToolsCount() < 3 )
809 m_pToolbar->AddSeparator();
810
811 if ( &bmp != &wxNullBitmap )
812 m_pToolbar->AddTool(m_nextTbInd,label,bmp,label,wxITEM_RADIO);
813 //m_pToolbar->InsertTool(index+3,m_nextTbInd,bmp);
814 else
815 m_pToolbar->AddTool(m_nextTbInd,label,wxBitmap( (const char**)gs_xpm_defpage ),
816 label,wxITEM_RADIO);
817
818 m_nextTbInd++;
819
820 m_pToolbar->Realize();
821 }
822 }
823 #else
824 wxUnusedVar(bmp);
825 #endif
826
827 // If selected page was above the point of insertion, fix the current page index
828 if ( isPageInserted )
829 {
830 if ( m_selPage >= index )
831 {
832 m_selPage += 1;
833 }
834 }
835 else
836 {
837 // Set this value only when adding the first page
838 m_selPage = 0;
839 }
840
841 pageObj->Init();
842
843 m_iFlags |= wxPG_MAN_FL_PAGE_INSERTED;
844
845 wxASSERT( pageObj->GetGrid() );
846
847 return pageObj;
848 }
849
850 // -----------------------------------------------------------------------
851
852 bool wxPropertyGridManager::IsAnyModified() const
853 {
854 size_t i;
855 for ( i=0; i<GetPageCount(); i++ )
856 {
857 if ( m_arrPages[i]->GetStatePtr()->m_anyModified )
858 return true;
859 }
860 return false;
861 }
862
863 // -----------------------------------------------------------------------
864
865 bool wxPropertyGridManager::IsPageModified( size_t index ) const
866 {
867 if ( m_arrPages[index]->GetStatePtr()->m_anyModified )
868 return true;
869 return false;
870 }
871
872 // -----------------------------------------------------------------------
873
874 wxPGProperty* wxPropertyGridManager::GetPageRoot( int index ) const
875 {
876 wxASSERT( index >= 0 );
877 wxASSERT( index < (int)m_arrPages.size() );
878
879 return m_arrPages[index]->GetStatePtr()->m_properties;
880 }
881
882 // -----------------------------------------------------------------------
883
884 bool wxPropertyGridManager::RemovePage( int page )
885 {
886 wxCHECK_MSG( (page >= 0) && (page < (int)GetPageCount()),
887 false,
888 wxT("invalid page index") );
889
890 wxPropertyGridPage* pd = m_arrPages[page];
891
892 if ( m_arrPages.size() == 1 )
893 {
894 // Last page: do not remove page entry
895 m_pPropGrid->Clear();
896 m_selPage = -1;
897 m_iFlags &= ~wxPG_MAN_FL_PAGE_INSERTED;
898 pd->m_label.clear();
899 }
900
901 // Change selection if current is page
902 else if ( page == m_selPage )
903 {
904 if ( !m_pPropGrid->ClearSelection() )
905 return false;
906
907 // Substitute page to select
908 int substitute = page - 1;
909 if ( substitute < 0 )
910 substitute = page + 1;
911
912 SelectPage(substitute);
913 }
914
915 // Remove toolbar icon
916 #if wxUSE_TOOLBAR
917 if ( HasFlag(wxPG_TOOLBAR) )
918 {
919 wxASSERT( m_pToolbar );
920
921 int toolPos = GetExtraStyle() & wxPG_EX_MODE_BUTTONS ? 3 : 0;
922 toolPos += page;
923
924 // Delete separator as well, for consistency
925 if ( (GetExtraStyle() & wxPG_EX_MODE_BUTTONS) &&
926 GetPageCount() == 1 )
927 m_pToolbar->DeleteToolByPos(2);
928
929 m_pToolbar->DeleteToolByPos(toolPos);
930 }
931 #endif
932
933 if ( m_arrPages.size() > 1 )
934 {
935 m_arrPages.erase(m_arrPages.begin() + page);
936 delete pd;
937 }
938
939 // Adjust indexes that were above removed
940 if ( m_selPage > page )
941 m_selPage--;
942
943 return true;
944 }
945
946 // -----------------------------------------------------------------------
947
948 bool wxPropertyGridManager::ProcessEvent( wxEvent& event )
949 {
950 int evtType = event.GetEventType();
951
952 // NB: For some reason, under wxPython, Connect in Init doesn't work properly,
953 // so we'll need to call OnPropertyGridSelect manually. Multiple call's
954 // don't really matter.
955 if ( evtType == wxEVT_PG_SELECTED )
956 OnPropertyGridSelect((wxPropertyGridEvent&)event);
957
958 // Property grid events get special attention
959 if ( evtType >= wxPG_BASE_EVT_TYPE &&
960 evtType < (wxPG_MAX_EVT_TYPE) &&
961 m_selPage >= 0 )
962 {
963 wxPropertyGridPage* page = GetPage(m_selPage);
964 wxPropertyGridEvent* pgEvent = wxDynamicCast(&event, wxPropertyGridEvent);
965
966 // Add property grid events to appropriate custom pages
967 // but stop propagating to parent if page says it is
968 // handling everything.
969 if ( pgEvent && !page->m_isDefault )
970 {
971 /*if ( pgEvent->IsPending() )
972 page->AddPendingEvent(event);
973 else*/
974 page->ProcessEvent(event);
975
976 if ( page->IsHandlingAllEvents() )
977 event.StopPropagation();
978 }
979 }
980
981 return wxPanel::ProcessEvent(event);
982 }
983
984 // -----------------------------------------------------------------------
985
986 void wxPropertyGridManager::RepaintDescBoxDecorations( wxDC& dc,
987 int newSplitterY,
988 int newWidth,
989 int newHeight )
990 {
991 // Draw background
992 wxColour bgcol = GetBackgroundColour();
993 dc.SetBrush(bgcol);
994 dc.SetPen(bgcol);
995 int rectHeight = m_splitterHeight;
996 dc.DrawRectangle(0, newSplitterY, newWidth, rectHeight);
997 dc.SetPen( wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW) );
998 int splitterBottom = newSplitterY + m_splitterHeight - 1;
999 int boxHeight = newHeight - splitterBottom;
1000 if ( boxHeight > 1 )
1001 dc.DrawRectangle(0, splitterBottom, newWidth, boxHeight);
1002 else
1003 dc.DrawLine(0, splitterBottom, newWidth, splitterBottom);
1004 }
1005
1006 // -----------------------------------------------------------------------
1007
1008 void wxPropertyGridManager::UpdateDescriptionBox( int new_splittery, int new_width, int new_height )
1009 {
1010 int use_hei = new_height;
1011 use_hei--;
1012
1013 // Fix help control positions.
1014 int cap_hei = m_pPropGrid->m_fontHeight;
1015 int cap_y = new_splittery+m_splitterHeight+5;
1016 int cnt_y = cap_y+cap_hei+3;
1017 int sub_cap_hei = cap_y+cap_hei-use_hei;
1018 int cnt_hei = use_hei-cnt_y;
1019 if ( sub_cap_hei > 0 )
1020 {
1021 cap_hei -= sub_cap_hei;
1022 cnt_hei = 0;
1023 }
1024 if ( cap_hei <= 2 )
1025 {
1026 m_pTxtHelpCaption->Show( false );
1027 m_pTxtHelpContent->Show( false );
1028 }
1029 else
1030 {
1031 m_pTxtHelpCaption->SetSize(3,cap_y,new_width-6,cap_hei);
1032 m_pTxtHelpCaption->Wrap(-1);
1033 m_pTxtHelpCaption->Show( true );
1034 if ( cnt_hei <= 2 )
1035 {
1036 m_pTxtHelpContent->Show( false );
1037 }
1038 else
1039 {
1040 m_pTxtHelpContent->SetSize(3,cnt_y,new_width-6,cnt_hei);
1041 m_pTxtHelpContent->Show( true );
1042 }
1043 }
1044
1045 wxRect r(0, new_splittery, new_width, new_height-new_splittery);
1046 RefreshRect(r);
1047
1048 m_splitterY = new_splittery;
1049
1050 m_iFlags &= ~(wxPG_FL_DESC_REFRESH_REQUIRED);
1051 }
1052
1053 // -----------------------------------------------------------------------
1054
1055 void wxPropertyGridManager::RecalculatePositions( int width, int height )
1056 {
1057 int propgridY = 0;
1058 int propgridBottomY = height;
1059
1060 // Toolbar at the top.
1061 #if wxUSE_TOOLBAR
1062 if ( m_pToolbar )
1063 {
1064 m_pToolbar->SetSize(0, 0, width, -1);
1065 propgridY += m_pToolbar->GetSize().y;
1066 }
1067 #endif
1068
1069 // Help box.
1070 if ( m_pTxtHelpCaption )
1071 {
1072 int new_splittery = m_splitterY;
1073
1074 // Move m_splitterY
1075 if ( ( m_splitterY >= 0 || m_nextDescBoxSize ) && m_height > 32 )
1076 {
1077 if ( m_nextDescBoxSize >= 0 )
1078 {
1079 new_splittery = m_height - m_nextDescBoxSize - m_splitterHeight;
1080 m_nextDescBoxSize = -1;
1081 }
1082 new_splittery += (height-m_height);
1083 }
1084 else
1085 {
1086 new_splittery = height - wxPGMAN_DEFAULT_NEGATIVE_SPLITTER_Y;
1087 if ( new_splittery < 32 )
1088 new_splittery = 32;
1089 }
1090
1091 // Check if beyond minimum.
1092 int nspy_min = propgridY + m_pPropGrid->m_lineHeight;
1093 if ( new_splittery < nspy_min )
1094 new_splittery = nspy_min;
1095
1096 propgridBottomY = new_splittery;
1097
1098 UpdateDescriptionBox( new_splittery, width, height );
1099 }
1100
1101 if ( m_iFlags & wxPG_FL_INITIALIZED )
1102 {
1103 int pgh = propgridBottomY - propgridY;
1104 if ( pgh < 0 )
1105 pgh = 0;
1106 m_pPropGrid->SetSize( 0, propgridY, width, pgh );
1107
1108 m_extraHeight = height - pgh;
1109
1110 m_width = width;
1111 m_height = height;
1112 }
1113 }
1114
1115 // -----------------------------------------------------------------------
1116
1117 void wxPropertyGridManager::SetDescBoxHeight( int ht, bool refresh )
1118 {
1119 if ( m_windowStyle & wxPG_DESCRIPTION )
1120 {
1121 if ( ht != GetDescBoxHeight() )
1122 {
1123 m_nextDescBoxSize = ht;
1124 if ( refresh )
1125 RecalculatePositions(m_width, m_height);
1126 }
1127 }
1128 }
1129
1130 // -----------------------------------------------------------------------
1131
1132 int wxPropertyGridManager::GetDescBoxHeight() const
1133 {
1134 return GetClientSize().y - m_splitterY - m_splitterHeight;
1135 }
1136
1137 // -----------------------------------------------------------------------
1138
1139 void wxPropertyGridManager::OnPaint( wxPaintEvent& WXUNUSED(event) )
1140 {
1141 wxPaintDC dc(this);
1142
1143 // Update everything inside the box
1144 wxRect r = GetUpdateRegion().GetBox();
1145
1146 // Repaint splitter and any other description box decorations
1147 if ( (r.y + r.height) >= m_splitterY )
1148 RepaintDescBoxDecorations( dc, m_splitterY, m_width, m_height );
1149 }
1150
1151 // -----------------------------------------------------------------------
1152
1153 void wxPropertyGridManager::Refresh(bool eraseBackground, const wxRect* rect )
1154 {
1155 m_pPropGrid->Refresh(eraseBackground);
1156 wxWindow::Refresh(eraseBackground,rect);
1157 }
1158
1159 // -----------------------------------------------------------------------
1160
1161 void wxPropertyGridManager::RefreshProperty( wxPGProperty* p )
1162 {
1163 wxPropertyGrid* grid = p->GetGrid();
1164
1165 if ( GetPage(m_selPage)->GetStatePtr() == p->GetParent()->GetParentState() )
1166 grid->RefreshProperty(p);
1167 }
1168
1169 // -----------------------------------------------------------------------
1170
1171 void wxPropertyGridManager::RecreateControls()
1172 {
1173
1174 bool was_shown = IsShown();
1175 if ( was_shown )
1176 Show ( false );
1177
1178 wxWindowID baseId = m_pPropGrid->GetId();
1179 if ( baseId < 0 )
1180 baseId = wxPG_MAN_ALTERNATE_BASE_ID;
1181
1182 #if wxUSE_TOOLBAR
1183 if ( m_windowStyle & wxPG_TOOLBAR )
1184 {
1185 // Has toolbar.
1186 if ( !m_pToolbar )
1187 {
1188 m_pToolbar = new wxToolBar(this,baseId+ID_ADVTOOLBAR_OFFSET,
1189 wxDefaultPosition,wxDefaultSize,
1190 ((GetExtraStyle()&wxPG_EX_NO_FLAT_TOOLBAR)?0:wxTB_FLAT)
1191 /*| wxTB_HORIZONTAL | wxNO_BORDER*/ );
1192 m_pToolbar->SetToolBitmapSize(wxSize(16, 15));
1193
1194 #if defined(__WXMSW__)
1195 // Eliminate toolbar flicker on XP
1196 // NOTE: Not enabled since it corrupts drawing somewhat.
1197
1198 /*
1199 #ifndef WS_EX_COMPOSITED
1200 #define WS_EX_COMPOSITED 0x02000000L
1201 #endif
1202
1203 HWND hWnd = (HWND)m_pToolbar->GetHWND();
1204
1205 ::SetWindowLong( hWnd, GWL_EXSTYLE,
1206 ::GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_COMPOSITED );
1207 */
1208
1209 #endif
1210
1211 m_pToolbar->SetCursor ( *wxSTANDARD_CURSOR );
1212
1213 if ( (GetExtraStyle()&wxPG_EX_MODE_BUTTONS) )
1214 {
1215 wxString desc1(_("Categorized Mode"));
1216 wxString desc2(_("Alphabetic Mode"));
1217 m_pToolbar->AddTool(baseId+ID_ADVTBITEMSBASE_OFFSET+0,
1218 desc1,wxBitmap ( (const char**)gs_xpm_catmode ),
1219 desc1,wxITEM_RADIO);
1220 m_pToolbar->AddTool(baseId+ID_ADVTBITEMSBASE_OFFSET+1,
1221 desc2,wxBitmap ( (const char**)gs_xpm_noncatmode ),
1222 desc2,wxITEM_RADIO);
1223 m_pToolbar->Realize();
1224 }
1225
1226 }
1227
1228 if ( (GetExtraStyle()&wxPG_EX_MODE_BUTTONS) )
1229 {
1230 // Toggle correct mode button.
1231 // TODO: This doesn't work in wxMSW (when changing,
1232 // both items will get toggled).
1233 int toggle_but_on_ind = ID_ADVTBITEMSBASE_OFFSET+0;
1234 int toggle_but_off_ind = ID_ADVTBITEMSBASE_OFFSET+1;
1235 if ( m_pPropGrid->m_pState->IsInNonCatMode() )
1236 {
1237 toggle_but_on_ind++;
1238 toggle_but_off_ind--;
1239 }
1240
1241 m_pToolbar->ToggleTool(baseId+toggle_but_on_ind,true);
1242 m_pToolbar->ToggleTool(baseId+toggle_but_off_ind,false);
1243 }
1244
1245 }
1246 else
1247 {
1248 // No toolbar.
1249 if ( m_pToolbar )
1250 m_pToolbar->Destroy();
1251 m_pToolbar = NULL;
1252 }
1253 #endif
1254
1255 if ( m_windowStyle & wxPG_DESCRIPTION )
1256 {
1257 // Has help box.
1258 m_pPropGrid->m_iFlags |= (wxPG_FL_NOSTATUSBARHELP);
1259
1260 if ( !m_pTxtHelpCaption )
1261 {
1262 m_pTxtHelpCaption = new wxStaticText(this,
1263 baseId+ID_ADVHELPCAPTION_OFFSET,
1264 wxT(""),
1265 wxDefaultPosition,
1266 wxDefaultSize,
1267 wxALIGN_LEFT|wxST_NO_AUTORESIZE);
1268 m_pTxtHelpCaption->SetFont( m_pPropGrid->m_captionFont );
1269 m_pTxtHelpCaption->SetCursor( *wxSTANDARD_CURSOR );
1270 }
1271 if ( !m_pTxtHelpContent )
1272 {
1273 m_pTxtHelpContent = new wxStaticText(this,
1274 baseId+ID_ADVHELPCONTENT_OFFSET,
1275 wxT(""),
1276 wxDefaultPosition,
1277 wxDefaultSize,
1278 wxALIGN_LEFT|wxST_NO_AUTORESIZE);
1279 m_pTxtHelpContent->SetCursor( *wxSTANDARD_CURSOR );
1280 }
1281
1282 SetDescribedProperty(GetSelection());
1283 }
1284 else
1285 {
1286 // No help box.
1287 m_pPropGrid->m_iFlags &= ~(wxPG_FL_NOSTATUSBARHELP);
1288
1289 if ( m_pTxtHelpCaption )
1290 m_pTxtHelpCaption->Destroy();
1291
1292 m_pTxtHelpCaption = NULL;
1293
1294 if ( m_pTxtHelpContent )
1295 m_pTxtHelpContent->Destroy();
1296
1297 m_pTxtHelpContent = NULL;
1298 }
1299
1300 int width, height;
1301
1302 GetClientSize(&width,&height);
1303
1304 RecalculatePositions(width,height);
1305
1306 if ( was_shown )
1307 Show ( true );
1308 }
1309
1310 // -----------------------------------------------------------------------
1311
1312 wxPGProperty* wxPropertyGridManager::DoGetPropertyByName( const wxString& name ) const
1313 {
1314 size_t i;
1315 for ( i=0; i<GetPageCount(); i++ )
1316 {
1317 wxPropertyGridPageState* pState = m_arrPages[i]->GetStatePtr();
1318 wxPGProperty* p = pState->BaseGetPropertyByName(name);
1319 if ( p )
1320 {
1321 return p;
1322 }
1323 }
1324 return NULL;
1325 }
1326
1327 // -----------------------------------------------------------------------
1328
1329 bool wxPropertyGridManager::EnsureVisible( wxPGPropArg id )
1330 {
1331 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
1332
1333 wxPropertyGridPageState* parentState = p->GetParentState();
1334
1335 // Select correct page.
1336 if ( m_pPropGrid->m_pState != parentState )
1337 DoSelectPage( GetPageByState(parentState) );
1338
1339 return m_pPropGrid->EnsureVisible(id);
1340 }
1341
1342 // -----------------------------------------------------------------------
1343
1344 void wxPropertyGridManager::OnToolbarClick( wxCommandEvent &event )
1345 {
1346 int id = event.GetId();
1347 if ( id >= 0 )
1348 {
1349 int baseId = m_pPropGrid->GetId();
1350 if ( baseId < 0 )
1351 baseId = wxPG_MAN_ALTERNATE_BASE_ID;
1352
1353 if ( id == ( baseId + ID_ADVTBITEMSBASE_OFFSET + 0 ) )
1354 {
1355 // Categorized mode.
1356 if ( m_pPropGrid->m_windowStyle & wxPG_HIDE_CATEGORIES )
1357 {
1358 if ( !m_pPropGrid->HasInternalFlag(wxPG_FL_CATMODE_AUTO_SORT) )
1359 m_pPropGrid->m_windowStyle &= ~wxPG_AUTO_SORT;
1360 m_pPropGrid->EnableCategories( true );
1361 }
1362 }
1363 else if ( id == ( baseId + ID_ADVTBITEMSBASE_OFFSET + 1 ) )
1364 {
1365 // Alphabetic mode.
1366 if ( !(m_pPropGrid->m_windowStyle & wxPG_HIDE_CATEGORIES) )
1367 {
1368 if ( m_pPropGrid->HasFlag(wxPG_AUTO_SORT) )
1369 m_pPropGrid->SetInternalFlag(wxPG_FL_CATMODE_AUTO_SORT);
1370 else
1371 m_pPropGrid->ClearInternalFlag(wxPG_FL_CATMODE_AUTO_SORT);
1372
1373 m_pPropGrid->m_windowStyle |= wxPG_AUTO_SORT;
1374 m_pPropGrid->EnableCategories( false );
1375 }
1376 }
1377 else
1378 {
1379 // Page Switching.
1380
1381 int index = -1;
1382 size_t i;
1383 wxPropertyGridPage* pdc;
1384
1385 // Find page with given id.
1386 for ( i=0; i<GetPageCount(); i++ )
1387 {
1388 pdc = m_arrPages[i];
1389 if ( pdc->m_id == id )
1390 {
1391 index = i;
1392 break;
1393 }
1394 }
1395
1396 wxASSERT( index >= 0 );
1397
1398 if ( DoSelectPage( index ) )
1399 {
1400
1401 // Event dispatching must be last.
1402 m_pPropGrid->SendEvent( wxEVT_PG_PAGE_CHANGED, NULL );
1403
1404 }
1405 else
1406 {
1407 // TODO: Depress the old button on toolbar.
1408 }
1409
1410 }
1411 }
1412 }
1413
1414 // -----------------------------------------------------------------------
1415
1416 bool wxPropertyGridManager::SetEditableStateItem( const wxString& name, wxVariant value )
1417 {
1418 if ( name == wxS("descboxheight") )
1419 {
1420 SetDescBoxHeight(value.GetLong(), true);
1421 return true;
1422 }
1423 return false;
1424 }
1425
1426 // -----------------------------------------------------------------------
1427
1428 wxVariant wxPropertyGridManager::GetEditableStateItem( const wxString& name ) const
1429 {
1430 if ( name == wxS("descboxheight") )
1431 {
1432 return (long) GetDescBoxHeight();
1433 }
1434 return wxNullVariant;
1435 }
1436
1437 // -----------------------------------------------------------------------
1438
1439 void wxPropertyGridManager::SetDescription( const wxString& label, const wxString& content )
1440 {
1441 if ( m_pTxtHelpCaption )
1442 {
1443 wxSize osz1 = m_pTxtHelpCaption->GetSize();
1444 wxSize osz2 = m_pTxtHelpContent->GetSize();
1445
1446 m_pTxtHelpCaption->SetLabel(label);
1447 m_pTxtHelpContent->SetLabel(content);
1448
1449 m_pTxtHelpCaption->SetSize(-1,osz1.y);
1450 m_pTxtHelpContent->SetSize(-1,osz2.y);
1451
1452 UpdateDescriptionBox( m_splitterY, m_width, m_height );
1453 }
1454 }
1455
1456 // -----------------------------------------------------------------------
1457
1458 void wxPropertyGridManager::SetDescribedProperty( wxPGProperty* p )
1459 {
1460 if ( m_pTxtHelpCaption )
1461 {
1462 if ( p )
1463 {
1464 SetDescription( p->GetLabel(), p->GetHelpString() );
1465 }
1466 else
1467 {
1468 SetDescription( wxEmptyString, wxEmptyString );
1469 }
1470 }
1471 }
1472
1473 // -----------------------------------------------------------------------
1474
1475 void wxPropertyGridManager::SetSplitterLeft( bool subProps, bool allPages )
1476 {
1477 if ( !allPages )
1478 {
1479 m_pPropGrid->SetSplitterLeft(subProps);
1480 }
1481 else
1482 {
1483 wxClientDC dc(this);
1484 dc.SetFont(m_pPropGrid->GetFont());
1485
1486 int highest = 0;
1487 unsigned int i;
1488
1489 for ( i=0; i<GetPageCount(); i++ )
1490 {
1491 int maxW = m_pState->GetColumnFitWidth(dc, m_arrPages[i]->m_properties, 0, subProps );
1492 maxW += m_pPropGrid->m_marginWidth;
1493 if ( maxW > highest )
1494 highest = maxW;
1495 }
1496
1497 if ( highest > 0 )
1498 m_pPropGrid->SetSplitterPosition( highest );
1499
1500 m_pPropGrid->m_iFlags |= wxPG_FL_DONT_CENTER_SPLITTER;
1501 }
1502 }
1503
1504 // -----------------------------------------------------------------------
1505
1506 void wxPropertyGridManager::OnPropertyGridSelect( wxPropertyGridEvent& event )
1507 {
1508 // Check id.
1509 wxASSERT_MSG( GetId() == m_pPropGrid->GetId(),
1510 wxT("wxPropertyGridManager id must be set with wxPropertyGridManager::SetId (not wxWindow::SetId).") );
1511
1512 SetDescribedProperty(event.GetProperty());
1513 event.Skip();
1514 }
1515
1516 // -----------------------------------------------------------------------
1517
1518 void wxPropertyGridManager::OnResize( wxSizeEvent& WXUNUSED(event) )
1519 {
1520 int width, height;
1521
1522 GetClientSize(&width,&height);
1523
1524 if ( m_width == -12345 )
1525 RecreateControls();
1526
1527 RecalculatePositions(width,height);
1528 }
1529
1530 // -----------------------------------------------------------------------
1531
1532 void wxPropertyGridManager::OnMouseEntry( wxMouseEvent& WXUNUSED(event) )
1533 {
1534 // Correct cursor. This is required atleast for wxGTK, for which
1535 // setting button's cursor to *wxSTANDARD_CURSOR does not work.
1536 SetCursor( wxNullCursor );
1537 m_onSplitter = 0;
1538 }
1539
1540 // -----------------------------------------------------------------------
1541
1542 void wxPropertyGridManager::OnMouseMove( wxMouseEvent &event )
1543 {
1544 if ( !m_pTxtHelpCaption )
1545 return;
1546
1547 int y = event.m_y;
1548
1549 if ( m_dragStatus > 0 )
1550 {
1551 int sy = y - m_dragOffset;
1552
1553 // Calculate drag limits
1554 int bottom_limit = m_height - m_splitterHeight + 1;
1555 int top_limit = m_pPropGrid->m_lineHeight;
1556 #if wxUSE_TOOLBAR
1557 if ( m_pToolbar ) top_limit += m_pToolbar->GetSize().y;
1558 #endif
1559
1560 if ( sy >= top_limit && sy < bottom_limit )
1561 {
1562
1563 int change = sy - m_splitterY;
1564 if ( change )
1565 {
1566 m_splitterY = sy;
1567
1568 m_pPropGrid->SetSize( m_width, m_splitterY - m_pPropGrid->GetPosition().y );
1569 UpdateDescriptionBox( m_splitterY, m_width, m_height );
1570
1571 m_extraHeight -= change;
1572 InvalidateBestSize();
1573 }
1574
1575 }
1576
1577 }
1578 else
1579 {
1580 if ( y >= m_splitterY && y < (m_splitterY+m_splitterHeight+2) )
1581 {
1582 SetCursor ( m_cursorSizeNS );
1583 m_onSplitter = 1;
1584 }
1585 else
1586 {
1587 if ( m_onSplitter )
1588 {
1589 SetCursor ( wxNullCursor );
1590 }
1591 m_onSplitter = 0;
1592 }
1593 }
1594 }
1595
1596 // -----------------------------------------------------------------------
1597
1598 void wxPropertyGridManager::OnMouseClick( wxMouseEvent &event )
1599 {
1600 int y = event.m_y;
1601
1602 // Click on splitter.
1603 if ( y >= m_splitterY && y < (m_splitterY+m_splitterHeight+2) )
1604 {
1605 if ( m_dragStatus == 0 )
1606 {
1607 //
1608 // Begin draggin the splitter
1609 //
1610
1611 BEGIN_MOUSE_CAPTURE
1612
1613 m_dragStatus = 1;
1614
1615 m_dragOffset = y - m_splitterY;
1616
1617 }
1618 }
1619 }
1620
1621 // -----------------------------------------------------------------------
1622
1623 void wxPropertyGridManager::OnMouseUp( wxMouseEvent &event )
1624 {
1625 // No event type check - basicly calling this method should
1626 // just stop dragging.
1627
1628 if ( m_dragStatus >= 1 )
1629 {
1630 //
1631 // End Splitter Dragging
1632 //
1633
1634 int y = event.m_y;
1635
1636 // DO NOT ENABLE FOLLOWING LINE!
1637 // (it is only here as a reminder to not to do it)
1638 //m_splitterY = y;
1639
1640 // This is necessary to return cursor
1641 END_MOUSE_CAPTURE
1642
1643 // Set back the default cursor, if necessary
1644 if ( y < m_splitterY || y >= (m_splitterY+m_splitterHeight+2) )
1645 {
1646 SetCursor ( wxNullCursor );
1647 }
1648
1649 m_dragStatus = 0;
1650 }
1651 }
1652
1653 // -----------------------------------------------------------------------
1654
1655 void wxPropertyGridManager::SetSplitterPosition( int pos, int splitterColumn )
1656 {
1657 wxASSERT_MSG( GetPageCount(),
1658 wxT("SetSplitterPosition() has no effect until pages have been added") );
1659
1660 size_t i;
1661 for ( i=0; i<GetPageCount(); i++ )
1662 {
1663 wxPropertyGridPage* page = GetPage(i);
1664 page->DoSetSplitterPosition( pos, splitterColumn, false );
1665 }
1666
1667 m_pPropGrid->SetInternalFlag(wxPG_FL_SPLITTER_PRE_SET);
1668 }
1669
1670 // -----------------------------------------------------------------------
1671 // wxPGVIterator_Manager
1672 // -----------------------------------------------------------------------
1673
1674 // Default returned by wxPropertyGridInterface::CreateVIterator().
1675 class wxPGVIteratorBase_Manager : public wxPGVIteratorBase
1676 {
1677 public:
1678 wxPGVIteratorBase_Manager( wxPropertyGridManager* manager, int flags )
1679 : m_manager(manager), m_flags(flags), m_curPage(0)
1680 {
1681 m_it.Init(manager->GetPage(0), flags);
1682 }
1683 virtual ~wxPGVIteratorBase_Manager() { }
1684 virtual void Next()
1685 {
1686 m_it.Next();
1687
1688 // Next page?
1689 if ( m_it.AtEnd() )
1690 {
1691 m_curPage++;
1692 if ( m_curPage < m_manager->GetPageCount() )
1693 m_it.Init( m_manager->GetPage(m_curPage), m_flags );
1694 }
1695 }
1696 private:
1697 wxPropertyGridManager* m_manager;
1698 int m_flags;
1699 unsigned int m_curPage;
1700 };
1701
1702 wxPGVIterator wxPropertyGridManager::GetVIterator( int flags ) const
1703 {
1704 return wxPGVIterator( new wxPGVIteratorBase_Manager( (wxPropertyGridManager*)this, flags ) );
1705 }
1706
1707 #endif // wxUSE_PROPGRID