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