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