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