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