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