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