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