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