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