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