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