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