///////////////////////////////////////////////////////////////////////////// // Name: src/propgrid/advprops.cpp // Purpose: wxPropertyGrid Advanced Properties (font, colour, etc.) // Author: Jaakko Salli // Modified by: // Created: 2004-09-25 // Copyright: (c) Jaakko Salli // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #if wxUSE_PROPGRID #ifndef WX_PRECOMP #include "wx/defs.h" #include "wx/object.h" #include "wx/hash.h" #include "wx/string.h" #include "wx/log.h" #include "wx/event.h" #include "wx/window.h" #include "wx/panel.h" #include "wx/dc.h" #include "wx/dcclient.h" #include "wx/button.h" #include "wx/pen.h" #include "wx/brush.h" #include "wx/cursor.h" #include "wx/dialog.h" #include "wx/settings.h" #include "wx/msgdlg.h" #include "wx/choice.h" #include "wx/stattext.h" #include "wx/textctrl.h" #include "wx/scrolwin.h" #include "wx/dirdlg.h" #include "wx/combobox.h" #include "wx/sizer.h" #include "wx/textdlg.h" #include "wx/filedlg.h" #include "wx/intl.h" #include "wx/wxcrtvararg.h" #endif #define __wxPG_SOURCE_FILE__ #include "wx/propgrid/propgrid.h" #if wxPG_INCLUDE_ADVPROPS #include "wx/propgrid/advprops.h" #ifdef __WXMSW__ #include "wx/msw/private.h" #include "wx/msw/dc.h" #endif #include "wx/odcombo.h" #include "wx/numformatter.h" // ----------------------------------------------------------------------- #if defined(__WXMSW__) #define wxPG_CAN_DRAW_CURSOR 1 #elif defined(__WXGTK__) #define wxPG_CAN_DRAW_CURSOR 1 #elif defined(__WXMAC__) #define wxPG_CAN_DRAW_CURSOR 0 #else #define wxPG_CAN_DRAW_CURSOR 0 #endif // ----------------------------------------------------------------------- // Value type related // ----------------------------------------------------------------------- // Implement dynamic class for type value. IMPLEMENT_DYNAMIC_CLASS(wxColourPropertyValue, wxObject) bool operator == (const wxColourPropertyValue& a, const wxColourPropertyValue& b) { return ( ( a.m_colour == b.m_colour ) && (a.m_type == b.m_type) ); } bool operator == (const wxArrayInt& array1, const wxArrayInt& array2) { if ( array1.size() != array2.size() ) return false; size_t i; for ( i=0; iGetCursor()); 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) // Destructor. It is useful to reset the global pointer in it. wxPGSpinCtrlEditor::~wxPGSpinCtrlEditor() { wxPG_EDITOR(SpinCtrl) = NULL; } // Create controls and initialize event handling. wxPGWindowList wxPGSpinCtrlEditor::CreateControls( wxPropertyGrid* propgrid, wxPGProperty* property, const wxPoint& pos, const wxSize& sz ) const { const int margin = 1; wxSize butSz(18, sz.y); wxSize tcSz(sz.x - butSz.x - margin, sz.y); wxPoint butPos(pos.x + tcSz.x + margin, pos.y); 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 wnd2->Create( propgrid->GetPanel(), wxID_ANY, butPos, butSz, wxSP_VERTICAL ); wnd2->SetRange( INT_MIN, INT_MAX ); wnd2->SetValue( 0 ); 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); wnd1->SetValidator(validator); #endif return wxPGWindowList(wnd1, wnd2); } // Control's events are redirected here bool wxPGSpinCtrlEditor::OnEvent( wxPropertyGrid* propgrid, wxPGProperty* property, wxWindow* wnd, wxEvent& event ) const { int evtType = event.GetEventType(); int keycode = -1; int spins = 1; bool bigStep = false; if ( evtType == wxEVT_KEY_DOWN ) { wxKeyEvent& keyEvent = (wxKeyEvent&)event; keycode = keyEvent.GetKeyCode(); if ( keycode == WXK_UP ) evtType = wxEVT_SCROLL_LINEUP; else if ( keycode == WXK_DOWN ) evtType = wxEVT_SCROLL_LINEDOWN; else if ( keycode == WXK_PAGEUP ) { evtType = wxEVT_SCROLL_LINEUP; bigStep = true; } else if ( keycode == WXK_PAGEDOWN ) { evtType = wxEVT_SCROLL_LINEDOWN; bigStep = true; } } 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); if ( tc ) s = tc->GetValue(); else s = property->GetValueAsString(wxPG_FULL_VALUE); int mode = wxPG_PROPERTY_VALIDATION_SATURATE; if ( property->GetAttributeAsLong(wxPG_ATTR_SPINCTRL_WRAP, 0) ) mode = wxPG_PROPERTY_VALIDATION_WRAP; if ( property->GetValueType() == wxT("double") ) { double v_d; double step = property->GetAttributeAsDouble(wxPG_ATTR_SPINCTRL_STEP, 1.0); // Try double if ( s.ToDouble(&v_d) ) { if ( bigStep ) step *= 10.0; step *= (double) spins; if ( evtType == wxEVT_SCROLL_LINEUP ) v_d += step; else v_d -= step; // Min/Max check wxFloatProperty::DoValidation(property, v_d, NULL, mode); int precision = -1; wxVariant v = property->GetAttribute(wxPG_FLOAT_PRECISION); if ( !v.IsNull() ) { precision = v.GetInteger(); } s = wxNumberFormatter::ToString(v_d, precision, wxNumberFormatter::Style_NoTrailingZeroes); } else { return false; } } else { wxLongLong_t v_ll; wxLongLong_t step = property->GetAttributeAsLong(wxPG_ATTR_SPINCTRL_STEP, 1); // Try (long) long if ( s.ToLongLong(&v_ll, 10) ) { if ( bigStep ) step *= 10; step *= spins; if ( evtType == wxEVT_SCROLL_LINEUP ) v_ll += step; else v_ll -= step; // Min/Max check wxIntProperty::DoValidation(property, v_ll, NULL, mode); s = wxLongLong(v_ll).ToString(); } else { return false; } } if ( tc ) { int ip = tc->GetInsertionPoint(); int lp = tc->GetLastPosition(); tc->SetValue(s); tc->SetInsertionPoint(ip+(tc->GetLastPosition()-lp)); } return true; } return wxPGTextCtrlEditor::OnEvent(propgrid,property,wnd,event); } #endif // wxUSE_SPINBTN // ----------------------------------------------------------------------- // wxDatePickerCtrl-based property editor // ----------------------------------------------------------------------- #if wxUSE_DATEPICKCTRL #include "wx/datectrl.h" #include "wx/dateevt.h" class wxPGDatePickerCtrlEditor : public wxPGEditor { DECLARE_DYNAMIC_CLASS(wxPGDatePickerCtrlEditor) public: virtual ~wxPGDatePickerCtrlEditor(); wxString GetName() const wxOVERRIDE; virtual wxPGWindowList CreateControls(wxPropertyGrid* propgrid, wxPGProperty* property, const wxPoint& pos, const wxSize& size) const wxOVERRIDE; virtual void UpdateControl( wxPGProperty* property, wxWindow* wnd ) const wxOVERRIDE; virtual bool OnEvent( wxPropertyGrid* propgrid, wxPGProperty* property, wxWindow* wnd, wxEvent& event ) const wxOVERRIDE; virtual bool GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* wnd ) const wxOVERRIDE; virtual void SetValueToUnspecified( wxPGProperty* WXUNUSED(property), wxWindow* wnd ) const wxOVERRIDE; }; WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(DatePickerCtrl, wxPGDatePickerCtrlEditor, wxPGEditor) wxPGDatePickerCtrlEditor::~wxPGDatePickerCtrlEditor() { wxPG_EDITOR(DatePickerCtrl) = NULL; } wxPGWindowList wxPGDatePickerCtrlEditor::CreateControls( wxPropertyGrid* propgrid, wxPGProperty* property, const wxPoint& pos, const wxSize& sz ) const { wxCHECK_MSG( wxDynamicCast(property, wxDateProperty), NULL, wxT("DatePickerCtrl editor can only be used with wxDateProperty or derivative.") ); wxDateProperty* prop = wxDynamicCast(property, wxDateProperty); // Use two stage creation to allow cleaner display on wxMSW wxDatePickerCtrl* ctrl = new wxDatePickerCtrl(); #ifdef __WXMSW__ ctrl->Hide(); wxSize useSz = wxDefaultSize; useSz.x = sz.x; #else wxSize useSz = sz; #endif wxDateTime dateValue(wxInvalidDateTime); wxVariant value = prop->GetValue(); if ( value.GetType() == wxT("datetime") ) dateValue = value.GetDateTime(); ctrl->Create(propgrid->GetPanel(), wxID_ANY, dateValue, pos, useSz, prop->GetDatePickerStyle() | wxNO_BORDER); #ifdef __WXMSW__ ctrl->Show(); #endif return ctrl; } // Copies value from property to control void wxPGDatePickerCtrlEditor::UpdateControl( wxPGProperty* property, wxWindow* wnd ) const { wxDatePickerCtrl* ctrl = (wxDatePickerCtrl*) wnd; wxASSERT( wxDynamicCast(ctrl, wxDatePickerCtrl) ); wxDateTime dateValue(wxInvalidDateTime); wxVariant v(property->GetValue()); if ( v.GetType() == wxT("datetime") ) dateValue = v.GetDateTime(); ctrl->SetValue( dateValue ); } // Control's events are redirected here bool wxPGDatePickerCtrlEditor::OnEvent( wxPropertyGrid* WXUNUSED(propgrid), wxPGProperty* WXUNUSED(property), wxWindow* WXUNUSED(wnd), wxEvent& event ) const { if ( event.GetEventType() == wxEVT_DATE_CHANGED ) return true; return false; } bool wxPGDatePickerCtrlEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* WXUNUSED(property), wxWindow* wnd ) const { wxDatePickerCtrl* ctrl = (wxDatePickerCtrl*) wnd; wxASSERT( wxDynamicCast(ctrl, wxDatePickerCtrl) ); variant = ctrl->GetValue(); return true; } void wxPGDatePickerCtrlEditor::SetValueToUnspecified( wxPGProperty* property, wxWindow* wnd ) const { wxDatePickerCtrl* ctrl = (wxDatePickerCtrl*) wnd; wxASSERT( wxDynamicCast(ctrl, wxDatePickerCtrl) ); wxDateProperty* prop = wxDynamicCast(property, wxDateProperty); if ( prop ) { int datePickerStyle = prop->GetDatePickerStyle(); if ( datePickerStyle & wxDP_ALLOWNONE ) ctrl->SetValue(wxInvalidDateTime); } } #endif // wxUSE_DATEPICKCTRL // ----------------------------------------------------------------------- // wxFontProperty // ----------------------------------------------------------------------- #include "wx/fontdlg.h" #include "wx/fontenum.h" // // NB: Do not use wxS here since unlike wxT it doesn't translate to wxChar* // static const wxChar* const gs_fp_es_family_labels[] = { wxT("Default"), wxT("Decorative"), wxT("Roman"), wxT("Script"), wxT("Swiss"), wxT("Modern"), wxT("Teletype"), wxT("Unknown"), (const wxChar*) NULL }; static const long gs_fp_es_family_values[] = { wxFONTFAMILY_DEFAULT, wxFONTFAMILY_DECORATIVE, wxFONTFAMILY_ROMAN, wxFONTFAMILY_SCRIPT, wxFONTFAMILY_SWISS, wxFONTFAMILY_MODERN, wxFONTFAMILY_TELETYPE, wxFONTFAMILY_UNKNOWN }; static const wxChar* const gs_fp_es_style_labels[] = { wxT("Normal"), wxT("Slant"), wxT("Italic"), (const wxChar*) NULL }; static const long gs_fp_es_style_values[] = { wxFONTSTYLE_NORMAL, wxFONTSTYLE_SLANT, wxFONTSTYLE_ITALIC }; static const wxChar* const gs_fp_es_weight_labels[] = { wxT("Normal"), wxT("Light"), wxT("Bold"), (const wxChar*) NULL }; static const long gs_fp_es_weight_values[] = { wxFONTWEIGHT_NORMAL, wxFONTWEIGHT_LIGHT, wxFONTWEIGHT_BOLD }; // Class body is in advprops.h WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFontProperty,wxPGProperty, wxFont,const wxFont&,TextCtrlAndButton) wxFontProperty::wxFontProperty( const wxString& label, const wxString& name, const wxFont& value ) : wxPGProperty(label,name) { SetValue(WXVARIANT(value)); // Initialize font family choices list if ( !wxPGGlobalVars->m_fontFamilyChoices ) { wxArrayString faceNames = wxFontEnumerator::GetFacenames(); faceNames.Sort(); wxPGGlobalVars->m_fontFamilyChoices = new wxPGChoices(faceNames); } wxString emptyString(wxEmptyString); wxFont font; font << m_value; AddPrivateChild( new wxIntProperty( _("Point Size"), wxS("Point Size"),(long)font.GetPointSize() ) ); wxString faceName = font.GetFaceName(); // If font was not in there, add it now if ( !faceName.empty() && wxPGGlobalVars->m_fontFamilyChoices->Index(faceName) == wxNOT_FOUND ) wxPGGlobalVars->m_fontFamilyChoices->AddAsSorted(faceName); wxPGProperty* p = new wxEnumProperty(_("Face Name"), wxS("Face Name"), *wxPGGlobalVars->m_fontFamilyChoices); p->SetValueFromString(faceName, wxPG_FULL_VALUE); AddPrivateChild( p ); AddPrivateChild( new wxEnumProperty(_("Style"), wxS("Style"), gs_fp_es_style_labels,gs_fp_es_style_values, font.GetStyle()) ); AddPrivateChild( new wxEnumProperty(_("Weight"), wxS("Weight"), gs_fp_es_weight_labels,gs_fp_es_weight_values, font.GetWeight()) ); AddPrivateChild( new wxBoolProperty(_("Underlined"), wxS("Underlined"), font.GetUnderlined()) ); AddPrivateChild( new wxEnumProperty(_("Family"), wxS("PointSize"), gs_fp_es_family_labels,gs_fp_es_family_values, font.GetFamily()) ); } wxFontProperty::~wxFontProperty() { } void wxFontProperty::OnSetValue() { wxFont font; font << m_value; if ( !font.IsOk() ) { m_value << *wxNORMAL_FONT; } } wxString wxFontProperty::ValueToString( wxVariant& value, int argFlags ) const { return wxPGProperty::ValueToString(value, argFlags); } bool wxFontProperty::OnEvent( wxPropertyGrid* propgrid, wxWindow* WXUNUSED(primary), wxEvent& event ) { if ( propgrid->IsMainButtonEvent(event) ) { // Update value from last minute changes wxVariant useValue = propgrid->GetUncommittedPropertyValue(); wxFontData data; wxFont font; if ( useValue.GetType() == wxS("wxFont") ) font << useValue; data.SetInitialFont( font ); data.SetColour(*wxBLACK); wxFontDialog dlg(propgrid, data); if ( dlg.ShowModal() == wxID_OK ) { propgrid->EditorsValueWasModified(); wxVariant variant; variant << dlg.GetFontData().GetChosenFont(); SetValueInEvent( variant ); return true; } } return false; } void wxFontProperty::RefreshChildren() { if ( !GetChildCount() ) return; wxFont font; font << m_value; Item(0)->SetValue( (long)font.GetPointSize() ); Item(1)->SetValueFromString( font.GetFaceName(), wxPG_FULL_VALUE ); Item(2)->SetValue( (long)font.GetStyle() ); Item(3)->SetValue( (long)font.GetWeight() ); Item(4)->SetValue( font.GetUnderlined() ); Item(5)->SetValue( (long)font.GetFamily() ); } wxVariant wxFontProperty::ChildChanged( wxVariant& thisValue, int ind, wxVariant& childValue ) const { wxFont font; font << thisValue; if ( ind == 0 ) { font.SetPointSize( childValue.GetLong() ); } else if ( ind == 1 ) { wxString faceName; int faceIndex = childValue.GetLong(); if ( faceIndex >= 0 ) faceName = wxPGGlobalVars->m_fontFamilyChoices->GetLabel(faceIndex); font.SetFaceName( faceName ); } else if ( ind == 2 ) { int st = childValue.GetLong(); if ( st != wxFONTSTYLE_NORMAL && st != wxFONTSTYLE_SLANT && st != wxFONTSTYLE_ITALIC ) st = wxFONTWEIGHT_NORMAL; font.SetStyle( static_cast(st) ); } else if ( ind == 3 ) { int wt = childValue.GetLong(); if ( wt != wxFONTWEIGHT_NORMAL && wt != wxFONTWEIGHT_LIGHT && wt != wxFONTWEIGHT_BOLD ) wt = wxFONTWEIGHT_NORMAL; font.SetWeight( static_cast(wt) ); } else if ( ind == 4 ) { font.SetUnderlined( childValue.GetBool() ); } else if ( ind == 5 ) { int fam = childValue.GetLong(); if ( fam < wxFONTFAMILY_DEFAULT || fam > wxFONTFAMILY_TELETYPE ) fam = wxFONTFAMILY_DEFAULT; font.SetFamily( static_cast(fam) ); } wxVariant newVariant; newVariant << font; return newVariant; } /* wxSize wxFontProperty::OnMeasureImage() const { return wxSize(-1,-1); } void wxFontProperty::OnCustomPaint(wxDC& dc, const wxRect& rect, wxPGPaintData& paintData) { wxString drawFace; if ( paintData.m_choiceItem >= 0 ) drawFace = wxPGGlobalVars->m_fontFamilyChoices->GetLabel(paintData.m_choiceItem); else drawFace = m_value_wxFont.GetFaceName(); if ( !drawFace.empty() ) { // Draw the background dc.SetBrush( wxColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)) ); //dc.SetBrush( *wxWHITE_BRUSH ); //dc.SetPen( *wxMEDIUM_GREY_PEN ); dc.DrawRectangle( rect ); wxFont oldFont = dc.GetFont(); dc.SetFont(wxFontInfo(oldFont.GetPointSize().Bold().FaceName(drawFace)); dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT) ); dc.DrawText( wxT("Aa"), rect.x+2, rect.y+1 ); dc.SetFont(oldFont); } else { // No file - just draw a white box dc.SetBrush ( *wxWHITE_BRUSH ); dc.DrawRectangle ( rect ); } } */ // ----------------------------------------------------------------------- // wxSystemColourProperty // ----------------------------------------------------------------------- // wxEnumProperty based classes cannot use wxPG_PROP_CLASS_SPECIFIC_1 #define wxPG_PROP_HIDE_CUSTOM_COLOUR wxPG_PROP_CLASS_SPECIFIC_2 #include "wx/colordlg.h" //#define wx_cp_es_syscolours_len 25 static const char* const gs_cp_es_syscolour_labels[] = { wxTRANSLATE("AppWorkspace"), wxTRANSLATE("ActiveBorder"), wxTRANSLATE("ActiveCaption"), wxTRANSLATE("ButtonFace"), wxTRANSLATE("ButtonHighlight"), wxTRANSLATE("ButtonShadow"), wxTRANSLATE("ButtonText"), wxTRANSLATE("CaptionText"), wxTRANSLATE("ControlDark"), wxTRANSLATE("ControlLight"), wxTRANSLATE("Desktop"), wxTRANSLATE("GrayText"), wxTRANSLATE("Highlight"), wxTRANSLATE("HighlightText"), wxTRANSLATE("InactiveBorder"), wxTRANSLATE("InactiveCaption"), wxTRANSLATE("InactiveCaptionText"), wxTRANSLATE("Menu"), wxTRANSLATE("Scrollbar"), wxTRANSLATE("Tooltip"), wxTRANSLATE("TooltipText"), wxTRANSLATE("Window"), wxTRANSLATE("WindowFrame"), wxTRANSLATE("WindowText"), wxTRANSLATE("Custom"), NULL }; static const long gs_cp_es_syscolour_values[] = { wxSYS_COLOUR_APPWORKSPACE, wxSYS_COLOUR_ACTIVEBORDER, wxSYS_COLOUR_ACTIVECAPTION, wxSYS_COLOUR_BTNFACE, wxSYS_COLOUR_BTNHIGHLIGHT, wxSYS_COLOUR_BTNSHADOW, wxSYS_COLOUR_BTNTEXT , wxSYS_COLOUR_CAPTIONTEXT, wxSYS_COLOUR_3DDKSHADOW, wxSYS_COLOUR_3DLIGHT, wxSYS_COLOUR_BACKGROUND, wxSYS_COLOUR_GRAYTEXT, wxSYS_COLOUR_HIGHLIGHT, wxSYS_COLOUR_HIGHLIGHTTEXT, wxSYS_COLOUR_INACTIVEBORDER, wxSYS_COLOUR_INACTIVECAPTION, wxSYS_COLOUR_INACTIVECAPTIONTEXT, wxSYS_COLOUR_MENU, wxSYS_COLOUR_SCROLLBAR, wxSYS_COLOUR_INFOBK, wxSYS_COLOUR_INFOTEXT, wxSYS_COLOUR_WINDOW, wxSYS_COLOUR_WINDOWFRAME, wxSYS_COLOUR_WINDOWTEXT, wxPG_COLOUR_CUSTOM }; IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxColourPropertyValue, WXDLLIMPEXP_PROPGRID) // Class body is in advprops.h WX_PG_IMPLEMENT_PROPERTY_CLASS(wxSystemColourProperty,wxEnumProperty, wxColourPropertyValue,const wxColourPropertyValue&,Choice) void wxSystemColourProperty::Init( int type, const wxColour& colour ) { wxColourPropertyValue cpv; if ( colour.IsOk() ) cpv.Init( type, colour ); else cpv.Init( type, *wxWHITE ); m_flags |= wxPG_PROP_STATIC_CHOICES; // Colour selection cannot be changed. m_value << cpv; OnSetValue(); } static wxPGChoices gs_wxSystemColourProperty_choicesCache; wxSystemColourProperty::wxSystemColourProperty( const wxString& label, const wxString& name, const wxColourPropertyValue& value ) : wxEnumProperty( label, name, gs_cp_es_syscolour_labels, gs_cp_es_syscolour_values, &gs_wxSystemColourProperty_choicesCache ) { if ( &value ) Init( value.m_type, value.m_colour ); else Init( wxPG_COLOUR_CUSTOM, *wxWHITE ); } wxSystemColourProperty::wxSystemColourProperty( const wxString& label, const wxString& name, const char* const* labels, const long* values, wxPGChoices* choicesCache, const wxColourPropertyValue& value ) : wxEnumProperty( label, name, labels, values, choicesCache ) { if ( &value ) Init( value.m_type, value.m_colour ); else Init( wxPG_COLOUR_CUSTOM, *wxWHITE ); } wxSystemColourProperty::wxSystemColourProperty( const wxString& label, const wxString& name, const char* const* labels, const long* values, wxPGChoices* choicesCache, const wxColour& value ) : wxEnumProperty( label, name, labels, values, choicesCache ) { if ( &value ) Init( wxPG_COLOUR_CUSTOM, value ); else Init( wxPG_COLOUR_CUSTOM, *wxWHITE ); } wxSystemColourProperty::~wxSystemColourProperty() { } wxColourPropertyValue wxSystemColourProperty::GetVal( const wxVariant* pVariant ) const { if ( !pVariant ) pVariant = &m_value; if ( pVariant->IsNull() ) return wxColourPropertyValue(wxPG_COLOUR_UNSPECIFIED, wxColour()); if ( pVariant->GetType() == wxS("wxColourPropertyValue") ) { wxColourPropertyValue v; v << *pVariant; return v; } wxColour col; bool variantProcessed = true; if ( pVariant->GetType() == wxS("wxColour*") ) { wxColour* pCol = wxStaticCast(pVariant->GetWxObjectPtr(), wxColour); col = *pCol; } else if ( pVariant->GetType() == wxS("wxColour") ) { col << *pVariant; } else if ( pVariant->GetType() == wxArrayInt_VariantType ) { // This code is mostly needed for wxPython bindings, which // may offer tuple of integers as colour value. wxArrayInt arr; arr << *pVariant; if ( arr.size() >= 3 ) { int r, g, b; int a = 255; r = arr[0]; g = arr[1]; b = arr[2]; if ( arr.size() >= 4 ) a = arr[3]; col = wxColour(r, g, b, a); } else { variantProcessed = false; } } else { variantProcessed = false; } if ( !variantProcessed ) return wxColourPropertyValue(wxPG_COLOUR_UNSPECIFIED, wxColour()); wxColourPropertyValue v2( wxPG_COLOUR_CUSTOM, col ); int colInd = ColToInd(col); if ( colInd != wxNOT_FOUND ) v2.m_type = colInd; return v2; } wxVariant wxSystemColourProperty::DoTranslateVal( wxColourPropertyValue& v ) const { wxVariant variant; variant << v; return variant; } int wxSystemColourProperty::ColToInd( const wxColour& colour ) const { const unsigned int i_max = m_choices.GetCount(); for ( unsigned int i=0; iHasInternalFlag(wxPG_FL_IN_HANDLECUSTOMEDITOREVENT) ) return res; wxColourPropertyValue val = GetVal(); val.m_type = wxPG_COLOUR_CUSTOM; wxColourData data; data.SetChooseFull(true); data.SetColour(val.m_colour); int i; for ( i = 0; i < 16; i++) { wxColour colour(i*16, i*16, i*16); data.SetCustomColour(i, colour); } wxColourDialog dialog(propgrid, &data); if ( dialog.ShowModal() == wxID_OK ) { wxColourData retData = dialog.GetColourData(); val.m_colour = retData.GetColour(); variant = DoTranslateVal(val); SetValueInEvent(variant); res = true; } return res; } bool wxSystemColourProperty::IntToValue( wxVariant& variant, int number, int argFlags ) const { int index = number; const int type = m_choices.GetValue(index); if ( type == wxPG_COLOUR_CUSTOM ) { if ( !(argFlags & wxPG_PROPERTY_SPECIFIC) ) return QueryColourFromUser(variant); // Call from event handler. // User will be asked for custom color later on in OnEvent(). wxColourPropertyValue val = GetVal(); variant = DoTranslateVal(val); } else { variant = TranslateVal( type, GetColour(type) ); } return true; } // Need to do some extra event handling. 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_COMBOBOX ) { // 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; } return false; } /*class wxPGColourPropertyRenderer : public wxPGDefaultRenderer { public: virtual void Render( wxDC& dc, const wxRect& rect, const wxPropertyGrid* propertyGrid, wxPGProperty* property, int WXUNUSED(column), int item, int WXUNUSED(flags) ) const { wxASSERT( wxDynamicCast(property, wxSystemColourProperty) ); wxSystemColourProperty* prop = wxStaticCast(property, wxSystemColourProperty); dc.SetPen(*wxBLACK_PEN); if ( item >= 0 && ( item < (int)(GetCustomColourIndex) || (prop->HasFlag(wxPG_PROP_HIDE_CUSTOM_COLOUR))) ) { int colInd; const wxArrayInt& values = prop->GetValues(); if ( values.GetChildCount() ) colInd = values[item]; else colInd = item; dc.SetBrush( wxColour( prop->GetColour( colInd ) ) ); } else if ( !prop->IsValueUnspecified() ) dc.SetBrush( prop->GetVal().m_colour ); else dc.SetBrush( *wxWHITE ); wxRect imageRect = propertyGrid->GetImageRect(property, item); wxLogDebug(wxT("%i, %i"),imageRect.x,imageRect.y); dc.DrawRectangle( rect.x+imageRect.x, rect.y+imageRect.y, imageRect.width, imageRect.height ); wxString text; if ( item == -1 ) text = property->GetValueAsString(); else text = property->GetChoiceString(item); DrawText( dc, rect, imageRect.width, text ); } protected: }; wxPGColourPropertyRenderer g_wxPGColourPropertyRenderer; wxPGCellRenderer* wxSystemColourProperty::GetCellRenderer( int column ) const { if ( column == 1 ) return &g_wxPGColourPropertyRenderer; return wxEnumProperty::GetCellRenderer(column); }*/ void wxSystemColourProperty::OnCustomPaint( wxDC& dc, const wxRect& rect, wxPGPaintData& paintdata ) { wxColour col; 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 ); } else if ( !IsValueUnspecified() ) { col = GetVal().m_colour; } if ( col.IsOk() ) { dc.SetBrush(col); dc.DrawRectangle(rect); } } bool wxSystemColourProperty::StringToValue( wxVariant& value, const wxString& text, int argFlags ) const { const int custIndex = GetCustomColourIndex(); wxString custColName; if (custIndex != wxNOT_FOUND) custColName = m_choices.GetLabel(custIndex); wxString colStr(text); colStr.Trim(true); colStr.Trim(false); const bool isCustomColour = (colStr == custColName); wxColour customColour; bool conversionSuccess = false; if ( !isCustomColour ) { if ( colStr.Find(wxS("(")) == 0 ) { // Eliminate whitespace colStr.Replace(wxS(" "), wxEmptyString); int commaCount = colStr.Freq(wxS(',')); if ( commaCount == 2 ) { // Convert (R,G,B) to rgb(R,G,B) colStr = wxS("rgb") + colStr; } else if ( commaCount == 3 ) { // We have int alpha, CSS format that wxColour takes as // input processes float alpha. So, let's parse the colour // ourselves instead of trying to convert it to a format // that wxColour::FromString() understands. int r = -1, g = -1, b = -1, a = -1; wxSscanf(colStr, wxS("(%i,%i,%i,%i)"), &r, &g, &b, &a); customColour.Set(r, g, b, a); conversionSuccess = customColour.IsOk(); } } if ( !conversionSuccess ) conversionSuccess = customColour.Set(colStr); } if ( !conversionSuccess && m_choices.GetCount() && !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) && isCustomColour ) { if ( !(argFlags & wxPG_EDITABLE_VALUE )) { // This really should not occur... // wxASSERT(false); return false; } if ( !QueryColourFromUser(value) ) { if ( !(argFlags & wxPG_PROPERTY_SPECIFIC) ) return false; // If query for value comes from the event handler // use current pending value to be processed later on in OnEvent(). SetValueInEvent(value); } } else { wxColourPropertyValue val; bool done = false; if ( !conversionSuccess ) { // Try predefined colour first int index; bool res = ValueFromString_(value, &index, colStr, argFlags); if ( res && index >= 0 ) { val.m_type = index; if ( val.m_type < m_choices.GetCount() ) val.m_type = m_choices[val.m_type].GetValue(); // Get proper colour for type. val.m_colour = GetColour(val.m_type); done = true; } } else { val.m_type = wxPG_COLOUR_CUSTOM; val.m_colour = customColour; done = true; } if ( !done ) { return false; } value = DoTranslateVal(val); } return true; } bool wxSystemColourProperty::DoSetAttribute( const wxString& name, wxVariant& value ) { if ( name == wxPG_COLOUR_ALLOW_CUSTOM ) { int ival = value.GetLong(); if ( ival && (m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) ) { // Show custom choice m_choices.Add(_("Custom"), wxPG_COLOUR_CUSTOM); m_flags &= ~(wxPG_PROP_HIDE_CUSTOM_COLOUR); } else if ( !ival && !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) ) { // Hide custom choice m_choices.RemoveAt(GetCustomColourIndex()); m_flags |= wxPG_PROP_HIDE_CUSTOM_COLOUR; } return true; } return false; } // ----------------------------------------------------------------------- // wxColourProperty // ----------------------------------------------------------------------- static const char* const gs_cp_es_normcolour_labels[] = { wxTRANSLATE("Black"), wxTRANSLATE("Maroon"), wxTRANSLATE("Navy"), wxTRANSLATE("Purple"), wxTRANSLATE("Teal"), wxTRANSLATE("Gray"), wxTRANSLATE("Green"), wxTRANSLATE("Olive"), wxTRANSLATE("Brown"), wxTRANSLATE("Blue"), wxTRANSLATE("Fuchsia"), wxTRANSLATE("Red"), wxTRANSLATE("Orange"), wxTRANSLATE("Silver"), wxTRANSLATE("Lime"), wxTRANSLATE("Aqua"), wxTRANSLATE("Yellow"), wxTRANSLATE("White"), wxTRANSLATE("Custom"), NULL }; static const long gs_cp_es_normcolour_values[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, wxPG_COLOUR_CUSTOM }; static const unsigned long gs_cp_es_normcolour_colours[] = { wxPG_COLOUR(0,0,0), wxPG_COLOUR(128,0,0), wxPG_COLOUR(0,0,128), wxPG_COLOUR(128,0,128), wxPG_COLOUR(0,128,128), wxPG_COLOUR(128,128,128), wxPG_COLOUR(0,128,0), wxPG_COLOUR(128,128,0), wxPG_COLOUR(166,124,81), wxPG_COLOUR(0,0,255), wxPG_COLOUR(255,0,255), wxPG_COLOUR(255,0,0), wxPG_COLOUR(247,148,28), wxPG_COLOUR(192,192,192), wxPG_COLOUR(0,255,0), wxPG_COLOUR(0,255,255), wxPG_COLOUR(255,255,0), wxPG_COLOUR(255,255,255), wxPG_COLOUR(0,0,0) }; WX_PG_IMPLEMENT_PROPERTY_CLASS(wxColourProperty, wxSystemColourProperty, wxColour, const wxColour&, TextCtrlAndButton) static wxPGChoices gs_wxColourProperty_choicesCache; wxColourProperty::wxColourProperty( const wxString& label, const wxString& name, const wxColour& value ) : wxSystemColourProperty(label, name, gs_cp_es_normcolour_labels, gs_cp_es_normcolour_values, &gs_wxColourProperty_choicesCache, value ) { wxASSERT_MSG( wxTheColourDatabase, wxT("No colour database") ); if ( wxTheColourDatabase ) { // Extend colour database with PG-specific colours. const char* const* colourLabels = gs_cp_es_normcolour_labels; for ( int i = 0; *colourLabels; colourLabels++, i++ ) { // Don't take into account user-defined custom colour. if (gs_cp_es_normcolour_values[i] != wxPG_COLOUR_CUSTOM) { wxColour clr = wxTheColourDatabase->Find(*colourLabels); // Use standard wx colour value if its label was found, // otherwise register custom PG colour. if ( !clr.IsOk() ) { clr.Set(gs_cp_es_normcolour_colours[i]); wxTheColourDatabase->AddColour(*colourLabels, clr); } } } } Init( value ); m_flags |= wxPG_PROP_TRANSLATE_CUSTOM; } wxColourProperty::~wxColourProperty() { } void wxColourProperty::Init( wxColour colour ) { if ( !colour.IsOk() ) colour = *wxWHITE; wxVariant variant; variant << colour; m_value = variant; int ind = ColToInd(colour); if ( ind < 0 ) ind = m_choices.GetCount() - 1; SetIndex( ind ); } wxString wxColourProperty::ValueToString( wxVariant& value, int argFlags ) const { const wxPGEditor* editor = GetEditorClass(); if ( editor != wxPGEditor_Choice && editor != wxPGEditor_ChoiceAndButton && editor != wxPGEditor_ComboBox ) argFlags |= wxPG_PROPERTY_SPECIFIC; return wxSystemColourProperty::ValueToString(value, argFlags); } wxColour wxColourProperty::GetColour( int index ) const { return wxColour(gs_cp_es_normcolour_labels[m_choices.GetValue(index)]); } wxVariant wxColourProperty::DoTranslateVal( wxColourPropertyValue& v ) const { wxVariant variant; variant << v.m_colour; return variant; } // ----------------------------------------------------------------------- // wxCursorProperty // ----------------------------------------------------------------------- #if wxPG_CAN_DRAW_CURSOR #define wxPG_CURSOR_IMAGE_WIDTH 32 #endif #define NUM_CURSORS 28 //#define wx_cp_es_syscursors_len 28 static const char* const gs_cp_es_syscursors_labels[NUM_CURSORS+1] = { wxTRANSLATE("Default"), wxTRANSLATE("Arrow"), wxTRANSLATE("Right Arrow"), wxTRANSLATE("Blank"), wxTRANSLATE("Bullseye"), wxTRANSLATE("Character"), wxTRANSLATE("Cross"), wxTRANSLATE("Hand"), wxTRANSLATE("I-Beam"), wxTRANSLATE("Left Button"), wxTRANSLATE("Magnifier"), wxTRANSLATE("Middle Button"), wxTRANSLATE("No Entry"), wxTRANSLATE("Paint Brush"), wxTRANSLATE("Pencil"), wxTRANSLATE("Point Left"), wxTRANSLATE("Point Right"), wxTRANSLATE("Question Arrow"), wxTRANSLATE("Right Button"), wxTRANSLATE("Sizing NE-SW"), wxTRANSLATE("Sizing N-S"), wxTRANSLATE("Sizing NW-SE"), wxTRANSLATE("Sizing W-E"), wxTRANSLATE("Sizing"), wxTRANSLATE("Spraycan"), wxTRANSLATE("Wait"), wxTRANSLATE("Watch"), wxTRANSLATE("Wait Arrow"), NULL }; static const long gs_cp_es_syscursors_values[NUM_CURSORS] = { wxCURSOR_NONE, wxCURSOR_ARROW, wxCURSOR_RIGHT_ARROW, wxCURSOR_BLANK, wxCURSOR_BULLSEYE, wxCURSOR_CHAR, wxCURSOR_CROSS, wxCURSOR_HAND, wxCURSOR_IBEAM, wxCURSOR_LEFT_BUTTON, wxCURSOR_MAGNIFIER, wxCURSOR_MIDDLE_BUTTON, wxCURSOR_NO_ENTRY, wxCURSOR_PAINT_BRUSH, wxCURSOR_PENCIL, wxCURSOR_POINT_LEFT, wxCURSOR_POINT_RIGHT, wxCURSOR_QUESTION_ARROW, wxCURSOR_RIGHT_BUTTON, wxCURSOR_SIZENESW, wxCURSOR_SIZENS, wxCURSOR_SIZENWSE, wxCURSOR_SIZEWE, wxCURSOR_SIZING, wxCURSOR_SPRAYCAN, wxCURSOR_WAIT, wxCURSOR_WATCH, wxCURSOR_ARROWWAIT }; IMPLEMENT_DYNAMIC_CLASS(wxCursorProperty, wxEnumProperty) static wxPGChoices gs_wxCursorProperty_choicesCache; wxCursorProperty::wxCursorProperty( const wxString& label, const wxString& name, int value ) : wxEnumProperty( label, name, gs_cp_es_syscursors_labels, gs_cp_es_syscursors_values, &gs_wxCursorProperty_choicesCache, value ) { m_flags |= wxPG_PROP_STATIC_CHOICES; // Cursor selection cannot be changed. } wxCursorProperty::~wxCursorProperty() { } wxSize wxCursorProperty::OnMeasureImage( int item ) const { #if wxPG_CAN_DRAW_CURSOR if ( item != -1 && item < NUM_CURSORS ) return wxSize(wxPG_CURSOR_IMAGE_WIDTH,wxPG_CURSOR_IMAGE_WIDTH); #else wxUnusedVar(item); #endif return wxSize(0,0); } #if wxPG_CAN_DRAW_CURSOR void wxCursorProperty::OnCustomPaint( wxDC& dc, const wxRect& rect, wxPGPaintData& paintdata ) { // Background brush dc.SetBrush( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) ); if ( paintdata.m_choiceItem >= 0 ) { dc.DrawRectangle( rect ); if ( paintdata.m_choiceItem < NUM_CURSORS ) { wxStockCursor cursorIndex = (wxStockCursor) gs_cp_es_syscursors_values[paintdata.m_choiceItem]; if ( cursorIndex == wxCURSOR_NONE ) cursorIndex = wxCURSOR_ARROW; wxCursor cursor( cursorIndex ); #if defined(__WXMSW__) || ( defined(__WXGTK__) && defined(__WXGTK20__) ) wxBitmap bmp(cursor); if ( bmp.IsOk() ) { dc.DrawBitmap(bmp, rect.GetTopLeft(), true); } #endif } } } #else void wxCursorProperty::OnCustomPaint( wxDC&, const wxRect&, wxPGPaintData& ) { } /*wxPGCellRenderer* wxCursorProperty::GetCellRenderer( int column ) const { return wxEnumProperty::GetCellRenderer(column); }*/ #endif // ----------------------------------------------------------------------- // wxImageFileProperty // ----------------------------------------------------------------------- #if wxUSE_IMAGE const wxString& wxPGGetDefaultImageWildcard() { // Form the wildcard, if not done yet if ( wxPGGlobalVars->m_pDefaultImageWildcard.empty() ) { wxString str; // TODO: This section may require locking (using global). wxList& handlers = wxImage::GetHandlers(); wxList::iterator node; // Let's iterate over the image handler list. //for ( wxList::Node *node = handlers.GetFirst(); node; node = node->GetNext() ) for ( node = handlers.begin(); node != handlers.end(); ++node ) { wxImageHandler *handler = (wxImageHandler*)*node; wxString ext_lo = handler->GetExtension(); wxString ext_up = ext_lo.Upper(); str.append( ext_up ); str.append( wxT(" files (*.") ); str.append( ext_up ); str.append( wxT(")|*.") ); str.append( ext_lo ); str.append( wxT("|") ); } str.append ( wxT("All files (*.*)|*.*") ); wxPGGlobalVars->m_pDefaultImageWildcard = str; } return wxPGGlobalVars->m_pDefaultImageWildcard; } IMPLEMENT_DYNAMIC_CLASS(wxImageFileProperty, wxFileProperty) wxImageFileProperty::wxImageFileProperty( const wxString& label, const wxString& name, const wxString& value ) : wxFileProperty(label,name,value) { SetAttribute( wxPG_FILE_WILDCARD, wxPGGetDefaultImageWildcard() ); m_pImage = NULL; m_pBitmap = NULL; LoadImageFromFile(); } wxImageFileProperty::~wxImageFileProperty() { if ( m_pBitmap ) delete m_pBitmap; if ( m_pImage ) delete m_pImage; } void wxImageFileProperty::OnSetValue() { wxFileProperty::OnSetValue(); // Delete old image wxDELETE(m_pImage); wxDELETE(m_pBitmap); LoadImageFromFile(); } void wxImageFileProperty::LoadImageFromFile() { wxFileName filename = GetFileName(); // Create the image thumbnail if ( filename.FileExists() ) { m_pImage = new wxImage( filename.GetFullPath() ); } } wxSize wxImageFileProperty::OnMeasureImage( int ) const { return wxPG_DEFAULT_IMAGE_SIZE; } void wxImageFileProperty::OnCustomPaint( wxDC& dc, const wxRect& rect, wxPGPaintData& ) { if ( m_pBitmap || (m_pImage && m_pImage->IsOk() ) ) { // Draw the thumbnail // Create the bitmap here because required size is not known in OnSetValue(). if ( !m_pBitmap ) { m_pImage->Rescale( rect.width, rect.height ); m_pBitmap = new wxBitmap( *m_pImage ); wxDELETE(m_pImage); } dc.DrawBitmap( *m_pBitmap, rect.x, rect.y, false ); } else { // No file - just draw a white box dc.SetBrush( *wxWHITE_BRUSH ); dc.DrawRectangle ( rect ); } } #endif // wxUSE_IMAGE // ----------------------------------------------------------------------- // wxMultiChoiceProperty // ----------------------------------------------------------------------- #if wxUSE_CHOICEDLG #include "wx/choicdlg.h" WX_PG_IMPLEMENT_PROPERTY_CLASS(wxMultiChoiceProperty,wxPGProperty, wxArrayInt,const wxArrayInt&,TextCtrlAndButton) wxMultiChoiceProperty::wxMultiChoiceProperty( const wxString& label, const wxString& name, const wxPGChoices& choices, const wxArrayString& value) : wxPGProperty(label,name) { m_choices.Assign(choices); SetValue(value); } wxMultiChoiceProperty::wxMultiChoiceProperty( const wxString& label, const wxString& name, const wxArrayString& strings, const wxArrayString& value) : wxPGProperty(label,name) { m_choices.Set(strings); SetValue(value); } wxMultiChoiceProperty::wxMultiChoiceProperty( const wxString& label, const wxString& name, const wxArrayString& value) : wxPGProperty(label,name) { wxArrayString strings; m_choices.Set(strings); SetValue(value); } wxMultiChoiceProperty::~wxMultiChoiceProperty() { } void wxMultiChoiceProperty::OnSetValue() { GenerateValueAsString(m_value, &m_display); } wxString wxMultiChoiceProperty::ValueToString( wxVariant& value, int argFlags ) const { // If possible, use cached string if ( argFlags & wxPG_VALUE_IS_CURRENT ) return m_display; wxString s; GenerateValueAsString(value, &s); return s; } void wxMultiChoiceProperty::GenerateValueAsString( wxVariant& value, wxString* target ) const { wxArrayString strings; if ( value.GetType() == wxPG_VARIANT_TYPE_ARRSTRING ) strings = value.GetArrayString(); wxString& tempStr = *target; unsigned int i; unsigned int itemCount = strings.size(); tempStr.Empty(); if ( itemCount ) tempStr.append( wxT("\"") ); for ( i = 0; i < itemCount; i++ ) { tempStr.append( strings[i] ); tempStr.append( wxT("\"") ); if ( i < (itemCount-1) ) tempStr.append ( wxT(" \"") ); } } wxArrayInt wxMultiChoiceProperty::GetValueAsIndices() const { wxVariant variant = GetValue(); const wxArrayInt& valueArr = wxArrayIntRefFromVariant(variant); unsigned int i; // Translate values to string indices. wxArrayInt selections; if ( !m_choices.IsOk() || !m_choices.GetCount() || !(&valueArr) ) { for ( i=0; i= 0 ) selections.Add(sIndex); } } return selections; } bool wxMultiChoiceProperty::OnEvent( wxPropertyGrid* propgrid, wxWindow* WXUNUSED(primary), wxEvent& event ) { if ( propgrid->IsMainButtonEvent(event) ) { // Update the value wxVariant useValue = propgrid->GetUncommittedPropertyValue(); wxArrayString labels = m_choices.GetLabels(); unsigned int choiceCount; if ( m_choices.IsOk() ) choiceCount = m_choices.GetCount(); else choiceCount = 0; // launch editor dialog wxMultiChoiceDialog dlg( propgrid, _("Make a selection:"), m_label, choiceCount, choiceCount?&labels[0]:NULL, wxCHOICEDLG_STYLE ); dlg.Move( propgrid->GetGoodEditorDialogPosition(this,dlg.GetSize()) ); wxArrayString strings = useValue.GetArrayString(); wxArrayString extraStrings; dlg.SetSelections(m_choices.GetIndicesForStrings(strings, &extraStrings)); if ( dlg.ShowModal() == wxID_OK && choiceCount ) { int userStringMode = GetAttributeAsLong(wxT("UserStringMode"), 0); wxArrayInt arrInt = dlg.GetSelections(); wxVariant variant; // Strings that were not in list of choices wxArrayString value; // Translate string indices to strings unsigned int n; if ( userStringMode == 1 ) { for (n=0;n 0 || (m_choices.IsOk() && m_choices.Index( token ) != wxNOT_FOUND) ) arr.Add(token); WX_PG_TOKENIZER2_END() wxVariant v( WXVARIANT(arr) ); variant = v; return true; } #endif // wxUSE_CHOICEDLG // ----------------------------------------------------------------------- // wxDateProperty // ----------------------------------------------------------------------- #if wxUSE_DATETIME #if wxUSE_DATEPICKCTRL #define dtCtrl DatePickerCtrl #else #define dtCtrl TextCtrl #endif WX_PG_IMPLEMENT_PROPERTY_CLASS(wxDateProperty, wxPGProperty, wxDateTime, const wxDateTime&, dtCtrl) wxString wxDateProperty::ms_defaultDateFormat; wxDateProperty::wxDateProperty( const wxString& label, const wxString& name, const wxDateTime& value ) : wxPGProperty(label,name) { //wxPGRegisterDefaultValueType(wxDateTime) #if wxUSE_DATEPICKCTRL wxPGRegisterEditorClass(DatePickerCtrl); m_dpStyle = wxDP_DEFAULT | wxDP_SHOWCENTURY; #else m_dpStyle = 0; #endif SetValue( value ); } 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; // 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 ) { variant = dt; return true; } return false; } wxString wxDateProperty::ValueToString( wxVariant& value, int argFlags ) const { const wxChar* format = (const wxChar*) NULL; wxDateTime dateTime = value.GetDateTime(); if ( !dateTime.IsValid() ) return wxT("Invalid"); if ( ms_defaultDateFormat.empty() ) { #if wxUSE_DATEPICKCTRL bool showCentury = m_dpStyle & wxDP_SHOWCENTURY ? true : false; #else bool showCentury = true; #endif ms_defaultDateFormat = DetermineDefaultDateFormat( showCentury ); } if ( !m_format.empty() && !(argFlags & wxPG_FULL_VALUE) ) format = m_format.c_str(); // Determine default from locale // NB: This is really simple stuff, but can't figure anything // better without proper support in wxLocale if ( !format ) format = ms_defaultDateFormat.c_str(); return dateTime.Format(format); } wxString wxDateProperty::DetermineDefaultDateFormat( bool showCentury ) { // This code is basically copied from datectlg.cpp's SetFormat // wxString format; wxDateTime dt; dt.ParseFormat(wxT("2003-10-13"), wxT("%Y-%m-%d")); wxString str(dt.Format(wxT("%x"))); const wxChar *p = str.c_str(); while ( *p ) { int n=wxAtoi(p); if (n == dt.GetDay()) { format.Append(wxT("%d")); p += 2; } else if (n == (int)dt.GetMonth()+1) { format.Append(wxT("%m")); p += 2; } else if (n == dt.GetYear()) { format.Append(wxT("%Y")); p += 4; } else if (n == (dt.GetYear() % 100)) { if (showCentury) format.Append(wxT("%Y")); else format.Append(wxT("%y")); p += 2; } else format.Append(*p++); } return format; } bool wxDateProperty::DoSetAttribute( const wxString& name, wxVariant& value ) { if ( name == wxPG_DATE_FORMAT ) { m_format = value.GetString(); return true; } else if ( name == wxPG_DATE_PICKER_STYLE ) { m_dpStyle = value.GetLong(); ms_defaultDateFormat.clear(); // This may need recalculation return true; } return false; } #endif // wxUSE_DATETIME // ----------------------------------------------------------------------- // wxPropertyGridInterface // ----------------------------------------------------------------------- void wxPropertyGridInterface::InitAllTypeHandlers() { } // ----------------------------------------------------------------------- void wxPropertyGridInterface::RegisterAdditionalEditors() { // Register editor classes, if necessary. if ( wxPGGlobalVars->m_mapEditorClasses.empty() ) wxPropertyGrid::RegisterDefaultEditors(); #if wxUSE_SPINBTN wxPGRegisterEditorClass(SpinCtrl); #endif #if wxUSE_DATEPICKCTRL wxPGRegisterEditorClass(DatePickerCtrl); #endif } // ----------------------------------------------------------------------- #endif // wxPG_INCLUDE_ADVPROPS #endif // wxUSE_PROPGRID