///////////////////////////////////////////////////////////////////////////// // 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" // Drawing ARGB on standard DC is supported by OSX and GTK3 #if defined(__WXOSX__) || defined(__WXGTK3__) #define wxPG_DC_SUPPORTS_ALPHA 1 #else #define wxPG_DC_SUPPORTS_ALPHA 0 #endif // __WXOSX__ || __WXGTK3__ #define wxPG_USE_GC_FOR_ALPHA (wxUSE_GRAPHICS_CONTEXT && !wxPG_DC_SUPPORTS_ALPHA) #if wxPG_USE_GC_FOR_ALPHA #include "wx/dcgraph.h" #include "wx/dcmemory.h" // for wxDynamicCast purposes #if wxUSE_METAFILE #include "wx/metafile.h" // for wxDynamicCast purposes #endif // wxUSE_METAFILE #endif // wxPG_USE_GC_FOR_ALPHA // ----------------------------------------------------------------------- #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. wxIMPLEMENT_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; for ( size_t i = 0; i < array1.size(); i++ ) { if ( array1[i] != array2[i] ) return false; } return true; } // ----------------------------------------------------------------------- // wxSpinCtrl-based property editor // ----------------------------------------------------------------------- #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; Bind(wxEVT_LEFT_DOWN, &wxPGSpinButton::OnMouseEvent, this); Bind(wxEVT_LEFT_UP, &wxPGSpinButton::OnMouseEvent, this); Bind(wxEVT_MOTION, &wxPGSpinButton::OnMouseEvent, this); Bind(wxEVT_MOUSE_CAPTURE_LOST, &wxPGSpinButton::OnMouseCaptureLost, this); } 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) // 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; wxSpinButton* wnd2; #if IS_MOTION_SPIN_SUPPORTED if ( property->GetAttributeAsLong(wxPG_ATTR_SPINCTRL_MOTION, 0) ) { wnd2 = new wxPGSpinButton(); } else #endif { wnd2 = new wxSpinButton(); } #ifdef __WXMSW__ wnd2->Hide(); #endif wnd2->Create( propgrid->GetPanel(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_VERTICAL ); // Scale spin button to the required height (row height) wxSize butSz = wnd2->GetBestSize(); #ifdef __WXGTK3__ // Under GTK+ 3 spin button is always horizontal and cannot be downscaled int butWidth = butSz.x; #else double sc = (double)sz.y / butSz.y; int butWidth = wxMax(18, wxRound(sc*butSz.x)); #endif wxSize tcSz(sz.x - butWidth - margin, sz.y); wnd2->SetSize(pos.x + tcSz.x + margin, pos.y, butWidth, sz.y); 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 { wxEventType evtType = event.GetEventType(); bool bigStep = false; if ( evtType == wxEVT_KEY_DOWN ) { wxKeyEvent& keyEvent = (wxKeyEvent&)event; int keycode; 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 ) { int spins = 1; #if IS_MOTION_SPIN_SUPPORTED if ( property->GetAttributeAsLong(wxPG_ATTR_SPINCTRL_MOTION, 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() == wxPG_VARIANT_TYPE_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); wxVariant v(v_d); s = property->ValueToString(v, 0); } else { return false; } } else { long step = property->GetAttributeAsLong(wxPG_ATTR_SPINCTRL_STEP, 1); #if defined(wxLongLong_t) && wxUSE_LONGLONG wxLongLong_t v_ll; // Try long long if ( s.ToLongLong(&v_ll, 10) ) #else long v_ll; // Try long if ( s.ToLong(&v_ll, 10) ) #endif { 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); #if defined(wxLongLong_t) && wxUSE_LONGLONG s = wxLongLong(v_ll).ToString(); #else s = wxString::Format(wxS("%ld"), v_ll); #endif } 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 { wxDECLARE_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, wxS("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.IsType(wxPG_VARIANT_TYPE_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.IsType(wxPG_VARIANT_TYPE_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("Thin"), wxT("ExtraLight"), wxT("Light"), wxT("Normal"), wxT("Medium"), wxT("SemiBold"), wxT("Bold"), wxT("ExtraBold"), wxT("Heavy"), wxT("ExtraHeavy"), (const wxChar*) NULL }; static const long gs_fp_es_weight_values[] = { wxFONTWEIGHT_THIN, wxFONTWEIGHT_EXTRALIGHT, wxFONTWEIGHT_LIGHT, wxFONTWEIGHT_NORMAL, wxFONTWEIGHT_MEDIUM, wxFONTWEIGHT_SEMIBOLD, wxFONTWEIGHT_BOLD, wxFONTWEIGHT_EXTRABOLD, wxFONTWEIGHT_HEAVY, wxFONTWEIGHT_EXTRAHEAVY }; // Class body is in advprops.h wxPG_IMPLEMENT_PROPERTY_CLASS(wxFontProperty,wxPGProperty,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); } wxFont font; font << m_value; /* TRANSLATORS: Label of font point size */ 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); /* TRANSLATORS: Label of font face name */ wxPGProperty* p = new wxEnumProperty(_("Face Name"), wxS("Face Name"), *wxPGGlobalVars->m_fontFamilyChoices); p->SetValueFromString(faceName, wxPG_FULL_VALUE); AddPrivateChild( p ); /* TRANSLATORS: Label of font style */ AddPrivateChild( new wxEnumProperty(_("Style"), wxS("Style"), gs_fp_es_style_labels,gs_fp_es_style_values, font.GetStyle()) ); /* TRANSLATORS: Label of font weight */ AddPrivateChild( new wxEnumProperty(_("Weight"), wxS("Weight"), gs_fp_es_weight_labels,gs_fp_es_weight_values, font.GetWeight()) ); /* TRANSLATORS: Label of underlined font */ AddPrivateChild( new wxBoolProperty(_("Underlined"), wxS("Underlined"), font.GetUnderlined()) ); /* TRANSLATORS: Label of font family */ 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.IsType(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_THIN || wt > wxFONTWEIGHT_MAX ) 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 wxPG_DEFAULT_IMAGE_SIZE; } 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( wxS("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 #define wxPG_PROP_COLOUR_HAS_ALPHA wxPG_PROP_CLASS_SPECIFIC_3 #include "wx/colordlg.h" static const char* const gs_cp_es_syscolour_labels[] = { /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("AppWorkspace"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("ActiveBorder"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("ActiveCaption"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("ButtonFace"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("ButtonHighlight"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("ButtonShadow"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("ButtonText"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("CaptionText"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("ControlDark"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("ControlLight"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("Desktop"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("GrayText"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("Highlight"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("HighlightText"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("InactiveBorder"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("InactiveCaption"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("InactiveCaptionText"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("Menu"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("Scrollbar"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("Tooltip"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("TooltipText"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("Window"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("WindowFrame"), /* TRANSLATORS: Keyword of system colour */ wxTRANSLATE("WindowText"), /* TRANSLATORS: Custom colour choice entry */ 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 wxPG_IMPLEMENT_PROPERTY_CLASS(wxSystemColourProperty,wxEnumProperty,Choice) void wxSystemColourProperty::Init( int type, const wxColour& colour ) { wxColourPropertyValue cpv; cpv.Init(type, colour.IsOk() ? colour : *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 ) { Init( value.m_type, value.m_colour ); } 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 ) { Init( value.m_type, value.m_colour ); } 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 ) { Init( wxPG_COLOUR_CUSTOM, value ); } wxSystemColourProperty::~wxSystemColourProperty() { } wxColourPropertyValue wxSystemColourProperty::GetVal( const wxVariant* pVariant ) const { if ( !pVariant ) pVariant = &m_value; if ( pVariant->IsNull() ) return wxColourPropertyValue(wxPG_COLOUR_UNSPECIFIED, wxColour()); const wxString valType(pVariant->GetType()); if ( valType == wxS("wxColourPropertyValue") ) { wxColourPropertyValue v; v << *pVariant; return v; } wxColour col; bool variantProcessed = true; if ( valType == wxS("wxColour*") ) { wxColour* pCol = wxStaticCast(pVariant->GetWxObjectPtr(), wxColour); col = *pCol; } else if ( valType == wxS("wxColour") ) { col << *pVariant; } else if ( valType == 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.SetChooseAlpha((m_flags & wxPG_PROP_COLOUR_HAS_ALPHA) != 0); data.SetColour(val.m_colour); for ( int i = 0; i < wxColourData::NUM_CUSTOM; i++ ) { unsigned char n = i*(256/wxColourData::NUM_CUSTOM); data.SetCustomColour(i, wxColour(n, n, n)); } 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(wxS("%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() ) { #if wxPG_USE_GC_FOR_ALPHA wxGCDC *gdc = NULL; if ( col.Alpha() != wxALPHA_OPAQUE ) { if ( wxPaintDC *paintdc = wxDynamicCast(&dc, wxPaintDC) ) { gdc = new wxGCDC(*paintdc); } else if ( wxMemoryDC *memdc = wxDynamicCast(&dc, wxMemoryDC) ) { gdc = new wxGCDC(*memdc); } #if wxUSE_METAFILE && defined(wxMETAFILE_IS_ENH) else if ( wxMetafileDC *metadc = wxDynamicCast(&dc, wxMetafileDC) ) { gdc = new wxGCDC(*metadc); } #endif else { wxFAIL_MSG( wxS("Unknown wxDC kind") ); } } if ( gdc ) { gdc->SetBrush(col); gdc->DrawRectangle(rect); delete gdc; } else #endif // wxPG_USE_GC_FOR_ALPHA { 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 ) { bool allow = value.GetBool(); if ( allow && (m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) ) { // Show custom choice /* TRANSLATORS: Custom colour choice entry */ m_choices.Add(_("Custom"), wxPG_COLOUR_CUSTOM); m_flags &= ~(wxPG_PROP_HIDE_CUSTOM_COLOUR); } else if ( !allow && !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) ) { // Hide custom choice m_choices.RemoveAt(GetCustomColourIndex()); m_flags |= wxPG_PROP_HIDE_CUSTOM_COLOUR; } return true; } else if ( name == wxPG_COLOUR_HAS_ALPHA ) { ChangeFlag(wxPG_PROP_COLOUR_HAS_ALPHA, value.GetBool()); return true; } return wxEnumProperty::DoSetAttribute(name, value); } // ----------------------------------------------------------------------- // 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"), /* TRANSLATORS: Custom colour choice entry */ 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) }; wxPG_IMPLEMENT_PROPERTY_CLASS(wxColourProperty, wxSystemColourProperty, 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, wxS("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 static const char* const gs_cp_es_syscursors_labels[NUM_CURSORS+1] = { /* TRANSLATORS: System cursor name */ wxTRANSLATE("Default"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Arrow"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Right Arrow"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Blank"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Bullseye"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Character"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Cross"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Hand"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("I-Beam"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Left Button"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Magnifier"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Middle Button"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("No Entry"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Paint Brush"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Pencil"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Point Left"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Point Right"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Question Arrow"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Right Button"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Sizing NE-SW"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Sizing N-S"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Sizing NW-SE"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Sizing W-E"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Sizing"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Spraycan"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Wait"), /* TRANSLATORS: System cursor name */ wxTRANSLATE("Watch"), /* TRANSLATORS: System cursor name */ 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 }; wxIMPLEMENT_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( wxS(" files (*.") ); str.append( ext_up ); str.append( wxS(")|*.") ); str.append( ext_lo ); str.append( wxS("|") ); } str.append ( wxS("All files (*.*)|*.*") ); wxPGGlobalVars->m_pDefaultImageWildcard = str; } return wxPGGlobalVars->m_pDefaultImageWildcard; } wxIMPLEMENT_DYNAMIC_CLASS(wxImageFileProperty, wxFileProperty); wxImageFileProperty::wxImageFileProperty( const wxString& label, const wxString& name, const wxString& value ) : wxFileProperty(label,name,value) { m_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" wxPG_IMPLEMENT_PROPERTY_CLASS(wxMultiChoiceProperty,wxPGProperty, TextCtrlAndButton) wxMultiChoiceProperty::wxMultiChoiceProperty( const wxString& label, const wxString& name, const wxPGChoices& choices, const wxArrayString& value) : wxPGProperty(label,name) { m_userStringMode = 0; m_choices.Assign(choices); SetValue(value); } wxMultiChoiceProperty::wxMultiChoiceProperty( const wxString& label, const wxString& name, const wxArrayString& strings, const wxArrayString& value) : wxPGProperty(label,name) { m_userStringMode = 0; m_choices.Set(strings); SetValue(value); } wxMultiChoiceProperty::wxMultiChoiceProperty( const wxString& label, const wxString& name, const wxArrayString& value) : wxPGProperty(label,name) { m_userStringMode = 0; 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.IsType(wxPG_VARIANT_TYPE_ARRSTRING) ) strings = value.GetArrayString(); wxString& tempStr = *target; size_t itemCount = strings.size(); tempStr.Empty(); if ( itemCount ) tempStr.append( wxS("\"") ); for ( size_t i = 0; i < itemCount; i++ ) { tempStr.append( strings[i] ); tempStr.append( wxS("\"") ); if ( i < (itemCount-1) ) tempStr.append ( wxS(" \"") ); } } 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() ) { 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 ) { 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 ( m_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; } bool wxMultiChoiceProperty::DoSetAttribute( const wxString& name, wxVariant& value ) { if ( name == wxPG_ATTR_MULTICHOICE_USERSTRINGMODE ) { m_userStringMode = (int)value.GetLong(); return true; } return wxPGProperty::DoSetAttribute(name, value); } #endif // wxUSE_CHOICEDLG // ----------------------------------------------------------------------- // wxDateProperty // ----------------------------------------------------------------------- #if wxUSE_DATETIME #if wxUSE_DATEPICKCTRL #define dtCtrl DatePickerCtrl #else #define dtCtrl TextCtrl #endif wxPG_IMPLEMENT_PROPERTY_CLASS(wxDateProperty,wxPGProperty, 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.IsType(wxPG_VARIANT_TYPE_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 { wxDateTime dateTime = value.GetDateTime(); if ( !dateTime.IsValid() ) return wxS("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 ); } wxString format; if ( !m_format.empty() && !(argFlags & wxPG_FULL_VALUE) ) format = m_format; // Determine default from locale if ( format.empty() ) format = ms_defaultDateFormat; return dateTime.Format(format); } wxString wxDateProperty::DetermineDefaultDateFormat( bool showCentury ) { // This code is based on datectlg.cpp's GetLocaleDateFormat() #if wxUSE_INTL wxString format = wxLocale::GetOSInfo(wxLOCALE_SHORT_DATE_FMT); if ( showCentury ) format.Replace(wxS("%y"), wxS("%Y")); else format.Replace(wxS("%Y"), wxS("%y")); return format; #else return wxS("%x"); #endif // wxUSE_INTL/!wxUSE_INTL } 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 wxPGProperty::DoSetAttribute(name, value); } #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