X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b7bc9d806b57f20e1d3135025ba0e6f603e7450e..0c2a7270577c4d007d464ed28d8addb76a9a4a14:/src/propgrid/property.cpp diff --git a/src/propgrid/property.cpp b/src/propgrid/property.cpp index 10ba288e65..333a27d0c8 100644 --- a/src/propgrid/property.cpp +++ b/src/propgrid/property.cpp @@ -6,7 +6,7 @@ // Created: 2008-08-23 // RCS-ID: $Id$ // Copyright: (c) Jaakko Salli -// Licence: wxWindows license +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx/wx.h". @@ -94,8 +94,6 @@ wxSize wxPGCellRenderer::GetImageSize( const wxPGProperty* WXUNUSED(property), void wxPGCellRenderer::DrawText( wxDC& dc, const wxRect& rect, int xOffset, const wxString& text ) const { - if ( xOffset ) - xOffset += wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2; dc.DrawText( text, rect.x+xOffset+wxPG_XBEFORETEXT, rect.y+((rect.height-dc.GetCharHeight())/2) ); @@ -106,14 +104,11 @@ void wxPGCellRenderer::DrawEditorValue( wxDC& dc, const wxRect& rect, wxPGProperty* property, const wxPGEditor* editor ) const { - if ( xOffset ) - xOffset += wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2; - int yOffset = ((rect.height-dc.GetCharHeight())/2); if ( editor ) { - wxRect rect2(rect); + wxRect rect2(rect); rect2.x += xOffset; rect2.y += yOffset; rect2.height -= yOffset; @@ -135,13 +130,14 @@ void wxPGCellRenderer::DrawCaptionSelectionRect( wxDC& dc, int x, int y, int w, int wxPGCellRenderer::PreDrawCell( wxDC& dc, const wxRect& rect, const wxPGCell& cell, int flags ) const { - int imageOffset = 0; + int imageWidth = 0; // If possible, use cell colours if ( !(flags & DontUseCellBgCol) ) { - dc.SetPen(cell.GetBgCol()); - dc.SetBrush(cell.GetBgCol()); + const wxColour& bgCol = cell.GetBgCol(); + dc.SetPen(bgCol); + dc.SetBrush(bgCol); } if ( !(flags & DontUseCellFgCol) ) @@ -149,8 +145,15 @@ int wxPGCellRenderer::PreDrawCell( wxDC& dc, const wxRect& rect, const wxPGCell& dc.SetTextForeground(cell.GetFgCol()); } - // Draw Background - dc.DrawRectangle(rect); + // Draw Background, but only if not rendering in control + // (as control already has rendered correct background). + if ( !(flags & (Control|ChoicePopup)) ) + dc.DrawRectangle(rect); + + // Use cell font, if provided + const wxFont& font = cell.GetFont(); + if ( font.IsOk() ) + dc.SetFont(font); const wxBitmap& bmp = cell.GetBitmap(); if ( bmp.Ok() && @@ -162,20 +165,35 @@ int wxPGCellRenderer::PreDrawCell( wxDC& dc, const wxRect& rect, const wxPGCell& rect.x + wxPG_CONTROL_MARGIN + wxCC_CUSTOM_IMAGE_MARGIN1, rect.y + wxPG_CUSTOM_IMAGE_SPACINGY, true ); - imageOffset = bmp.GetWidth(); + imageWidth = bmp.GetWidth(); } - return imageOffset; + return imageWidth; +} + +void wxPGCellRenderer::PostDrawCell( wxDC& dc, + const wxPropertyGrid* propGrid, + const wxPGCell& cell, + int WXUNUSED(flags) ) const +{ + // Revert font + const wxFont& font = cell.GetFont(); + if ( font.IsOk() ) + dc.SetFont(propGrid->GetFont()); } // ----------------------------------------------------------------------- // wxPGDefaultRenderer // ----------------------------------------------------------------------- -void wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect, +bool wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect, const wxPropertyGrid* propertyGrid, wxPGProperty* property, int column, int item, int flags ) const { + const wxPGEditor* editor = NULL; + const wxPGCell* cell = NULL; + + wxString text; bool isUnspecified = property->IsValueUnspecified(); if ( column == 1 && item == -1 ) @@ -185,28 +203,30 @@ void wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect, { // Common Value if ( !isUnspecified ) - DrawText( dc, rect, 0, propertyGrid->GetCommonValueLabel(cmnVal) ); - return; + { + text = propertyGrid->GetCommonValueLabel(cmnVal); + DrawText( dc, rect, 0, text ); + if ( text.length() ) + return true; + } + return false; } } - const wxPGEditor* editor = NULL; - const wxPGCell* cell = NULL; - - wxString text; - int imageOffset = 0; + int imageWidth = 0; int preDrawFlags = flags; + bool res = false; property->GetDisplayInfo(column, item, flags, &text, &cell); - imageOffset = PreDrawCell( dc, rect, *cell, preDrawFlags ); + imageWidth = PreDrawCell( dc, rect, *cell, preDrawFlags ); if ( column == 1 ) { + editor = property->GetColumnEditor(column); + if ( !isUnspecified ) { - editor = property->GetColumnEditor(column); - // Regular property value wxSize imageSize = propertyGrid->GetImageSize(property, item); @@ -229,7 +249,7 @@ void wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect, property->OnCustomPaint( dc, imageRect, paintdata ); - imageOffset = paintdata.m_drawnWidth; + imageWidth = paintdata.m_drawnWidth; } text = property->GetValueAsString(); @@ -245,25 +265,40 @@ void wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect, if ( text.length() == 0 ) { - // Try to show inline help if no text - wxVariant vInlineHelp = property->GetAttribute(wxPGGlobalVars->m_strInlineHelp); - if ( !vInlineHelp.IsNull() ) + text = property->GetHintText(); + if ( text.length() > 0 ) { - text = vInlineHelp.GetString(); - dc.SetTextForeground(propertyGrid->GetCellDisabledTextColour()); + res = true; + + const wxColour& hCol = + propertyGrid->GetCellDisabledTextColour(); + dc.SetTextForeground(hCol); + + // Must make the editor NULL to override it's own rendering + // code. + editor = NULL; } } + else + { + res = true; + } } + int imageOffset = property->GetImageOffset(imageWidth); + DrawEditorValue( dc, rect, imageOffset, text, property, editor ); // active caption gets nice dotted rectangle - if ( property->IsCategory() /*&& column == 0*/ ) + if ( property->IsCategory() && column == 0 ) { if ( flags & Selected ) { if ( imageOffset > 0 ) + { + imageOffset -= DEFAULT_IMAGE_OFFSET_INCREMENT; imageOffset += wxCC_CUSTOM_IMAGE_MARGIN2 + 4; + } DrawCaptionSelectionRect( dc, rect.x+wxPG_XBEFORETEXT-wxPG_CAPRECTXMARGIN+imageOffset, @@ -274,6 +309,10 @@ void wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect, propertyGrid->GetFontHeight()+(wxPG_CAPRECTYMARGIN*2) ); } } + + PostDrawCell(dc, propertyGrid, *cell, preDrawFlags); + + return res; } wxSize wxPGDefaultRenderer::GetImageSize( const wxPGProperty* property, @@ -360,6 +399,13 @@ void wxPGCell::SetFgCol( const wxColour& col ) GetData()->SetFgCol(col); } +void wxPGCell::SetFont( const wxFont& font ) +{ + AllocExclusive(); + + GetData()->SetFont(font); +} + void wxPGCell::SetBgCol( const wxColour& col ) { AllocExclusive(); @@ -386,6 +432,12 @@ void wxPGCell::MergeFrom( const wxPGCell& srcCell ) data->SetBitmap(srcCell.GetBitmap()); } +void wxPGCell::SetEmptyData() +{ + AllocExclusive(); +} + + // ----------------------------------------------------------------------- // wxPGProperty // ----------------------------------------------------------------------- @@ -400,16 +452,16 @@ void wxPGProperty::Init() m_arrIndex = 0xFFFF; m_parent = NULL; - m_parentState = (wxPropertyGridPageState*) NULL; + m_parentState = NULL; m_clientData = NULL; m_clientObject = NULL; - m_customEditor = (wxPGEditor*) NULL; + m_customEditor = NULL; #if wxUSE_VALIDATORS - m_validator = (wxValidator*) NULL; + m_validator = NULL; #endif - m_valueBitmap = (wxBitmap*) NULL; + m_valueBitmap = NULL; m_maxLen = 0; // infinite maximum length @@ -537,10 +589,12 @@ void wxPGProperty::InitAfterAdded( wxPropertyGridPageState* pageState, if ( GetChildCount() ) { // Check parental flags - wxASSERT_MSG( (m_flags & wxPG_PROP_PARENTAL_FLAGS), - "Call SetFlag(wxPG_PROP_MISC_PARENT) or" - "SetFlag(wxPG_PROP_AGGREGATE) before calling" - "wxPGProperty::AddChild()." ); + wxASSERT_MSG( ((m_flags & wxPG_PROP_PARENTAL_FLAGS) == + wxPG_PROP_AGGREGATE) || + ((m_flags & wxPG_PROP_PARENTAL_FLAGS) == + wxPG_PROP_MISC_PARENT), + "wxPGProperty parental flags set incorrectly at " + "this time" ); if ( HasFlag(wxPG_PROP_AGGREGATE) ) { @@ -609,6 +663,15 @@ bool wxPGProperty::IsSomeParent( wxPGProperty* candidate ) const return false; } +void wxPGProperty::SetName( const wxString& newName ) +{ + wxPropertyGrid* pg = GetGrid(); + + if ( pg ) + pg->SetPropertyName(this, newName); + else + DoSetName(newName); +} wxString wxPGProperty::GetName() const { @@ -629,18 +692,7 @@ wxPropertyGrid* wxPGProperty::GetGrid() const int wxPGProperty::Index( const wxPGProperty* p ) const { - for ( unsigned int i = 0; iUpdateControl(this, primary); + return wxPGFindInVector(m_children, p); } bool wxPGProperty::ValidateValue( wxVariant& WXUNUSED(value), wxPGValidationInfo& WXUNUSED(validationInfo) ) const @@ -656,6 +708,10 @@ void wxPGProperty::RefreshChildren () { } +void wxPGProperty::OnValidationFailure( wxVariant& WXUNUSED(pendingValue) ) +{ +} + void wxPGProperty::GetDisplayInfo( unsigned int column, int choiceIndex, int flags, @@ -666,8 +722,17 @@ void wxPGProperty::GetDisplayInfo( unsigned int column, if ( !(flags & wxPGCellRenderer::ChoicePopup) ) { - // Not painting listi of choice popups, so get text from property - cell = &GetCell(column); + // Not painting list of choice popups, so get text from property + if ( column != 1 || !IsValueUnspecified() || IsCategory() ) + { + cell = &GetCell(column); + } + else + { + // Use special unspecified value cell + cell = &GetGrid()->GetUnspecifiedValueAppearance(); + } + if ( cell->HasText() ) { *pString = cell->GetText(); @@ -710,7 +775,7 @@ void wxPGProperty::GetDisplayInfo( unsigned int column, /* wxString wxPGProperty::GetColumnText( unsigned int col, int choiceIndex ) const { - + if ( col != 1 || choiceIndex == wxNOT_FOUND ) { const wxPGCell& cell = GetCell(col); @@ -816,7 +881,7 @@ void wxPGProperty::DoGenerateComposedValue( wxString& text, argFlags|wxPG_COMPOSITE_FRAGMENT); } } - + if ( childResults && curChild->GetChildCount() ) (*childResults)[curChild->GetName()] = s; @@ -888,8 +953,10 @@ wxString wxPGProperty::GetValueAsString( int argFlags ) const } #endif + wxPropertyGrid* pg = GetGrid(); + if ( IsValueUnspecified() ) - return wxEmptyString; + return pg->GetUnspecifiedValueText(argFlags); if ( m_commonValue == -1 ) { @@ -899,7 +966,6 @@ wxString wxPGProperty::GetValueAsString( int argFlags ) const // // Return common value's string representation - wxPropertyGrid* pg = GetGrid(); const wxPGCommonValue* cv = pg->GetCommonValue(m_commonValue); if ( argFlags & wxPG_FULL_VALUE ) @@ -957,14 +1023,8 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int int propagatedFlags = argFlags & (wxPG_REPORT_ERROR|wxPG_PROGRAMMATIC_VALUE); -#ifdef __WXDEBUG__ - bool debug_print = false; -#endif - -#ifdef __WXDEBUG__ - if ( debug_print ) - wxLogDebug(wxT(">> %s.StringToValue('%s')"),GetLabel().c_str(),text.c_str()); -#endif + wxLogTrace("propgrid", + wxT(">> %s.StringToValue('%s')"), GetLabel(), text); wxString::const_iterator it = text.begin(); wxUniChar a; @@ -976,6 +1036,11 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int for ( ;; ) { + // How many units we iterate string forward at the end of loop? + // We need to keep track of this or risk going to negative + // with it-- operation. + unsigned int strPosIncrement = 1; + if ( tokenStart != 0xFFFFFF ) { // Token is running @@ -989,21 +1054,31 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int { const wxPGProperty* child = Item(curChild); wxVariant variant(child->GetValue()); - variant.SetName(child->GetBaseName()); + wxString childName = child->GetBaseName(); - #ifdef __WXDEBUG__ - if ( debug_print ) - wxLogDebug(wxT("token = '%s', child = %s"),token.c_str(),child->GetLabel().c_str()); - #endif + wxLogTrace("propgrid", + wxT("token = '%s', child = %s"), + token, childName); // Add only if editable or setting programmatically if ( (argFlags & wxPG_PROGRAMMATIC_VALUE) || - !child->HasFlag(wxPG_PROP_DISABLED|wxPG_PROP_READONLY) ) + (!child->HasFlag(wxPG_PROP_DISABLED) && + !child->HasFlag(wxPG_PROP_READONLY)) ) { if ( len > 0 ) { - if ( child->StringToValue(variant, token, propagatedFlags|wxPG_COMPOSITE_FRAGMENT) ) + if ( child->StringToValue(variant, token, + propagatedFlags|wxPG_COMPOSITE_FRAGMENT) ) { + // We really need to set the variant's name + // *after* child->StringToValue() has been + // called, since variant's value may be set by + // assigning another variant into it, which + // then usually causes name to be copied (ie. + // usually cleared) as well. wxBoolProperty + // being case in point with its use of + // wxPGVariant_Bool macro as an optimization. + variant.SetName(childName); list.Append(variant); changed = true; @@ -1013,6 +1088,7 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int { // Empty, becomes unspecified variant.MakeNull(); + variant.SetName(childName); list.Append(variant); changed = true; } @@ -1067,25 +1143,26 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int wxVariant variant(oldChildValue); if ( (argFlags & wxPG_PROGRAMMATIC_VALUE) || - !child->HasFlag(wxPG_PROP_DISABLED|wxPG_PROP_READONLY) ) + (!child->HasFlag(wxPG_PROP_DISABLED) && + !child->HasFlag(wxPG_PROP_READONLY)) ) { - bool stvRes = child->StringToValue( variant, token, propagatedFlags ); + wxString childName = child->GetBaseName(); + + bool stvRes = child->StringToValue( variant, token, + propagatedFlags ); if ( stvRes || (variant != oldChildValue) ) { - if ( stvRes ) - changed = true; + variant.SetName(childName); + list.Append(variant); + + changed = true; } else { - // Failed, becomes unspecified - variant.MakeNull(); - changed = true; + // No changes... } } - variant.SetName(child->GetBaseName()); - list.Append(variant); - curChild++; if ( curChild >= iMax ) break; @@ -1099,10 +1176,7 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int tokenStart = pos; if ( a == delimeter ) - { - pos--; - --it; - } + strPosIncrement -= 1; } } } @@ -1110,7 +1184,8 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int if ( a == 0 ) break; - ++it; + it += strPosIncrement; + if ( it != text.end() ) { a = *it; @@ -1119,7 +1194,8 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int { a = 0; } - pos++; + + pos += strPosIncrement; } if ( changed ) @@ -1154,6 +1230,22 @@ wxSize wxPGProperty::OnMeasureImage( int WXUNUSED(item) ) const return wxSize(0,0); } +int wxPGProperty::GetImageOffset( int imageWidth ) const +{ + int imageOffset = 0; + + if ( imageWidth ) + { + // Do not increment offset too much for wide images + if ( imageWidth <= (wxPG_CUSTOM_IMAGE_WIDTH+5) ) + imageOffset = imageWidth + DEFAULT_IMAGE_OFFSET_INCREMENT; + else + imageOffset = imageWidth + 1; + } + + return imageOffset; +} + wxPGCellRenderer* wxPGProperty::GetCellRenderer( int WXUNUSED(column) ) const { return wxPGGlobalVars->m_defaultRenderer; @@ -1267,15 +1359,18 @@ void wxPGProperty::SetValue( wxVariant value, wxVariant* pList, int flags ) } i++; } + + // Always call OnSetValue() for a parent property (do not call it + // here if the value is non-null because it will then be called + // below) + if ( value.IsNull() ) + OnSetValue(); } if ( !value.IsNull() ) { m_value = value; OnSetValue(); - - if ( !(flags & wxPG_SETVAL_FROM_PARENT) ) - UpdateParentValues(); } if ( flags & wxPG_SETVAL_BY_USER ) @@ -1305,13 +1400,28 @@ void wxPGProperty::SetValue( wxVariant value, wxVariant* pList, int flags ) } } - // - // Update editor control - // + if ( !(flags & wxPG_SETVAL_FROM_PARENT) ) + UpdateParentValues(); - // We need to check for these, otherwise GetGrid() may fail. + // + // Update editor control. if ( flags & wxPG_SETVAL_REFRESH_EDITOR ) - RefreshEditor(); + { + wxPropertyGrid* pg = GetGridIfDisplayed(); + if ( pg ) + { + wxPGProperty* selected = pg->GetSelectedProperty(); + + // Only refresh the control if this was selected, or + // this was some parent of selected, or vice versa) + if ( selected && (selected == this || + selected->IsSomeParent(this) || + this->IsSomeParent(selected)) ) + RefreshEditor(); + + pg->DrawItemAndValueRelated(this); + } + } } @@ -1320,12 +1430,9 @@ void wxPGProperty::SetValueInEvent( wxVariant value ) const GetGrid()->ValueChangeInEvent(value); } -void wxPGProperty::SetFlagRecursively( FlagType flag, bool set ) +void wxPGProperty::SetFlagRecursively( wxPGPropertyFlags flag, bool set ) { - if ( set ) - SetFlag(flag); - else - ClearFlag(flag); + ChangeFlag(flag, set); unsigned int i; for ( i = 0; i < GetChildCount(); i++ ) @@ -1334,22 +1441,17 @@ void wxPGProperty::SetFlagRecursively( FlagType flag, bool set ) void wxPGProperty::RefreshEditor() { - if ( m_parent && GetParentState() ) - { - wxPropertyGrid* pg = GetParentState()->GetGrid(); - if ( pg->GetSelectedProperty() == this ) - { - wxWindow* editor = pg->GetEditorControl(); - if ( editor ) - GetEditorClass()->UpdateControl( this, editor ); - } - } -} + if ( !m_parent ) + return; + wxPropertyGrid* pg = GetGrid(); + if ( pg && pg->GetSelectedProperty() == this ) + pg->RefreshEditor(); +} wxVariant wxPGProperty::GetDefaultValue() const { - wxVariant defVal = GetAttribute(wxS("DefaultValue")); + wxVariant defVal = GetAttribute(wxPG_ATTR_DEFAULT_VALUE); if ( !defVal.IsNull() ) return defVal; @@ -1398,10 +1500,14 @@ void wxPGProperty::EnsureCells( unsigned int column ) wxPropertyGrid* pg = GetGrid(); wxPGCell defaultCell; + // Work around possible VC6 bug by using intermediate variables + const wxPGCell& propDefCell = pg->GetPropertyDefaultCell(); + const wxPGCell& catDefCell = pg->GetCategoryDefaultCell(); + if ( !HasFlag(wxPG_PROP_CATEGORY) ) - defaultCell = pg->GetPropertyDefaultCell(); + defaultCell = propDefCell; else - defaultCell = pg->GetCategoryDefaultCell(); + defaultCell = catDefCell; // TODO: Replace with resize() call unsigned int cellCountMax = column+1; @@ -1479,16 +1585,17 @@ const wxPGCell& wxPGProperty::GetCell( unsigned int column ) const return pg->GetPropertyDefaultCell(); } -wxPGCell& wxPGProperty::GetCell( unsigned int column ) +wxPGCell& wxPGProperty::GetOrCreateCell( unsigned int column ) { EnsureCells(column); return m_cells[column]; } void wxPGProperty::SetBackgroundColour( const wxColour& colour, - bool recursively ) + int flags ) { wxPGProperty* firstProp = this; + bool recursively = flags & wxPG_RECURSE ? true : false; // // If category is tried to set recursively, skip it and only @@ -1521,9 +1628,10 @@ void wxPGProperty::SetBackgroundColour( const wxColour& colour, } void wxPGProperty::SetTextColour( const wxColour& colour, - bool recursively ) + int flags ) { wxPGProperty* firstProp = this; + bool recursively = flags & wxPG_RECURSE ? true : false; // // If category is tried to set recursively, skip it and only @@ -1611,18 +1719,20 @@ long wxPGProperty::GetAttributeAsLong( const wxString& name, long defVal ) const { wxVariant variant = m_attributes.FindValue(name); - return wxPGVariantToInt(variant, defVal); + if ( variant.IsNull() ) + return defVal; + + return variant.GetLong(); } double wxPGProperty::GetAttributeAsDouble( const wxString& name, double defVal ) const { - double retVal; wxVariant variant = m_attributes.FindValue(name); - if ( wxPGVariantToDouble(variant, &retVal) ) - return retVal; + if ( variant.IsNull() ) + return defVal; - return defVal; + return variant.GetDouble(); } wxVariant wxPGProperty::GetAttributesAsList() const @@ -1642,7 +1752,7 @@ wxVariant wxPGProperty::GetAttributesAsList() const // Slots of utility flags are NULL const unsigned int gs_propFlagToStringSize = 14; -static const wxChar* gs_propFlagToString[gs_propFlagToStringSize] = { +static const wxChar* const gs_propFlagToString[gs_propFlagToStringSize] = { NULL, wxT("DISABLED"), wxT("HIDDEN"), @@ -1704,7 +1814,7 @@ void wxPGProperty::SetFlagsFromString( const wxString& str ) wxValidator* wxPGProperty::DoGetValidator() const { - return (wxValidator*) NULL; + return NULL; } int wxPGProperty::InsertChoice( const wxString& label, int index, int value ) @@ -1802,8 +1912,14 @@ void wxPGProperty::SetChoiceSelection( int newValue ) } } -bool wxPGProperty::SetChoices( wxPGChoices& choices ) +bool wxPGProperty::SetChoices( const wxPGChoices& choices ) { + // Property must be de-selected first (otherwise choices in + // the control would be de-synced with true choices) + wxPropertyGrid* pg = GetGrid(); + if ( pg && pg->GetSelection() == this ) + pg->ClearSelection(); + m_choices.Assign(choices); { @@ -1847,6 +1963,32 @@ const wxPGEditor* wxPGProperty::GetEditorClass() const return editor; } +bool wxPGProperty::Hide( bool hide, int flags ) +{ + wxPropertyGrid* pg = GetGrid(); + if ( pg ) + return pg->HideProperty(this, hide, flags); + + return DoHide( hide, flags ); +} + +bool wxPGProperty::DoHide( bool hide, int flags ) +{ + if ( !hide ) + ClearFlag( wxPG_PROP_HIDDEN ); + else + SetFlag( wxPG_PROP_HIDDEN ); + + if ( flags & wxPG_RECURSE ) + { + unsigned int i; + for ( i = 0; i < GetChildCount(); i++ ) + Item(i)->DoHide(hide, flags | wxPG_RECURSE_STARTS); + } + + return true; +} + bool wxPGProperty::HasVisibleChildren() const { unsigned int i; @@ -1887,7 +2029,7 @@ void wxPGProperty::SetValueImage( wxBitmap& bmp ) wxSize maxSz = GetGrid()->GetImageSize(); wxSize imSz(bmp.GetWidth(),bmp.GetHeight()); - if ( imSz.x != maxSz.x || imSz.y != maxSz.y ) + if ( imSz.y != maxSz.y ) { // Create a memory DC wxBitmap* bmpNew = new wxBitmap(maxSz.x,maxSz.y,bmp.GetDepth()); @@ -1897,12 +2039,11 @@ void wxPGProperty::SetValueImage( wxBitmap& bmp ) // Scale // FIXME: This is ugly - use image or wait for scaling patch. - double scaleX = (double)maxSz.x / (double)imSz.x; double scaleY = (double)maxSz.y / (double)imSz.y; - dc.SetUserScale(scaleX,scaleY); + dc.SetUserScale(scaleY, scaleY); - dc.DrawBitmap( bmp, 0, 0 ); + dc.DrawBitmap(bmp, 0, 0); m_valueBitmap = bmpNew; } @@ -1966,6 +2107,8 @@ bool wxPGProperty::IsVisible() const wxPropertyGrid* wxPGProperty::GetGridIfDisplayed() const { wxPropertyGridPageState* state = GetParentState(); + if ( !state ) + return NULL; wxPropertyGrid* propGrid = state->GetGrid(); if ( state == propGrid->GetState() ) return propGrid; @@ -2001,7 +2144,8 @@ int wxPGProperty::GetY() const } // This is used by Insert etc. -void wxPGProperty::AddChild2( wxPGProperty* prop, int index, bool correct_mode ) +void wxPGProperty::DoAddChild( wxPGProperty* prop, int index, + bool correct_mode ) { if ( index < 0 || (size_t)index >= m_children.size() ) { @@ -2017,14 +2161,15 @@ void wxPGProperty::AddChild2( wxPGProperty* prop, int index, bool correct_mode ) prop->m_parent = this; } -// This is used by properties that have fixed sub-properties -void wxPGProperty::AddChild( wxPGProperty* prop ) +void wxPGProperty::DoPreAddChild( int index, wxPGProperty* prop ) { wxASSERT_MSG( prop->GetBaseName().length(), - "Property's children must have unique, non-empty names within their scope" ); + "Property's children must have unique, non-empty " + "names within their scope" ); - prop->m_arrIndex = m_children.size(); - m_children.push_back( prop ); + prop->m_arrIndex = index; + m_children.insert( m_children.begin()+index, + prop ); int custImgHeight = prop->OnMeasureImage().y; if ( custImgHeight < 0 /*|| custImgHeight > 1*/ ) @@ -2033,6 +2178,52 @@ void wxPGProperty::AddChild( wxPGProperty* prop ) prop->m_parent = this; } +void wxPGProperty::AddPrivateChild( wxPGProperty* prop ) +{ + if ( !(m_flags & wxPG_PROP_PARENTAL_FLAGS) ) + SetParentalType(wxPG_PROP_AGGREGATE); + + wxASSERT_MSG( (m_flags & wxPG_PROP_PARENTAL_FLAGS) == + wxPG_PROP_AGGREGATE, + "Do not mix up AddPrivateChild() calls with other " + "property adders." ); + + DoPreAddChild( m_children.size(), prop ); +} + +#if wxPG_COMPATIBILITY_1_4 +void wxPGProperty::AddChild( wxPGProperty* prop ) +{ + AddPrivateChild(prop); +} +#endif + +wxPGProperty* wxPGProperty::InsertChild( int index, + wxPGProperty* childProperty ) +{ + if ( index < 0 ) + index = m_children.size(); + + if ( m_parentState ) + { + m_parentState->DoInsert(this, index, childProperty); + } + else + { + if ( !(m_flags & wxPG_PROP_PARENTAL_FLAGS) ) + SetParentalType(wxPG_PROP_MISC_PARENT); + + wxASSERT_MSG( (m_flags & wxPG_PROP_PARENTAL_FLAGS) == + wxPG_PROP_MISC_PARENT, + "Do not mix up AddPrivateChild() calls with other " + "property adders." ); + + DoPreAddChild( index, childProperty ); + } + + return childProperty; +} + void wxPGProperty::RemoveChild( wxPGProperty* p ) { wxArrayPGProperty::iterator it; @@ -2042,7 +2233,7 @@ void wxPGProperty::RemoveChild( wxPGProperty* p ) { if ( *it == p ) { - m_children.erase(it); + children.erase(it); break; } } @@ -2091,7 +2282,10 @@ void wxPGProperty::AdaptListToValue( wxVariant& list, wxVariant* value ) const } if ( allChildrenSpecified ) - ChildChanged(*value, i, childValue); + { + *value = ChildChanged(*value, i, childValue); + } + n++; if ( n == (unsigned int)list.GetCount() ) break; @@ -2124,7 +2318,7 @@ wxPGProperty* wxPGProperty::GetPropertyByName( const wxString& name ) const // Does it have point, then? int pos = name.Find(wxS('.')); if ( pos <= 0 ) - return (wxPGProperty*) NULL; + return NULL; wxPGProperty* p = GetPropertyByName(name. substr(0,pos)); @@ -2202,7 +2396,9 @@ int wxPGProperty::GetChildrenHeight( int lh, int iMax_ ) const return h; } -wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y, unsigned int lh, unsigned int* nextItemY ) const +wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y, + unsigned int lh, + unsigned int* nextItemY ) const { wxASSERT( nextItemY ); @@ -2252,9 +2448,13 @@ wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y, unsigned int lh, unsigne /* if ( current ) + { wxLogDebug(wxT("%s::GetItemAtY(%i) -> %s"),this->GetLabel().c_str(),y,current->GetLabel().c_str()); + } else + { wxLogDebug(wxT("%s::GetItemAtY(%i) -> NULL"),this->GetLabel().c_str(),y); + } */ return (wxPGProperty*) result; @@ -2274,10 +2474,34 @@ void wxPGProperty::Empty() m_children.clear(); } -void wxPGProperty::ChildChanged( wxVariant& WXUNUSED(thisValue), - int WXUNUSED(childIndex), - wxVariant& WXUNUSED(childValue) ) const +wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y ) const +{ + unsigned int nextItem; + return GetItemAtY( y, GetGrid()->GetRowHeight(), &nextItem); +} + +void wxPGProperty::DeleteChildren() +{ + wxPropertyGridPageState* state = m_parentState; + + if ( !GetChildCount() ) + return; + + // Because deletion is sometimes deferred, we have to use + // this sort of code for enumerating the child properties. + unsigned int i = GetChildCount(); + while ( i > 0 ) + { + i--; + state->DoDelete(Item(i), true); + } +} + +wxVariant wxPGProperty::ChildChanged( wxVariant& WXUNUSED(thisValue), + int WXUNUSED(childIndex), + wxVariant& WXUNUSED(childValue) ) const { + return wxNullVariant; } bool wxPGProperty::AreAllChildrenSpecified( wxVariant* pendingList ) const @@ -2382,7 +2606,7 @@ void wxPGProperty::SubPropsChanged( int oldSelInd ) child->InitAfterAdded(state, grid); } - wxPGProperty* sel = (wxPGProperty*) NULL; + wxPGProperty* sel = NULL; if ( oldSelInd >= (int)m_children.size() ) oldSelInd = (int)m_children.size() - 1; @@ -2408,12 +2632,11 @@ WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPGRootProperty,none,TextCtrl) IMPLEMENT_DYNAMIC_CLASS(wxPGRootProperty, wxPGProperty) -wxPGRootProperty::wxPGRootProperty() +wxPGRootProperty::wxPGRootProperty( const wxString& name ) : wxPGProperty() { -#ifdef __WXDEBUG__ - m_name = wxS(""); -#endif + m_name = name; + m_label = m_name; SetParentalType(0); m_depth = 0; } @@ -2461,25 +2684,311 @@ wxPropertyCategory::~wxPropertyCategory() wxString wxPropertyCategory::ValueToString( wxVariant& WXUNUSED(value), int WXUNUSED(argFlags) ) const { + if ( m_value.GetType() == wxPG_VARIANT_TYPE_STRING ) + return m_value.GetString(); return wxEmptyString; } +wxString wxPropertyCategory::GetValueAsString( int argFlags ) const +{ +#if wxPG_COMPATIBILITY_1_4 + // This is backwards compatibility test + // That is, to make sure this function is not overridden + // (instead, ValueToString() should be). + if ( argFlags == 0xFFFF ) + { + // Do not override! (for backwards compliancy) + return g_invalidStringContent; + } +#endif + + // Unspecified value is always empty string + if ( IsValueUnspecified() ) + return wxEmptyString; + + return wxPGProperty::GetValueAsString(argFlags); +} + int wxPropertyCategory::GetTextExtent( const wxWindow* wnd, const wxFont& font ) const { if ( m_textExtent > 0 ) return m_textExtent; int x = 0, y = 0; - ((wxWindow*)wnd)->GetTextExtent( m_label, &x, &y, 0, 0, &font ); + ((wxWindow*)wnd)->GetTextExtent( m_label, &x, &y, 0, 0, &font ); return x; } void wxPropertyCategory::CalculateTextExtent( wxWindow* wnd, const wxFont& font ) { int x = 0, y = 0; - wnd->GetTextExtent( m_label, &x, &y, 0, 0, &font ); + wnd->GetTextExtent( m_label, &x, &y, 0, 0, &font ); m_textExtent = x; } +// ----------------------------------------------------------------------- +// wxPGChoices +// ----------------------------------------------------------------------- + +wxPGChoiceEntry& wxPGChoices::Add( const wxString& label, int value ) +{ + AllocExclusive(); + + wxPGChoiceEntry entry(label, value); + return m_data->Insert( -1, entry ); +} + +// ----------------------------------------------------------------------- + +wxPGChoiceEntry& wxPGChoices::Add( const wxString& label, const wxBitmap& bitmap, int value ) +{ + AllocExclusive(); + + wxPGChoiceEntry entry(label, value); + entry.SetBitmap(bitmap); + return m_data->Insert( -1, entry ); +} + +// ----------------------------------------------------------------------- + +wxPGChoiceEntry& wxPGChoices::Insert( const wxPGChoiceEntry& entry, int index ) +{ + AllocExclusive(); + + return m_data->Insert( index, entry ); +} + +// ----------------------------------------------------------------------- + +wxPGChoiceEntry& wxPGChoices::Insert( const wxString& label, int index, int value ) +{ + AllocExclusive(); + + wxPGChoiceEntry entry(label, value); + return m_data->Insert( index, entry ); +} + +// ----------------------------------------------------------------------- + +wxPGChoiceEntry& wxPGChoices::AddAsSorted( const wxString& label, int value ) +{ + AllocExclusive(); + + size_t index = 0; + + while ( index < GetCount() ) + { + int cmpRes = GetLabel(index).Cmp(label); + if ( cmpRes > 0 ) + break; + index++; + } + + wxPGChoiceEntry entry(label, value); + return m_data->Insert( index, entry ); +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::Add( const wxChar* const* labels, const ValArrItem* values ) +{ + AllocExclusive(); + + unsigned int itemcount = 0; + const wxChar* const* p = &labels[0]; + while ( *p ) { p++; itemcount++; } + + unsigned int i; + for ( i = 0; i < itemcount; i++ ) + { + int value = i; + if ( values ) + value = values[i]; + wxPGChoiceEntry entry(labels[i], value); + m_data->Insert( i, entry ); + } +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::Add( const wxArrayString& arr, const wxArrayInt& arrint ) +{ + AllocExclusive(); + + unsigned int i; + unsigned int itemcount = arr.size(); + + for ( i = 0; i < itemcount; i++ ) + { + int value = i; + if ( &arrint && arrint.size() ) + value = arrint[i]; + wxPGChoiceEntry entry(arr[i], value); + m_data->Insert( i, entry ); + } +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::RemoveAt(size_t nIndex, size_t count) +{ + AllocExclusive(); + + wxASSERT( m_data->GetRefCount() != -1 ); + m_data->m_items.erase(m_data->m_items.begin()+nIndex, + m_data->m_items.begin()+nIndex+count); +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::Clear() +{ + if ( m_data != wxPGChoicesEmptyData ) + { + AllocExclusive(); + m_data->Clear(); + } +} + +// ----------------------------------------------------------------------- + +int wxPGChoices::Index( const wxString& str ) const +{ + if ( IsOk() ) + { + unsigned int i; + for ( i=0; i< m_data->GetCount(); i++ ) + { + const wxPGChoiceEntry& entry = m_data->Item(i); + if ( entry.HasText() && entry.GetText() == str ) + return i; + } + } + return -1; +} + +// ----------------------------------------------------------------------- + +int wxPGChoices::Index( int val ) const +{ + if ( IsOk() ) + { + unsigned int i; + for ( i=0; i< m_data->GetCount(); i++ ) + { + const wxPGChoiceEntry& entry = m_data->Item(i); + if ( entry.GetValue() == val ) + return i; + } + } + return -1; +} + +// ----------------------------------------------------------------------- + +wxArrayString wxPGChoices::GetLabels() const +{ + wxArrayString arr; + unsigned int i; + + if ( this && IsOk() ) + for ( i=0; i= 0 ) + arr.Add(GetValue(index)); + else + arr.Add(wxPG_INVALID_VALUE); + } + } + + return arr; +} + +// ----------------------------------------------------------------------- + +wxArrayInt wxPGChoices::GetIndicesForStrings( const wxArrayString& strings, + wxArrayString* unmatched ) const +{ + wxArrayInt arr; + + if ( IsOk() ) + { + unsigned int i; + for ( i=0; i< strings.size(); i++ ) + { + const wxString& str = strings[i]; + int index = Index(str); + if ( index >= 0 ) + arr.Add(index); + else if ( unmatched ) + unmatched->Add(str); + } + } + + return arr; +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::AllocExclusive() +{ + EnsureData(); + + if ( m_data->GetRefCount() != 1 ) + { + wxPGChoicesData* data = new wxPGChoicesData(); + data->CopyDataFrom(m_data); + Free(); + m_data = data; + } +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::AssignData( wxPGChoicesData* data ) +{ + Free(); + + if ( data != wxPGChoicesEmptyData ) + { + m_data = data; + data->IncRef(); + } +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::Init() +{ + m_data = wxPGChoicesEmptyData; +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::Free() +{ + if ( m_data != wxPGChoicesEmptyData ) + { + m_data->DecRef(); + m_data = wxPGChoicesEmptyData; + } +} + // ----------------------------------------------------------------------- // wxPGAttributeStorage // -----------------------------------------------------------------------