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