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