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