]> git.saurik.com Git - wxWidgets.git/blob - src/propgrid/editors.cpp
Added command to set wxPG_PROP_READONLY in the propgrid sample
[wxWidgets.git] / src / propgrid / editors.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/editors.cpp
3 // Purpose: wxPropertyGrid editors
4 // Author: Jaakko Salli
5 // Modified by:
6 // Created: 2007-04-14
7 // RCS-ID: $Id$
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_PROPGRID
20
21 #ifndef WX_PRECOMP
22 #include "wx/defs.h"
23 #include "wx/object.h"
24 #include "wx/hash.h"
25 #include "wx/string.h"
26 #include "wx/log.h"
27 #include "wx/event.h"
28 #include "wx/window.h"
29 #include "wx/panel.h"
30 #include "wx/dc.h"
31 #include "wx/dcclient.h"
32 #include "wx/dcmemory.h"
33 #include "wx/button.h"
34 #include "wx/pen.h"
35 #include "wx/brush.h"
36 #include "wx/cursor.h"
37 #include "wx/dialog.h"
38 #include "wx/settings.h"
39 #include "wx/msgdlg.h"
40 #include "wx/choice.h"
41 #include "wx/stattext.h"
42 #include "wx/scrolwin.h"
43 #include "wx/dirdlg.h"
44 #include "wx/sizer.h"
45 #include "wx/textdlg.h"
46 #include "wx/filedlg.h"
47 #include "wx/statusbr.h"
48 #include "wx/intl.h"
49 #include "wx/frame.h"
50 #endif
51
52
53 #include "wx/timer.h"
54 #include "wx/dcbuffer.h"
55 #include "wx/bmpbuttn.h"
56
57
58 // This define is necessary to prevent macro clearing
59 #define __wxPG_SOURCE_FILE__
60
61 #include "wx/propgrid/propgrid.h"
62 #include "wx/propgrid/editors.h"
63 #include "wx/propgrid/props.h"
64
65 #if wxPG_USE_RENDERER_NATIVE
66 #include "wx/renderer.h"
67 #endif
68
69 // How many pixels between textctrl and button
70 #ifdef __WXMAC__
71 #define wxPG_TEXTCTRL_AND_BUTTON_SPACING 4
72 #else
73 #define wxPG_TEXTCTRL_AND_BUTTON_SPACING 2
74 #endif
75
76 #define wxPG_BUTTON_SIZEDEC 0
77
78 #include "wx/odcombo.h"
79
80 // -----------------------------------------------------------------------
81
82 #if defined(__WXMSW__)
83 // tested
84 #define wxPG_NAT_BUTTON_BORDER_ANY 1
85 #define wxPG_NAT_BUTTON_BORDER_X 1
86 #define wxPG_NAT_BUTTON_BORDER_Y 1
87
88 #define wxPG_CHECKMARK_XADJ 1
89 #define wxPG_CHECKMARK_YADJ (-1)
90 #define wxPG_CHECKMARK_WADJ 0
91 #define wxPG_CHECKMARK_HADJ 0
92 #define wxPG_CHECKMARK_DEFLATE 0
93
94 #define wxPG_TEXTCTRLYADJUST (m_spacingy+0)
95
96 #elif defined(__WXGTK__)
97 // tested
98 #define wxPG_CHECKMARK_XADJ 0
99 #define wxPG_CHECKMARK_YADJ 0
100 #define wxPG_CHECKMARK_WADJ (-1)
101 #define wxPG_CHECKMARK_HADJ (-1)
102 #define wxPG_CHECKMARK_DEFLATE 3
103
104 #define wxPG_NAT_BUTTON_BORDER_ANY 1
105 #define wxPG_NAT_BUTTON_BORDER_X 1
106 #define wxPG_NAT_BUTTON_BORDER_Y 1
107
108 #define wxPG_TEXTCTRLYADJUST 0
109
110 #elif defined(__WXMAC__)
111 // *not* tested
112 #define wxPG_CHECKMARK_XADJ 0
113 #define wxPG_CHECKMARK_YADJ 0
114 #define wxPG_CHECKMARK_WADJ 0
115 #define wxPG_CHECKMARK_HADJ 0
116 #define wxPG_CHECKMARK_DEFLATE 0
117
118 #define wxPG_NAT_BUTTON_BORDER_ANY 0
119 #define wxPG_NAT_BUTTON_BORDER_X 0
120 #define wxPG_NAT_BUTTON_BORDER_Y 0
121
122 #define wxPG_TEXTCTRLYADJUST 0
123
124 #else
125 // defaults
126 #define wxPG_CHECKMARK_XADJ 0
127 #define wxPG_CHECKMARK_YADJ 0
128 #define wxPG_CHECKMARK_WADJ 0
129 #define wxPG_CHECKMARK_HADJ 0
130 #define wxPG_CHECKMARK_DEFLATE 0
131
132 #define wxPG_NAT_BUTTON_BORDER_ANY 0
133 #define wxPG_NAT_BUTTON_BORDER_X 0
134 #define wxPG_NAT_BUTTON_BORDER_Y 0
135
136 #define wxPG_TEXTCTRLYADJUST 0
137
138 #endif
139
140 // for odcombo
141 #ifdef __WXMAC__
142 #define wxPG_CHOICEXADJUST -3 // required because wxComboCtrl reserves 3pixels for wxTextCtrl's focus ring
143 #define wxPG_CHOICEYADJUST -3
144 #else
145 #define wxPG_CHOICEXADJUST 0
146 #define wxPG_CHOICEYADJUST 0
147 #endif
148
149 // Number added to image width for SetCustomPaintWidth
150 #define ODCB_CUST_PAINT_MARGIN 6
151
152 // Milliseconds to wait for two mouse-ups after focus inorder
153 // to trigger a double-click.
154 #define DOUBLE_CLICK_CONVERSION_TRESHOLD 500
155
156 // -----------------------------------------------------------------------
157 // wxPGEditor
158 // -----------------------------------------------------------------------
159
160 IMPLEMENT_ABSTRACT_CLASS(wxPGEditor, wxObject)
161
162
163 wxPGEditor::~wxPGEditor()
164 {
165 }
166
167 wxString wxPGEditor::GetName() const
168 {
169 return GetClassInfo()->GetClassName();
170 }
171
172 void wxPGEditor::DrawValue( wxDC& dc, const wxRect& rect,
173 wxPGProperty* WXUNUSED(property),
174 const wxString& text ) const
175 {
176 dc.DrawText( text, rect.x+wxPG_XBEFORETEXT, rect.y );
177 }
178
179 bool wxPGEditor::GetValueFromControl( wxVariant&, wxPGProperty*, wxWindow* ) const
180 {
181 return false;
182 }
183
184 void wxPGEditor::SetControlStringValue( wxPGProperty* WXUNUSED(property), wxWindow*, const wxString& ) const
185 {
186 }
187
188
189 void wxPGEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow*, int ) const
190 {
191 }
192
193
194 int wxPGEditor::InsertItem( wxWindow*, const wxString&, int ) const
195 {
196 return -1;
197 }
198
199
200 void wxPGEditor::DeleteItem( wxWindow*, int ) const
201 {
202 return;
203 }
204
205
206 void wxPGEditor::OnFocus( wxPGProperty*, wxWindow* ) const
207 {
208 }
209
210 void wxPGEditor::SetControlAppearance( wxPropertyGrid* pg,
211 wxPGProperty* property,
212 wxWindow* ctrl,
213 const wxPGCell& cell,
214 const wxPGCell& oCell,
215 bool unspecified ) const
216 {
217 // Get old editor appearance
218 wxTextCtrl* tc = NULL;
219 wxComboCtrl* cb = NULL;
220 if ( ctrl->IsKindOf(CLASSINFO(wxTextCtrl)) )
221 {
222 tc = (wxTextCtrl*) ctrl;
223 }
224 else
225 {
226 if ( ctrl->IsKindOf(CLASSINFO(wxComboCtrl)) )
227 {
228 cb = (wxComboCtrl*) ctrl;
229 tc = cb->GetTextCtrl();
230 }
231 }
232
233 if ( tc || cb )
234 {
235 wxString tcText;
236 bool changeText = false;
237
238 if ( cell.HasText() && !pg->IsEditorFocused() )
239 {
240 tcText = cell.GetText();
241 changeText = true;
242 }
243 else if ( oCell.HasText() )
244 {
245 tcText = property->GetValueAsString(
246 property->HasFlag(wxPG_PROP_READONLY)?0:wxPG_EDITABLE_VALUE);
247 changeText = true;
248 }
249
250 if ( changeText )
251 {
252 // This prevents value from being modified
253 if ( tc )
254 {
255 pg->SetupTextCtrlValue(tcText);
256 tc->SetValue(tcText);
257 }
258 else
259 {
260 cb->SetText(tcText);
261 }
262 }
263 }
264
265 // Do not make the mistake of calling GetClassDefaultAttributes()
266 // here. It is static, while GetDefaultAttributes() is virtual
267 // and the correct one to use.
268 wxVisualAttributes vattrs = ctrl->GetDefaultAttributes();
269
270 // Foreground colour
271 const wxColour& fgCol = cell.GetFgCol();
272 if ( fgCol.IsOk() )
273 {
274 ctrl->SetForegroundColour(fgCol);
275 }
276 else if ( oCell.GetFgCol().IsOk() )
277 {
278 ctrl->SetForegroundColour(vattrs.colFg);
279 }
280
281 // Background colour
282 const wxColour& bgCol = cell.GetBgCol();
283 if ( bgCol.IsOk() )
284 {
285 ctrl->SetBackgroundColour(bgCol);
286 }
287 else if ( oCell.GetBgCol().IsOk() )
288 {
289 ctrl->SetBackgroundColour(vattrs.colBg);
290 }
291
292 // Font
293 const wxFont& font = cell.GetFont();
294 if ( font.IsOk() )
295 {
296 ctrl->SetFont(font);
297 }
298 else if ( oCell.GetFont().IsOk() )
299 {
300 ctrl->SetFont(vattrs.font);
301 }
302
303 // Also call the old SetValueToUnspecified()
304 if ( unspecified )
305 SetValueToUnspecified(property, ctrl);
306 }
307
308 void wxPGEditor::SetValueToUnspecified( wxPGProperty* WXUNUSED(property),
309 wxWindow* WXUNUSED(ctrl) ) const
310 {
311 }
312
313 bool wxPGEditor::CanContainCustomImage() const
314 {
315 return false;
316 }
317
318 // -----------------------------------------------------------------------
319 // wxPGTextCtrlEditor
320 // -----------------------------------------------------------------------
321
322 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(TextCtrl,wxPGTextCtrlEditor,wxPGEditor)
323
324
325 wxPGWindowList wxPGTextCtrlEditor::CreateControls( wxPropertyGrid* propGrid,
326 wxPGProperty* property,
327 const wxPoint& pos,
328 const wxSize& sz ) const
329 {
330 wxString text;
331
332 //
333 // If has children, and limited editing is specified, then don't create.
334 if ( (property->GetFlags() & wxPG_PROP_NOEDITOR) &&
335 property->GetChildCount() )
336 return NULL;
337
338 int argFlags = 0;
339 if ( !property->HasFlag(wxPG_PROP_READONLY) &&
340 !property->IsValueUnspecified() )
341 argFlags |= wxPG_EDITABLE_VALUE;
342 text = property->GetValueAsString(argFlags);
343
344 int flags = 0;
345 if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
346 property->IsKindOf(CLASSINFO(wxStringProperty)) )
347 flags |= wxTE_PASSWORD;
348
349 wxWindow* wnd = propGrid->GenerateEditorTextCtrl(pos,sz,text,NULL,flags,
350 property->GetMaxLength());
351
352 return wnd;
353 }
354
355 #if 0
356 void wxPGTextCtrlEditor::DrawValue( wxDC& dc, wxPGProperty* property, const wxRect& rect ) const
357 {
358 if ( !property->IsValueUnspecified() )
359 {
360 wxString drawStr = property->GetDisplayedString();
361
362 // Code below should no longer be needed, as the obfuscation
363 // is now done in GetValueAsString.
364 /*if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
365 property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
366 {
367 size_t a = drawStr.length();
368 drawStr.Empty();
369 drawStr.Append(wxS('*'),a);
370 }*/
371 dc.DrawText( drawStr, rect.x+wxPG_XBEFORETEXT, rect.y );
372 }
373 }
374 #endif
375
376 void wxPGTextCtrlEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
377 {
378 wxTextCtrl* tc = wxDynamicCast(ctrl, wxTextCtrl);
379 if (!tc) return;
380
381 wxString s;
382
383 if ( tc->HasFlag(wxTE_PASSWORD) )
384 s = property->GetValueAsString(wxPG_FULL_VALUE);
385 else
386 s = property->GetDisplayedString();
387
388 wxPropertyGrid* pg = property->GetGrid();
389
390 pg->SetupTextCtrlValue(s);
391 tc->SetValue(s);
392
393 //
394 // Fix indentation, just in case (change in font boldness is one good
395 // reason).
396 tc->SetMargins(0);
397 }
398
399 // Provided so that, for example, ComboBox editor can use the same code
400 // (multiple inheritance would get way too messy).
401 bool wxPGTextCtrlEditor::OnTextCtrlEvent( wxPropertyGrid* propGrid,
402 wxPGProperty* WXUNUSED(property),
403 wxWindow* ctrl,
404 wxEvent& event )
405 {
406 if ( !ctrl )
407 return false;
408
409 if ( event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER )
410 {
411 if ( propGrid->IsEditorsValueModified() )
412 {
413 return true;
414 }
415 }
416 else if ( event.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED )
417 {
418 //
419 // Pass this event outside wxPropertyGrid so that,
420 // if necessary, program can tell when user is editing
421 // a textctrl.
422 // FIXME: Is it safe to change event id in the middle of event
423 // processing (seems to work, but...)?
424 event.Skip();
425 event.SetId(propGrid->GetId());
426
427 propGrid->EditorsValueWasModified();
428 }
429 return false;
430 }
431
432
433 bool wxPGTextCtrlEditor::OnEvent( wxPropertyGrid* propGrid,
434 wxPGProperty* property,
435 wxWindow* ctrl,
436 wxEvent& event ) const
437 {
438 return wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid,property,ctrl,event);
439 }
440
441
442 bool wxPGTextCtrlEditor::GetTextCtrlValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl )
443 {
444 wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
445 wxString textVal = tc->GetValue();
446
447 if ( property->UsesAutoUnspecified() && !textVal.length() )
448 {
449 variant.MakeNull();
450 return true;
451 }
452
453 bool res = property->StringToValue(variant, textVal, wxPG_EDITABLE_VALUE);
454
455 // Changing unspecified always causes event (returning
456 // true here should be enough to trigger it).
457 // TODO: Move to propgrid.cpp
458 if ( !res && variant.IsNull() )
459 res = true;
460
461 return res;
462 }
463
464
465 bool wxPGTextCtrlEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
466 {
467 return wxPGTextCtrlEditor::GetTextCtrlValueFromControl(variant, property, ctrl);
468 }
469
470
471 void wxPGTextCtrlEditor::SetControlStringValue( wxPGProperty* property, wxWindow* ctrl, const wxString& txt ) const
472 {
473 wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
474
475 wxPropertyGrid* pg = property->GetGrid();
476 wxASSERT(pg); // Really, property grid should exist if editor does
477 if ( pg )
478 {
479 pg->SetupTextCtrlValue(txt);
480 tc->SetValue(txt);
481 }
482 }
483
484
485 void wxPGTextCtrlEditor_OnFocus( wxPGProperty* property,
486 wxTextCtrl* tc )
487 {
488 // Make sure there is correct text (instead of unspecified value
489 // indicator or hint text)
490 int flags = property->HasFlag(wxPG_PROP_READONLY) ?
491 0 : wxPG_EDITABLE_VALUE;
492 wxString correctText = property->GetValueAsString(flags);
493
494 if ( tc->GetValue() != correctText )
495 {
496 property->GetGrid()->SetupTextCtrlValue(correctText);
497 tc->SetValue(correctText);
498 }
499
500 tc->SetSelection(-1,-1);
501 }
502
503 void wxPGTextCtrlEditor::OnFocus( wxPGProperty* property,
504 wxWindow* wnd ) const
505 {
506 wxTextCtrl* tc = wxStaticCast(wnd, wxTextCtrl);
507 wxPGTextCtrlEditor_OnFocus(property, tc);
508 }
509
510 wxPGTextCtrlEditor::~wxPGTextCtrlEditor() { }
511
512
513 // -----------------------------------------------------------------------
514 // wxPGChoiceEditor
515 // -----------------------------------------------------------------------
516
517
518 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(Choice,wxPGChoiceEditor,wxPGEditor)
519
520
521 // This is a special enhanced double-click processor class.
522 // In essence, it allows for double-clicks for which the
523 // first click "created" the control.
524 class wxPGDoubleClickProcessor : public wxEvtHandler
525 {
526 public:
527
528 wxPGDoubleClickProcessor( wxOwnerDrawnComboBox* combo, wxPGProperty* property )
529 : wxEvtHandler()
530 {
531 m_timeLastMouseUp = 0;
532 m_combo = combo;
533 m_property = property;
534 m_downReceived = false;
535 }
536
537 protected:
538
539 void OnMouseEvent( wxMouseEvent& event )
540 {
541 wxLongLong t = ::wxGetLocalTimeMillis();
542 int evtType = event.GetEventType();
543
544 if ( m_property->HasFlag(wxPG_PROP_USE_DCC) &&
545 m_property->IsKindOf(CLASSINFO(wxBoolProperty)) &&
546 !m_combo->IsPopupShown() )
547 {
548 // Just check that it is in the text area
549 wxPoint pt = event.GetPosition();
550 if ( m_combo->GetTextRect().Contains(pt) )
551 {
552 if ( evtType == wxEVT_LEFT_DOWN )
553 {
554 // Set value to avoid up-events without corresponding downs
555 m_downReceived = true;
556 }
557 else if ( evtType == wxEVT_LEFT_DCLICK )
558 {
559 // We'll make our own double-clicks
560 event.SetEventType(0);
561 return;
562 }
563 else if ( evtType == wxEVT_LEFT_UP )
564 {
565 if ( m_downReceived || m_timeLastMouseUp == 1 )
566 {
567 wxLongLong timeFromLastUp = (t-m_timeLastMouseUp);
568
569 if ( timeFromLastUp < DOUBLE_CLICK_CONVERSION_TRESHOLD )
570 {
571 event.SetEventType(wxEVT_LEFT_DCLICK);
572 m_timeLastMouseUp = 1;
573 }
574 else
575 {
576 m_timeLastMouseUp = t;
577 }
578 }
579 }
580 }
581 }
582
583 event.Skip();
584 }
585
586 void OnSetFocus( wxFocusEvent& event )
587 {
588 m_timeLastMouseUp = ::wxGetLocalTimeMillis();
589 event.Skip();
590 }
591
592 private:
593 wxLongLong m_timeLastMouseUp;
594 wxOwnerDrawnComboBox* m_combo;
595 wxPGProperty* m_property; // Selected property
596 bool m_downReceived;
597
598 DECLARE_EVENT_TABLE()
599 };
600
601 BEGIN_EVENT_TABLE(wxPGDoubleClickProcessor, wxEvtHandler)
602 EVT_MOUSE_EVENTS(wxPGDoubleClickProcessor::OnMouseEvent)
603 EVT_SET_FOCUS(wxPGDoubleClickProcessor::OnSetFocus)
604 END_EVENT_TABLE()
605
606
607
608 class wxPGComboBox : public wxOwnerDrawnComboBox
609 {
610 public:
611
612 wxPGComboBox()
613 : wxOwnerDrawnComboBox()
614 {
615 m_dclickProcessor = NULL;
616 m_sizeEventCalled = false;
617 }
618
619 ~wxPGComboBox()
620 {
621 if ( m_dclickProcessor )
622 {
623 RemoveEventHandler(m_dclickProcessor);
624 delete m_dclickProcessor;
625 }
626 }
627
628 bool Create(wxWindow *parent,
629 wxWindowID id,
630 const wxString& value,
631 const wxPoint& pos,
632 const wxSize& size,
633 const wxArrayString& choices,
634 long style = 0,
635 const wxValidator& validator = wxDefaultValidator,
636 const wxString& name = wxS("wxOwnerDrawnComboBox"))
637 {
638 if ( !wxOwnerDrawnComboBox::Create( parent,
639 id,
640 value,
641 pos,
642 size,
643 choices,
644 style,
645 validator,
646 name ) )
647 return false;
648
649 m_dclickProcessor = new
650 wxPGDoubleClickProcessor( this, GetGrid()->GetSelection() );
651
652 PushEventHandler(m_dclickProcessor);
653
654 return true;
655 }
656
657 virtual void OnDrawItem( wxDC& dc,
658 const wxRect& rect,
659 int item,
660 int flags ) const
661 {
662 wxPropertyGrid* pg = GetGrid();
663
664 // Handle hint text via super class
665 if ( (flags & wxODCB_PAINTING_CONTROL) &&
666 ShouldUseHintText(flags) )
667 {
668 wxOwnerDrawnComboBox::OnDrawItem(dc, rect, item, flags);
669 }
670 else
671 {
672 pg->OnComboItemPaint( this, item, &dc, (wxRect&)rect, flags );
673 }
674 }
675
676 virtual wxCoord OnMeasureItem( size_t item ) const
677 {
678 wxPropertyGrid* pg = GetGrid();
679 wxRect rect;
680 rect.x = -1;
681 rect.width = 0;
682 pg->OnComboItemPaint( this, item, NULL, rect, 0 );
683 return rect.height;
684 }
685
686 wxPropertyGrid* GetGrid() const
687 {
688 wxPropertyGrid* pg = wxDynamicCast(GetParent(),
689 wxPropertyGrid);
690 wxASSERT(pg);
691 return pg;
692 }
693
694 virtual wxCoord OnMeasureItemWidth( size_t item ) const
695 {
696 wxPropertyGrid* pg = GetGrid();
697 wxRect rect;
698 rect.x = -1;
699 rect.width = -1;
700 pg->OnComboItemPaint( this, item, NULL, rect, 0 );
701 return rect.width;
702 }
703
704 virtual void PositionTextCtrl( int textCtrlXAdjust,
705 int WXUNUSED(textCtrlYAdjust) )
706 {
707 wxPropertyGrid* pg = GetGrid();
708 #ifdef wxPG_TEXTCTRLXADJUST
709 textCtrlXAdjust = wxPG_TEXTCTRLXADJUST -
710 (wxPG_XBEFOREWIDGET+wxPG_CONTROL_MARGIN+1) - 1,
711 #endif
712 wxOwnerDrawnComboBox::PositionTextCtrl(
713 textCtrlXAdjust,
714 pg->GetSpacingY() + 2
715 );
716 }
717
718 private:
719 wxPGDoubleClickProcessor* m_dclickProcessor;
720 bool m_sizeEventCalled;
721 };
722
723
724 void wxPropertyGrid::OnComboItemPaint( const wxPGComboBox* pCb,
725 int item,
726 wxDC* pDc,
727 wxRect& rect,
728 int flags )
729 {
730 // Sanity check
731 wxASSERT( IsKindOf(CLASSINFO(wxPropertyGrid)) );
732
733 wxPGProperty* p = GetSelection();
734 wxString text;
735
736 const wxPGChoices& choices = p->GetChoices();
737 const wxPGCommonValue* comVal = NULL;
738 int comVals = p->GetDisplayedCommonValueCount();
739 int comValIndex = -1;
740
741 int choiceCount = 0;
742 if ( choices.IsOk() )
743 choiceCount = choices.GetCount();
744
745 if ( item >= choiceCount && comVals > 0 )
746 {
747 comValIndex = item - choiceCount;
748 comVal = GetCommonValue(comValIndex);
749 if ( !p->IsValueUnspecified() )
750 text = comVal->GetLabel();
751 }
752 else
753 {
754 if ( !(flags & wxODCB_PAINTING_CONTROL) )
755 {
756 text = pCb->GetString(item);
757 }
758 else
759 {
760 if ( !p->IsValueUnspecified() )
761 text = p->GetValueAsString(0);
762 }
763 }
764
765 if ( item < 0 )
766 return;
767
768 wxSize cis;
769
770 const wxBitmap* itemBitmap = NULL;
771
772 if ( item >= 0 && choices.IsOk() && choices.Item(item).GetBitmap().Ok() && comValIndex == -1 )
773 itemBitmap = &choices.Item(item).GetBitmap();
774
775 //
776 // Decide what custom image size to use
777 if ( itemBitmap )
778 {
779 cis.x = itemBitmap->GetWidth();
780 cis.y = itemBitmap->GetHeight();
781 }
782 else
783 {
784 cis = GetImageSize(p, item);
785 }
786
787 if ( rect.x < 0 )
788 {
789 // Default measure behaviour (no flexible, custom paint image only)
790 if ( rect.width < 0 )
791 {
792 wxCoord x, y;
793 pCb->GetTextExtent(text, &x, &y, 0, 0);
794 rect.width = cis.x + wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2 + 9 + x;
795 }
796
797 rect.height = cis.y + 2;
798 return;
799 }
800
801 wxPGPaintData paintdata;
802 paintdata.m_parent = NULL;
803 paintdata.m_choiceItem = item;
804
805 // This is by the current (1.0.0b) spec - if painting control, item is -1
806 if ( (flags & wxODCB_PAINTING_CONTROL) )
807 paintdata.m_choiceItem = -1;
808
809 if ( pDc )
810 pDc->SetBrush(*wxWHITE_BRUSH);
811
812 wxPGCellRenderer* renderer = NULL;
813 const wxPGChoiceEntry* cell = NULL;
814
815 if ( rect.x >= 0 )
816 {
817 //
818 // DrawItem call
819 wxDC& dc = *pDc;
820
821 wxPoint pt(rect.x + wxPG_CONTROL_MARGIN - wxPG_CHOICEXADJUST - 1,
822 rect.y + 1);
823
824 int renderFlags = wxPGCellRenderer::DontUseCellColours;
825 bool useCustomPaintProcedure;
826
827 // If custom image had some size, we will start from the assumption
828 // that custom paint procedure is required
829 if ( cis.x > 0 )
830 useCustomPaintProcedure = true;
831 else
832 useCustomPaintProcedure = false;
833
834 if ( flags & wxODCB_PAINTING_SELECTED )
835 renderFlags |= wxPGCellRenderer::Selected;
836
837 if ( flags & wxODCB_PAINTING_CONTROL )
838 {
839 renderFlags |= wxPGCellRenderer::Control;
840
841 // If wxPG_PROP_CUSTOMIMAGE was set, then that means any custom
842 // image will not appear on the control row (it may be too
843 // large to fit, for instance). Also do not draw custom image
844 // if no choice was selected.
845 if ( !p->HasFlag(wxPG_PROP_CUSTOMIMAGE) || item < 0 )
846 useCustomPaintProcedure = false;
847 }
848 else
849 {
850 renderFlags |= wxPGCellRenderer::ChoicePopup;
851 }
852
853 // If not drawing a selected popup item, then give property's
854 // m_valueBitmap a chance.
855 if ( p->m_valueBitmap && item != pCb->GetSelection() )
856 useCustomPaintProcedure = false;
857 // If current choice had a bitmap set by the application, then
858 // use it instead of any custom paint procedure.
859 else if ( itemBitmap )
860 useCustomPaintProcedure = false;
861
862 if ( useCustomPaintProcedure )
863 {
864 pt.x += wxCC_CUSTOM_IMAGE_MARGIN1;
865 wxRect r(pt.x,pt.y,cis.x,cis.y);
866
867 if ( flags & wxODCB_PAINTING_CONTROL )
868 {
869 //r.width = cis.x;
870 r.height = wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight);
871 }
872
873 paintdata.m_drawnWidth = r.width;
874
875 dc.SetPen(m_colPropFore);
876 if ( comValIndex >= 0 )
877 {
878 const wxPGCommonValue* cv = GetCommonValue(comValIndex);
879 wxPGCellRenderer* renderer = cv->GetRenderer();
880 r.width = rect.width;
881 renderer->Render( dc, r, this, p, m_selColumn, comValIndex, renderFlags );
882 return;
883 }
884 else if ( item >= 0 )
885 {
886 p->OnCustomPaint( dc, r, paintdata );
887 }
888 else
889 {
890 dc.DrawRectangle( r );
891 }
892
893 pt.x += paintdata.m_drawnWidth + wxCC_CUSTOM_IMAGE_MARGIN2 - 1;
894 }
895 else
896 {
897 // TODO: This aligns text so that it seems to be horizontally
898 // on the same line as property values. Not really
899 // sure if its needed, but seems to not cause any harm.
900 pt.x -= 1;
901
902 if ( item < 0 && (flags & wxODCB_PAINTING_CONTROL) )
903 item = pCb->GetSelection();
904
905 if ( choices.IsOk() && item >= 0 && comValIndex < 0 )
906 {
907 cell = &choices.Item(item);
908 renderer = wxPGGlobalVars->m_defaultRenderer;
909 int imageOffset = renderer->PreDrawCell(dc, rect, *cell,
910 renderFlags );
911 if ( imageOffset )
912 imageOffset += wxCC_CUSTOM_IMAGE_MARGIN1 +
913 wxCC_CUSTOM_IMAGE_MARGIN2;
914 pt.x += imageOffset;
915 }
916 }
917
918 //
919 // Draw text
920 //
921
922 pt.y += (rect.height-m_fontHeight)/2 - 1;
923
924 pt.x += 1;
925
926 dc.DrawText( text, pt.x + wxPG_XBEFORETEXT, pt.y );
927
928 if ( renderer )
929 renderer->PostDrawCell(dc, this, *cell, renderFlags);
930 }
931 else
932 {
933 //
934 // MeasureItem call
935 wxDC& dc = *pDc;
936
937 p->OnCustomPaint( dc, rect, paintdata );
938 rect.height = paintdata.m_drawnHeight + 2;
939 rect.width = cis.x + wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2 + 9;
940 }
941 }
942
943 bool wxPGChoiceEditor_SetCustomPaintWidth( wxPropertyGrid* propGrid, wxPGComboBox* cb, int cmnVal )
944 {
945 wxPGProperty* property = propGrid->GetSelectedProperty();
946 wxASSERT( property );
947
948 wxSize imageSize;
949 bool res;
950
951 // TODO: Do this always when cell has custom text.
952 if ( property->IsValueUnspecified() )
953 {
954 cb->SetCustomPaintWidth( 0 );
955 return true;
956 }
957
958 if ( cmnVal >= 0 )
959 {
960 // Yes, a common value is being selected
961 property->SetCommonValue( cmnVal );
962 imageSize = propGrid->GetCommonValue(cmnVal)->
963 GetRenderer()->GetImageSize(property, 1, cmnVal);
964 res = false;
965 }
966 else
967 {
968 imageSize = propGrid->GetImageSize(property, -1);
969 res = true;
970 }
971
972 if ( imageSize.x )
973 imageSize.x += ODCB_CUST_PAINT_MARGIN;
974 cb->SetCustomPaintWidth( imageSize.x );
975
976 return res;
977 }
978
979 // CreateControls calls this with CB_READONLY in extraStyle
980 wxWindow* wxPGChoiceEditor::CreateControlsBase( wxPropertyGrid* propGrid,
981 wxPGProperty* property,
982 const wxPoint& pos,
983 const wxSize& sz,
984 long extraStyle ) const
985 {
986 const wxPGChoices& choices = property->GetChoices();
987 wxString defString;
988 int index = property->GetChoiceSelection();
989
990 int argFlags = 0;
991 if ( !property->HasFlag(wxPG_PROP_READONLY) &&
992 !property->IsValueUnspecified() )
993 argFlags |= wxPG_EDITABLE_VALUE;
994 defString = property->GetValueAsString(argFlags);
995
996 wxArrayString labels = choices.GetLabels();
997
998 wxPGComboBox* cb;
999
1000 wxPoint po(pos);
1001 wxSize si(sz);
1002 po.y += wxPG_CHOICEYADJUST;
1003 si.y -= (wxPG_CHOICEYADJUST*2);
1004
1005 po.x += wxPG_CHOICEXADJUST;
1006 si.x -= wxPG_CHOICEXADJUST;
1007 wxWindow* ctrlParent = propGrid->GetPanel();
1008
1009 int odcbFlags = extraStyle | wxBORDER_NONE | wxTE_PROCESS_ENTER;
1010
1011 if ( (property->GetFlags() & wxPG_PROP_USE_DCC) &&
1012 (property->IsKindOf(CLASSINFO(wxBoolProperty)) ) )
1013 odcbFlags |= wxODCB_DCLICK_CYCLES;
1014
1015 //
1016 // If common value specified, use appropriate index
1017 unsigned int cmnVals = property->GetDisplayedCommonValueCount();
1018 if ( cmnVals )
1019 {
1020 if ( !property->IsValueUnspecified() )
1021 {
1022 int cmnVal = property->GetCommonValue();
1023 if ( cmnVal >= 0 )
1024 {
1025 index = labels.size() + cmnVal;
1026 }
1027 }
1028
1029 unsigned int i;
1030 for ( i=0; i<cmnVals; i++ )
1031 labels.Add(propGrid->GetCommonValueLabel(i));
1032 }
1033
1034 cb = new wxPGComboBox();
1035 #ifdef __WXMSW__
1036 cb->Hide();
1037 #endif
1038 cb->Create(ctrlParent,
1039 wxPG_SUBID1,
1040 wxString(),
1041 po,
1042 si,
1043 labels,
1044 odcbFlags);
1045
1046 cb->SetButtonPosition(si.y,0,wxRIGHT);
1047 cb->SetMargins(wxPG_XBEFORETEXT-1);
1048
1049 // Set hint text
1050 cb->SetHint(property->GetHintText());
1051
1052 wxPGChoiceEditor_SetCustomPaintWidth( propGrid, cb,
1053 property->GetCommonValue() );
1054
1055 if ( index >= 0 && index < (int)cb->GetCount() )
1056 {
1057 cb->SetSelection( index );
1058 if ( defString.length() )
1059 cb->SetText( defString );
1060 }
1061 else if ( !(extraStyle & wxCB_READONLY) && defString.length() )
1062 {
1063 propGrid->SetupTextCtrlValue(defString);
1064 cb->SetValue( defString );
1065 }
1066 else
1067 {
1068 cb->SetSelection( -1 );
1069 }
1070
1071 #ifdef __WXMSW__
1072 cb->Show();
1073 #endif
1074
1075 return (wxWindow*) cb;
1076 }
1077
1078
1079 void wxPGChoiceEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
1080 {
1081 wxASSERT( ctrl );
1082 wxOwnerDrawnComboBox* cb = (wxOwnerDrawnComboBox*)ctrl;
1083 wxASSERT( cb->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)));
1084 int ind = property->GetChoiceSelection();
1085 cb->SetSelection(ind);
1086 }
1087
1088 wxPGWindowList wxPGChoiceEditor::CreateControls( wxPropertyGrid* propGrid, wxPGProperty* property,
1089 const wxPoint& pos, const wxSize& sz ) const
1090 {
1091 return CreateControlsBase(propGrid,property,pos,sz,wxCB_READONLY);
1092 }
1093
1094
1095 int wxPGChoiceEditor::InsertItem( wxWindow* ctrl, const wxString& label, int index ) const
1096 {
1097 wxASSERT( ctrl );
1098 wxOwnerDrawnComboBox* cb = (wxOwnerDrawnComboBox*)ctrl;
1099 wxASSERT( cb->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)));
1100
1101 if (index < 0)
1102 index = cb->GetCount();
1103
1104 return cb->Insert(label,index);
1105 }
1106
1107
1108 void wxPGChoiceEditor::DeleteItem( wxWindow* ctrl, int index ) const
1109 {
1110 wxASSERT( ctrl );
1111 wxOwnerDrawnComboBox* cb = (wxOwnerDrawnComboBox*)ctrl;
1112 wxASSERT( cb->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)));
1113
1114 cb->Delete(index);
1115 }
1116
1117 bool wxPGChoiceEditor::OnEvent( wxPropertyGrid* propGrid, wxPGProperty* property,
1118 wxWindow* ctrl, wxEvent& event ) const
1119 {
1120 if ( event.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED )
1121 {
1122 wxPGComboBox* cb = (wxPGComboBox*)ctrl;
1123 int index = cb->GetSelection();
1124 int cmnValIndex = -1;
1125 int cmnVals = property->GetDisplayedCommonValueCount();
1126 int items = cb->GetCount();
1127
1128 if ( index >= (items-cmnVals) )
1129 {
1130 // Yes, a common value is being selected
1131 cmnValIndex = index - (items-cmnVals);
1132 property->SetCommonValue( cmnValIndex );
1133
1134 // Truly set value to unspecified?
1135 if ( propGrid->GetUnspecifiedCommonValue() == cmnValIndex )
1136 {
1137 if ( !property->IsValueUnspecified() )
1138 propGrid->SetInternalFlag(wxPG_FL_VALUE_CHANGE_IN_EVENT);
1139 property->SetValueToUnspecified();
1140 if ( !cb->HasFlag(wxCB_READONLY) )
1141 {
1142 wxString unspecValueText;
1143 unspecValueText = propGrid->GetUnspecifiedValueText();
1144 propGrid->SetupTextCtrlValue(unspecValueText);
1145 cb->GetTextCtrl()->SetValue(unspecValueText);
1146 }
1147 return false;
1148 }
1149 }
1150 return wxPGChoiceEditor_SetCustomPaintWidth( propGrid, cb, cmnValIndex );
1151 }
1152 return false;
1153 }
1154
1155
1156 bool wxPGChoiceEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
1157 {
1158 wxOwnerDrawnComboBox* cb = (wxOwnerDrawnComboBox*)ctrl;
1159
1160 int index = cb->GetSelection();
1161
1162 if ( index != property->GetChoiceSelection() ||
1163 // Changing unspecified always causes event (returning
1164 // true here should be enough to trigger it).
1165 property->IsValueUnspecified()
1166 )
1167 {
1168 return property->IntToValue( variant, index, 0 );
1169 }
1170 return false;
1171 }
1172
1173
1174 void wxPGChoiceEditor::SetControlStringValue( wxPGProperty* property,
1175 wxWindow* ctrl,
1176 const wxString& txt ) const
1177 {
1178 wxOwnerDrawnComboBox* cb = (wxOwnerDrawnComboBox*)ctrl;
1179 wxASSERT( cb );
1180 property->GetGrid()->SetupTextCtrlValue(txt);
1181 cb->SetValue(txt);
1182 }
1183
1184
1185 void wxPGChoiceEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow* ctrl, int value ) const
1186 {
1187 wxOwnerDrawnComboBox* cb = (wxOwnerDrawnComboBox*)ctrl;
1188 wxASSERT( cb );
1189 cb->SetSelection(value);
1190 }
1191
1192
1193 void wxPGChoiceEditor::SetValueToUnspecified( wxPGProperty* WXUNUSED(property),
1194 wxWindow* ctrl ) const
1195 {
1196 wxOwnerDrawnComboBox* cb = (wxOwnerDrawnComboBox*)ctrl;
1197
1198 if ( cb->HasFlag(wxCB_READONLY) )
1199 cb->SetSelection(-1);
1200 }
1201
1202
1203 bool wxPGChoiceEditor::CanContainCustomImage() const
1204 {
1205 return true;
1206 }
1207
1208
1209 wxPGChoiceEditor::~wxPGChoiceEditor() { }
1210
1211
1212 // -----------------------------------------------------------------------
1213 // wxPGComboBoxEditor
1214 // -----------------------------------------------------------------------
1215
1216
1217 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(ComboBox,
1218 wxPGComboBoxEditor,
1219 wxPGChoiceEditor)
1220
1221
1222 void wxPGComboBoxEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
1223 {
1224 wxOwnerDrawnComboBox* cb = (wxOwnerDrawnComboBox*)ctrl;
1225 wxString s = property->GetValueAsString(wxPG_EDITABLE_VALUE);
1226 property->GetGrid()->SetupTextCtrlValue(s);
1227 cb->SetValue(s);
1228
1229 // TODO: If string matches any selection, then select that.
1230 }
1231
1232
1233 wxPGWindowList wxPGComboBoxEditor::CreateControls( wxPropertyGrid* propGrid,
1234 wxPGProperty* property,
1235 const wxPoint& pos,
1236 const wxSize& sz ) const
1237 {
1238 return CreateControlsBase(propGrid,property,pos,sz,0);
1239 }
1240
1241
1242 bool wxPGComboBoxEditor::OnEvent( wxPropertyGrid* propGrid,
1243 wxPGProperty* property,
1244 wxWindow* ctrl,
1245 wxEvent& event ) const
1246 {
1247 wxOwnerDrawnComboBox* cb = NULL;
1248 wxWindow* textCtrl = NULL;
1249
1250 if ( ctrl )
1251 {
1252 cb = (wxOwnerDrawnComboBox*)ctrl;
1253 textCtrl = cb->GetTextCtrl();
1254 }
1255
1256 if ( wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid,property,textCtrl,event) )
1257 return true;
1258
1259 return wxPGChoiceEditor::OnEvent(propGrid,property,ctrl,event);
1260 }
1261
1262
1263 bool wxPGComboBoxEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
1264 {
1265 wxOwnerDrawnComboBox* cb = (wxOwnerDrawnComboBox*)ctrl;
1266 wxString textVal = cb->GetValue();
1267
1268 if ( property->UsesAutoUnspecified() && !textVal.length() )
1269 {
1270 variant.MakeNull();
1271 return true;
1272 }
1273
1274 bool res = property->StringToValue(variant, textVal, wxPG_EDITABLE_VALUE);
1275
1276 // Changing unspecified always causes event (returning
1277 // true here should be enough to trigger it).
1278 if ( !res && variant.IsNull() )
1279 res = true;
1280
1281 return res;
1282 }
1283
1284
1285 void wxPGComboBoxEditor::OnFocus( wxPGProperty* property,
1286 wxWindow* ctrl ) const
1287 {
1288 wxOwnerDrawnComboBox* cb = (wxOwnerDrawnComboBox*)ctrl;
1289 wxPGTextCtrlEditor_OnFocus(property, cb->GetTextCtrl());
1290 }
1291
1292
1293 wxPGComboBoxEditor::~wxPGComboBoxEditor() { }
1294
1295
1296 // -----------------------------------------------------------------------
1297 // wxPGChoiceAndButtonEditor
1298 // -----------------------------------------------------------------------
1299
1300
1301 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(ChoiceAndButton,
1302 wxPGChoiceAndButtonEditor,
1303 wxPGChoiceEditor)
1304
1305
1306 wxPGWindowList wxPGChoiceAndButtonEditor::CreateControls( wxPropertyGrid* propGrid,
1307 wxPGProperty* property,
1308 const wxPoint& pos,
1309 const wxSize& sz ) const
1310 {
1311 // Use one two units smaller to match size of the combo's dropbutton.
1312 // (normally a bigger button is used because it looks better)
1313 int bt_wid = sz.y;
1314 bt_wid -= 2;
1315 wxSize bt_sz(bt_wid,bt_wid);
1316
1317 // Position of button.
1318 wxPoint bt_pos(pos.x+sz.x-bt_sz.x,pos.y);
1319 #ifdef __WXMAC__
1320 bt_pos.y -= 1;
1321 #else
1322 bt_pos.y += 1;
1323 #endif
1324
1325 wxWindow* bt = propGrid->GenerateEditorButton( bt_pos, bt_sz );
1326
1327 // Size of choice.
1328 wxSize ch_sz(sz.x-bt->GetSize().x,sz.y);
1329
1330 #ifdef __WXMAC__
1331 ch_sz.x -= wxPG_TEXTCTRL_AND_BUTTON_SPACING;
1332 #endif
1333
1334 wxWindow* ch = wxPGEditor_Choice->CreateControls(propGrid,property,
1335 pos,ch_sz).m_primary;
1336
1337 #ifdef __WXMSW__
1338 bt->Show();
1339 #endif
1340
1341 return wxPGWindowList(ch, bt);
1342 }
1343
1344
1345 wxPGChoiceAndButtonEditor::~wxPGChoiceAndButtonEditor() { }
1346
1347
1348 // -----------------------------------------------------------------------
1349 // wxPGTextCtrlAndButtonEditor
1350 // -----------------------------------------------------------------------
1351
1352 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(TextCtrlAndButton,
1353 wxPGTextCtrlAndButtonEditor,
1354 wxPGTextCtrlEditor)
1355
1356
1357 wxPGWindowList wxPGTextCtrlAndButtonEditor::CreateControls( wxPropertyGrid* propGrid,
1358 wxPGProperty* property,
1359 const wxPoint& pos,
1360 const wxSize& sz ) const
1361 {
1362 wxWindow* wnd2;
1363 wxWindow* wnd = propGrid->GenerateEditorTextCtrlAndButton( pos, sz, &wnd2,
1364 property->GetFlags() & wxPG_PROP_NOEDITOR, property);
1365
1366 return wxPGWindowList(wnd, wnd2);
1367 }
1368
1369
1370 wxPGTextCtrlAndButtonEditor::~wxPGTextCtrlAndButtonEditor() { }
1371
1372
1373 // -----------------------------------------------------------------------
1374 // wxPGCheckBoxEditor
1375 // -----------------------------------------------------------------------
1376
1377 #if wxPG_INCLUDE_CHECKBOX
1378
1379 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(CheckBox,
1380 wxPGCheckBoxEditor,
1381 wxPGEditor)
1382
1383
1384 // Check box state flags
1385 enum
1386 {
1387 wxSCB_STATE_UNCHECKED = 0,
1388 wxSCB_STATE_CHECKED = 1,
1389 wxSCB_STATE_BOLD = 2,
1390 wxSCB_STATE_UNSPECIFIED = 4
1391 };
1392
1393 const int wxSCB_SETVALUE_CYCLE = 2;
1394
1395
1396 static void DrawSimpleCheckBox( wxDC& dc, const wxRect& rect, int box_hei,
1397 int state, const wxColour& lineCol )
1398 {
1399 // Box rectangle.
1400 wxRect r(rect.x+wxPG_XBEFORETEXT,rect.y+((rect.height-box_hei)/2),
1401 box_hei,box_hei);
1402 wxColour useCol = lineCol;
1403
1404 if ( state & wxSCB_STATE_UNSPECIFIED )
1405 {
1406 useCol = wxColour(220, 220, 220);
1407 }
1408
1409 // Draw check mark first because it is likely to overdraw the
1410 // surrounding rectangle.
1411 if ( state & wxSCB_STATE_CHECKED )
1412 {
1413 wxRect r2(r.x+wxPG_CHECKMARK_XADJ,
1414 r.y+wxPG_CHECKMARK_YADJ,
1415 r.width+wxPG_CHECKMARK_WADJ,
1416 r.height+wxPG_CHECKMARK_HADJ);
1417 #if wxPG_CHECKMARK_DEFLATE
1418 r2.Deflate(wxPG_CHECKMARK_DEFLATE);
1419 #endif
1420 dc.DrawCheckMark(r2);
1421
1422 // This would draw a simple cross check mark.
1423 // dc.DrawLine(r.x,r.y,r.x+r.width-1,r.y+r.height-1);
1424 // dc.DrawLine(r.x,r.y+r.height-1,r.x+r.width-1,r.y);
1425 }
1426
1427 if ( !(state & wxSCB_STATE_BOLD) )
1428 {
1429 // Pen for thin rectangle.
1430 dc.SetPen(useCol);
1431 }
1432 else
1433 {
1434 // Pen for bold rectangle.
1435 wxPen linepen(useCol,2,wxSOLID);
1436 linepen.SetJoin(wxJOIN_MITER); // This prevents round edges.
1437 dc.SetPen(linepen);
1438 r.x++;
1439 r.y++;
1440 r.width--;
1441 r.height--;
1442 }
1443
1444 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1445
1446 dc.DrawRectangle(r);
1447 dc.SetPen(*wxTRANSPARENT_PEN);
1448 }
1449
1450 //
1451 // Real simple custom-drawn checkbox-without-label class.
1452 //
1453 class wxSimpleCheckBox : public wxControl
1454 {
1455 public:
1456
1457 void SetValue( int value );
1458
1459 wxSimpleCheckBox( wxWindow* parent,
1460 wxWindowID id,
1461 const wxPoint& pos = wxDefaultPosition,
1462 const wxSize& size = wxDefaultSize )
1463 : wxControl(parent,id,pos,size,wxBORDER_NONE|wxWANTS_CHARS)
1464 {
1465 // Due to SetOwnFont stuff necessary for GTK+ 1.2, we need to have this
1466 SetFont( parent->GetFont() );
1467
1468 m_state = 0;
1469 m_boxHeight = 12;
1470
1471 SetBackgroundStyle( wxBG_STYLE_CUSTOM );
1472 }
1473
1474 virtual ~wxSimpleCheckBox();
1475
1476 int m_state;
1477 int m_boxHeight;
1478
1479 private:
1480 void OnPaint( wxPaintEvent& event );
1481 void OnLeftClick( wxMouseEvent& event );
1482 void OnKeyDown( wxKeyEvent& event );
1483
1484 void OnResize( wxSizeEvent& event )
1485 {
1486 Refresh();
1487 event.Skip();
1488 }
1489
1490 static wxBitmap* ms_doubleBuffer;
1491
1492 DECLARE_EVENT_TABLE()
1493 };
1494
1495 BEGIN_EVENT_TABLE(wxSimpleCheckBox, wxControl)
1496 EVT_PAINT(wxSimpleCheckBox::OnPaint)
1497 EVT_LEFT_DOWN(wxSimpleCheckBox::OnLeftClick)
1498 EVT_LEFT_DCLICK(wxSimpleCheckBox::OnLeftClick)
1499 EVT_KEY_DOWN(wxSimpleCheckBox::OnKeyDown)
1500 EVT_SIZE(wxSimpleCheckBox::OnResize)
1501 END_EVENT_TABLE()
1502
1503 wxSimpleCheckBox::~wxSimpleCheckBox()
1504 {
1505 delete ms_doubleBuffer;
1506 ms_doubleBuffer = NULL;
1507 }
1508
1509 wxBitmap* wxSimpleCheckBox::ms_doubleBuffer = NULL;
1510
1511 void wxSimpleCheckBox::OnPaint( wxPaintEvent& WXUNUSED(event) )
1512 {
1513 wxSize clientSize = GetClientSize();
1514 wxAutoBufferedPaintDC dc(this);
1515
1516 dc.Clear();
1517 wxRect rect(0,0,clientSize.x,clientSize.y);
1518 rect.y += 1;
1519 rect.width += 1;
1520
1521 wxColour bgcol = GetBackgroundColour();
1522 dc.SetBrush( bgcol );
1523 dc.SetPen( bgcol );
1524 dc.DrawRectangle( rect );
1525
1526 wxColour txcol = GetForegroundColour();
1527
1528 int state = m_state;
1529 if ( !(state & wxSCB_STATE_UNSPECIFIED) &&
1530 GetFont().GetWeight() == wxBOLD )
1531 state |= wxSCB_STATE_BOLD;
1532
1533 DrawSimpleCheckBox(dc,rect,m_boxHeight,state,txcol);
1534 }
1535
1536 void wxSimpleCheckBox::OnLeftClick( wxMouseEvent& event )
1537 {
1538 if ( (event.m_x > (wxPG_XBEFORETEXT-2)) &&
1539 (event.m_x <= (wxPG_XBEFORETEXT-2+m_boxHeight)) )
1540 {
1541 SetValue(wxSCB_SETVALUE_CYCLE);
1542 }
1543 }
1544
1545 void wxSimpleCheckBox::OnKeyDown( wxKeyEvent& event )
1546 {
1547 if ( event.GetKeyCode() == WXK_SPACE )
1548 {
1549 SetValue(wxSCB_SETVALUE_CYCLE);
1550 }
1551 }
1552
1553 void wxSimpleCheckBox::SetValue( int value )
1554 {
1555 if ( value == wxSCB_SETVALUE_CYCLE )
1556 {
1557 if ( m_state & wxSCB_STATE_CHECKED )
1558 m_state &= ~wxSCB_STATE_CHECKED;
1559 else
1560 m_state |= wxSCB_STATE_CHECKED;
1561 }
1562 else
1563 {
1564 m_state = value;
1565 }
1566 Refresh();
1567
1568 wxCommandEvent evt(wxEVT_COMMAND_CHECKBOX_CLICKED,GetParent()->GetId());
1569
1570 wxPropertyGrid* propGrid = (wxPropertyGrid*) GetParent();
1571 wxASSERT( propGrid->IsKindOf(CLASSINFO(wxPropertyGrid)) );
1572 propGrid->HandleCustomEditorEvent(evt);
1573 }
1574
1575 wxPGWindowList wxPGCheckBoxEditor::CreateControls( wxPropertyGrid* propGrid,
1576 wxPGProperty* property,
1577 const wxPoint& pos,
1578 const wxSize& size ) const
1579 {
1580 wxPoint pt = pos;
1581 pt.x -= wxPG_XBEFOREWIDGET;
1582 wxSize sz = size;
1583 sz.x = propGrid->GetFontHeight() + (wxPG_XBEFOREWIDGET*2) + 4;
1584
1585 wxSimpleCheckBox* cb = new wxSimpleCheckBox(propGrid->GetPanel(),
1586 wxPG_SUBID1, pt, sz);
1587
1588 cb->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
1589
1590 UpdateControl(property, cb);
1591
1592 if ( !property->IsValueUnspecified() )
1593 {
1594 // If mouse cursor was on the item, toggle the value now.
1595 if ( propGrid->GetInternalFlags() & wxPG_FL_ACTIVATION_BY_CLICK )
1596 {
1597 wxPoint pt = cb->ScreenToClient(::wxGetMousePosition());
1598 if ( pt.x <= (wxPG_XBEFORETEXT-2+cb->m_boxHeight) )
1599 {
1600 if ( cb->m_state & wxSCB_STATE_CHECKED )
1601 cb->m_state &= ~wxSCB_STATE_CHECKED;
1602 else
1603 cb->m_state |= wxSCB_STATE_CHECKED;
1604
1605 // Makes sure wxPG_EVT_CHANGING etc. is sent for this initial
1606 // click
1607 propGrid->ChangePropertyValue(property,
1608 wxPGVariant_Bool(cb->m_state));
1609 }
1610 }
1611 }
1612
1613 propGrid->SetInternalFlag( wxPG_FL_FIXED_WIDTH_EDITOR );
1614
1615 return cb;
1616 }
1617
1618 void wxPGCheckBoxEditor::DrawValue( wxDC& dc, const wxRect& rect,
1619 wxPGProperty* property,
1620 const wxString& WXUNUSED(text) ) const
1621 {
1622 int state = wxSCB_STATE_UNCHECKED;
1623 wxColour rectCol = dc.GetTextForeground();
1624
1625 if ( !property->IsValueUnspecified() )
1626 {
1627 state = property->GetChoiceSelection();
1628 if ( dc.GetFont().GetWeight() == wxBOLD )
1629 state |= wxSCB_STATE_BOLD;
1630 }
1631 else
1632 {
1633 state |= wxSCB_STATE_UNSPECIFIED;
1634 }
1635
1636 DrawSimpleCheckBox(dc, rect, dc.GetCharHeight(), state, rectCol);
1637 }
1638
1639 void wxPGCheckBoxEditor::UpdateControl( wxPGProperty* property,
1640 wxWindow* ctrl ) const
1641 {
1642 wxSimpleCheckBox* cb = (wxSimpleCheckBox*) ctrl;
1643 wxASSERT( cb );
1644
1645 if ( !property->IsValueUnspecified() )
1646 cb->m_state = property->GetChoiceSelection();
1647 else
1648 cb->m_state = wxSCB_STATE_UNSPECIFIED;
1649
1650 wxPropertyGrid* propGrid = property->GetGrid();
1651 cb->m_boxHeight = propGrid->GetFontHeight();
1652
1653 cb->Refresh();
1654 }
1655
1656 bool wxPGCheckBoxEditor::OnEvent( wxPropertyGrid* WXUNUSED(propGrid), wxPGProperty* WXUNUSED(property),
1657 wxWindow* WXUNUSED(ctrl), wxEvent& event ) const
1658 {
1659 if ( event.GetEventType() == wxEVT_COMMAND_CHECKBOX_CLICKED )
1660 {
1661 return true;
1662 }
1663 return false;
1664 }
1665
1666
1667 bool wxPGCheckBoxEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
1668 {
1669 wxSimpleCheckBox* cb = (wxSimpleCheckBox*)ctrl;
1670
1671 int index = cb->m_state;
1672
1673 if ( index != property->GetChoiceSelection() ||
1674 // Changing unspecified always causes event (returning
1675 // true here should be enough to trigger it).
1676 property->IsValueUnspecified()
1677 )
1678 {
1679 return property->IntToValue(variant, index, 0);
1680 }
1681 return false;
1682 }
1683
1684
1685 void wxPGCheckBoxEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow* ctrl, int value ) const
1686 {
1687 if ( value != 0 ) value = 1;
1688 ((wxSimpleCheckBox*)ctrl)->m_state = value;
1689 ctrl->Refresh();
1690 }
1691
1692
1693 void wxPGCheckBoxEditor::SetValueToUnspecified( wxPGProperty* WXUNUSED(property), wxWindow* ctrl ) const
1694 {
1695 ((wxSimpleCheckBox*)ctrl)->m_state = wxSCB_STATE_UNSPECIFIED;
1696 ctrl->Refresh();
1697 }
1698
1699
1700 wxPGCheckBoxEditor::~wxPGCheckBoxEditor() { }
1701
1702
1703 #endif // wxPG_INCLUDE_CHECKBOX
1704
1705 // -----------------------------------------------------------------------
1706
1707 wxWindow* wxPropertyGrid::GetEditorControl() const
1708 {
1709 wxWindow* ctrl = m_wndEditor;
1710
1711 if ( !ctrl )
1712 return ctrl;
1713
1714 return ctrl;
1715 }
1716
1717 // -----------------------------------------------------------------------
1718
1719 void wxPropertyGrid::CorrectEditorWidgetSizeX()
1720 {
1721 int secWid = 0;
1722 int newSplitterx = m_pState->DoGetSplitterPosition(m_selColumn-1);
1723 int newWidth = newSplitterx + m_pState->m_colWidths[m_selColumn];
1724
1725 if ( m_wndEditor2 )
1726 {
1727 // if width change occurred, move secondary wnd by that amount
1728 wxRect r = m_wndEditor2->GetRect();
1729 secWid = r.width;
1730 r.x = newWidth - secWid;
1731
1732 m_wndEditor2->SetSize( r );
1733
1734 // if primary is textctrl, then we have to add some extra space
1735 #ifdef __WXMAC__
1736 if ( m_wndEditor )
1737 #else
1738 if ( m_wndEditor && m_wndEditor->IsKindOf(CLASSINFO(wxTextCtrl)) )
1739 #endif
1740 secWid += wxPG_TEXTCTRL_AND_BUTTON_SPACING;
1741 }
1742
1743 if ( m_wndEditor )
1744 {
1745 wxRect r = m_wndEditor->GetRect();
1746
1747 r.x = newSplitterx+m_ctrlXAdjust;
1748
1749 if ( !(m_iFlags & wxPG_FL_FIXED_WIDTH_EDITOR) )
1750 r.width = newWidth - r.x - secWid;
1751
1752 m_wndEditor->SetSize(r);
1753 }
1754
1755 if ( m_wndEditor2 )
1756 m_wndEditor2->Refresh();
1757 }
1758
1759 // -----------------------------------------------------------------------
1760
1761 void wxPropertyGrid::CorrectEditorWidgetPosY()
1762 {
1763 if ( GetSelection() && (m_wndEditor || m_wndEditor2) )
1764 {
1765 wxRect r = GetEditorWidgetRect(GetSelection(), m_selColumn);
1766
1767 if ( m_wndEditor )
1768 {
1769 wxPoint pos = m_wndEditor->GetPosition();
1770
1771 // Calculate y offset
1772 int offset = pos.y % m_lineHeight;
1773
1774 m_wndEditor->Move(pos.x, r.y + offset);
1775 }
1776
1777 if ( m_wndEditor2 )
1778 {
1779 wxPoint pos = m_wndEditor2->GetPosition();
1780
1781 m_wndEditor2->Move(pos.x, r.y);
1782 }
1783 }
1784 }
1785
1786 // -----------------------------------------------------------------------
1787
1788 // Fixes position of wxTextCtrl-like control (wxSpinCtrl usually
1789 // fits into that category as well).
1790 void wxPropertyGrid::FixPosForTextCtrl( wxWindow* ctrl,
1791 unsigned int WXUNUSED(forColumn),
1792 const wxPoint& offset )
1793 {
1794 // Center the control vertically
1795 wxRect finalPos = ctrl->GetRect();
1796 int y_adj = (m_lineHeight - finalPos.height)/2 + wxPG_TEXTCTRLYADJUST;
1797
1798 // Prevent over-sized control
1799 int sz_dec = (y_adj + finalPos.height) - m_lineHeight;
1800 if ( sz_dec < 0 ) sz_dec = 0;
1801
1802 finalPos.y += y_adj;
1803 finalPos.height -= (y_adj+sz_dec);
1804
1805 #ifndef wxPG_TEXTCTRLXADJUST
1806 int textCtrlXAdjust = wxPG_XBEFORETEXT - 1;
1807
1808 wxTextCtrl* tc = static_cast<wxTextCtrl*>(ctrl);
1809 tc->SetMargins(0);
1810 #else
1811 int textCtrlXAdjust = wxPG_TEXTCTRLXADJUST;
1812 #endif
1813
1814 finalPos.x += textCtrlXAdjust;
1815 finalPos.width -= textCtrlXAdjust;
1816
1817 finalPos.x += offset.x;
1818 finalPos.y += offset.y;
1819
1820 ctrl->SetSize(finalPos);
1821 }
1822
1823 // -----------------------------------------------------------------------
1824
1825 wxWindow* wxPropertyGrid::GenerateEditorTextCtrl( const wxPoint& pos,
1826 const wxSize& sz,
1827 const wxString& value,
1828 wxWindow* secondary,
1829 int extraStyle,
1830 int maxLen,
1831 unsigned int forColumn )
1832 {
1833 wxWindowID id = wxPG_SUBID1;
1834 wxPGProperty* prop = GetSelection();
1835 wxASSERT(prop);
1836
1837 int tcFlags = wxTE_PROCESS_ENTER | extraStyle;
1838
1839 if ( prop->HasFlag(wxPG_PROP_READONLY) && forColumn == 1 )
1840 tcFlags |= wxTE_READONLY;
1841
1842 wxPoint p(pos.x,pos.y);
1843 wxSize s(sz.x,sz.y);
1844
1845 // Need to reduce width of text control on Mac
1846 #if defined(__WXMAC__)
1847 s.x -= 8;
1848 #endif
1849
1850 // For label editors, trim the size to allow better splitter grabbing
1851 if ( forColumn != 1 )
1852 s.x -= 2;
1853
1854 // Take button into acccount
1855 if ( secondary )
1856 {
1857 s.x -= (secondary->GetSize().x + wxPG_TEXTCTRL_AND_BUTTON_SPACING);
1858 m_iFlags &= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE);
1859 }
1860
1861 // If the height is significantly higher, then use border, and fill the rect exactly.
1862 bool hasSpecialSize = false;
1863
1864 if ( (sz.y - m_lineHeight) > 5 )
1865 hasSpecialSize = true;
1866
1867 wxWindow* ctrlParent = GetPanel();
1868
1869 if ( !hasSpecialSize )
1870 tcFlags |= wxBORDER_NONE;
1871
1872 wxTextCtrl* tc = new wxTextCtrl();
1873
1874 #if defined(__WXMSW__)
1875 tc->Hide();
1876 #endif
1877 SetupTextCtrlValue(value);
1878 tc->Create(ctrlParent,id,value, p, s,tcFlags);
1879
1880 #if defined(__WXMSW__)
1881 // On Windows, we need to override read-only text ctrl's background
1882 // colour to white. One problem with native 'grey' background is that
1883 // tc->GetBackgroundColour() doesn't seem to return correct value
1884 // for it.
1885 if ( tcFlags & wxTE_READONLY )
1886 {
1887 wxVisualAttributes vattrs = tc->GetDefaultAttributes();
1888 tc->SetBackgroundColour(vattrs.colBg);
1889 }
1890 #endif
1891
1892 // Center the control vertically
1893 if ( !hasSpecialSize )
1894 FixPosForTextCtrl(tc, forColumn);
1895
1896 if ( forColumn != 1 )
1897 {
1898 tc->SetBackgroundColour(m_colSelBack);
1899 tc->SetForegroundColour(m_colSelFore);
1900 }
1901
1902 #ifdef __WXMSW__
1903 tc->Show();
1904 if ( secondary )
1905 secondary->Show();
1906 #endif
1907
1908 // Set maximum length
1909 if ( maxLen > 0 )
1910 tc->SetMaxLength( maxLen );
1911
1912 wxVariant attrVal = prop->GetAttribute(wxPG_ATTR_AUTOCOMPLETE);
1913 if ( !attrVal.IsNull() )
1914 {
1915 wxASSERT(attrVal.GetType() == wxS("arrstring"));
1916 tc->AutoComplete(attrVal.GetArrayString());
1917 }
1918
1919 // Set hint text
1920 tc->SetHint(prop->GetHintText());
1921
1922 return tc;
1923 }
1924
1925 // -----------------------------------------------------------------------
1926
1927 wxWindow* wxPropertyGrid::GenerateEditorButton( const wxPoint& pos, const wxSize& sz )
1928 {
1929 wxWindowID id = wxPG_SUBID2;
1930 wxPGProperty* selected = GetSelection();
1931 wxASSERT(selected);
1932
1933 #ifdef __WXMAC__
1934 // Decorations are chunky on Mac, and we can't make the button square, so
1935 // do things a bit differently on this platform.
1936
1937 wxPoint p(pos.x+sz.x,
1938 pos.y+wxPG_BUTTON_SIZEDEC-wxPG_NAT_BUTTON_BORDER_Y);
1939 wxSize s(25, -1);
1940
1941 wxButton* but = new wxButton();
1942 but->Create(GetPanel(),id,wxS("..."),p,s,wxWANTS_CHARS);
1943
1944 // Now that we know the size, move to the correct position
1945 p.x = pos.x + sz.x - but->GetSize().x - 2;
1946 but->Move(p);
1947
1948 #else
1949 wxSize s(sz.y-(wxPG_BUTTON_SIZEDEC*2)+(wxPG_NAT_BUTTON_BORDER_Y*2),
1950 sz.y-(wxPG_BUTTON_SIZEDEC*2)+(wxPG_NAT_BUTTON_BORDER_Y*2));
1951
1952 // Reduce button width to lineheight
1953 if ( s.x > m_lineHeight )
1954 s.x = m_lineHeight;
1955
1956 #ifdef __WXGTK__
1957 // On wxGTK, take fixed button margins into account
1958 if ( s.x < 25 )
1959 s.x = 25;
1960 #endif
1961
1962 wxPoint p(pos.x+sz.x-s.x,
1963 pos.y+wxPG_BUTTON_SIZEDEC-wxPG_NAT_BUTTON_BORDER_Y);
1964
1965 wxButton* but = new wxButton();
1966 #ifdef __WXMSW__
1967 but->Hide();
1968 #endif
1969 but->Create(GetPanel(),id,wxS("..."),p,s,wxWANTS_CHARS);
1970
1971 #ifdef __WXGTK__
1972 wxFont font = GetFont();
1973 font.SetPointSize(font.GetPointSize()-2);
1974 but->SetFont(font);
1975 #else
1976 but->SetFont(GetFont());
1977 #endif
1978 #endif
1979
1980 if ( selected->HasFlag(wxPG_PROP_READONLY) )
1981 but->Disable();
1982
1983 return but;
1984 }
1985
1986 // -----------------------------------------------------------------------
1987
1988 wxWindow* wxPropertyGrid::GenerateEditorTextCtrlAndButton( const wxPoint& pos,
1989 const wxSize& sz,
1990 wxWindow** psecondary,
1991 int limitedEditing,
1992 wxPGProperty* property )
1993 {
1994 wxButton* but = (wxButton*)GenerateEditorButton(pos,sz);
1995 *psecondary = (wxWindow*)but;
1996
1997 if ( limitedEditing )
1998 {
1999 #ifdef __WXMSW__
2000 // There is button Show in GenerateEditorTextCtrl as well
2001 but->Show();
2002 #endif
2003 return NULL;
2004 }
2005
2006 wxString text;
2007
2008 if ( !property->IsValueUnspecified() )
2009 text = property->GetValueAsString(property->HasFlag(wxPG_PROP_READONLY)?0:wxPG_EDITABLE_VALUE);
2010
2011 return GenerateEditorTextCtrl(pos,sz,text,but,property->m_maxLen);
2012 }
2013
2014 // -----------------------------------------------------------------------
2015
2016 void wxPropertyGrid::SetEditorAppearance( const wxPGCell& cell,
2017 bool unspecified )
2018 {
2019 wxPGProperty* property = GetSelection();
2020 if ( !property )
2021 return;
2022 wxWindow* ctrl = GetEditorControl();
2023 if ( !ctrl )
2024 return;
2025
2026 property->GetEditorClass()->SetControlAppearance( this,
2027 property,
2028 ctrl,
2029 cell,
2030 m_editorAppearance,
2031 unspecified );
2032
2033 m_editorAppearance = cell;
2034 }
2035
2036 // -----------------------------------------------------------------------
2037
2038 wxTextCtrl* wxPropertyGrid::GetEditorTextCtrl() const
2039 {
2040 wxWindow* wnd = GetEditorControl();
2041
2042 if ( !wnd )
2043 return NULL;
2044
2045 if ( wnd->IsKindOf(CLASSINFO(wxTextCtrl)) )
2046 return wxStaticCast(wnd, wxTextCtrl);
2047
2048 if ( wnd->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) )
2049 {
2050 wxOwnerDrawnComboBox* cb = wxStaticCast(wnd, wxOwnerDrawnComboBox);
2051 return cb->GetTextCtrl();
2052 }
2053
2054 return NULL;
2055 }
2056
2057 // -----------------------------------------------------------------------
2058
2059 wxPGEditor* wxPropertyGridInterface::GetEditorByName( const wxString& editorName )
2060 {
2061 wxPGHashMapS2P::const_iterator it;
2062
2063 it = wxPGGlobalVars->m_mapEditorClasses.find(editorName);
2064 if ( it == wxPGGlobalVars->m_mapEditorClasses.end() )
2065 return NULL;
2066 return (wxPGEditor*) it->second;
2067 }
2068
2069 // -----------------------------------------------------------------------
2070 // wxPGEditorDialogAdapter
2071 // -----------------------------------------------------------------------
2072
2073 IMPLEMENT_ABSTRACT_CLASS(wxPGEditorDialogAdapter, wxObject)
2074
2075 bool wxPGEditorDialogAdapter::ShowDialog( wxPropertyGrid* propGrid, wxPGProperty* property )
2076 {
2077 if ( !propGrid->EditorValidate() )
2078 return false;
2079
2080 bool res = DoShowDialog( propGrid, property );
2081
2082 if ( res )
2083 {
2084 propGrid->ValueChangeInEvent( m_value );
2085 return true;
2086 }
2087
2088 return false;
2089 }
2090
2091 // -----------------------------------------------------------------------
2092 // wxPGMultiButton
2093 // -----------------------------------------------------------------------
2094
2095 wxPGMultiButton::wxPGMultiButton( wxPropertyGrid* pg, const wxSize& sz )
2096 : wxWindow( pg->GetPanel(), wxPG_SUBID2, wxPoint(-100,-100), wxSize(0, sz.y) ),
2097 m_fullEditorSize(sz), m_buttonsWidth(0)
2098 {
2099 SetBackgroundColour(pg->GetCellBackgroundColour());
2100 }
2101
2102 void wxPGMultiButton::Finalize( wxPropertyGrid* WXUNUSED(propGrid),
2103 const wxPoint& pos )
2104 {
2105 Move( pos.x + m_fullEditorSize.x - m_buttonsWidth, pos.y );
2106 }
2107
2108 int wxPGMultiButton::GenId( int id ) const
2109 {
2110 if ( id < -1 )
2111 {
2112 if ( m_buttons.size() )
2113 id = GetButton(m_buttons.size()-1)->GetId() + 1;
2114 else
2115 id = wxPG_SUBID2;
2116 }
2117 return id;
2118 }
2119
2120 #if wxUSE_BMPBUTTON
2121 void wxPGMultiButton::Add( const wxBitmap& bitmap, int id )
2122 {
2123 id = GenId(id);
2124 wxSize sz = GetSize();
2125 wxButton* button = new wxBitmapButton( this, id, bitmap,
2126 wxPoint(sz.x, 0),
2127 wxSize(sz.y, sz.y) );
2128 DoAddButton( button, sz );
2129 }
2130 #endif
2131
2132 void wxPGMultiButton::Add( const wxString& label, int id )
2133 {
2134 id = GenId(id);
2135 wxSize sz = GetSize();
2136 wxButton* button = new wxButton( this, id, label, wxPoint(sz.x, 0),
2137 wxSize(sz.y, sz.y) );
2138 DoAddButton( button, sz );
2139 }
2140
2141 void wxPGMultiButton::DoAddButton( wxWindow* button,
2142 const wxSize& sz )
2143 {
2144 m_buttons.push_back(button);
2145 int bw = button->GetSize().x;
2146 SetSize(wxSize(sz.x+bw,sz.y));
2147 m_buttonsWidth += bw;
2148 }
2149
2150 // -----------------------------------------------------------------------
2151
2152 #endif // wxUSE_PROPGRID