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