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