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