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