1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        editors.cpp
3 // Purpose:     wxPropertyGrid editors
4 // Author:      Jaakko Salli
5 // Modified by:
6 // Created:     Apr-14-2007
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 #ifndef WX_PRECOMP
20     #include "wx/defs.h"
21     #include "wx/object.h"
22     #include "wx/hash.h"
23     #include "wx/string.h"
24     #include "wx/log.h"
25     #include "wx/event.h"
26     #include "wx/window.h"
27     #include "wx/panel.h"
28     #include "wx/dc.h"
29     #include "wx/dcclient.h"
30     #include "wx/dcmemory.h"
31     #include "wx/button.h"
32     #include "wx/pen.h"
33     #include "wx/brush.h"
34     #include "wx/cursor.h"
35     #include "wx/dialog.h"
36     #include "wx/settings.h"
37     #include "wx/msgdlg.h"
38     #include "wx/choice.h"
39     #include "wx/stattext.h"
40     #include "wx/scrolwin.h"
41     #include "wx/dirdlg.h"
42     #include "wx/layout.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/propdev.h>
62 #include <wx/propgrid/editors.h>
63 #include <wx/propgrid/props.h>
64 
65 #ifdef __WXPYTHON__
66     #include <wx/propgrid/advprops.h>
67     #include <wx/propgrid/extras.h>
68 #endif
69 
70 #if wxPG_USE_RENDERER_NATIVE
71     #include <wx/renderer.h>
72 #endif
73 
74 // How many pixels between textctrl and button
75 #ifdef __WXMAC__
76     // Backported from wx2.9 by Julian Smart (old value was 8)
77     #define wxPG_TEXTCTRL_AND_BUTTON_SPACING        4
78 #else
79     #define wxPG_TEXTCTRL_AND_BUTTON_SPACING        2
80 #endif
81 
82 #define wxPG_BUTTON_SIZEDEC                         0
83 
84 #if wxPG_USING_WXOWNERDRAWNCOMBOBOX
85     #include <wx/odcombo.h>
86 #else
87     #include <wx/propgrid/odcombo.h>
88 #endif
89 
90 #ifdef __WXMSW__
91     #include <wx/msw/private.h>
92 #endif
93 
94 // -----------------------------------------------------------------------
95 
96 #if defined(__WXMSW__)
97     // tested
98     #define wxPG_NAT_TEXTCTRL_BORDER_X          0 // Unremovable border of native textctrl.
99     #define wxPG_NAT_TEXTCTRL_BORDER_Y          0 // Unremovable border of native textctrl.
100 
101     #define wxPG_NAT_BUTTON_BORDER_ANY          1
102     #define wxPG_NAT_BUTTON_BORDER_X            1
103     #define wxPG_NAT_BUTTON_BORDER_Y            1
104 
105     #define wxPG_CHECKMARK_XADJ                 1
106     #define wxPG_CHECKMARK_YADJ                 (-1)
107     #define wxPG_CHECKMARK_WADJ                 0
108     #define wxPG_CHECKMARK_HADJ                 0
109     #define wxPG_CHECKMARK_DEFLATE              0
110 
111     #define wxPG_TEXTCTRLYADJUST                (m_spacingy+0)
112 
113 #elif defined(__WXGTK__)
114     // tested
115     #define wxPG_CHECKMARK_XADJ                 0
116     #define wxPG_CHECKMARK_YADJ                 0
117     #define wxPG_CHECKMARK_WADJ                 (-1)
118     #define wxPG_CHECKMARK_HADJ                 (-1)
119     #define wxPG_CHECKMARK_DEFLATE              3
120 
121     #define wxPG_NAT_TEXTCTRL_BORDER_X      3 // Unremovable border of native textctrl.
122     #define wxPG_NAT_TEXTCTRL_BORDER_Y      3 // Unremovable border of native textctrl.
123 
124     #define wxPG_NAT_BUTTON_BORDER_ANY      1
125     #define wxPG_NAT_BUTTON_BORDER_X        1
126     #define wxPG_NAT_BUTTON_BORDER_Y        1
127 
128     #define wxPG_TEXTCTRLYADJUST            0
129 
130 #elif defined(__WXMAC__)
131     // *not* tested
132     #define wxPG_CHECKMARK_XADJ                 0
133     #define wxPG_CHECKMARK_YADJ                 0
134     #define wxPG_CHECKMARK_WADJ                 0
135     #define wxPG_CHECKMARK_HADJ                 0
136     #define wxPG_CHECKMARK_DEFLATE              0
137 
138     #define wxPG_NAT_TEXTCTRL_BORDER_X      0 // Unremovable border of native textctrl.
139     #define wxPG_NAT_TEXTCTRL_BORDER_Y      0 // Unremovable border of native textctrl.
140 
141     #define wxPG_NAT_BUTTON_BORDER_ANY      0
142     #define wxPG_NAT_BUTTON_BORDER_X        0
143     #define wxPG_NAT_BUTTON_BORDER_Y        0
144 
145     // Backported from wx2.9 by Julian Smart (old value was 3)
146     #define wxPG_TEXTCTRLYADJUST            0
147 
148 #else
149     // defaults
150     #define wxPG_CHECKMARK_XADJ                 0
151     #define wxPG_CHECKMARK_YADJ                 0
152     #define wxPG_CHECKMARK_WADJ                 0
153     #define wxPG_CHECKMARK_HADJ                 0
154     #define wxPG_CHECKMARK_DEFLATE              0
155 
156     #define wxPG_NAT_TEXTCTRL_BORDER_X      0 // Unremovable border of native textctrl.
157     #define wxPG_NAT_TEXTCTRL_BORDER_Y      0 // Unremovable border of native textctrl.
158 
159     #define wxPG_NAT_BUTTON_BORDER_ANY      0
160     #define wxPG_NAT_BUTTON_BORDER_X        0
161     #define wxPG_NAT_BUTTON_BORDER_Y        0
162 
163     #define wxPG_TEXTCTRLYADJUST            0
164 
165 #endif
166 
167 #if (!wxPG_NAT_TEXTCTRL_BORDER_X && !wxPG_NAT_TEXTCTRL_BORDER_Y)
168     #define wxPG_ENABLE_CLIPPER_WINDOW      0
169 #else
170     #define wxPG_ENABLE_CLIPPER_WINDOW      1
171 #endif
172 
173 
174 // for odcombo
175 #ifdef __WXMAC__
176     // Backported from wx2.9 by Julian Smart
177     // required because wxComboCtrl reserves 3pixels for wxTextCtrl's
178     // focus ring.
179     #define wxPG_CHOICEXADJUST           -3
180     #define wxPG_CHOICEYADJUST           -3
181 #else
182     #define wxPG_CHOICEXADJUST           0
183     #define wxPG_CHOICEYADJUST           0
184 #endif
185 
186 //
187 // Number added to image width for SetCustomPaintWidth
188 // NOTE: Use different custom paint margin because of better textctrl spacing
189 #define ODCB_CUST_PAINT_MARGIN_RO            6
190 #define ODCB_CUST_PAINT_MARGIN               8
191 
192 // Milliseconds to wait for two mouse-ups after focus inorder
193 // to trigger a double-click.
194 #define DOUBLE_CLICK_CONVERSION_TRESHOLD        500
195 
196 // -----------------------------------------------------------------------
197 // wxPGEditor
198 // -----------------------------------------------------------------------
199 
IMPLEMENT_ABSTRACT_CLASS(wxPGEditor,wxObject)200 IMPLEMENT_ABSTRACT_CLASS(wxPGEditor, wxObject)
201 
202 wxPGEditor::~wxPGEditor()
203 {
204 }
205 
206 
207 /*wxPGCellRenderer* wxPGEditor::GetCellRenderer() const
208 {
209     return &g_wxPGDefaultRenderer;
210 }*/
211 
DrawValue(wxDC & dc,const wxRect & rect,wxPGProperty * property,const wxString & text) const212 void wxPGEditor::DrawValue( wxDC& dc, const wxRect& rect, wxPGProperty* property, const wxString& text ) const
213 {
214     if ( !property->IsValueUnspecified() )
215         dc.DrawText( text, rect.x+wxPG_XBEFORETEXT, rect.y );
216 }
217 
218 #ifdef __WXPYTHON__
GetValueFromControl(wxVariant &,wxPGProperty *,wxWindow *) const219 bool wxPGEditor::GetValueFromControl( wxVariant&, wxPGProperty*, wxWindow* ) const
220 {
221     return false;
222 }
223 
PyGetValueFromControl(wxPGProperty * property,wxWindow * ctrl) const224 wxPGVariantAndBool wxPGEditor::PyGetValueFromControl( wxPGProperty* property, wxWindow* ctrl ) const
225 {
226     wxPGVariantAndBool vab;
227     vab.m_result = GetValueFromControl(vab.m_value, property, ctrl);
228     if ( vab.m_result )
229         vab.m_valueValid = true;
230     return vab;
231 }
232 #endif
233 
SetControlStringValue(wxPGProperty * WXUNUSED (property),wxWindow *,const wxString &) const234 void wxPGEditor::SetControlStringValue( wxPGProperty* WXUNUSED(property), wxWindow*, const wxString& ) const
235 {
236 }
237 
238 
SetControlIntValue(wxPGProperty * WXUNUSED (property),wxWindow *,int) const239 void wxPGEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow*, int ) const
240 {
241 }
242 
243 
InsertItem(wxWindow *,const wxString &,int) const244 int wxPGEditor::InsertItem( wxWindow*, const wxString&, int ) const
245 {
246     return -1;
247 }
248 
249 
DeleteItem(wxWindow *,int) const250 void wxPGEditor::DeleteItem( wxWindow*, int ) const
251 {
252     return;
253 }
254 
255 
OnFocus(wxPGProperty *,wxWindow *) const256 void wxPGEditor::OnFocus( wxPGProperty*, wxWindow* ) const
257 {
258 }
259 
260 
CanContainCustomImage() const261 bool wxPGEditor::CanContainCustomImage() const
262 {
263     return false;
264 }
265 
266 // -----------------------------------------------------------------------
267 // wxPGClipperWindow
268 // -----------------------------------------------------------------------
269 
270 #if wxPG_ENABLE_CLIPPER_WINDOW
271 
272 //
273 // Clipper window is used to "remove" borders from controls
274 // which otherwise insist on having them despite of supplied
275 // wxNO_BORDER window style.
276 //
277 class wxPGClipperWindow : public wxWindow
278 {
279     DECLARE_CLASS(wxPGClipperWindow)
280 public:
281 
wxPGClipperWindow()282     wxPGClipperWindow()
283         : wxWindow()
284     {
285         wxPGClipperWindow::Init();
286     }
287 
wxPGClipperWindow(wxWindow * parent,wxWindowID id,const wxPoint & pos=wxDefaultPosition,const wxSize & size=wxDefaultSize)288     wxPGClipperWindow(wxWindow* parent,
289                       wxWindowID id,
290                       const wxPoint& pos = wxDefaultPosition,
291                       const wxSize& size = wxDefaultSize)
292     {
293         Init();
294         Create(parent,id,pos,size);
295     }
296 
297     void Create(wxWindow* parent,
298                 wxWindowID id,
299                 const wxPoint& pos = wxDefaultPosition,
300                 const wxSize& size = wxDefaultSize);
301 
302     ~wxPGClipperWindow() override;
303 
304     bool ProcessEvent(wxEvent& event) override;
305 
GetControl() const306     inline wxWindow* GetControl() const { return m_ctrl; }
307 
308     // This is called before wxControl is constructed.
309     void GetControlRect( int xadj, int yadj, wxPoint& pt, wxSize& sz );
310 
311     // This is caleed after wxControl has been constructed.
312     void SetControl( wxWindow* ctrl );
313 
314     void Refresh( bool eraseBackground = true,
315                           const wxRect *rect = (const wxRect *) NULL ) override;
316     void SetFocus() override;
317 
318     bool SetFont(const wxFont& font) override;
319 
SetForegroundColour(const wxColour & col)320     bool SetForegroundColour(const wxColour& col) override
321     {
322         bool res = wxWindow::SetForegroundColour(col);
323         if ( m_ctrl )
324             m_ctrl->SetForegroundColour(col);
325         return res;
326     }
327 
SetBackgroundColour(const wxColour & col)328     bool SetBackgroundColour(const wxColour& col) override
329     {
330         bool res = wxWindow::SetBackgroundColour(col);
331         if ( m_ctrl )
332             m_ctrl->SetBackgroundColour(col);
333         return res;
334     }
335 
GetXClip() const336     inline int GetXClip() const { return m_xadj; }
337 
GetYClip() const338     inline int GetYClip() const { return m_yadj; }
339 
340 protected:
341     wxWindow*       m_ctrl;
342 
343     int             m_xadj; // Horizontal border clip.
344 
345     int             m_yadj; // Vertical border clip.
346 
347 private:
Init()348     void Init ()
349     {
350         m_ctrl = (wxWindow*) NULL;
351     }
352 };
353 
354 
IMPLEMENT_CLASS(wxPGClipperWindow,wxWindow)355 IMPLEMENT_CLASS(wxPGClipperWindow,wxWindow)
356 
357 
358 // This is called before wxControl is constructed.
359 void wxPGClipperWindow::GetControlRect( int xadj, int yadj, wxPoint& pt, wxSize& sz )
360 {
361     m_xadj = xadj;
362     m_yadj = yadj;
363     pt.x = -xadj;
364     pt.y = -yadj;
365     wxSize own_size = GetSize();
366     sz.x = own_size.x+(xadj*2);
367     sz.y = own_size.y+(yadj*2);
368 }
369 
370 
371 // This is caleed after wxControl has been constructed.
SetControl(wxWindow * ctrl)372 void wxPGClipperWindow::SetControl( wxWindow* ctrl )
373 {
374     m_ctrl = ctrl;
375 
376     // GTK requires this.
377     ctrl->SetSizeHints(3,3);
378 
379     // Correct size of this window to match the child.
380     wxSize sz = GetSize();
381     wxSize chsz = ctrl->GetSize();
382 
383     int hei_adj = chsz.y - (sz.y+(m_yadj*2));
384     if ( hei_adj )
385         SetSize(sz.x,chsz.y-(m_yadj*2));
386 
387 }
388 
389 
Refresh(bool eraseBackground,const wxRect * rect)390 void wxPGClipperWindow::Refresh( bool eraseBackground, const wxRect *rect )
391 {
392     wxWindow::Refresh(false,rect);
393     if ( m_ctrl )
394         m_ctrl->Refresh(eraseBackground);
395 }
396 
397 
398 // Pass focus to control
SetFocus()399 void wxPGClipperWindow::SetFocus()
400 {
401     if ( m_ctrl )
402         m_ctrl->SetFocus();
403     else
404         wxWindow::SetFocus();
405 }
406 
407 
SetFont(const wxFont & font)408 bool wxPGClipperWindow::SetFont(const wxFont& font)
409 {
410     bool res = wxWindow::SetFont(font);
411     if ( m_ctrl )
412         return m_ctrl->SetFont(font);
413     return res;
414 }
415 
416 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size)417 void wxPGClipperWindow::Create(wxWindow* parent,
418                                wxWindowID id,
419                                const wxPoint& pos,
420                                const wxSize& size )
421 {
422     wxWindow::Create(parent,id,pos,size);
423 }
424 
425 
~wxPGClipperWindow()426 wxPGClipperWindow::~wxPGClipperWindow()
427 {
428 }
429 
430 
ProcessEvent(wxEvent & event)431 bool wxPGClipperWindow::ProcessEvent(wxEvent& event)
432 {
433     if ( event.GetEventType() == wxEVT_SIZE )
434     {
435         if ( m_ctrl )
436         {
437             // Maintain correct size relationship.
438             wxSize sz = GetSize();
439             m_ctrl->SetSize(sz.x+(m_xadj*2),sz.y+(m_yadj*2));
440             event.Skip();
441             return false;
442         }
443     }
444     return wxWindow::ProcessEvent(event);
445 }
446 
447 #endif // wxPG_ENABLE_CLIPPER_WINDOW
448 
449 /*wxWindow* wxPropertyGrid::GetActualEditorControl( wxWindow* ctrl )
450 {
451 #if wxPG_ENABLE_CLIPPER_WINDOW
452     // Pass real control instead of clipper window
453     if ( ctrl->IsKindOf(CLASSINFO(wxPGClipperWindow)) )
454     {
455         return ((wxPGClipperWindow*)ctrl)->GetControl();
456     }
457 #else
458     return ctrl;
459 #endif
460 }*/
461 
462 // -----------------------------------------------------------------------
463 // wxPGTextCtrlEditor
464 // -----------------------------------------------------------------------
465 
466 // Clipper window support macro (depending on whether it is used
467 // for this editor or not)
468 #if wxPG_NAT_TEXTCTRL_BORDER_X || wxPG_NAT_TEXTCTRL_BORDER_Y
469     #define wxPG_NAT_TEXTCTRL_BORDER_ANY    1
470 #else
471     #define wxPG_NAT_TEXTCTRL_BORDER_ANY    0
472 #endif
473 
474 
WX_PG_IMPLEMENT_EDITOR_CLASS(TextCtrl,wxPGTextCtrlEditor,wxPGEditor)475 WX_PG_IMPLEMENT_EDITOR_CLASS(TextCtrl,wxPGTextCtrlEditor,wxPGEditor)
476 
477 
478 wxPGWindowList wxPGTextCtrlEditor::CreateControls( wxPropertyGrid* propGrid,
479                                                    wxPGProperty* property,
480                                                    const wxPoint& pos,
481                                                    const wxSize& sz ) const
482 {
483     wxString text;
484 
485     //
486     // If has children, and limited editing is specified, then don't create.
487     if ( (property->GetFlags() & wxPG_PROP_NOEDITOR) &&
488          property->GetChildCount() )
489         return (wxWindow*) NULL;
490 
491     if ( !property->IsValueUnspecified() )
492     {
493         int flags = property->HasFlag(wxPG_PROP_READONLY) ?
494             0 : wxPG_EDITABLE_VALUE;
495         text = property->GetValueString(flags);
496     }
497     else
498     {
499         text = propGrid->GetUnspecifiedValueText();
500     }
501 
502     int flags = 0;
503     if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
504          property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
505         flags |= wxTE_PASSWORD;
506 
507     wxWindow* wnd = propGrid->GenerateEditorTextCtrl(pos,sz,text,(wxWindow*)NULL,flags,
508                                                      property->GetMaxLength());
509 
510     return wnd;
511 }
512 
513 #if 0
514 void wxPGTextCtrlEditor::DrawValue( wxDC& dc, wxPGProperty* property, const wxRect& rect ) const
515 {
516     if ( !property->IsValueUnspecified() )
517     {
518         wxString drawStr = property->GetDisplayedString();
519 
520         // Code below should no longer be needed, as the obfuscation
521         // is now done in GetValueAsString.
522         /*if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
523              property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
524         {
525             size_t a = drawStr.length();
526             drawStr.Empty();
527             drawStr.Append(wxT('*'),a);
528         }*/
529         dc.DrawText( drawStr, rect.x+wxPG_XBEFORETEXT, rect.y );
530     }
531 }
532 #endif
533 
UpdateControl(wxPGProperty * property,wxWindow * ctrl) const534 void wxPGTextCtrlEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
535 {
536     wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
537 
538     wxString s;
539 
540     if ( tc->HasFlag(wxTE_PASSWORD) )
541         s = property->GetValueAsString(wxPG_FULL_VALUE);
542     else
543         s = property->GetDisplayedString();
544 
545     wxPropertyGrid* pg = property->GetGrid();
546 
547     pg->SetupTextCtrlValue(s);
548     tc->SetValue(s);
549 
550     // Must always fix indentation, just in case
551 #if defined(__WXMSW__) && !defined(__WXWINCE__)
552         ::SendMessage(GetHwndOf(tc), EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0));
553 #endif
554 }
555 
556 
557 // Provided so that, for example, ComboBox editor can use the same code
558 // (multiple inheritance would get way too messy).
OnTextCtrlEvent(wxPropertyGrid * propGrid,wxPGProperty * WXUNUSED (property),wxWindow * ctrl,wxEvent & event)559 bool wxPGTextCtrlEditor::OnTextCtrlEvent( wxPropertyGrid* propGrid,
560                                           wxPGProperty* WXUNUSED(property),
561                                           wxWindow* ctrl,
562                                           wxEvent& event )
563 {
564     if ( !ctrl )
565         return false;
566 
567     if ( event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER )
568     {
569         if ( propGrid->IsEditorsValueModified() )
570         {
571             return true;
572         }
573     }
574     else if ( event.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED )
575     {
576         //
577         // Pass this event outside wxPropertyGrid so that,
578         // if necessary, program can tell when user is editing
579         // a textctrl.
580         // FIXME: Is it safe to change event id in the middle of event
581         //        processing (seems to work, but...)?
582         event.Skip();
583         event.SetId(propGrid->GetId());
584 
585         propGrid->EditorsValueWasModified();
586     }
587     return false;
588 }
589 
590 
OnEvent(wxPropertyGrid * propGrid,wxPGProperty * property,wxWindow * ctrl,wxEvent & event) const591 bool wxPGTextCtrlEditor::OnEvent( wxPropertyGrid* propGrid,
592                                   wxPGProperty* property,
593                                   wxWindow* ctrl,
594                                   wxEvent& event ) const
595 {
596     return wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid,property,ctrl,event);
597 }
598 
599 
GetTextCtrlValueFromControl(wxVariant & variant,wxPGProperty * property,wxWindow * ctrl)600 bool wxPGTextCtrlEditor::GetTextCtrlValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl )
601 {
602     wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
603     wxString textVal = tc->GetValue();
604 
605     if ( property->UsesAutoUnspecified() && !textVal.length() )
606     {
607         variant.MakeNull();
608         return true;
609     }
610 
611     bool res = property->ActualStringToValue(variant, textVal, wxPG_EDITABLE_VALUE);
612 
613     // Changing unspecified always causes event (returning
614     // true here should be enough to trigger it).
615     // TODO: Move to propgrid.cpp
616     if ( !res && variant.IsNull() )
617         res = true;
618 
619     return res;
620 }
621 
622 
GetValueFromControl(wxVariant & variant,wxPGProperty * property,wxWindow * ctrl) const623 bool wxPGTextCtrlEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
624 {
625     return wxPGTextCtrlEditor::GetTextCtrlValueFromControl(variant, property, ctrl);
626 }
627 
628 
SetValueToUnspecified(wxPGProperty * property,wxWindow * ctrl) const629 void wxPGTextCtrlEditor::SetValueToUnspecified( wxPGProperty* property, wxWindow* ctrl ) const
630 {
631     wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
632 
633     wxPropertyGrid* pg = property->GetGrid();
634     wxASSERT(pg);  // Really, property grid should exist if editor does
635     if ( pg )
636     {
637         wxString tcText = pg->GetUnspecifiedValueText();
638         pg->SetupTextCtrlValue(tcText);
639         tc->SetValue(tcText);
640     }
641 }
642 
643 
SetControlStringValue(wxPGProperty * property,wxWindow * ctrl,const wxString & txt) const644 void wxPGTextCtrlEditor::SetControlStringValue( wxPGProperty* property, wxWindow* ctrl, const wxString& txt ) const
645 {
646     wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
647 
648     wxPropertyGrid* pg = property->GetGrid();
649     wxASSERT(pg);  // Really, property grid should exist if editor does
650     if ( pg )
651         tc->SetValue(txt);
652 }
653 
wxPGTextCtrlEditor_OnFocus(wxPGProperty * property,wxTextCtrl * tc)654 void wxPGTextCtrlEditor_OnFocus( wxPGProperty* property,
655                                  wxTextCtrl*tc )
656 {
657     // Make sure there is correct text (instead of unspecified value
658     // indicator or inline help)
659     int flags = property->HasFlag(wxPG_PROP_READONLY) ?
660         0 : wxPG_EDITABLE_VALUE;
661     wxString correctText = property->GetValueString(flags);
662 
663     if ( tc->GetValue() != correctText )
664     {
665         property->GetGrid()->SetupTextCtrlValue(correctText);
666         tc->SetValue(correctText);
667     }
668 
669     tc->SetSelection(-1,-1);
670 }
671 
OnFocus(wxPGProperty * property,wxWindow * wnd) const672 void wxPGTextCtrlEditor::OnFocus( wxPGProperty* property,
673                                   wxWindow* wnd ) const
674 {
675     wxTextCtrl* tc = wxStaticCast(wnd, wxTextCtrl);
676     wxPGTextCtrlEditor_OnFocus(property, tc);
677 }
678 
~wxPGTextCtrlEditor()679 wxPGTextCtrlEditor::~wxPGTextCtrlEditor()
680 {
681     // Reset the global pointer. Useful when wxPropertyGrid is accessed
682     // from an external main loop.
683     wxPG_EDITOR(TextCtrl) = NULL;
684 }
685 
686 // -----------------------------------------------------------------------
687 // wxPGChoiceEditor
688 // -----------------------------------------------------------------------
689 
690 
691 WX_PG_IMPLEMENT_EDITOR_CLASS(Choice,wxPGChoiceEditor,wxPGEditor)
692 
693 
694 // This is a special enhanced double-click processor class.
695 // In essence, it allows for double-clicks for which the
696 // first click "created" the control.
697 class wxPGDoubleClickProcessor : public wxEvtHandler
698 {
699 public:
700 
wxPGDoubleClickProcessor(wxPGOwnerDrawnComboBox * combo)701     wxPGDoubleClickProcessor( wxPGOwnerDrawnComboBox* combo )
702         : wxEvtHandler()
703     {
704         m_timeLastMouseUp = 0;
705         m_combo = combo;
706         m_downReceived = false;
707     }
708 
709 protected:
710 
OnMouseEvent(wxMouseEvent & event)711     void OnMouseEvent( wxMouseEvent& event )
712     {
713         wxLongLong t = ::wxGetLocalTimeMillis();
714         int evtType = event.GetEventType();
715 
716         if ( m_combo->HasFlag(wxPGCC_DCLICK_CYCLES) &&
717              !m_combo->IsPopupShown() )
718         {
719             // Just check that it is in the text area
720             wxPoint pt = event.GetPosition();
721             if ( m_combo->GetTextRect().wxPGRectContains(pt) )
722             {
723                 if ( evtType == wxEVT_LEFT_DOWN )
724                 {
725                     // Set value to avoid up-events without corresponding downs
726                     m_downReceived = true;
727                 }
728                 else if ( evtType == wxEVT_LEFT_DCLICK )
729                 {
730                     // We'll make our own double-clicks
731                     event.SetEventType(0);
732                     return;
733                 }
734                 else if ( evtType == wxEVT_LEFT_UP )
735                 {
736                     if ( m_downReceived || m_timeLastMouseUp == 1 )
737                     {
738                         wxLongLong timeFromLastUp = (t-m_timeLastMouseUp);
739 
740                         if ( timeFromLastUp < DOUBLE_CLICK_CONVERSION_TRESHOLD )
741                         {
742                             event.SetEventType(wxEVT_LEFT_DCLICK);
743                             m_timeLastMouseUp = 1;
744                         }
745                         else
746                         {
747                             m_timeLastMouseUp = t;
748                         }
749                     }
750                 }
751             }
752         }
753 
754         event.Skip();
755     }
756 
OnSetFocus(wxFocusEvent & event)757     void OnSetFocus( wxFocusEvent& event )
758     {
759         m_timeLastMouseUp = ::wxGetLocalTimeMillis();
760         event.Skip();
761     }
762 
763 private:
764     wxLongLong                  m_timeLastMouseUp;
765     wxPGOwnerDrawnComboBox*     m_combo;
766     bool                        m_downReceived;
767 
768     DECLARE_EVENT_TABLE()
769 };
770 
771 BEGIN_EVENT_TABLE(wxPGDoubleClickProcessor, wxEvtHandler)
772     EVT_MOUSE_EVENTS(wxPGDoubleClickProcessor::OnMouseEvent)
773     EVT_SET_FOCUS(wxPGDoubleClickProcessor::OnSetFocus)
774 END_EVENT_TABLE()
775 
776 
777 
778 class wxPGComboBox : public wxPGOwnerDrawnComboBox
779 {
780 public:
781 
wxPGComboBox()782     wxPGComboBox()
783         : wxPGOwnerDrawnComboBox()
784     {
785         m_dclickProcessor = (wxPGDoubleClickProcessor*) NULL;
786         m_sizeEventCalled = false;
787     }
788 
~wxPGComboBox()789     ~wxPGComboBox() override
790     {
791         if ( m_dclickProcessor )
792         {
793             RemoveEventHandler(m_dclickProcessor);
794             delete m_dclickProcessor;
795         }
796     }
797 
Create(wxWindow * parent,wxWindowID id,const wxString & value,const wxPoint & pos,const wxSize & size,const wxArrayString & choices,long style=0,const wxValidator & validator=wxDefaultValidator,const wxString & name=wxT ("wxOwnerDrawnComboBox"))798     bool Create(wxWindow *parent,
799                 wxWindowID id,
800                 const wxString& value,
801                 const wxPoint& pos,
802                 const wxSize& size,
803                 const wxArrayString& choices,
804                 long style = 0,
805                 const wxValidator& validator = wxDefaultValidator,
806                 const wxString& name = wxT("wxOwnerDrawnComboBox"))
807     {
808         if ( !wxPGOwnerDrawnComboBox::Create( parent,
809                                               id,
810                                               value,
811                                               pos,
812                                               size,
813                                               choices,
814                                               style,
815                                               validator,
816                                               name ) )
817             return false;
818 
819         m_dclickProcessor = new wxPGDoubleClickProcessor(this);
820 
821         PushEventHandler(m_dclickProcessor);
822 
823         return true;
824     }
825 
826 #if wxPG_USING_WXOWNERDRAWNCOMBOBOX
OnDrawItem(wxDC & dc,const wxRect & rect,int item,int flags) const827     void OnDrawItem( wxDC& dc, const wxRect& rect, int item, int flags ) const override
828 #else
829     virtual bool OnDrawItem( wxDC& dc, const wxRect& rect, int item, int flags ) const
830 #endif
831     {
832         wxPropertyGrid* pg = GetGrid();
833         pg->OnComboItemPaint((wxPGCustomComboControl*)this,item,&dc,(wxRect&)rect,flags);
834 #if !wxPG_USING_WXOWNERDRAWNCOMBOBOX
835         return true;
836 #endif
837     }
OnMeasureItem(size_t item) const838     wxCoord OnMeasureItem( size_t item ) const override
839     {
840         wxPropertyGrid* pg = GetGrid();
841         wxRect rect;
842         rect.x = -1;
843         rect.width = 0;
844         pg->OnComboItemPaint((wxPGCustomComboControl*)this,item,NULL,rect,0);
845         return rect.height;
846     }
847 
GetGrid() const848     wxPropertyGrid* GetGrid() const
849     {
850         wxPropertyGrid* pg = wxDynamicCast(GetParent()->GetParent(),wxPropertyGrid);
851         wxASSERT(pg);
852         return pg;
853     }
854 
OnMeasureItemWidth(size_t item) const855     wxCoord OnMeasureItemWidth( size_t item ) const override
856     {
857         wxPropertyGrid* pg = GetGrid();
858         wxRect rect;
859         rect.x = -1;
860         rect.width = -1;
861         pg->OnComboItemPaint((wxPGCustomComboControl*)this,item,NULL,rect,0);
862         return rect.width;
863     }
864 
PositionTextCtrl(int WXUNUSED (textCtrlXAdjust),int WXUNUSED (textCtrlYAdjust))865     virtual void PositionTextCtrl( int WXUNUSED(textCtrlXAdjust), int WXUNUSED(textCtrlYAdjust) )
866     {
867         wxPropertyGrid* pg = GetGrid();
868         wxPGOwnerDrawnComboBox::PositionTextCtrl(
869             wxPG_TEXTCTRLXADJUST - (wxPG_XBEFOREWIDGET+wxPG_CONTROL_MARGIN+1) - 1,
870             pg->GetSpacingY() + 2
871         );
872     }
873 
874 private:
875     wxPGDoubleClickProcessor*   m_dclickProcessor;
876     bool                        m_sizeEventCalled;
877 };
878 
879 
OnComboItemPaint(wxPGCustomComboControl * pCc,int item,wxDC * pDc,wxRect & rect,int flags)880 void wxPropertyGrid::OnComboItemPaint( wxPGCustomComboControl* pCc,
881                                        int item,
882                                        wxDC* pDc,
883                                        wxRect& rect,
884                                        int flags )
885 {
886     wxPGComboBox* pCb = (wxPGComboBox*)pCc;
887 
888     // Sanity check
889     wxASSERT( IsKindOf(CLASSINFO(wxPropertyGrid)) );
890 
891     wxPGProperty* p = GetSelection();
892     wxString text;
893 
894     const wxPGChoices* pChoices = &p->GetChoices();
895     const wxPGCommonValue* comVal = NULL;
896     int choiceCount = p->GetChoiceCount();
897     int comVals = p->GetDisplayedCommonValueCount();
898     int comValIndex = -1;
899     if ( item >= choiceCount && comVals > 0 )
900     {
901         comValIndex = item - choiceCount;
902         comVal = GetCommonValue(comValIndex);
903         if ( !p->IsValueUnspecified() )
904             text = comVal->GetLabel();
905     }
906     else
907     {
908         if ( !(flags & wxPGCC_PAINTING_CONTROL) )
909         {
910             text = pCb->GetString(item);
911         }
912         else
913         {
914             if ( !p->IsValueUnspecified() )
915                 text = p->GetValueString(0);
916         }
917     }
918 
919     if ( item < 0 )
920         return;
921 
922 #if !wxPG_USING_WXOWNERDRAWNCOMBOBOX
923     // Add wxPGCC_PAINTING_SELECTED
924     if ( !(flags & wxPGCC_PAINTING_CONTROL) &&
925          wxDynamicCast(pCb->GetPopup()->GetControl(),wxVListBox)->GetSelection() == item )
926          flags |= wxPGCC_PAINTING_SELECTED;
927 #endif
928 
929     wxSize cis;
930 
931     const wxBitmap* itemBitmap = NULL;
932 
933     if ( item >= 0 && pChoices && pChoices->Item(item).GetBitmap().Ok() && comValIndex == -1 )
934         itemBitmap = &pChoices->Item(item).GetBitmap();
935 
936     //
937     // Decide what custom image size to use
938     if ( itemBitmap )
939     {
940         cis.x = itemBitmap->GetWidth();
941         cis.y = itemBitmap->GetHeight();
942     }
943     else
944     {
945         cis = GetImageSize(p, item);
946     }
947 
948     if ( rect.x < 0 )
949     {
950         // Default measure behaviour (no flexible, custom paint image only)
951         if ( rect.width < 0 )
952         {
953             wxCoord x, y;
954             GetTextExtent(text, &x, &y, 0, 0);
955             rect.width = cis.x + wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2 + 9 + x;
956         }
957 
958         rect.height = cis.y + 2;
959         return;
960     }
961 
962     wxPGPaintData paintdata;
963     paintdata.m_parent = NULL;
964     paintdata.m_choiceItem = item;
965 
966     // This is by the current (1.0.0b) spec - if painting control, item is -1
967     if ( (flags & wxPGCC_PAINTING_CONTROL) )
968         paintdata.m_choiceItem = -1;
969 
970     wxASSERT( pDc );
971     pDc->SetBrush(*wxWHITE_BRUSH);
972 
973     wxPGCellRenderer* renderer = NULL;
974     const wxPGCell* cell = NULL;
975 
976     if ( rect.x >= 0 )
977     {
978         //
979         // DrawItem call
980 
981         wxPoint pt(rect.x + wxPG_CONTROL_MARGIN - wxPG_CHOICEXADJUST - 1,
982                    rect.y + 1);
983 
984         int renderFlags = 0;
985 
986         if ( flags & wxPGCC_PAINTING_CONTROL )
987         {
988             renderFlags |= wxPGCellRenderer::Control;
989         }
990         else
991         {
992             // For consistency, always use normal font when drawing drop down
993             // items
994             pDc->SetFont(GetFont());
995         }
996 
997         if ( flags & wxPGCC_PAINTING_SELECTED )
998             renderFlags |= wxPGCellRenderer::Selected;
999 
1000         if ( cis.x > 0 && (p->HasFlag(wxPG_PROP_CUSTOMIMAGE) || !(flags & wxPGCC_PAINTING_CONTROL)) &&
1001              ( !p->m_valueBitmap || item == pCb->GetSelection() ) &&
1002              ( item >= 0 || (flags & wxPGCC_PAINTING_CONTROL) ) &&
1003              !itemBitmap
1004            )
1005         {
1006             pt.x += wxCC_CUSTOM_IMAGE_MARGIN1;
1007             wxRect r(pt.x,pt.y,cis.x,cis.y);
1008 
1009             if ( flags & wxPGCC_PAINTING_CONTROL )
1010             {
1011                 //r.width = cis.x;
1012                 r.height = wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight);
1013             }
1014 
1015             paintdata.m_drawnWidth = r.width;
1016 
1017             pDc->SetPen(m_colPropFore);
1018             if ( comValIndex >= 0 )
1019             {
1020                 const wxPGCommonValue* cv = GetCommonValue(comValIndex);
1021                 wxPGCellRenderer* renderer = cv->GetRenderer();
1022                 r.width = rect.width;
1023                 renderer->Render( *pDc, r, this, p, m_selColumn, comValIndex, renderFlags );
1024                 return;
1025             }
1026             else if ( item >= 0 )
1027             {
1028                 p->OnCustomPaint( *pDc, r, paintdata );
1029             }
1030             else
1031             {
1032                 pDc->DrawRectangle( r );
1033             }
1034 
1035             pt.x += paintdata.m_drawnWidth + wxCC_CUSTOM_IMAGE_MARGIN2 - 1;
1036         }
1037         else
1038         {
1039             // TODO: This aligns text so that it seems to be horizontally
1040             //       on the same line as property values. Not really
1041             //       sure if its needed, but seems to not cause any harm.
1042             pt.x -= 1;
1043 
1044             if ( (flags & wxPGCC_PAINTING_CONTROL) )
1045             {
1046                 if ( p->IsValueUnspecified() )
1047                     cell = &m_unspecifiedAppearance;
1048                 else if ( item < 0 )
1049                     item = pCb->GetSelection();
1050             }
1051 
1052             if ( p->IsValueUnspecified() && item < 0 )
1053             {
1054                 cell = &m_unspecifiedAppearance;
1055             }
1056 
1057             if ( pChoices && item >= 0 && comValIndex < 0 )
1058             {
1059                 cell = &pChoices->Item(item);
1060                 renderer = wxPGGlobalVars->m_defaultRenderer;
1061                 int imageOffset = renderer->PreDrawCell(*pDc, rect, *cell,
1062                                                         renderFlags );
1063                 if ( imageOffset )
1064                     imageOffset += wxCC_CUSTOM_IMAGE_MARGIN1 +
1065                                    wxCC_CUSTOM_IMAGE_MARGIN2;
1066                 pt.x += imageOffset;
1067             }
1068         }
1069 
1070         //
1071         // Draw text
1072         //
1073 
1074         pt.y += (rect.height-m_fontHeight)/2 - 1;
1075 
1076         pt.x += 1;
1077 
1078         pDc->DrawText( text, pt.x + wxPG_XBEFORETEXT, pt.y );
1079 
1080         if ( renderer )
1081             renderer->PostDrawCell(*pDc, this, *cell, renderFlags);
1082     }
1083     else
1084     {
1085         //
1086         // MeasureItem call
1087 
1088         p->OnCustomPaint( *pDc, rect, paintdata );
1089         rect.height = paintdata.m_drawnHeight + 2;
1090         rect.width = cis.x + wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2 + 9;
1091     }
1092 }
1093 
wxPGChoiceEditor_SetCustomPaintWidth(wxPropertyGrid * propGrid,wxPGComboBox * cb,wxPGProperty * property,int cmnVal)1094 bool wxPGChoiceEditor_SetCustomPaintWidth( wxPropertyGrid* propGrid,
1095                                            wxPGComboBox* cb,
1096                                            wxPGProperty* property,
1097                                            int cmnVal )
1098 {
1099     // Must return true if value was not a common value
1100     int custPaintMargin;
1101 
1102     //
1103     // Use different custom paint margin because of better textctrl spacing
1104     if ( cb->HasFlag(wxCB_READONLY) )
1105         custPaintMargin = ODCB_CUST_PAINT_MARGIN_RO;
1106     else
1107         custPaintMargin = ODCB_CUST_PAINT_MARGIN;
1108 
1109     if ( property->IsValueUnspecified() )
1110     {
1111         cb->SetCustomPaintWidth( 0 );
1112         return true;
1113     }
1114 
1115     if ( cmnVal >= 0 )
1116     {
1117         // Yes, a common value is being selected
1118         property->SetCommonValue( cmnVal );
1119         wxSize imageSize = propGrid->GetCommonValue(cmnVal)->
1120                             GetRenderer()->GetImageSize(property, 1, cmnVal);
1121         if ( imageSize.x ) imageSize.x += custPaintMargin;
1122         cb->SetCustomPaintWidth( imageSize.x );
1123         return false;
1124     }
1125     else
1126     {
1127         wxSize imageSize = propGrid->GetImageSize(property, -1);
1128         if ( imageSize.x ) imageSize.x += custPaintMargin;
1129         cb->SetCustomPaintWidth( imageSize.x );
1130         return true;
1131     }
1132 }
1133 
1134 // CreateControls calls this with CB_READONLY in extraStyle
CreateControlsBase(wxPropertyGrid * propGrid,wxPGProperty * property,const wxPoint & pos,const wxSize & sz,long extraStyle) const1135 wxWindow* wxPGChoiceEditor::CreateControlsBase( wxPropertyGrid* propGrid,
1136                                                 wxPGProperty* property,
1137                                                 const wxPoint& pos,
1138                                                 const wxSize& sz,
1139                                                 long extraStyle ) const
1140 {
1141     wxString        defString;
1142 
1143     // Since it is not possible (yet) to create a read-only combo box in
1144     // the same sense that wxTextCtrl is read-only, simply do not create
1145     // the control in this case.
1146     if ( property->HasFlag(wxPG_PROP_READONLY) )
1147         return NULL;
1148 
1149     // Get choices.
1150     int index = property->GetChoiceInfo( NULL );
1151 
1152     bool isUnspecified = property->IsValueUnspecified();
1153 
1154     if ( isUnspecified )
1155         index = -1;
1156     else
1157         defString = property->GetDisplayedString();
1158 
1159     const wxPGChoices& choices = property->GetChoices();
1160 
1161     wxArrayString labels = choices.GetLabels();
1162 
1163     wxPGComboBox* cb;
1164 
1165     wxPoint po(pos);
1166     wxSize si(sz);
1167     po.y += wxPG_CHOICEYADJUST;
1168     si.y -= (wxPG_CHOICEYADJUST*2);
1169 
1170     po.x += wxPG_CHOICEXADJUST;
1171     si.x -= wxPG_CHOICEXADJUST;
1172     wxWindow* ctrlParent = propGrid->GetPanel();
1173 
1174     int odcbFlags = extraStyle | wxNO_BORDER | wxPGCC_PROCESS_ENTER | wxPGCC_ALT_KEYS;
1175 
1176     if ( (property->GetFlags() & wxPG_PROP_USE_DCC) &&
1177          (property->IsKindOf(CLASSINFO(wxBoolProperty)) ) )
1178         odcbFlags |= wxPGCC_DCLICK_CYCLES;
1179 
1180     //
1181     // If common value specified, use appropriate index
1182     unsigned int cmnVals = property->GetDisplayedCommonValueCount();
1183     if ( cmnVals )
1184     {
1185         if ( !isUnspecified )
1186         {
1187             int cmnVal = property->GetCommonValue();
1188             if ( cmnVal >= 0 )
1189             {
1190                 index = labels.size() + cmnVal;
1191             }
1192         }
1193 
1194         unsigned int i;
1195         for ( i=0; i<cmnVals; i++ )
1196             labels.Add(propGrid->GetCommonValueLabel(i));
1197     }
1198 
1199     cb = new wxPGComboBox();
1200 #ifdef __WXMSW__
1201     cb->Hide();
1202 #endif
1203     cb->Create(ctrlParent,
1204                wxPG_SUBID1,
1205                wxString(),
1206                po,
1207                si,
1208                labels,
1209                odcbFlags);
1210 
1211     //int extRight = propGrid->GetClientSize().x - (po.x+si.x);
1212     //int extRight =  - (po.x+si.x);
1213 
1214     cb->SetButtonPosition(si.y,0,wxRIGHT);
1215     //cb->SetPopupExtents( 1, extRight );
1216     cb->SetTextIndent(wxPG_XBEFORETEXT-1);
1217 
1218     wxPGChoiceEditor_SetCustomPaintWidth( propGrid, cb, property,
1219                                           property->GetCommonValue() );
1220     /*if ( property->GetFlags() & wxPG_PROP_CUSTOMIMAGE )
1221     {
1222         wxSize imageSize = propGrid->GetImageSize(property, index);
1223         if ( imageSize.x ) imageSize.x += ODCB_CUST_PAINT_MARGIN;
1224         cb->SetCustomPaintWidth( imageSize.x );
1225     }*/
1226 
1227     if ( index >= 0 && index < (int)cb->GetCount() )
1228     {
1229         cb->SetSelection( index );
1230         if ( defString.length() )
1231             cb->SetText( defString );
1232     }
1233     else if ( !(extraStyle & wxCB_READONLY) && defString.length() )
1234         cb->SetValue( defString );
1235     else
1236         cb->SetSelection( -1 );
1237 
1238 #ifdef __WXMSW__
1239     cb->Show();
1240 #endif
1241 
1242     return (wxWindow*) cb;
1243 }
1244 
1245 
UpdateControl(wxPGProperty * property,wxWindow * ctrl) const1246 void wxPGChoiceEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
1247 {
1248     wxASSERT( ctrl );
1249     wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1250     wxASSERT( cb->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)));
1251     int ind = property->GetChoiceInfo( (wxPGChoiceInfo*)NULL );
1252     cb->SetSelection(ind);
1253 }
1254 
CreateControls(wxPropertyGrid * propGrid,wxPGProperty * property,const wxPoint & pos,const wxSize & sz) const1255 wxPGWindowList wxPGChoiceEditor::CreateControls( wxPropertyGrid* propGrid, wxPGProperty* property,
1256         const wxPoint& pos, const wxSize& sz ) const
1257 {
1258     return CreateControlsBase(propGrid,property,pos,sz,wxCB_READONLY);
1259 }
1260 
1261 
InsertItem(wxWindow * ctrl,const wxString & label,int index) const1262 int wxPGChoiceEditor::InsertItem( wxWindow* ctrl, const wxString& label, int index ) const
1263 {
1264     wxASSERT( ctrl );
1265     wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1266     wxASSERT( cb->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)));
1267 
1268     if (index < 0)
1269         index = cb->GetCount();
1270 
1271     return cb->Insert(label,index);
1272 }
1273 
1274 
DeleteItem(wxWindow * ctrl,int index) const1275 void wxPGChoiceEditor::DeleteItem( wxWindow* ctrl, int index ) const
1276 {
1277     wxASSERT( ctrl );
1278     wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1279     wxASSERT( cb->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)));
1280 
1281     cb->Delete(index);
1282 }
1283 
OnEvent(wxPropertyGrid * propGrid,wxPGProperty * property,wxWindow * ctrl,wxEvent & event) const1284 bool wxPGChoiceEditor::OnEvent( wxPropertyGrid* propGrid, wxPGProperty* property,
1285     wxWindow* ctrl, wxEvent& event ) const
1286 {
1287     if ( event.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED )
1288     {
1289         wxPGComboBox* cb = (wxPGComboBox*)ctrl;
1290         int index = cb->GetSelection();
1291         int cmnValIndex = -1;
1292         int cmnVals = property->GetDisplayedCommonValueCount();
1293         int items = cb->GetCount();
1294 
1295         if ( index >= (items-cmnVals) )
1296         {
1297             // Yes, a common value is being selected
1298             cmnValIndex = index - (items-cmnVals);
1299             property->SetCommonValue( cmnValIndex );
1300 
1301             // Truly set value to unspecified?
1302             if ( propGrid->GetUnspecifiedCommonValue() == cmnValIndex )
1303             {
1304                 if ( !property->IsValueUnspecified() )
1305                     propGrid->SetInternalFlag(wxPG_FL_VALUE_CHANGE_IN_EVENT);
1306                 property->SetValueToUnspecified();
1307                 if ( !cb->HasFlag(wxCB_READONLY) )
1308                     cb->GetTextCtrl()->SetValue(wxEmptyString);
1309                 return false;
1310             }
1311         }
1312         return wxPGChoiceEditor_SetCustomPaintWidth( propGrid, cb, property,
1313                                                      cmnValIndex);
1314     }
1315     return false;
1316 }
1317 
1318 
GetValueFromControl(wxVariant & variant,wxPGProperty * property,wxWindow * ctrl) const1319 bool wxPGChoiceEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
1320 {
1321     wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1322 
1323     int index = cb->GetSelection();
1324 
1325     if ( index != property->GetChoiceInfo( (wxPGChoiceInfo*) NULL ) ||
1326         // Changing unspecified always causes event (returning
1327         // true here should be enough to trigger it).
1328          property->IsValueUnspecified()
1329        )
1330     {
1331         return property->ActualIntToValue( variant, index, 0 );
1332     }
1333     return false;
1334 }
1335 
1336 
SetControlStringValue(wxPGProperty * WXUNUSED (property),wxWindow * ctrl,const wxString & txt) const1337 void wxPGChoiceEditor::SetControlStringValue( wxPGProperty* WXUNUSED(property), wxWindow* ctrl, const wxString& txt ) const
1338 {
1339     wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1340     wxASSERT( cb );
1341     cb->SetValue(txt);
1342 }
1343 
1344 
SetControlIntValue(wxPGProperty * WXUNUSED (property),wxWindow * ctrl,int value) const1345 void wxPGChoiceEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow* ctrl, int value ) const
1346 {
1347     wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1348     wxASSERT( cb );
1349     cb->SetSelection(value);
1350 }
1351 
1352 
SetValueToUnspecified(wxPGProperty * property,wxWindow * ctrl) const1353 void wxPGChoiceEditor::SetValueToUnspecified( wxPGProperty* property,
1354                                               wxWindow* ctrl ) const
1355 {
1356     wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1357 
1358     if ( !cb->HasFlag(wxCB_READONLY) )
1359     {
1360         wxPropertyGrid* pg = property->GetGrid();
1361         if ( pg )
1362         {
1363             wxString tcText = pg->GetUnspecifiedValueText();
1364             pg->SetupTextCtrlValue(tcText);
1365             cb->SetValue(tcText);
1366         }
1367     }
1368     else
1369     {
1370         cb->SetSelection(-1);
1371     }
1372 }
1373 
1374 
CanContainCustomImage() const1375 bool wxPGChoiceEditor::CanContainCustomImage() const
1376 {
1377     return true;
1378 }
1379 
1380 
~wxPGChoiceEditor()1381 wxPGChoiceEditor::~wxPGChoiceEditor()
1382 {
1383     // Reset the global pointer. Useful when wxPropertyGrid is accessed
1384     // from an external main loop.
1385     wxPG_EDITOR(Choice) = NULL;
1386 }
1387 
1388 // -----------------------------------------------------------------------
1389 // wxPGComboBoxEditor
1390 // -----------------------------------------------------------------------
1391 
1392 
WX_PG_IMPLEMENT_EDITOR_CLASS(ComboBox,wxPGComboBoxEditor,wxPGChoiceEditor)1393 WX_PG_IMPLEMENT_EDITOR_CLASS(ComboBox,wxPGComboBoxEditor,wxPGChoiceEditor)
1394 
1395 
1396 void wxPGComboBoxEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
1397 {
1398     wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1399     cb->SetValue(property->GetValueString(wxPG_EDITABLE_VALUE));
1400 
1401     // TODO: If string matches any selection, then select that.
1402 }
1403 
1404 
CreateControls(wxPropertyGrid * propGrid,wxPGProperty * property,const wxPoint & pos,const wxSize & sz) const1405 wxPGWindowList wxPGComboBoxEditor::CreateControls( wxPropertyGrid* propGrid,
1406                                                    wxPGProperty* property,
1407                                                    const wxPoint& pos,
1408                                                    const wxSize& sz ) const
1409 {
1410     return CreateControlsBase(propGrid,property,pos,sz,0);
1411 }
1412 
1413 
OnEvent(wxPropertyGrid * propGrid,wxPGProperty * property,wxWindow * ctrl,wxEvent & event) const1414 bool wxPGComboBoxEditor::OnEvent( wxPropertyGrid* propGrid,
1415                                   wxPGProperty* property,
1416                                   wxWindow* ctrl,
1417                                   wxEvent& event ) const
1418 {
1419     wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*) NULL;
1420     wxWindow* textCtrl = (wxWindow*) NULL;
1421 
1422     if ( ctrl )
1423     {
1424         cb = (wxPGOwnerDrawnComboBox*)ctrl;
1425         textCtrl = cb->GetTextCtrl();
1426     }
1427 
1428     if ( wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid,property,textCtrl,event) )
1429         return true;
1430 
1431     return wxPGChoiceEditor::OnEvent(propGrid,property,ctrl,event);
1432 }
1433 
1434 
GetValueFromControl(wxVariant & variant,wxPGProperty * property,wxWindow * ctrl) const1435 bool wxPGComboBoxEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
1436 {
1437     wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1438     wxString textVal = cb->GetValue();
1439 
1440     if ( property->UsesAutoUnspecified() && !textVal.length() )
1441     {
1442         variant.MakeNull();
1443         return true;
1444     }
1445 
1446     bool res = property->ActualStringToValue(variant, textVal, wxPG_EDITABLE_VALUE);
1447 
1448     // Changing unspecified always causes event (returning
1449     // true here should be enough to trigger it).
1450     if ( !res && variant.IsNull() )
1451         res = true;
1452 
1453     return res;
1454 }
1455 
OnFocus(wxPGProperty * property,wxWindow * ctrl) const1456 void wxPGComboBoxEditor::OnFocus( wxPGProperty* property,
1457                                   wxWindow* ctrl ) const
1458 {
1459     wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1460     wxPGTextCtrlEditor_OnFocus(property, cb->GetTextCtrl());
1461 }
1462 
~wxPGComboBoxEditor()1463 wxPGComboBoxEditor::~wxPGComboBoxEditor()
1464 {
1465     // Reset the global pointer. Useful when wxPropertyGrid is accessed
1466     // from an external main loop.
1467     wxPG_EDITOR(ComboBox) = NULL;
1468 }
1469 
1470 // -----------------------------------------------------------------------
1471 // wxPGChoiceAndButtonEditor
1472 // -----------------------------------------------------------------------
1473 
1474 
1475 // This simpler implement_editor macro doesn't define class body.
WX_PG_IMPLEMENT_EDITOR_CLASS(ChoiceAndButton,wxPGChoiceAndButtonEditor,wxPGChoiceEditor)1476 WX_PG_IMPLEMENT_EDITOR_CLASS(ChoiceAndButton,wxPGChoiceAndButtonEditor,wxPGChoiceEditor)
1477 
1478 
1479 wxPGWindowList wxPGChoiceAndButtonEditor::CreateControls( wxPropertyGrid* propGrid,
1480                                                           wxPGProperty* property,
1481                                                           const wxPoint& pos,
1482                                                           const wxSize& sz ) const
1483 {
1484     // Use one two units smaller to match size of the combo's dropbutton.
1485     // (normally a bigger button is used because it looks better)
1486     int bt_wid = sz.y;
1487     bt_wid -= 2;
1488     wxSize bt_sz(bt_wid,bt_wid);
1489 
1490     // Position of button.
1491     wxPoint bt_pos(pos.x+sz.x-bt_sz.x,pos.y);
1492 #ifdef __WXMAC__
1493     bt_pos.y -= 1;
1494 #else
1495     bt_pos.y += 1;
1496 #endif
1497 
1498     wxWindow* bt = propGrid->GenerateEditorButton( bt_pos, bt_sz );
1499 
1500     // Size of choice.
1501     wxSize ch_sz(sz.x-bt->GetSize().x,sz.y);
1502 
1503 #ifdef __WXMAC__
1504     ch_sz.x -= wxPG_TEXTCTRL_AND_BUTTON_SPACING;
1505 #endif
1506 
1507     wxWindow* ch = wxPG_EDITOR(Choice)->CreateControls(propGrid,property,
1508         pos,ch_sz).m_primary;
1509 
1510 #ifdef __WXMSW__
1511     bt->Show();
1512 #endif
1513 
1514     return wxPGWindowList(ch, bt);
1515 }
1516 
~wxPGChoiceAndButtonEditor()1517 wxPGChoiceAndButtonEditor::~wxPGChoiceAndButtonEditor()
1518 {
1519     // Reset the global pointer. Useful when wxPropertyGrid is accessed
1520     // from an external main loop.
1521     wxPG_EDITOR(ChoiceAndButton) = NULL;
1522 }
1523 
1524 // -----------------------------------------------------------------------
1525 // wxPGTextCtrlAndButtonEditor
1526 // -----------------------------------------------------------------------
1527 
1528 
1529 // This simpler implement_editor macro doesn't define class body.
WX_PG_IMPLEMENT_EDITOR_CLASS(TextCtrlAndButton,wxPGTextCtrlAndButtonEditor,wxPGTextCtrlEditor)1530 WX_PG_IMPLEMENT_EDITOR_CLASS(TextCtrlAndButton,wxPGTextCtrlAndButtonEditor,wxPGTextCtrlEditor)
1531 
1532 
1533 wxPGWindowList wxPGTextCtrlAndButtonEditor::CreateControls( wxPropertyGrid* propGrid,
1534                                                             wxPGProperty* property,
1535                                                             const wxPoint& pos,
1536                                                             const wxSize& sz ) const
1537 {
1538     wxWindow* wnd2;
1539     wxWindow* wnd = propGrid->GenerateEditorTextCtrlAndButton( pos, sz, &wnd2,
1540         property->GetFlags() & wxPG_PROP_NOEDITOR, property);
1541 
1542     return wxPGWindowList(wnd, wnd2);
1543 }
1544 
~wxPGTextCtrlAndButtonEditor()1545 wxPGTextCtrlAndButtonEditor::~wxPGTextCtrlAndButtonEditor()
1546 {
1547     // Reset the global pointer. Useful when wxPropertyGrid is accessed
1548     // from an external main loop.
1549     wxPG_EDITOR(TextCtrlAndButton) = NULL;
1550 }
1551 
1552 // -----------------------------------------------------------------------
1553 // wxPGCheckBoxEditor
1554 // -----------------------------------------------------------------------
1555 
1556 #if wxPG_INCLUDE_CHECKBOX
1557 
1558 WX_PG_IMPLEMENT_EDITOR_CLASS(CheckBox,wxPGCheckBoxEditor,wxPGEditor)
1559 
1560 
1561 // Check box state flags
1562 enum
1563 {
1564     wxSCB_STATE_UNCHECKED   = 0,
1565     wxSCB_STATE_CHECKED     = 1,
1566     wxSCB_STATE_BOLD        = 2,
1567     wxSCB_STATE_UNSPECIFIED = 4
1568 };
1569 
1570 const int wxSCB_SETVALUE_CYCLE = 2;
1571 
1572 
DrawSimpleCheckBox(wxDC & dc,const wxRect & rect,int box_hei,int state)1573 static void DrawSimpleCheckBox( wxDC& dc, const wxRect& rect, int box_hei,
1574                                 int state )
1575 {
1576     // Box rectangle.
1577     wxRect r(rect.x+wxPG_XBEFORETEXT,rect.y+((rect.height-box_hei)/2),
1578              box_hei,box_hei);
1579     wxColour useCol = dc.GetTextForeground();
1580 
1581     // Draw check mark first because it is likely to overdraw the
1582     // surrounding rectangle.
1583     if ( state & wxSCB_STATE_CHECKED )
1584     {
1585         wxRect r2(r.x+wxPG_CHECKMARK_XADJ,
1586                   r.y+wxPG_CHECKMARK_YADJ,
1587                   r.width+wxPG_CHECKMARK_WADJ,
1588                   r.height+wxPG_CHECKMARK_HADJ);
1589     #if wxPG_CHECKMARK_DEFLATE
1590         r2.Deflate(wxPG_CHECKMARK_DEFLATE);
1591     #endif
1592         dc.DrawCheckMark(r2);
1593 
1594         // This would draw a simple cross check mark.
1595         // dc.DrawLine(r.x,r.y,r.x+r.width-1,r.y+r.height-1);
1596         // dc.DrawLine(r.x,r.y+r.height-1,r.x+r.width-1,r.y);
1597 
1598     }
1599 
1600     if ( !(state & wxSCB_STATE_BOLD) )
1601     {
1602         // Pen for thin rectangle.
1603         dc.SetPen(useCol);
1604     }
1605     else
1606     {
1607         // Pen for bold rectangle.
1608         wxPen linepen(useCol,2,wxSOLID);
1609         linepen.SetJoin(wxJOIN_MITER); // This prevents round edges.
1610         dc.SetPen(linepen);
1611         r.x++;
1612         r.y++;
1613         r.width--;
1614         r.height--;
1615     }
1616 
1617     dc.SetBrush(*wxTRANSPARENT_BRUSH);
1618 
1619     dc.DrawRectangle(r);
1620     dc.SetPen(*wxTRANSPARENT_PEN);
1621 }
1622 
1623 //
1624 // Real simple custom-drawn checkbox-without-label class.
1625 //
1626 class wxSimpleCheckBox : public wxControl
1627 {
1628 public:
1629 
1630     void SetValue( int value );
1631 
wxSimpleCheckBox(wxWindow * parent,wxWindowID id,const wxPoint & pos=wxDefaultPosition,const wxSize & size=wxDefaultSize)1632     wxSimpleCheckBox( wxWindow* parent,
1633                       wxWindowID id,
1634                       const wxPoint& pos = wxDefaultPosition,
1635                       const wxSize& size = wxDefaultSize )
1636         : wxControl(parent,id,pos,size,wxNO_BORDER|wxWANTS_CHARS)
1637     {
1638         // Due to SetOwnFont stuff necessary for GTK+ 1.2, we need to have this
1639         SetFont( parent->GetFont() );
1640 
1641         m_state = wxSCB_STATE_UNCHECKED;
1642         wxPropertyGrid* pg = (wxPropertyGrid*) parent->GetParent();
1643         wxASSERT( pg->IsKindOf(CLASSINFO(wxPropertyGrid)) );
1644         m_boxHeight = pg->GetFontHeight();
1645         SetBackgroundStyle( wxBG_STYLE_COLOUR );
1646     }
1647 
1648     ~wxSimpleCheckBox() override;
1649 
1650     bool ProcessEvent(wxEvent& event) override;
1651 
1652     int m_state;
1653     int m_boxHeight;
1654 
1655     static wxBitmap* ms_doubleBuffer;
1656 
1657 };
1658 
~wxSimpleCheckBox()1659 wxSimpleCheckBox::~wxSimpleCheckBox()
1660 {
1661     delete ms_doubleBuffer;
1662     ms_doubleBuffer = NULL;
1663 }
1664 
1665 
1666 wxBitmap* wxSimpleCheckBox::ms_doubleBuffer = (wxBitmap*) NULL;
1667 
SetValue(int value)1668 void wxSimpleCheckBox::SetValue( int value )
1669 {
1670     if ( value == wxSCB_SETVALUE_CYCLE )
1671     {
1672         if ( m_state & wxSCB_STATE_CHECKED )
1673             m_state &= ~wxSCB_STATE_CHECKED;
1674         else
1675             m_state |= wxSCB_STATE_CHECKED;
1676     }
1677     else
1678     {
1679         m_state = value;
1680     }
1681     Refresh();
1682 
1683     wxCommandEvent evt(wxEVT_COMMAND_CHECKBOX_CLICKED,GetParent()->GetId());
1684 
1685     wxPropertyGrid* propGrid = (wxPropertyGrid*) GetParent()->GetParent();
1686     wxASSERT( propGrid->IsKindOf(CLASSINFO(wxPropertyGrid)) );
1687     propGrid->OnCustomEditorEvent(evt);
1688 }
1689 
1690 
ProcessEvent(wxEvent & event)1691 bool wxSimpleCheckBox::ProcessEvent(wxEvent& event)
1692 {
1693     wxPropertyGrid* propGrid = (wxPropertyGrid*) GetParent()->GetParent();
1694     wxASSERT( propGrid->IsKindOf(CLASSINFO(wxPropertyGrid)) );
1695 
1696     if ( event.GetEventType() == wxEVT_NAVIGATION_KEY )
1697     {
1698         //wxLogDebug(wxT("wxEVT_NAVIGATION_KEY"));
1699         //SetFocusFromKbd();
1700         //event.Skip();
1701         //return wxControl::ProcessEvent(event);
1702     }
1703     else
1704     if ( ( (event.GetEventType() == wxEVT_LEFT_DOWN || event.GetEventType() == wxEVT_LEFT_DCLICK)
1705           && ((wxMouseEvent&)event).m_x > (wxPG_XBEFORETEXT-2)
1706           && ((wxMouseEvent&)event).m_x <= (wxPG_XBEFORETEXT-2+m_boxHeight) )
1707        )
1708     {
1709         SetValue(wxSCB_SETVALUE_CYCLE);
1710         return true;
1711     }
1712     else if ( event.GetEventType() == wxEVT_PAINT )
1713     {
1714         wxSize clientSize = GetClientSize();
1715         wxPaintDC dc(this);
1716 
1717         /*
1718         // Buffered paint DC doesn't seem to do much good
1719         if ( !ms_doubleBuffer ||
1720              clientSize.x > ms_doubleBuffer->GetWidth() ||
1721              clientSize.y > ms_doubleBuffer->GetHeight() )
1722         {
1723             delete ms_doubleBuffer;
1724             ms_doubleBuffer = new wxBitmap(clientSize.x+25,clientSize.y+25);
1725         }
1726 
1727         wxBufferedPaintDC dc(this,*ms_doubleBuffer);
1728         */
1729 
1730         wxRect rect(0,0,clientSize.x,clientSize.y);
1731         //rect.x -= 1;
1732         rect.y += 1;
1733         rect.width += 1;
1734 
1735         m_boxHeight = propGrid->GetFontHeight();
1736 
1737         wxColour bgcol = GetBackgroundColour();
1738         dc.SetBrush( bgcol );
1739         dc.SetPen( bgcol );
1740         dc.DrawRectangle( rect );
1741 
1742         dc.SetTextForeground(GetForegroundColour());
1743 
1744         int state = m_state;
1745         if ( !(state & wxSCB_STATE_UNSPECIFIED) &&
1746              GetFont().GetWeight() == wxBOLD )
1747             state |= wxSCB_STATE_BOLD;
1748 
1749         DrawSimpleCheckBox(dc, rect, m_boxHeight, state);
1750 
1751         return true;
1752     }
1753     else if ( event.GetEventType() == wxEVT_SIZE ||
1754               event.GetEventType() == wxEVT_SET_FOCUS ||
1755               event.GetEventType() == wxEVT_KILL_FOCUS
1756             )
1757     {
1758         Refresh();
1759     }
1760     else if ( event.GetEventType() == wxEVT_KEY_DOWN )
1761     {
1762         wxKeyEvent& keyEv = (wxKeyEvent&) event;
1763 
1764         if ( keyEv.GetKeyCode() == WXK_TAB )
1765         {
1766             propGrid->SendNavigationKeyEvent( keyEv.ShiftDown()?0:1 );
1767             return true;
1768         }
1769         else
1770         if ( keyEv.GetKeyCode() == WXK_SPACE )
1771         {
1772             SetValue(wxSCB_SETVALUE_CYCLE);
1773             return true;
1774         }
1775     }
1776     return wxControl::ProcessEvent(event);
1777 }
1778 
1779 
CreateControls(wxPropertyGrid * propGrid,wxPGProperty * property,const wxPoint & pos,const wxSize & size) const1780 wxPGWindowList wxPGCheckBoxEditor::CreateControls( wxPropertyGrid* propGrid,
1781                                                    wxPGProperty* property,
1782                                                    const wxPoint& pos,
1783                                                    const wxSize& size ) const
1784 {
1785     if ( property->HasFlag(wxPG_PROP_READONLY) )
1786         return NULL;
1787 
1788     wxPoint pt = pos;
1789     pt.x -= wxPG_XBEFOREWIDGET;
1790     wxSize sz = size;
1791     sz.x = propGrid->GetFontHeight() + (wxPG_XBEFOREWIDGET*2) + 4;
1792 
1793     wxSimpleCheckBox* cb = new wxSimpleCheckBox(propGrid->GetPanel(),wxPG_SUBID1,pt,sz);
1794 
1795     cb->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
1796 
1797     cb->Connect( wxPG_SUBID1, wxEVT_LEFT_DOWN,
1798             (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
1799             &wxPropertyGrid::OnCustomEditorEvent, NULL, propGrid );
1800 
1801     cb->Connect( wxPG_SUBID1, wxEVT_LEFT_DCLICK,
1802             (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
1803             &wxPropertyGrid::OnCustomEditorEvent, NULL, propGrid );
1804 
1805     if ( property->IsValueUnspecified() )
1806     {
1807         cb->m_state = wxSCB_STATE_UNSPECIFIED;
1808     }
1809     else
1810     {
1811         if ( property->GetChoiceInfo((wxPGChoiceInfo*)NULL) )
1812             cb->m_state = wxSCB_STATE_CHECKED;
1813 
1814         // If mouse cursor was on the item, toggle the value now.
1815         if ( propGrid->GetInternalFlags() & wxPG_FL_ACTIVATION_BY_CLICK )
1816         {
1817             // C::B patch: Fix shadowed variable warning
1818             pt = cb->ScreenToClient(::wxGetMousePosition());
1819             if ( pt.x <= (wxPG_XBEFORETEXT-2+cb->m_boxHeight) )
1820             {
1821                 if ( cb->m_state & wxSCB_STATE_CHECKED )
1822                     cb->m_state &= ~wxSCB_STATE_CHECKED;
1823                 else
1824                     cb->m_state |= wxSCB_STATE_CHECKED;
1825 
1826                 // Makes sure wxPG_EVT_CHANGING etc. is sent for this initial
1827                 // click
1828                 propGrid->ChangePropertyValue(property,
1829                                               wxPGVariant_Bool(cb->m_state));
1830             }
1831         }
1832     }
1833 
1834     propGrid->SetInternalFlag( wxPG_FL_FIXED_WIDTH_EDITOR );
1835 
1836     return cb;
1837 }
1838 
DrawValue(wxDC & dc,const wxRect & rect,wxPGProperty * property,const wxString & WXUNUSED (text)) const1839 void wxPGCheckBoxEditor::DrawValue( wxDC& dc, const wxRect& rect,
1840                                     wxPGProperty* property,
1841                                     const wxString& WXUNUSED(text) ) const
1842 {
1843     int state = wxSCB_STATE_UNCHECKED;
1844 
1845     if ( !property->IsValueUnspecified() )
1846     {
1847         state = property->GetChoiceInfo((wxPGChoiceInfo*)NULL);
1848         if ( dc.GetFont().GetWeight() == wxBOLD )
1849             state |= wxSCB_STATE_BOLD;
1850     }
1851     else
1852     {
1853         state |= wxSCB_STATE_UNSPECIFIED;
1854     }
1855 
1856     DrawSimpleCheckBox(dc, rect, dc.GetCharHeight(), state);
1857 }
1858 
UpdateControl(wxPGProperty * property,wxWindow * ctrl) const1859 void wxPGCheckBoxEditor::UpdateControl( wxPGProperty* property,
1860                                         wxWindow* ctrl ) const
1861 {
1862     wxSimpleCheckBox* cb = (wxSimpleCheckBox*) ctrl;
1863     wxASSERT( cb );
1864 
1865     if ( !property->IsValueUnspecified() )
1866         cb->m_state = property->GetChoiceInfo((wxPGChoiceInfo*)NULL);
1867     else
1868         cb->m_state = wxSCB_STATE_UNSPECIFIED;
1869 
1870     cb->Refresh();
1871 }
1872 
OnEvent(wxPropertyGrid * WXUNUSED (propGrid),wxPGProperty * WXUNUSED (property),wxWindow * WXUNUSED (ctrl),wxEvent & event) const1873 bool wxPGCheckBoxEditor::OnEvent( wxPropertyGrid* WXUNUSED(propGrid), wxPGProperty* WXUNUSED(property),
1874     wxWindow* WXUNUSED(ctrl), wxEvent& event ) const
1875 {
1876     if ( event.GetEventType() == wxEVT_COMMAND_CHECKBOX_CLICKED )
1877     {
1878         return true;
1879     }
1880     return false;
1881 }
1882 
1883 
GetValueFromControl(wxVariant & variant,wxPGProperty * property,wxWindow * ctrl) const1884 bool wxPGCheckBoxEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
1885 {
1886     wxSimpleCheckBox* cb = (wxSimpleCheckBox*)ctrl;
1887 
1888     int index = cb->m_state;
1889 
1890     if ( index != property->GetChoiceInfo( (wxPGChoiceInfo*) NULL ) ||
1891          // Changing unspecified always causes event (returning
1892          // true here should be enough to trigger it).
1893          property->IsValueUnspecified()
1894        )
1895     {
1896         return property->ActualIntToValue(variant, index, 0);
1897     }
1898     return false;
1899 }
1900 
1901 
SetControlIntValue(wxPGProperty * WXUNUSED (property),wxWindow * ctrl,int value) const1902 void wxPGCheckBoxEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow* ctrl, int value ) const
1903 {
1904     if ( value != 0 ) value = 1;
1905     ((wxSimpleCheckBox*)ctrl)->m_state = value;
1906     ctrl->Refresh();
1907 }
1908 
1909 
SetValueToUnspecified(wxPGProperty * WXUNUSED (property),wxWindow * ctrl) const1910 void wxPGCheckBoxEditor::SetValueToUnspecified( wxPGProperty* WXUNUSED(property), wxWindow* ctrl ) const
1911 {
1912     ((wxSimpleCheckBox*)ctrl)->m_state = wxSCB_STATE_UNSPECIFIED;
1913     ctrl->Refresh();
1914 }
1915 
~wxPGCheckBoxEditor()1916 wxPGCheckBoxEditor::~wxPGCheckBoxEditor()
1917 {
1918     // Reset the global pointer. Useful when wxPropertyGrid is accessed
1919     // from an external main loop.
1920     wxPG_EDITOR(CheckBox) = NULL;
1921 }
1922 
1923 #endif // wxPG_INCLUDE_CHECKBOX
1924 
1925 // -----------------------------------------------------------------------
1926 
GetEditorControl() const1927 wxWindow* wxPropertyGrid::GetEditorControl() const
1928 {
1929     wxWindow* ctrl = m_wndEditor;
1930 
1931     if ( !ctrl )
1932         return ctrl;
1933 
1934     // If it's clipper window, return its child instead
1935 #if wxPG_ENABLE_CLIPPER_WINDOW
1936     if ( ctrl->IsKindOf(CLASSINFO(wxPGClipperWindow)) )
1937     {
1938         return ((wxPGClipperWindow*)ctrl)->GetControl();
1939     }
1940 #endif
1941 
1942     return ctrl;
1943 }
1944 
1945 // -----------------------------------------------------------------------
1946 
GetLabelEditor() const1947 wxTextCtrl* wxPropertyGrid::GetLabelEditor() const
1948 {
1949     wxWindow* tcWnd = m_labelEditor;
1950 
1951     if ( !tcWnd )
1952         return NULL;
1953 
1954 #if wxPG_ENABLE_CLIPPER_WINDOW
1955     if ( tcWnd->IsKindOf(CLASSINFO(wxPGClipperWindow)) )
1956     {
1957         tcWnd = ((wxPGClipperWindow*)tcWnd)->GetControl();
1958     }
1959 #endif
1960 
1961     return wxStaticCast(tcWnd, wxTextCtrl);
1962 }
1963 
1964 // -----------------------------------------------------------------------
1965 
CorrectEditorWidgetSizeX()1966 void wxPropertyGrid::CorrectEditorWidgetSizeX()
1967 {
1968     int secWid = 0;
1969 
1970     // Use fixed selColumn 1 for main editor widgets
1971     int newSplitterx = m_pState->DoGetSplitterPosition(0);
1972     int newWidth = newSplitterx + m_pState->m_colWidths[1];
1973 
1974     if ( m_wndEditor2 )
1975     {
1976         // if width change occurred, move secondary wnd by that amount
1977         wxRect r = m_wndEditor2->GetRect();
1978         secWid = r.width;
1979         r.x = newWidth - secWid;
1980 
1981         m_wndEditor2->SetSize( r );
1982 
1983         // if primary is textctrl, then we have to add some extra space
1984 #ifdef __WXMAC__
1985         if ( m_wndEditor )
1986 #else
1987         if ( m_wndEditor && m_wndEditor->IsKindOf(CLASSINFO(wxTextCtrl)) )
1988 #endif
1989             secWid += wxPG_TEXTCTRL_AND_BUTTON_SPACING;
1990     }
1991 
1992     if ( m_wndEditor )
1993     {
1994         wxRect r = m_wndEditor->GetRect();
1995 
1996         r.x = newSplitterx+m_ctrlXAdjust;
1997 
1998         if ( !(m_iFlags & wxPG_FL_FIXED_WIDTH_EDITOR) )
1999             r.width = newWidth - r.x - secWid;
2000 
2001         m_wndEditor->SetSize(r);
2002     }
2003 
2004     if ( m_wndEditor2 )
2005         m_wndEditor2->Refresh();
2006 }
2007 
2008 // -----------------------------------------------------------------------
2009 
CorrectEditorWidgetPosY()2010 void wxPropertyGrid::CorrectEditorWidgetPosY()
2011 {
2012     wxPGProperty* selected = GetSelection();
2013 
2014     if ( selected )
2015     {
2016         if ( m_labelEditor )
2017         {
2018             wxRect r = GetEditorWidgetRect(selected, m_selColumn);
2019             wxPoint pos = m_labelEditor->GetPosition();
2020 
2021             // Calculate y offset
2022             int offset = pos.y % m_lineHeight;
2023 
2024             m_labelEditor->Move(pos.x, r.y + offset);
2025         }
2026 
2027         if ( m_wndEditor || m_wndEditor2 )
2028         {
2029             wxRect r = GetEditorWidgetRect(selected, 1);
2030 
2031             if ( m_wndEditor )
2032             {
2033                 wxPoint pos = m_wndEditor->GetPosition();
2034 
2035                 // Calculate y offset
2036                 int offset = pos.y % m_lineHeight;
2037 
2038                 m_wndEditor->Move(pos.x, r.y + offset);
2039             }
2040 
2041             if ( m_wndEditor2 )
2042             {
2043                 wxPoint pos = m_wndEditor2->GetPosition();
2044 
2045                 m_wndEditor2->Move(pos.x, r.y);
2046             }
2047         }
2048     }
2049 }
2050 
2051 // -----------------------------------------------------------------------
2052 
AdjustPosForClipperWindow(wxWindow * topCtrlWnd,int * x,int * y)2053 bool wxPropertyGrid::AdjustPosForClipperWindow( wxWindow* topCtrlWnd, int* x, int* y )
2054 {
2055 #if wxPG_ENABLE_CLIPPER_WINDOW
2056     // Take clipper window into account
2057     if (topCtrlWnd->GetPosition().x < 1 &&
2058         !topCtrlWnd->IsKindOf(CLASSINFO(wxPGClipperWindow)))
2059     {
2060         topCtrlWnd = topCtrlWnd->GetParent();
2061         wxASSERT( topCtrlWnd->IsKindOf(CLASSINFO(wxPGClipperWindow)) );
2062         *x -= ((wxPGClipperWindow*)topCtrlWnd)->GetXClip();
2063         *y -= ((wxPGClipperWindow*)topCtrlWnd)->GetYClip();
2064         return true;
2065     }
2066 #else
2067     wxUnusedVar(topCtrlWnd);
2068     wxUnusedVar(x);
2069     wxUnusedVar(y);
2070 #endif
2071     return false;
2072 }
2073 
2074 // -----------------------------------------------------------------------
2075 
2076 // Fixes position of wxTextCtrl-like control (wxSpinCtrl usually
2077 // fits into that category as well).
FixPosForTextCtrl(wxWindow * ctrl,unsigned int forColumn,const wxPoint & offset)2078 void wxPropertyGrid::FixPosForTextCtrl( wxWindow* ctrl,
2079                                         unsigned int forColumn,
2080                                         const wxPoint& offset )
2081 {
2082     // Center the control vertically
2083     wxRect finalPos = ctrl->GetRect();
2084     int y_adj = (m_lineHeight - finalPos.height)/2 + wxPG_TEXTCTRLYADJUST;
2085 
2086     // Prevent over-sized control
2087     int sz_dec = (y_adj + finalPos.height) - m_lineHeight;
2088     if ( sz_dec < 0 ) sz_dec = 0;
2089 
2090     finalPos.y += y_adj;
2091     finalPos.height -= (y_adj+sz_dec);
2092 
2093     int textCtrlXAdjust = wxPG_TEXTCTRLXADJUST;
2094 
2095     if ( forColumn != 1 )
2096         textCtrlXAdjust -= 3;  // magic number!
2097 
2098     finalPos.x += textCtrlXAdjust;
2099     finalPos.width -= textCtrlXAdjust;
2100 
2101     finalPos.x += offset.x;
2102     finalPos.y += offset.y;
2103 
2104     ctrl->SetSize(finalPos);
2105 }
2106 
2107 // -----------------------------------------------------------------------
2108 
GenerateEditorTextCtrl(const wxPoint & pos,const wxSize & sz,const wxString & value,wxWindow * secondary,int extraStyle,int maxLen,unsigned int forColumn)2109 wxWindow* wxPropertyGrid::GenerateEditorTextCtrl( const wxPoint& pos,
2110                                                   const wxSize& sz,
2111                                                   const wxString& value,
2112                                                   wxWindow* secondary,
2113                                                   int extraStyle,
2114                                                   int maxLen,
2115                                                   unsigned int forColumn )
2116 {
2117     wxPGProperty* selected = GetSelection();
2118     wxASSERT(selected);
2119 
2120     int tcFlags = wxTE_PROCESS_ENTER | extraStyle;
2121 
2122     if ( selected->HasFlag(wxPG_PROP_READONLY) && forColumn == 1 )
2123         tcFlags |= wxTE_READONLY;
2124 
2125     wxPoint p(pos.x,pos.y);
2126     wxSize s(sz.x,sz.y);
2127 
2128    // Need to reduce width of text control on Mac
2129 #if defined(__WXMAC__)
2130    s.x -= 8;
2131 #endif
2132 
2133     // For label editors, trim the size to allow better splitter grabbing
2134     if ( forColumn != 1 )
2135         s.x -= 2;
2136 
2137      // Take button into acccount
2138     if ( secondary )
2139     {
2140         s.x -= (secondary->GetSize().x + wxPG_TEXTCTRL_AND_BUTTON_SPACING);
2141         m_iFlags &= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE);
2142     }
2143 
2144     // If the height is significantly higher, then use border, and fill the rect exactly.
2145     bool hasSpecialSize = false;
2146 
2147     if ( (sz.y - m_lineHeight) > 5 )
2148         hasSpecialSize = true;
2149 
2150 #if wxPG_NAT_TEXTCTRL_BORDER_ANY
2151 
2152     // Create clipper window
2153     wxPGClipperWindow* wnd = new wxPGClipperWindow();
2154 #if defined(__WXMSW__)
2155     wnd->Hide();
2156 #endif
2157     wnd->Create(GetPanel(),wxPG_SUBID1,p,s);
2158 
2159     // This generates rect of the control inside the clipper window
2160     if ( !hasSpecialSize )
2161         wnd->GetControlRect(wxPG_NAT_TEXTCTRL_BORDER_X, wxPG_NAT_TEXTCTRL_BORDER_Y, p, s);
2162     else
2163         wnd->GetControlRect(0, 0, p, s);
2164 
2165     wxWindow* ctrlParent = wnd;
2166 
2167 #else
2168 
2169     wxWindow* ctrlParent = GetPanel();
2170 
2171     if ( !hasSpecialSize )
2172         tcFlags |= wxNO_BORDER;
2173 
2174 #endif
2175 
2176     wxTextCtrl* tc = new wxTextCtrl();
2177 
2178 #if defined(__WXMSW__) && !wxPG_NAT_TEXTCTRL_BORDER_ANY
2179     tc->Hide();
2180 #endif
2181     SetupTextCtrlValue(value);
2182     tc->Create(ctrlParent,wxPG_SUBID1,value, p, s,tcFlags);
2183 
2184 #if wxPG_NAT_TEXTCTRL_BORDER_ANY
2185     wxWindow* ed = wnd;
2186     wnd->SetControl(tc);
2187 #else
2188     wxWindow* ed = tc;
2189 #endif
2190 
2191     // Center the control vertically
2192     if ( !hasSpecialSize )
2193         FixPosForTextCtrl(ed, forColumn);
2194 
2195     if ( forColumn != 1 )
2196     {
2197         if ( tc != ed )
2198         {
2199             ed->SetBackgroundColour(m_colSelBack);
2200             ed->SetForegroundColour(m_colSelFore);
2201         }
2202         tc->SetBackgroundColour(m_colSelBack);
2203         tc->SetForegroundColour(m_colSelFore);
2204     }
2205 
2206 #ifdef __WXMSW__
2207     ed->Show();
2208     if ( secondary )
2209         secondary->Show();
2210 #endif
2211 
2212     // Set maximum length
2213     if ( maxLen > 0 )
2214         tc->SetMaxLength( maxLen );
2215 
2216     return (wxWindow*) ed;
2217 }
2218 
2219 // -----------------------------------------------------------------------
2220 
GenerateEditorButton(const wxPoint & pos,const wxSize & sz)2221 wxWindow* wxPropertyGrid::GenerateEditorButton( const wxPoint& pos, const wxSize& sz )
2222 {
2223     wxPGProperty* selected = GetSelection();
2224     wxASSERT(selected);
2225 
2226 #ifdef __WXMAC__
2227    // Decorations are chunky on Mac, and we can't make the button square, so
2228    // do things a bit differently on this platform.
2229 
2230    wxPoint p(pos.x+sz.x,
2231              pos.y+wxPG_BUTTON_SIZEDEC-wxPG_NAT_BUTTON_BORDER_Y);
2232    wxSize s(25, -1);
2233 
2234    wxButton* but = new wxButton();
2235    but->Create(GetPanel(),wxPG_SUBID2,wxT("..."),p,s,wxWANTS_CHARS);
2236 
2237    // Now that we know the size, move to the correct position
2238    p.x = pos.x + sz.x - but->GetSize().x - 2;
2239    but->Move(p);
2240 
2241 #else
2242     wxSize s(sz.y-(wxPG_BUTTON_SIZEDEC*2)+(wxPG_NAT_BUTTON_BORDER_Y*2),
2243         sz.y-(wxPG_BUTTON_SIZEDEC*2)+(wxPG_NAT_BUTTON_BORDER_Y*2));
2244 
2245     // Reduce button width to lineheight
2246     if ( s.x > m_lineHeight )
2247         s.x = m_lineHeight;
2248 
2249 #ifdef __WXGTK__
2250     // On wxGTK, take fixed button margins into account
2251     if ( s.x < 25 )
2252         s.x = 25;
2253 #endif
2254 
2255     wxPoint p(pos.x+sz.x-s.x,
2256         pos.y+wxPG_BUTTON_SIZEDEC-wxPG_NAT_BUTTON_BORDER_Y);
2257 
2258     wxButton* but = new wxButton();
2259   #ifdef __WXMSW__
2260     but->Hide();
2261   #endif
2262     but->Create(GetPanel(),wxPG_SUBID2,wxT("..."),p,s,wxWANTS_CHARS);
2263 
2264   #ifdef __WXGTK__
2265     wxFont font = GetFont();
2266     font.SetPointSize(font.GetPointSize()-2);
2267     but->SetFont(font);
2268   #else
2269     but->SetFont(GetFont());
2270   #endif
2271 #endif
2272 
2273     if ( selected->HasFlag(wxPG_PROP_READONLY) )
2274         but->Disable();
2275 
2276     return but;
2277 }
2278 
2279 // -----------------------------------------------------------------------
2280 
GenerateEditorTextCtrlAndButton(const wxPoint & pos,const wxSize & sz,wxWindow ** psecondary,int limitedEditing,wxPGProperty * property)2281 wxWindow* wxPropertyGrid::GenerateEditorTextCtrlAndButton( const wxPoint& pos,
2282                                                            const wxSize& sz,
2283                                                            wxWindow** psecondary,
2284                                                            int limitedEditing,
2285                                                            wxPGProperty* property )
2286 {
2287     wxButton* but = (wxButton*)GenerateEditorButton(pos,sz);
2288     *psecondary = (wxWindow*)but;
2289 
2290     if ( limitedEditing )
2291     {
2292     #ifdef __WXMSW__
2293         // There is button Show in GenerateEditorTextCtrl as well
2294         but->Show();
2295     #endif
2296         return (wxWindow*) NULL;
2297     }
2298 
2299     wxString text;
2300 
2301     if ( !property->IsValueUnspecified() )
2302         text = property->GetValueString(property->HasFlag(wxPG_PROP_READONLY)?0:wxPG_EDITABLE_VALUE);
2303 
2304     return GenerateEditorTextCtrl(pos,sz,text,but,property->m_maxLen);
2305 }
2306 
2307 // -----------------------------------------------------------------------
2308 
SetEditorAppearance(const wxPGCell & cell)2309 void wxPropertyGrid::SetEditorAppearance( const wxPGCell& cell )
2310 {
2311     wxWindow* editor = GetEditorControl();
2312     if ( !editor )
2313         return;
2314 
2315     // Get old editor appearance
2316     const wxPGCell& oCell = m_editorAppearance;
2317     wxPGProperty* property = GetSelection();
2318 
2319     wxTextCtrl* tc = GetEditorTextCtrl();
2320 
2321     wxPGComboBox* cb;
2322     if ( editor->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)) )
2323         cb = (wxPGComboBox*) editor;
2324     else
2325         cb = NULL;
2326 
2327     if ( tc || cb )
2328     {
2329         wxString tcText;
2330         bool changeText = false;
2331 
2332         if ( cell.HasText() && !IsEditorFocused() )
2333         {
2334             tcText = cell.GetText();
2335             changeText = true;
2336         }
2337         else if ( oCell.HasText() )
2338         {
2339             tcText = GetSelection()->GetValueString(
2340                 property->HasFlag(wxPG_PROP_READONLY)?0:wxPG_EDITABLE_VALUE);
2341             changeText = true;
2342         }
2343 
2344         if ( changeText )
2345         {
2346             if ( tc )
2347             {
2348                 // The next line prevents spurious EVT_TEXT from being
2349                 // received.
2350                 SetupTextCtrlValue(tcText);
2351                 tc->SetValue(tcText);
2352             }
2353             else
2354             {
2355                 cb->SetText(tcText);
2356             }
2357         }
2358     }
2359 
2360     // We used to obtain wxVisualAttributes via
2361     // editor->GetDefaultAttributes() here, but that is not
2362     // very consistently implemented in wx2.8, so it is safer
2363     // to just use colours from wxSystemSettings etc.
2364 
2365     const wxColour& fgCol = cell.GetFgCol();
2366     if ( wxGDI_IS_OK(fgCol) )
2367     {
2368         editor->SetForegroundColour(fgCol);
2369 
2370         // Set for wxTextCtrl separately to work around bug in wx2.8
2371         // that may not be fixable due to ABI compatibility issues.
2372         if ( tc && tc != editor )
2373             tc->SetForegroundColour(fgCol);
2374     }
2375     else if ( wxGDI_IS_OK(oCell.GetFgCol()) )
2376     {
2377         wxColour vColFg =
2378             wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
2379         editor->SetForegroundColour(vColFg);
2380         if ( tc && tc != editor )
2381             tc->SetForegroundColour(vColFg);
2382     }
2383 
2384     const wxColour& bgCol = cell.GetBgCol();
2385     if ( wxGDI_IS_OK(bgCol) )
2386     {
2387         editor->SetBackgroundColour(bgCol);
2388         if ( tc && tc != editor )
2389             tc->SetBackgroundColour(bgCol);
2390     }
2391     else if ( wxGDI_IS_OK(oCell.GetBgCol()) )
2392     {
2393         wxColour vColBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
2394         editor->SetBackgroundColour(vColBg);
2395         if ( tc && tc != editor )
2396             tc->SetBackgroundColour(vColBg);
2397     }
2398 
2399     const wxFont& font = cell.GetFont();
2400     if ( wxGDI_IS_OK(font) )
2401     {
2402         editor->SetFont(font);
2403         if ( tc && tc != editor )
2404             tc->SetFont(font);
2405     }
2406     else if ( wxGDI_IS_OK(oCell.GetFont()) )
2407     {
2408         wxFont vFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
2409         editor->SetFont(vFont);
2410         if ( tc && tc != editor )
2411             tc->SetFont(vFont);
2412     }
2413 
2414     m_editorAppearance.Assign(cell);
2415 }
2416 
2417 // -----------------------------------------------------------------------
2418 
GetEditorTextCtrl() const2419 wxTextCtrl* wxPropertyGrid::GetEditorTextCtrl() const
2420 {
2421     wxWindow* wnd = GetEditorControl();
2422 
2423     if ( !wnd )
2424         return NULL;
2425 
2426     if ( wnd->IsKindOf(CLASSINFO(wxTextCtrl)) )
2427         return wxStaticCast(wnd, wxTextCtrl);
2428 
2429     if ( wnd->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)) )
2430     {
2431         wxPGOwnerDrawnComboBox* cb = wxStaticCast(wnd, wxPGOwnerDrawnComboBox);
2432         return cb->GetTextCtrl();
2433     }
2434 
2435     return NULL;
2436 }
2437 
2438 // -----------------------------------------------------------------------
2439 
2440 #if defined(__WXMSW__) && !defined(__WXWINCE__)
2441 
wxPG_TextCtrl_SetMargins(wxWindow * tc,const wxPoint & margins)2442 bool wxPG_TextCtrl_SetMargins(wxWindow* tc, const wxPoint& margins)
2443 {
2444     ::SendMessage(GetHwndOf(tc),
2445                   EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN,
2446                   MAKELONG(margins.x, margins.x));
2447     return true;
2448 }
2449 
2450 /*#elif defined(__WXGTK20__)
2451 
2452 //
2453 // NOTE: For this to work we need to somehow include gtk devel
2454 //       in the bake/makefile.
2455 //
2456 
2457 #include <gtk/gtk.h>
2458 
2459 bool wxPG_TextCtrl_SetMargins(wxWindow* tc, const wxPoint& margins)
2460 {
2461     //
2462     // NB: This code has been ported from wx2.9 SVN trunk
2463     //
2464 
2465   #if GTK_CHECK_VERSION(2,10,0)
2466     GtkEntry *entry = NULL;
2467 
2468     entry = GTK_ENTRY( m_widget );
2469 
2470     if ( !entry )
2471         return false;
2472 
2473     const GtkBorder* oldBorder = gtk_entry_get_inner_border(entry);
2474     GtkBorder* newBorder;
2475 
2476     if ( oldBorder )
2477     {
2478         newBorder = gtk_border_copy(oldBorder);
2479     }
2480     else
2481     {
2482     #if GTK_CHECK_VERSION(2,14,0)
2483         newBorder = gtk_border_new();
2484     #else
2485         newBorder = g_slice_new0(GtkBorder);
2486     #endif
2487         // Use some reasonable defaults for initial margins
2488         newBorder->left = 2;
2489         newBorder->right = 2;
2490 
2491         // These numbers seem to let the text remain vertically centered
2492         // in common use scenarios when margins.y == -1.
2493         newBorder->top = 3;
2494         newBorder->bottom = 3;
2495     }
2496 
2497     if ( margins.x != -1 )
2498         newBorder->left = (gint) margins.x;
2499 
2500     if ( margins.y != -1 )
2501         newBorder->top = (gint) margins.y;
2502 
2503     gtk_entry_set_inner_border(entry, newBorder);
2504 
2505   #if GTK_CHECK_VERSION(2,14,0)
2506     gtk_border_free(newBorder);
2507   #else
2508     g_slice_free(GtkBorder, newBorder);
2509   #endif
2510 
2511     return true;
2512   #else
2513     wxUnusedVar(tc);
2514     wxUnusedVar(margins);
2515     return false;
2516   #endif
2517 }
2518 */
2519 #else
2520 
wxPG_TextCtrl_SetMargins(wxWindow * tc,const wxPoint & margins)2521 bool wxPG_TextCtrl_SetMargins(wxWindow* tc, const wxPoint& margins)
2522 {
2523     wxUnusedVar(tc);
2524     wxUnusedVar(margins);
2525     return false;
2526 }
2527 
2528 #endif
2529 
2530 // -----------------------------------------------------------------------
2531 // wxPGEditorDialogAdapter
2532 // -----------------------------------------------------------------------
2533 
IMPLEMENT_ABSTRACT_CLASS(wxPGEditorDialogAdapter,wxObject)2534 IMPLEMENT_ABSTRACT_CLASS(wxPGEditorDialogAdapter, wxObject)
2535 
2536 bool wxPGEditorDialogAdapter::ShowDialog( wxPropertyGrid* propGrid, wxPGProperty* property )
2537 {
2538     if ( !propGrid->EditorValidate() )
2539         return false;
2540 
2541     bool res = DoShowDialog( propGrid, property );
2542 
2543     if ( res )
2544     {
2545         propGrid->ValueChangeInEvent( m_value );
2546         return true;
2547     }
2548 
2549     return false;
2550 }
2551 
2552 // -----------------------------------------------------------------------
2553 // wxPGMultiButton
2554 // -----------------------------------------------------------------------
2555 
wxPGMultiButton(wxPropertyGrid * pg,const wxSize & sz)2556 wxPGMultiButton::wxPGMultiButton( wxPropertyGrid* pg, const wxSize& sz )
2557     : wxWindow( pg->GetPanel(), wxPG_SUBID2, wxPoint(-100,-100), wxSize(0, sz.y) ),
2558       m_fullEditorSize(sz), m_buttonsWidth(0)
2559 {
2560     SetBackgroundColour(pg->GetCellBackgroundColour());
2561 }
2562 
GenId(int id) const2563 int wxPGMultiButton::GenId( int id ) const
2564 {
2565     if ( id < -1 )
2566     {
2567         if ( m_buttons.size() )
2568             id = GetButton(m_buttons.size()-1)->GetId() + 1;
2569         else
2570             id = wxPG_SUBID2;
2571     }
2572     return id;
2573 }
2574 
2575 #if wxUSE_BMPBUTTON
Add(const wxBitmap & bitmap,int id)2576 void wxPGMultiButton::Add( const wxBitmap& bitmap, int id )
2577 {
2578     id = GenId(id);
2579     wxSize sz = GetSize();
2580     wxButton* button = new wxBitmapButton( this, id, bitmap, wxPoint(sz.x, 0), wxSize(sz.y, sz.y) );
2581     m_buttons.push_back(button);
2582     int bw = button->GetSize().x;
2583     SetSize(wxSize(sz.x+bw,sz.y));
2584     m_buttonsWidth += bw;
2585 }
2586 #endif
2587 
Add(const wxString & label,int id)2588 void wxPGMultiButton::Add( const wxString& label, int id )
2589 {
2590     id = GenId(id);
2591     wxSize sz = GetSize();
2592     wxButton* button = new wxButton( this, id, label, wxPoint(sz.x, 0), wxSize(sz.y, sz.y) );
2593     m_buttons.push_back(button);
2594     int bw = button->GetSize().x;
2595     SetSize(wxSize(sz.x+bw,sz.y));
2596     m_buttonsWidth += bw;
2597 }
2598 
2599 // -----------------------------------------------------------------------
2600