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