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