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