// Created: 2008-08-24
// RCS-ID: $Id$
// Copyright: (c) Jaakko Salli
-// Licence: wxWindows license
+// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx/wx.h".
void wxPropertyGridIteratorBase::Prev()
{
wxPGProperty* property = m_property;
- wxASSERT( property );
+ if ( !property )
+ return;
wxPGProperty* parent = property->GetParent();
wxASSERT( parent );
void wxPropertyGridIteratorBase::Next( bool iterateChildren )
{
wxPGProperty* property = m_property;
- wxASSERT( property );
+ if ( !property )
+ return;
if ( property->GetChildCount() &&
wxPG_ITERATOR_PARENTEXMASK_TEST(property, m_parentExMask) &&
m_colWidths.push_back( wxPG_DEFAULT_SPLITTERX );
m_colWidths.push_back( wxPG_DEFAULT_SPLITTERX );
m_fSplitterX = wxPG_DEFAULT_SPLITTERX;
+
+ m_columnProportions.push_back(1);
+ m_columnProportions.push_back(1);
+
+ m_isSplitterPreSet = false;
+ m_dontCenterSplitter = false;
+
+ // By default, we only have the 'value' column editable
+ m_editableColumns.push_back(1);
}
// -----------------------------------------------------------------------
void wxPropertyGridPageState::SetVirtualWidth( int width )
{
- wxASSERT( width >= 0 );
+ // Sometimes width less than 0 is offered. Let's make things easy for
+ // everybody and deal with it here.
+ if ( width < 0 )
+ width = 0;
+
wxPropertyGrid* pg = GetGrid();
int gw = pg->GetClientSize().x;
if ( width < gw )
widthChange = 0;
CheckColumnWidths(widthChange);
- if ( !(GetGrid()->GetInternalFlags() & wxPG_FL_SPLITTER_PRE_SET) &&
- (GetGrid()->GetInternalFlags() & wxPG_FL_DONT_CENTER_SPLITTER) )
+ if ( !m_isSplitterPreSet && m_dontCenterSplitter )
{
long timeSinceCreation = (::wxGetLocalTimeMillis() - GetGrid()->m_timeCreated).ToLong();
else
{
DoSetSplitterPosition( newWidth / 2 );
- GetGrid()->ClearInternalFlag(wxPG_FL_SPLITTER_PRE_SET);
+ m_isSplitterPreSet = false;
}
}
}
// -----------------------------------------------------------------------
-wxPropertyGridHitTestResult wxPropertyGridPageState::HitTest( const wxPoint&pt ) const
+wxPropertyGridHitTestResult
+wxPropertyGridPageState::HitTest( const wxPoint&pt ) const
{
wxPropertyGridHitTestResult result;
- result.column = HitTestH( pt.x, &result.splitter, &result.splitterHitOffset );
- result.property = DoGetItemAtY( pt.y );
+ result.m_column = HitTestH( pt.x, &result.m_splitter,
+ &result.m_splitterHitOffset );
+ result.m_property = DoGetItemAtY( pt.y );
return result;
}
if ( col == 0 )
w += ( ((int)p->m_depth-1) * pg->m_subgroup_extramargin );
- //
- // TODO: Add bitmap support.
+ // account for the bitmap
+ if ( col == 1 )
+ w += p->GetImageOffset(pg->GetImageRect(p, -1).GetWidth());
+
w += (wxPG_XBEFORETEXT*2);
return wxPG_DRAG_MARGIN;
}
-void wxPropertyGridPageState::PropagateColSizeDec( int column, int decrease, int dir )
+void wxPropertyGridPageState::PropagateColSizeDec( int column,
+ int decrease,
+ int dir )
{
int origWidth = m_colWidths[column];
m_colWidths[column] -= decrease;
PropagateColSizeDec( column, more, dir );
}
-void wxPropertyGridPageState::DoSetSplitterPosition( int newXPos, int splitterColumn, bool WXUNUSED(allPages), bool fromAutoCenter )
+void wxPropertyGridPageState::DoSetSplitterPosition( int newXPos,
+ int splitterColumn,
+ int flags )
{
wxPropertyGrid* pg = GetGrid();
if ( splitterColumn == 0 )
m_fSplitterX = (double) newXPos;
- if ( !fromAutoCenter )
+ if ( !(flags & wxPG_SPLITTER_FROM_AUTO_CENTER) &&
+ !(flags & wxPG_SPLITTER_FROM_EVENT) )
{
// Don't allow initial splitter auto-positioning after this.
- if ( pg->GetState() == this )
- pg->SetInternalFlag(wxPG_FL_SPLITTER_PRE_SET);
+ m_isSplitterPreSet = true;
CheckColumnWidths();
}
DoSetSplitterPosition( maxW );
}
- pg->SetInternalFlag(wxPG_FL_DONT_CENTER_SPLITTER);
+ m_dontCenterSplitter = true;
}
wxSize wxPropertyGridPageState::DoFitColumns( bool WXUNUSED(allowGridResize) )
int remaining = m_width - accWid;
m_colWidths[GetColumnCount()-1] += remaining;
- pg->SetInternalFlag(wxPG_FL_DONT_CENTER_SPLITTER);
+ m_dontCenterSplitter = true;
int firstSplitterX = marginWidth + m_colWidths[0];
m_fSplitterX = (double) firstSplitterX;
}
// Auto center splitter
- if ( !(pg->GetInternalFlags() & wxPG_FL_DONT_CENTER_SPLITTER) &&
- m_colWidths.size() == 2 )
+ if ( !m_dontCenterSplitter )
{
- float centerX = (float)(pg->m_width/2);
- float splitterX;
-
- if ( m_fSplitterX < 0.0 )
+ if ( m_colWidths.size() == 2 &&
+ m_columnProportions[0] == m_columnProportions[1] )
{
- splitterX = centerX;
- }
- else if ( widthChange )
- {
- //float centerX = float(pg->GetSize().x) * 0.5;
+ //
+ // When we have two columns of equal proportion, then use this
+ // code. It will look nicer when the scrollbar visibility is
+ // toggled on and off.
+ //
+ // TODO: Adapt this to generic recenter code.
+ //
+ float centerX = (float)(pg->m_width/2);
+ float splitterX;
- // Recenter?
- splitterX = m_fSplitterX + (float(widthChange) * 0.5);
- float deviation = fabs(centerX - splitterX);
+ if ( m_fSplitterX < 0.0 )
+ {
+ splitterX = centerX;
+ }
+ else if ( widthChange )
+ {
+ //float centerX = float(pg->GetSize().x) * 0.5;
+
+ // Recenter?
+ splitterX = m_fSplitterX + (float(widthChange) * 0.5);
+ float deviation = fabs(centerX - splitterX);
- // If deviating from center, adjust towards it
- if ( deviation > 20.0 )
+ // If deviating from center, adjust towards it
+ if ( deviation > 20.0 )
+ {
+ if ( splitterX > centerX)
+ splitterX -= 2;
+ else
+ splitterX += 2;
+ }
+ }
+ else
{
- if ( splitterX > centerX)
- splitterX -= 2;
- else
- splitterX += 2;
+ // No width change, just keep sure we keep splitter position intact
+ splitterX = m_fSplitterX;
+ float deviation = fabs(centerX - splitterX);
+ if ( deviation > 50.0 )
+ {
+ splitterX = centerX;
+ }
}
+
+ DoSetSplitterPosition((int)splitterX, 0,
+ wxPG_SPLITTER_FROM_AUTO_CENTER);
+
+ m_fSplitterX = splitterX; // needed to retain accuracy
}
else
{
- // No width change, just keep sure we keep splitter position intact
- splitterX = m_fSplitterX;
- float deviation = fabs(centerX - splitterX);
- if ( deviation > 50.0 )
- {
- splitterX = centerX;
- }
+ //
+ // Generic re-center code
+ //
+ ResetColumnSizes(wxPG_SPLITTER_FROM_AUTO_CENTER);
}
+ }
+}
- DoSetSplitterPosition((int)splitterX, 0, false, true);
+void wxPropertyGridPageState::ResetColumnSizes( int setSplitterFlags )
+{
+ unsigned int i;
+ // Calculate sum of proportions
+ int psum = 0;
+ for ( i=0; i<m_colWidths.size(); i++ )
+ psum += m_columnProportions[i];
+ int puwid = (m_pPropGrid->m_width*256) / psum;
+ int cpos = 0;
- m_fSplitterX = splitterX; // needed to retain accuracy
+ // Convert proportion to splitter positions
+ for ( i=0; i<(m_colWidths.size() - 1); i++ )
+ {
+ int cwid = (puwid*m_columnProportions[i]) / 256;
+ cpos += cwid;
+ DoSetSplitterPosition(cpos, i,
+ setSplitterFlags);
}
}
{
wxASSERT( colCount >= 2 );
m_colWidths.SetCount( colCount, wxPG_DRAG_MARGIN );
+ m_columnProportions.SetCount( colCount, 1 );
if ( m_colWidths.size() > (unsigned int)colCount )
- m_colWidths.RemoveAt( m_colWidths.size(), m_colWidths.size() - colCount );
+ m_colWidths.RemoveAt( m_colWidths.size()-1,
+ m_colWidths.size() - colCount );
if ( m_pPropGrid->GetState() == this )
m_pPropGrid->RecalculateVirtualSize();
CheckColumnWidths();
}
+void wxPropertyGridPageState::DoSetColumnProportion( unsigned int column,
+ int proportion )
+{
+ wxASSERT_MSG( proportion >= 1,
+ "Column proportion must 1 or higher" );
+
+ if ( proportion < 1 )
+ proportion = 1;
+
+ while ( m_columnProportions.size() <= column )
+ m_columnProportions.push_back(1);
+
+ m_columnProportions[column] = proportion;
+}
+
// Returns column index, -1 for margin
int wxPropertyGridPageState::HitTestH( int x, int* pSplitterHit, int* pSplitterHitOffset ) const
{
return col;
}
+bool wxPropertyGridPageState::ArePropertiesAdjacent( wxPGProperty* prop1,
+ wxPGProperty* prop2,
+ int iterFlags ) const
+{
+ const wxPGProperty* ap1 =
+ wxPropertyGridConstIterator::OneStep(this,
+ iterFlags,
+ prop1,
+ 1);
+ if ( ap1 && ap1 == prop2 )
+ return true;
+
+ const wxPGProperty* ap2 =
+ wxPropertyGridConstIterator::OneStep(this,
+ iterFlags,
+ prop1,
+ -1);
+ if ( ap2 && ap2 == prop2 )
+ return true;
+
+ return false;
+}
+
// -----------------------------------------------------------------------
// wxPropertyGridPageState property value setting and getting
// -----------------------------------------------------------------------
bool wxPropertyGridPageState::DoIsPropertySelected( wxPGProperty* prop ) const
{
- const wxArrayPGProperty& selection = m_selection;
-
- for ( unsigned int i=0; i<selection.size(); i++ )
- {
- if ( selection[i] == prop )
- return true;
- }
+ if ( wxPGFindInVector(m_selection, prop) != wxNOT_FOUND )
+ return true;
return false;
}
{
if ( m_selection[i] == prop )
{
- m_selection.erase( m_selection.begin() + i );
+ wxPropertyGrid* pg = m_pPropGrid;
+ if ( i == 0 && pg->GetState() == this )
+ {
+ // If first item (ie. one with the active editor) was
+ // deselected, then we need to take some extra measures.
+ wxArrayPGProperty sel = m_selection;
+ sel.erase( sel.begin() + i );
+
+ wxPGProperty* newFirst;
+ if ( sel.size() )
+ newFirst = sel[0];
+ else
+ newFirst = NULL;
+
+ pg->DoSelectProperty(newFirst,
+ wxPG_SEL_DONT_SEND_EVENT);
+
+ m_selection = sel;
+
+ pg->Refresh();
+ }
+ else
+ {
+ m_selection.erase( m_selection.begin() + i );
+ }
return;
}
}
bool wxPropertyGridPageState::DoHideProperty( wxPGProperty* p, bool hide, int flags )
{
- if ( !hide )
- p->ClearFlag( wxPG_PROP_HIDDEN );
- else
- p->SetFlag( wxPG_PROP_HIDDEN );
-
- if ( flags & wxPG_RECURSE )
- {
- unsigned int i;
- for ( i = 0; i < p->GetChildCount(); i++ )
- DoHideProperty(p->Item(i), hide, flags | wxPG_RECURSE_STARTS);
- }
-
+ p->DoHide(hide, flags);
VirtualHeightChanged();
return true;
}
-// -----------------------------------------------------------------------
-
-bool wxPropertyGridPageState::DoEnableProperty( wxPGProperty* p, bool enable )
-{
- if ( p )
- {
- if ( enable )
- {
- if ( !(p->m_flags & wxPG_PROP_DISABLED) )
- return false;
-
- // Enabling
-
- p->m_flags &= ~(wxPG_PROP_DISABLED);
- }
- else
- {
- if ( p->m_flags & wxPG_PROP_DISABLED )
- return false;
-
- // Disabling
-
- p->m_flags |= wxPG_PROP_DISABLED;
-
- }
-
- // Apply same to sub-properties as well
- unsigned int i;
- for ( i = 0; i < p->GetChildCount(); i++ )
- DoEnableProperty( p->Item(i), enable );
-
- return true;
- }
- return false;
-}
-
// -----------------------------------------------------------------------
// wxPropertyGridPageState wxVariant related routines
// -----------------------------------------------------------------------
}
#endif // wxDEBUG_LEVEL
- // Make sure nothing is selected.
- if ( propGrid )
- propGrid->ClearSelection(false);
-
// NULL parent == root parent
if ( !scheduledParent )
scheduledParent = DoGetRoot();
wxCHECK_RET( item != &m_regularArray && item != m_abcArray,
wxT("wxPropertyGrid: Do not attempt to remove the root item.") );
+ wxPropertyGrid* pg = GetGrid();
+
+ // Must defer deletion? Yes, if handling a wxPG event.
+ if ( pg && pg->m_processedEvent )
+ {
+ if ( doDelete )
+ pg->m_deletedProperties.push_back(item);
+ else
+ pg->m_removedProperties.push_back(item);
+
+ // Rename the property so it won't remain in the way
+ // of the user code.
+
+ // Let's trust that no sane property uses prefix like
+ // this. It would be anyway fairly inconvenient (in
+ // current code) to check whether a new name is used
+ // by another property with parent (due to the child
+ // name notation).
+ wxString newName = wxS("_&/_%$") + item->GetBaseName();
+ DoSetPropertyName(item, newName);
+
+ return;
+ }
+
unsigned int indinparent = item->GetIndexInParent();
wxPGProperty* pwc = (wxPGProperty*)item;
wxASSERT( item->GetParentState() == this );
- wxPropertyGrid* pg = GetGrid();
-
if ( DoIsPropertySelected(item) )
{
if ( pg && pg->GetState() == this )
}
}
- if ( item->GetBaseName().length() &&
+ if ( item->GetBaseName().length() &&
(parent->IsCategory() || parent->IsRoot()) )
m_dictName.erase(item->GetBaseName());
- // We need to clear parent grid's m_propHover, if it matches item
- if ( pg && pg->m_propHover == item )
- pg->m_propHover = NULL;
+ // We need to clear parent grid's m_propHover, if it matches item
+ if ( pg && pg->m_propHover == item )
+ pg->m_propHover = NULL;
+
+ // Mark the property as 'unattached'
+ item->m_parentState = NULL;
+ item->m_parent = NULL;
// We can actually delete it now
if ( doDelete )