X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b7bc9d806b57f20e1d3135025ba0e6f603e7450e..65702d2fe95b8ca16a9b74f53832780bf1c81970:/src/propgrid/advprops.cpp diff --git a/src/propgrid/advprops.cpp b/src/propgrid/advprops.cpp index 819014523d..bab9d937e4 100644 --- a/src/propgrid/advprops.cpp +++ b/src/propgrid/advprops.cpp @@ -62,6 +62,8 @@ #include "wx/msw/dc.h" #endif +#include "wx/odcombo.h" + // ----------------------------------------------------------------------- #if defined(__WXMSW__) @@ -108,6 +110,131 @@ bool operator == (const wxArrayInt& array1, const wxArrayInt& array2) #if wxUSE_SPINBTN +#ifdef __WXMSW__ + #define IS_MOTION_SPIN_SUPPORTED 1 +#else + #define IS_MOTION_SPIN_SUPPORTED 0 +#endif + +#if IS_MOTION_SPIN_SUPPORTED + +// +// This class implements ability to rapidly change "spin" value +// by moving mouse when one of the spin buttons is depressed. +class wxPGSpinButton : public wxSpinButton +{ +public: + wxPGSpinButton() : wxSpinButton() + { + m_bLeftDown = false; + m_hasCapture = false; + m_spins = 1; + + Connect( wxEVT_LEFT_DOWN, + wxMouseEventHandler(wxPGSpinButton::OnMouseEvent) ); + Connect( wxEVT_LEFT_UP, + wxMouseEventHandler(wxPGSpinButton::OnMouseEvent) ); + Connect( wxEVT_MOTION, + wxMouseEventHandler(wxPGSpinButton::OnMouseEvent) ); + Connect( wxEVT_MOUSE_CAPTURE_LOST, + wxMouseCaptureLostEventHandler(wxPGSpinButton::OnMouseCaptureLost) ); + } + + int GetSpins() const + { + return m_spins; + } + +private: + wxPoint m_ptPosition; + + // Having a separate spins variable allows us to handle validation etc. for + // multiple spin events at once (with quick mouse movements there could be + // hundreds of 'spins' being done at once). Technically things like this + // should be stored in event (wxSpinEvent in this case), but there probably + // isn't anything there that can be reliably reused. + int m_spins; + + bool m_bLeftDown; + + // SpinButton seems to be a special for mouse capture, so we may need track + // privately whether mouse is actually captured. + bool m_hasCapture; + + void Capture() + { + if ( !m_hasCapture ) + { + CaptureMouse(); + m_hasCapture = true; + } + + SetCursor(wxCURSOR_SIZENS); + } + void Release() + { + m_bLeftDown = false; + + if ( m_hasCapture ) + { + ReleaseMouse(); + m_hasCapture = false; + } + + wxWindow *parent = GetParent(); + if ( parent ) + SetCursor(parent->GetCursor()); + else + SetCursor(wxNullCursor); + } + + void OnMouseEvent(wxMouseEvent& event) + { + if ( event.GetEventType() == wxEVT_LEFT_DOWN ) + { + m_bLeftDown = true; + m_ptPosition = event.GetPosition(); + } + else if ( event.GetEventType() == wxEVT_LEFT_UP ) + { + Release(); + m_bLeftDown = false; + } + else if ( event.GetEventType() == wxEVT_MOTION ) + { + if ( m_bLeftDown ) + { + int dy = m_ptPosition.y - event.GetPosition().y; + if ( dy ) + { + Capture(); + m_ptPosition = event.GetPosition(); + + wxSpinEvent evtscroll( (dy >= 0) ? wxEVT_SCROLL_LINEUP : + wxEVT_SCROLL_LINEDOWN, + GetId() ); + evtscroll.SetEventObject(this); + + wxASSERT( m_spins == 1 ); + + m_spins = abs(dy); + GetEventHandler()->ProcessEvent(evtscroll); + m_spins = 1; + } + } + } + + event.Skip(); + } + void OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event)) + { + Release(); + } +}; + +#endif // IS_MOTION_SPIN_SUPPORTED + + WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(SpinCtrl, wxPGSpinCtrlEditor, wxPGEditor) @@ -128,7 +255,19 @@ wxPGWindowList wxPGSpinCtrlEditor::CreateControls( wxPropertyGrid* propgrid, wxP wxSize tcSz(sz.x - butSz.x - margin, sz.y); wxPoint butPos(pos.x + tcSz.x + margin, pos.y); - wxSpinButton* wnd2 = new wxSpinButton(); + wxSpinButton* wnd2; + +#if IS_MOTION_SPIN_SUPPORTED + if ( property->GetAttributeAsLong(wxT("MotionSpin"), 0) ) + { + wnd2 = new wxPGSpinButton(); + } + else +#endif + { + wnd2 = new wxSpinButton(); + } + #ifdef __WXMSW__ wnd2->Hide(); #endif @@ -137,23 +276,12 @@ wxPGWindowList wxPGSpinCtrlEditor::CreateControls( wxPropertyGrid* propgrid, wxP wnd2->SetRange( INT_MIN, INT_MAX ); wnd2->SetValue( 0 ); - wxWindowID id = wnd2->GetId(); - wnd2->Connect( id, wxEVT_SCROLL_LINEUP, - wxEventHandler(wxPropertyGrid::OnCustomEditorEvent), - NULL, propgrid ); - wnd2->Connect( id, wxEVT_SCROLL_LINEDOWN, - wxEventHandler(wxPropertyGrid::OnCustomEditorEvent), - NULL, propgrid ); - + wxWindow* wnd1 = wxPGTextCtrlEditor::CreateControls(propgrid, property, pos, tcSz).m_primary; +#if wxUSE_VALIDATORS // Let's add validator to make sure only numbers can be entered wxTextValidator validator(wxFILTER_NUMERIC, &m_tempString); - - wxTextCtrl* wnd1 = (wxTextCtrl*) wxPGTextCtrlEditor::CreateControls( propgrid, property, pos, tcSz ).m_primary; wnd1->SetValidator(validator); - - wnd1->Connect( wnd1->GetId(), wxEVT_KEY_DOWN, - wxEventHandler(wxPropertyGrid::OnCustomEditorEvent), - NULL, propgrid ); +#endif return wxPGWindowList(wnd1, wnd2); } @@ -164,6 +292,7 @@ bool wxPGSpinCtrlEditor::OnEvent( wxPropertyGrid* propgrid, wxPGProperty* proper { int evtType = event.GetEventType(); int keycode = -1; + int spins = 1; bool bigStep = false; if ( evtType == wxEVT_KEY_DOWN ) @@ -189,6 +318,17 @@ bool wxPGSpinCtrlEditor::OnEvent( wxPropertyGrid* propgrid, wxPGProperty* proper if ( evtType == wxEVT_SCROLL_LINEUP || evtType == wxEVT_SCROLL_LINEDOWN ) { + #if IS_MOTION_SPIN_SUPPORTED + if ( property->GetAttributeAsLong(wxT("MotionSpin"), 0) ) + { + wxPGSpinButton* spinButton = + (wxPGSpinButton*) propgrid->GetEditorControlSecondary(); + + if ( spinButton ) + spins = spinButton->GetSpins(); + } + #endif + wxString s; // Can't use wnd since it might be clipper window wxTextCtrl* tc = wxDynamicCast(propgrid->GetEditorControl(), wxTextCtrl); @@ -214,6 +354,8 @@ bool wxPGSpinCtrlEditor::OnEvent( wxPropertyGrid* propgrid, wxPGProperty* proper if ( bigStep ) step *= 10.0; + step *= (double) spins; + if ( evtType == wxEVT_SCROLL_LINEUP ) v_d += step; else v_d -= step; @@ -238,6 +380,8 @@ bool wxPGSpinCtrlEditor::OnEvent( wxPropertyGrid* propgrid, wxPGProperty* proper if ( bigStep ) step *= 10; + step *= spins; + if ( evtType == wxEVT_SCROLL_LINEUP ) v_ll += step; else v_ll -= step; @@ -316,7 +460,7 @@ wxPGWindowList wxPGDatePickerCtrlEditor::CreateControls( wxPropertyGrid* propgri NULL, wxT("DatePickerCtrl editor can only be used with wxDateProperty or derivative.") ); - wxDateProperty* prop = (wxDateProperty*) property; + wxDateProperty* prop = wxDynamicCast(property, wxDateProperty); // Use two stage creation to allow cleaner display on wxMSW wxDatePickerCtrl* ctrl = new wxDatePickerCtrl(); @@ -327,20 +471,20 @@ wxPGWindowList wxPGDatePickerCtrlEditor::CreateControls( wxPropertyGrid* propgri #else wxSize useSz = sz; #endif + + wxDateTime dateValue(wxInvalidDateTime); + + wxVariant value = prop->GetValue(); + if ( value.GetType() == wxT("datetime") ) + dateValue = value.GetDateTime(); + ctrl->Create(propgrid->GetPanel(), wxPG_SUBID1, - prop->GetDateValue(), + dateValue, pos, useSz, prop->GetDatePickerStyle() | wxNO_BORDER); - // Connect all required events to grid's OnCustomEditorEvent - // (all relevenat wxTextCtrl, wxComboBox and wxButton events are - // already connected) - ctrl->Connect( wxPG_SUBID1, wxEVT_DATE_CHANGED, - wxEventHandler(wxPropertyGrid::OnCustomEditorEvent), - NULL, propgrid ); - #ifdef __WXMSW__ ctrl->Show(); #endif @@ -349,14 +493,18 @@ wxPGWindowList wxPGDatePickerCtrlEditor::CreateControls( wxPropertyGrid* propgri } // Copies value from property to control -void wxPGDatePickerCtrlEditor::UpdateControl( wxPGProperty* property, wxWindow* wnd ) const +void wxPGDatePickerCtrlEditor::UpdateControl( wxPGProperty* property, + wxWindow* wnd ) const { wxDatePickerCtrl* ctrl = (wxDatePickerCtrl*) wnd; wxASSERT( ctrl && ctrl->IsKindOf(CLASSINFO(wxDatePickerCtrl)) ); - // We assume that property's data type is 'int' (or something similar), - // thus allowing us to get raw, unchecked value via DoGetValue. - ctrl->SetValue( property->GetValue().GetDateTime() ); + wxDateTime dateValue(wxInvalidDateTime); + wxVariant v(property->GetValue()); + if ( v.GetType() == wxT("datetime") ) + dateValue = v.GetDateTime(); + + ctrl->SetValue( dateValue ); } // Control's events are redirected here @@ -381,11 +529,20 @@ bool wxPGDatePickerCtrlEditor::GetValueFromControl( wxVariant& variant, wxPGProp return true; } -void wxPGDatePickerCtrlEditor::SetValueToUnspecified( wxPGProperty* WXUNUSED(property), wxWindow* WXUNUSED(wnd) ) const +void wxPGDatePickerCtrlEditor::SetValueToUnspecified( wxPGProperty* property, + wxWindow* wnd ) const { - // TODO? - //wxDateProperty* prop = (wxDateProperty*) property; - //ctrl->SetValue(?); + wxDatePickerCtrl* ctrl = (wxDatePickerCtrl*) wnd; + wxASSERT( ctrl && ctrl->IsKindOf(CLASSINFO(wxDatePickerCtrl)) ); + + wxDateProperty* prop = wxDynamicCast(property, wxDateProperty); + + if ( prop ) + { + int datePickerStyle = prop->GetDatePickerStyle(); + if ( datePickerStyle & wxDP_ALLOWNONE ) + ctrl->SetValue(wxInvalidDateTime); + } } #endif // wxUSE_DATEPICKCTRL @@ -465,13 +622,12 @@ wxFontProperty::wxFontProperty( const wxString& label, const wxString& name, wxFont font; font << m_value; - SetParentalType(wxPG_PROP_AGGREGATE); - - AddChild( new wxIntProperty( _("Point Size"), wxS("Point Size"),(long)font.GetPointSize() ) ); + AddPrivateChild( new wxIntProperty( _("Point Size"), + wxS("Point Size"),(long)font.GetPointSize() ) ); - AddChild( new wxEnumProperty(_("Family"), wxS("PointSize"), - gs_fp_es_family_labels,gs_fp_es_family_values, - font.GetFamily()) ); + AddPrivateChild( new wxEnumProperty(_("Family"), wxS("PointSize"), + gs_fp_es_family_labels,gs_fp_es_family_values, + font.GetFamily()) ); wxString faceName = font.GetFaceName(); // If font was not in there, add it now @@ -484,16 +640,18 @@ wxFontProperty::wxFontProperty( const wxString& label, const wxString& name, p->SetValueFromString(faceName, wxPG_FULL_VALUE); - AddChild( p ); + AddPrivateChild( p ); - AddChild( new wxEnumProperty(_("Style"), wxS("Style"), - gs_fp_es_style_labels,gs_fp_es_style_values,font.GetStyle()) ); + AddPrivateChild( new wxEnumProperty(_("Style"), wxS("Style"), + gs_fp_es_style_labels,gs_fp_es_style_values, + font.GetStyle()) ); - AddChild( new wxEnumProperty(_("Weight"), wxS("Weight"), - gs_fp_es_weight_labels,gs_fp_es_weight_values,font.GetWeight()) ); + AddPrivateChild( new wxEnumProperty(_("Weight"), wxS("Weight"), + gs_fp_es_weight_labels,gs_fp_es_weight_values, + font.GetWeight()) ); - AddChild( new wxBoolProperty(_("Underlined"), wxS("Underlined"), - font.GetUnderlined()) ); + AddPrivateChild( new wxBoolProperty(_("Underlined"), wxS("Underlined"), + font.GetUnderlined()) ); } wxFontProperty::~wxFontProperty() { } @@ -505,8 +663,7 @@ void wxFontProperty::OnSetValue() if ( !font.Ok() ) { - font = wxFont(10,wxSWISS,wxNORMAL,wxNORMAL); - m_value << font; + m_value << *wxNORMAL_FONT; } } @@ -557,14 +714,16 @@ void wxFontProperty::RefreshChildren() Item(5)->SetValue( font.GetUnderlined() ); } -void wxFontProperty::ChildChanged( wxVariant& thisValue, int ind, wxVariant& childValue ) const +wxVariant wxFontProperty::ChildChanged( wxVariant& thisValue, + int ind, + wxVariant& childValue ) const { wxFont font; font << thisValue; if ( ind == 0 ) { - font.SetPointSize( wxPGVariantToInt(childValue) ); + font.SetPointSize( childValue.GetLong() ); } else if ( ind == 1 ) { @@ -607,7 +766,9 @@ void wxFontProperty::ChildChanged( wxVariant& thisValue, int ind, wxVariant& chi font.SetUnderlined( childValue.GetBool() ); } - thisValue << font; + wxVariant newVariant; + newVariant << font; + return newVariant; } /* @@ -872,7 +1033,10 @@ wxVariant wxSystemColourProperty::DoTranslateVal( wxColourPropertyValue& v ) con int wxSystemColourProperty::ColToInd( const wxColour& colour ) const { size_t i; - size_t i_max = m_choices.GetCount() - 1; + size_t i_max = m_choices.GetCount(); + + if ( !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) ) + i_max -= 1; for ( i=0; iGetInternalFlags() & wxPG_FL_IN_ONCUSTOMEDITOREVENT) ) + if ( !(propgrid->GetInternalFlags() & wxPG_FL_IN_HANDLECUSTOMEDITOREVENT) ) return res; wxColourPropertyValue val = GetVal(); @@ -1078,12 +1245,37 @@ bool wxSystemColourProperty::IntToValue( wxVariant& variant, int number, int WXU } // Need to do some extra event handling. -bool wxSystemColourProperty::OnEvent( wxPropertyGrid* propgrid, wxWindow* WXUNUSED(primary), wxEvent& event ) +bool wxSystemColourProperty::OnEvent( wxPropertyGrid* propgrid, + wxWindow* WXUNUSED(primary), + wxEvent& event ) { + bool askColour = false; + if ( propgrid->IsMainButtonEvent(event) ) { // We need to handle button click in case editor has been // switched to one that has wxButton as well. + askColour = true; + } + else if ( event.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED ) + { + // Must override index detection since at this point GetIndex() + // will return old value. + wxOwnerDrawnComboBox* cb = + static_cast(propgrid->GetEditorControl()); + + if ( cb ) + { + int index = cb->GetSelection(); + + if ( index == GetCustomColourIndex() && + !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) ) + askColour = true; + } + } + + if ( askColour && !propgrid->WasValueChangedInEvent() ) + { wxVariant variant; if ( QueryColourFromUser(variant) ) return true; @@ -1148,8 +1340,10 @@ void wxSystemColourProperty::OnCustomPaint( wxDC& dc, const wxRect& rect, { wxColour col; - if ( paintdata.m_choiceItem >= 0 && paintdata.m_choiceItem < (int)m_choices.GetCount() && - paintdata.m_choiceItem != GetCustomColourIndex() ) + if ( paintdata.m_choiceItem >= 0 && + paintdata.m_choiceItem < (int)m_choices.GetCount() && + (paintdata.m_choiceItem != GetCustomColourIndex() || + m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) ) { int colInd = m_choices[paintdata.m_choiceItem].GetValue(); col = GetColour( colInd ); @@ -1198,6 +1392,7 @@ bool wxSystemColourProperty::StringToValue( wxVariant& value, const wxString& te colourRGB.clear(); if ( colourRGB.length() == 0 && m_choices.GetCount() && + !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) && colourName == m_choices.GetLabel(GetCustomColourIndex()) ) { if ( !(argFlags & wxPG_EDITABLE_VALUE )) @@ -1267,9 +1462,7 @@ bool wxSystemColourProperty::DoSetAttribute( const wxString& name, wxVariant& va { if ( name == wxPG_COLOUR_ALLOW_CUSTOM ) { - int ival = wxPGVariantToInt(value); - - SetChoicesExclusive(); // Make sure we don't corrupt colour lists of other properties + int ival = value.GetLong(); if ( ival && (m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) ) { @@ -1530,7 +1723,10 @@ void wxCursorProperty::OnCustomPaint( wxDC& dc, 0, 0, NULL, - DI_COMPAT | DI_DEFAULTSIZE | DI_NORMAL + #if !defined(__WXWINCE__) + DI_COMPAT | DI_DEFAULTSIZE | + #endif + DI_NORMAL ); #endif } @@ -1599,8 +1795,8 @@ wxImageFileProperty::wxImageFileProperty( const wxString& label, const wxString& { SetAttribute( wxPG_FILE_WILDCARD, wxPGGetDefaultImageWildcard() ); - m_pImage = (wxImage*) NULL; - m_pBitmap = (wxBitmap*) NULL; + m_pImage = NULL; + m_pBitmap = NULL; } wxImageFileProperty::~wxImageFileProperty() @@ -1760,7 +1956,8 @@ void wxMultiChoiceProperty::GenerateValueAsString( wxVariant& value, wxArrayInt wxMultiChoiceProperty::GetValueAsIndices() const { - const wxArrayInt& valueArr = wxArrayIntRefFromVariant(GetValue()); + wxVariant variant = GetValue(); + const wxArrayInt& valueArr = wxArrayIntRefFromVariant(variant); unsigned int i; // Translate values to string indices. @@ -1921,12 +2118,25 @@ wxDateProperty::~wxDateProperty() { } +void wxDateProperty::OnSetValue() +{ + // + // Convert invalid dates to unspecified value + if ( m_value.GetType() == wxT("datetime") ) + { + if ( !m_value.GetDateTime().IsValid() ) + m_value.MakeNull(); + } +} + bool wxDateProperty::StringToValue( wxVariant& variant, const wxString& text, int WXUNUSED(argFlags) ) const { wxDateTime dt; - const char* c = dt.ParseFormat(text, wxString(wxDefaultDateTimeFormat), wxDefaultDateTime, NULL); + // FIXME: do we really want to return true from here if only part of the + // string was parsed? + const char* c = dt.ParseFormat(text); if ( c ) {