3f66f6a5b3
This keyword is not expanded by Git which means it's not replaced with the correct revision value in the releases made using git-based scripts and it's confusing to have lines with unexpanded "$Id$" in the released files. As expanding them with Git is not that simple (it could be done with git archive and export-subst attribute) and there are not many benefits in having them in the first place, just remove all these lines. If nothing else, this will make an eventual transition to Git simpler. Closes #14487. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
665 lines
18 KiB
C++
665 lines
18 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: samples/propgrid/sampleprops.cpp
|
|
// Purpose: wxPropertyGrid Sample Properties
|
|
// Author: Jaakko Salli
|
|
// Modified by:
|
|
// Created: 2006-03-05
|
|
// 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
|
|
|
|
// for all others, include the necessary headers (this file is usually all you
|
|
// need because it includes almost all "standard" wxWidgets headers)
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/wx.h"
|
|
#endif
|
|
|
|
#include "wx/fontdlg.h"
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
#include <wx/propgrid/propgrid.h>
|
|
#include <wx/propgrid/advprops.h>
|
|
|
|
#ifndef WX_PROPGRID_SAMPLEPROPS_H
|
|
#include "sampleprops.h"
|
|
#endif
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// wxFontDataProperty
|
|
// -----------------------------------------------------------------------
|
|
|
|
// Dummy comparison required by value type implementation.
|
|
bool operator == (const wxFontData&, const wxFontData&)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Custom version of wxFontProperty that also holds colour in the value.
|
|
// Original version by Vladimir Vainer.
|
|
|
|
IMPLEMENT_VARIANT_OBJECT_SHALLOWCMP(wxFontData)
|
|
|
|
WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFontDataProperty,wxFontProperty,
|
|
wxFontData,const wxFontData&,TextCtrlAndButton)
|
|
|
|
wxFontDataProperty::wxFontDataProperty( const wxString& label, const wxString& name,
|
|
const wxFontData& value ) : wxFontProperty(label,name,value.GetInitialFont())
|
|
{
|
|
wxFontData fontData(value);
|
|
|
|
// Fix value.
|
|
fontData.SetChosenFont(value.GetInitialFont());
|
|
if ( !fontData.GetColour().IsOk() )
|
|
fontData.SetColour(*wxBLACK);
|
|
|
|
// Set initial value - should be done in a simpler way like this
|
|
// (instead of calling SetValue) in derived (wxObject) properties.
|
|
m_value_wxFontData << value;
|
|
|
|
// Add extra children.
|
|
AddPrivateChild( new wxColourProperty(_("Colour"), wxPG_LABEL,
|
|
fontData.GetColour() ) );
|
|
}
|
|
|
|
wxFontDataProperty::~wxFontDataProperty () { }
|
|
|
|
void wxFontDataProperty::OnSetValue()
|
|
{
|
|
if ( m_value.GetType() != "wxFontData" )
|
|
{
|
|
if ( m_value.GetType() == "wxFont" )
|
|
{
|
|
wxFont font;
|
|
font << m_value;
|
|
wxFontData fontData;
|
|
fontData.SetChosenFont(font);
|
|
if ( !m_value_wxFontData.IsNull() )
|
|
{
|
|
wxFontData oldFontData;
|
|
oldFontData << m_value_wxFontData;
|
|
fontData.SetColour(oldFontData.GetColour());
|
|
}
|
|
else
|
|
{
|
|
fontData.SetColour(*wxBLACK);
|
|
}
|
|
wxVariant variant;
|
|
variant << fontData;
|
|
m_value_wxFontData = variant;
|
|
}
|
|
else
|
|
{
|
|
wxFAIL_MSG(wxT("Value to wxFontDataProperty must be eithe wxFontData or wxFont"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Set m_value to wxFont so that wxFontProperty methods will work
|
|
// correctly.
|
|
m_value_wxFontData = m_value;
|
|
|
|
wxFontData fontData;
|
|
fontData << m_value_wxFontData;
|
|
|
|
wxFont font = fontData.GetChosenFont();
|
|
if ( !font.IsOk() )
|
|
font = wxFont(10,wxSWISS,wxNORMAL,wxNORMAL);
|
|
|
|
m_value = WXVARIANT(font);
|
|
}
|
|
}
|
|
|
|
wxVariant wxFontDataProperty::DoGetValue() const
|
|
{
|
|
return m_value_wxFontData;
|
|
}
|
|
|
|
// Must re-create font dialog displayer.
|
|
bool wxFontDataProperty::OnEvent( wxPropertyGrid* propgrid,
|
|
wxWindow* WXUNUSED(primary), wxEvent& event )
|
|
{
|
|
if ( propgrid->IsMainButtonEvent(event) )
|
|
{
|
|
wxVariant useValue = propgrid->GetUncommittedPropertyValue();
|
|
|
|
wxFontData fontData;
|
|
fontData << useValue;
|
|
|
|
fontData.SetInitialFont(fontData.GetChosenFont());
|
|
|
|
wxFontDialog dlg(propgrid, fontData);
|
|
|
|
if ( dlg.ShowModal() == wxID_OK )
|
|
{
|
|
wxVariant variant;
|
|
variant << dlg.GetFontData();
|
|
SetValueInEvent( variant );
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void wxFontDataProperty::RefreshChildren()
|
|
{
|
|
wxFontProperty::RefreshChildren();
|
|
if ( GetChildCount() < 6 ) // Number is count of wxFontProperty's children + 1.
|
|
return;
|
|
wxFontData fontData; fontData << m_value_wxFontData;
|
|
wxVariant variant; variant << fontData.GetColour();
|
|
Item(6)->SetValue( variant );
|
|
}
|
|
|
|
wxVariant wxFontDataProperty::ChildChanged( wxVariant& thisValue,
|
|
int childIndex,
|
|
wxVariant& childValue ) const
|
|
{
|
|
wxFontData fontData;
|
|
fontData << thisValue;
|
|
wxColour col;
|
|
wxVariant variant;
|
|
|
|
switch ( childIndex )
|
|
{
|
|
case 6:
|
|
col << childValue;
|
|
fontData.SetColour( col );
|
|
break;
|
|
default:
|
|
// Transfer from subset to superset.
|
|
wxFont font = fontData.GetChosenFont();
|
|
variant = WXVARIANT(font);
|
|
wxFontProperty::ChildChanged( variant, childIndex, childValue );
|
|
font << variant;
|
|
fontData.SetChosenFont(font);
|
|
}
|
|
|
|
wxVariant newVariant;
|
|
newVariant << fontData;
|
|
return newVariant;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// wxSizeProperty
|
|
// -----------------------------------------------------------------------
|
|
|
|
WX_PG_IMPLEMENT_PROPERTY_CLASS(wxSizeProperty,wxPGProperty,
|
|
wxSize,const wxSize&,TextCtrl)
|
|
|
|
wxSizeProperty::wxSizeProperty( const wxString& label, const wxString& name,
|
|
const wxSize& value) : wxPGProperty(label,name)
|
|
{
|
|
SetValueI(value);
|
|
AddPrivateChild( new wxIntProperty(wxT("Width"),wxPG_LABEL,value.x) );
|
|
AddPrivateChild( new wxIntProperty(wxT("Height"),wxPG_LABEL,value.y) );
|
|
}
|
|
|
|
wxSizeProperty::~wxSizeProperty() { }
|
|
|
|
void wxSizeProperty::RefreshChildren()
|
|
{
|
|
if ( !GetChildCount() ) return;
|
|
const wxSize& size = wxSizeRefFromVariant(m_value);
|
|
Item(0)->SetValue( (long)size.x );
|
|
Item(1)->SetValue( (long)size.y );
|
|
}
|
|
|
|
wxVariant wxSizeProperty::ChildChanged( wxVariant& thisValue,
|
|
int childIndex,
|
|
wxVariant& childValue ) const
|
|
{
|
|
wxSize& size = wxSizeRefFromVariant(thisValue);
|
|
int val = childValue.GetLong();
|
|
switch ( childIndex )
|
|
{
|
|
case 0: size.x = val; break;
|
|
case 1: size.y = val; break;
|
|
}
|
|
wxVariant newVariant;
|
|
newVariant << size;
|
|
return newVariant;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// wxPointProperty
|
|
// -----------------------------------------------------------------------
|
|
|
|
WX_PG_IMPLEMENT_PROPERTY_CLASS(wxPointProperty,wxPGProperty,
|
|
wxPoint,const wxPoint&,TextCtrl)
|
|
|
|
wxPointProperty::wxPointProperty( const wxString& label, const wxString& name,
|
|
const wxPoint& value) : wxPGProperty(label,name)
|
|
{
|
|
SetValueI(value);
|
|
AddPrivateChild( new wxIntProperty(wxT("X"),wxPG_LABEL,value.x) );
|
|
AddPrivateChild( new wxIntProperty(wxT("Y"),wxPG_LABEL,value.y) );
|
|
}
|
|
|
|
wxPointProperty::~wxPointProperty() { }
|
|
|
|
void wxPointProperty::RefreshChildren()
|
|
{
|
|
if ( !GetChildCount() ) return;
|
|
const wxPoint& point = wxPointRefFromVariant(m_value);
|
|
Item(0)->SetValue( (long)point.x );
|
|
Item(1)->SetValue( (long)point.y );
|
|
}
|
|
|
|
wxVariant wxPointProperty::ChildChanged( wxVariant& thisValue,
|
|
int childIndex,
|
|
wxVariant& childValue ) const
|
|
{
|
|
wxPoint& point = wxPointRefFromVariant(thisValue);
|
|
int val = childValue.GetLong();
|
|
switch ( childIndex )
|
|
{
|
|
case 0: point.x = val; break;
|
|
case 1: point.y = val; break;
|
|
}
|
|
wxVariant newVariant;
|
|
newVariant << point;
|
|
return newVariant;
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Dirs Property
|
|
// -----------------------------------------------------------------------
|
|
|
|
WX_PG_IMPLEMENT_ARRAYSTRING_PROPERTY_WITH_VALIDATOR(wxDirsProperty, ',',
|
|
"Browse")
|
|
|
|
#if wxUSE_VALIDATORS
|
|
|
|
wxValidator* wxDirsProperty::DoGetValidator() const
|
|
{
|
|
return wxFileProperty::GetClassValidator();
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
bool wxDirsProperty::OnCustomStringEdit( wxWindow* parent, wxString& value )
|
|
{
|
|
wxDirDialog dlg(parent,
|
|
_("Select a directory to be added to the list:"),
|
|
value,
|
|
0);
|
|
|
|
if ( dlg.ShowModal() == wxID_OK )
|
|
{
|
|
value = dlg.GetPath();
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// wxArrayDoubleEditorDialog
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
//
|
|
// You can *almost* convert wxArrayDoubleEditorDialog to wxArrayXXXEditorDialog
|
|
// by replacing each ArrayDouble with ArrayXXX.
|
|
//
|
|
|
|
class wxArrayDoubleEditorDialog : public wxPGArrayEditorDialog
|
|
{
|
|
public:
|
|
wxArrayDoubleEditorDialog();
|
|
|
|
void Init();
|
|
|
|
wxArrayDoubleEditorDialog(wxWindow *parent,
|
|
const wxString& message,
|
|
const wxString& caption,
|
|
wxArrayDouble& array,
|
|
long style = wxAEDIALOG_STYLE,
|
|
const wxPoint& pos = wxDefaultPosition,
|
|
const wxSize& sz = wxDefaultSize );
|
|
|
|
bool Create(wxWindow *parent,
|
|
const wxString& message,
|
|
const wxString& caption,
|
|
wxArrayDouble& array,
|
|
long style = wxAEDIALOG_STYLE,
|
|
const wxPoint& pos = wxDefaultPosition,
|
|
const wxSize& sz = wxDefaultSize );
|
|
|
|
const wxArrayDouble& GetArray() const { return m_array; }
|
|
|
|
// Extra method for this type of array
|
|
void SetPrecision ( int precision )
|
|
{
|
|
m_precision = precision;
|
|
m_dtoaTemplate.Empty();
|
|
}
|
|
|
|
protected:
|
|
// Mandatory array of type
|
|
wxArrayDouble m_array;
|
|
|
|
// Use this to avoid extra wxString creation+Printf
|
|
// on double-to-wxString conversion.
|
|
wxString m_dtoaTemplate;
|
|
|
|
int m_precision;
|
|
|
|
// Mandatory overridden methods
|
|
virtual wxString ArrayGet( size_t index );
|
|
virtual size_t ArrayGetCount();
|
|
virtual bool ArrayInsert( const wxString& str, int index );
|
|
virtual bool ArraySet( size_t index, const wxString& str );
|
|
virtual void ArrayRemoveAt( int index );
|
|
virtual void ArraySwap( size_t first, size_t second );
|
|
|
|
private:
|
|
DECLARE_DYNAMIC_CLASS_NO_COPY(wxArrayDoubleEditorDialog)
|
|
};
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxArrayDoubleEditorDialog, wxPGArrayEditorDialog)
|
|
|
|
//
|
|
// Array dialog array access and manipulation
|
|
//
|
|
|
|
wxString wxArrayDoubleEditorDialog::ArrayGet( size_t index )
|
|
{
|
|
wxString str;
|
|
wxPropertyGrid::DoubleToString(str,m_array[index],m_precision,true,&m_dtoaTemplate);
|
|
return str;
|
|
}
|
|
|
|
size_t wxArrayDoubleEditorDialog::ArrayGetCount()
|
|
{
|
|
return m_array.GetCount();
|
|
}
|
|
|
|
bool wxArrayDoubleEditorDialog::ArrayInsert( const wxString& str, int index )
|
|
{
|
|
double d;
|
|
if ( !str.ToDouble(&d) )
|
|
return FALSE;
|
|
|
|
if (index<0)
|
|
m_array.Add(d);
|
|
else
|
|
m_array.Insert(d,index);
|
|
return TRUE;
|
|
}
|
|
|
|
bool wxArrayDoubleEditorDialog::ArraySet( size_t index, const wxString& str )
|
|
{
|
|
double d;
|
|
if ( !str.ToDouble(&d) )
|
|
return FALSE;
|
|
m_array[index] = d;
|
|
return TRUE;
|
|
}
|
|
|
|
void wxArrayDoubleEditorDialog::ArrayRemoveAt( int index )
|
|
{
|
|
m_array.RemoveAt(index);
|
|
}
|
|
|
|
void wxArrayDoubleEditorDialog::ArraySwap( size_t first, size_t second )
|
|
{
|
|
double a = m_array[first];
|
|
double b = m_array[second];
|
|
m_array[first] = b;
|
|
m_array[second] = a;
|
|
}
|
|
|
|
//
|
|
// Array dialog construction etc.
|
|
//
|
|
|
|
wxArrayDoubleEditorDialog::wxArrayDoubleEditorDialog()
|
|
: wxPGArrayEditorDialog()
|
|
{
|
|
Init();
|
|
}
|
|
|
|
void wxArrayDoubleEditorDialog::Init()
|
|
{
|
|
wxPGArrayEditorDialog::Init();
|
|
SetPrecision(-1);
|
|
}
|
|
|
|
wxArrayDoubleEditorDialog::wxArrayDoubleEditorDialog(wxWindow *parent,
|
|
const wxString& message,
|
|
const wxString& caption,
|
|
wxArrayDouble& array,
|
|
long style,
|
|
const wxPoint& pos,
|
|
const wxSize& sz )
|
|
: wxPGArrayEditorDialog()
|
|
{
|
|
Init();
|
|
Create(parent,message,caption,array,style,pos,sz);
|
|
}
|
|
|
|
bool wxArrayDoubleEditorDialog::Create(wxWindow *parent,
|
|
const wxString& message,
|
|
const wxString& caption,
|
|
wxArrayDouble& array,
|
|
long style,
|
|
const wxPoint& pos,
|
|
const wxSize& sz )
|
|
{
|
|
|
|
m_array = array;
|
|
|
|
return wxPGArrayEditorDialog::Create (parent,message,caption,style,pos,sz);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// wxArrayDoubleProperty
|
|
// -----------------------------------------------------------------------
|
|
|
|
#include <math.h> // for fabs
|
|
|
|
// Comparison required by value type implementation.
|
|
bool operator == (const wxArrayDouble& a, const wxArrayDouble& b)
|
|
{
|
|
if ( a.GetCount() != b.GetCount() )
|
|
return FALSE;
|
|
|
|
size_t i;
|
|
|
|
for ( i=0; i<a.GetCount(); i++ )
|
|
{
|
|
// Can't do direct equality comparison with floating point numbers.
|
|
if ( fabs(a[i] - b[i]) > 0.0000000001 )
|
|
{
|
|
//wxLogDebug(wxT("%f != %f"),a[i],b[i]);
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
WX_PG_IMPLEMENT_VARIANT_DATA_DUMMY_EQ(wxArrayDouble)
|
|
|
|
WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayDoubleProperty,
|
|
wxPGProperty,
|
|
wxArrayDouble,
|
|
const wxArrayDouble&,
|
|
TextCtrlAndButton)
|
|
|
|
|
|
wxArrayDoubleProperty::wxArrayDoubleProperty (const wxString& label,
|
|
const wxString& name,
|
|
const wxArrayDouble& array )
|
|
: wxPGProperty(label,name)
|
|
{
|
|
m_precision = -1;
|
|
|
|
//
|
|
// Need to figure out delimiter needed for this locale
|
|
// (ie. can't use comma when comma acts as decimal point in float).
|
|
wxChar use_delimiter = wxT(',');
|
|
|
|
if (wxString::Format(wxT("%.2f"),12.34).Find(use_delimiter) >= 0)
|
|
use_delimiter = wxT(';');
|
|
|
|
m_delimiter = use_delimiter;
|
|
|
|
SetValue( WXVARIANT(array) );
|
|
}
|
|
|
|
wxArrayDoubleProperty::~wxArrayDoubleProperty () { }
|
|
|
|
void wxArrayDoubleProperty::OnSetValue()
|
|
{
|
|
// Generate cached display string, to optimize grid drawing
|
|
GenerateValueAsString( m_display, m_precision, true );
|
|
}
|
|
|
|
wxString wxArrayDoubleProperty::ValueToString( wxVariant& value,
|
|
int argFlags ) const
|
|
{
|
|
wxString s;
|
|
|
|
if ( argFlags & wxPG_FULL_VALUE )
|
|
{
|
|
GenerateValueAsString(s,-1,false);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Display cached string only if value truly matches m_value
|
|
if ( value.GetData() == m_value.GetData() )
|
|
return m_display;
|
|
else
|
|
GenerateValueAsString( s, m_precision, true );
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
void wxArrayDoubleProperty::GenerateValueAsString( wxString& target, int prec, bool removeZeroes ) const
|
|
{
|
|
wxString s;
|
|
wxString template_str;
|
|
wxChar between[3] = wxT(", ");
|
|
size_t i;
|
|
|
|
between[0] = m_delimiter;
|
|
|
|
target.Empty();
|
|
|
|
const wxArrayDouble& value = wxArrayDoubleRefFromVariant(m_value);
|
|
|
|
for ( i=0; i<value.GetCount(); i++ )
|
|
{
|
|
|
|
wxPropertyGrid::DoubleToString(s,value[i],prec,removeZeroes,&template_str);
|
|
|
|
target += s;
|
|
|
|
if ( i<(value.GetCount()-1) )
|
|
target += between;
|
|
}
|
|
}
|
|
|
|
bool wxArrayDoubleProperty::OnEvent( wxPropertyGrid* propgrid,
|
|
wxWindow* WXUNUSED(primary),
|
|
wxEvent& event)
|
|
{
|
|
if ( propgrid->IsMainButtonEvent(event) )
|
|
{
|
|
// Update the value in case of last minute changes
|
|
wxVariant useValue = propgrid->GetUncommittedPropertyValue();
|
|
|
|
wxArrayDouble& value = wxArrayDoubleRefFromVariant(useValue);
|
|
|
|
// Create editor dialog.
|
|
wxArrayDoubleEditorDialog dlg;
|
|
dlg.SetPrecision(m_precision);
|
|
dlg.Create( propgrid, wxEmptyString, m_label, value );
|
|
dlg.Move( propgrid->GetGoodEditorDialogPosition(this,dlg.GetSize()) );
|
|
|
|
// Execute editor dialog
|
|
int res = dlg.ShowModal();
|
|
if ( res == wxID_OK && dlg.IsModified() )
|
|
{
|
|
SetValueInEvent( WXVARIANT(dlg.GetArray()) );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool wxArrayDoubleProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
|
|
{
|
|
double tval;
|
|
wxString tstr;
|
|
// Add values to a temporary array so that in case
|
|
// of error we can opt not to use them.
|
|
wxArrayDouble new_array;
|
|
|
|
bool ok = true;
|
|
|
|
wxChar delimiter = m_delimiter;
|
|
|
|
WX_PG_TOKENIZER1_BEGIN(text,delimiter)
|
|
|
|
if ( !token.empty() )
|
|
{
|
|
|
|
// If token was invalid, exit the loop now
|
|
if ( !token.ToDouble(&tval) )
|
|
{
|
|
tstr.Printf ( _("\"%s\" is not a floating-point number."), token.c_str() );
|
|
ok = false;
|
|
break;
|
|
}
|
|
// TODO: Put validator code here
|
|
|
|
new_array.Add(tval);
|
|
|
|
}
|
|
|
|
WX_PG_TOKENIZER1_END()
|
|
|
|
// When invalid token found, show error message and don't change anything
|
|
if ( !ok )
|
|
{
|
|
//ShowError( tstr );
|
|
return false;
|
|
}
|
|
|
|
if ( !(wxArrayDoubleRefFromVariant(m_value) == new_array) )
|
|
{
|
|
variant = WXVARIANT(new_array);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wxArrayDoubleProperty::DoSetAttribute( const wxString& name, wxVariant& value )
|
|
{
|
|
if ( name == wxPG_FLOAT_PRECISION )
|
|
{
|
|
m_precision = value.GetLong();
|
|
GenerateValueAsString( m_display, m_precision, true );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|