// Author: Jaakko Salli
// Modified by:
// Created: 2004-09-25
-// RCS-ID: $Id:
+// RCS-ID: $Id$
// Copyright: (c) Jaakko Salli
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
#include "wx/stattext.h"
#include "wx/scrolwin.h"
#include "wx/dirdlg.h"
- #include "wx/layout.h"
#include "wx/sizer.h"
#include "wx/textdlg.h"
#include "wx/filedlg.h"
// This define is necessary to prevent macro clearing
#define __wxPG_SOURCE_FILE__
-#include <wx/propgrid/propgrid.h>
-#include <wx/propgrid/editors.h>
+#include "wx/propgrid/propgrid.h"
+#include "wx/propgrid/editors.h"
#if wxPG_USE_RENDERER_NATIVE
- #include <wx/renderer.h>
+ #include "wx/renderer.h"
#endif
-#include <wx/odcombo.h>
+#include "wx/odcombo.h"
#include "wx/timer.h"
#include "wx/dcbuffer.h"
-#include <wx/clipbrd.h>
-#include <wx/dataobj.h>
+#include "wx/clipbrd.h"
+#include "wx/dataobj.h"
#ifdef __WXMSW__
- #include <wx/msw/private.h>
+ #include "wx/msw/private.h"
#endif
-#include <typeinfo>
-
// Two pics for the expand / collapse buttons.
// Files are not supplied with this project (since it is
// recommended to use either custom or native rendering).
//#define wxPG_TEXT_INDENT 4 // For the wxComboControl
-#define wxPG_ALLOW_CLIPPING 1 // If 1, GetUpdateRegion() in OnPaint event handler is not ignored
+//#define wxPG_ALLOW_CLIPPING 1 // If 1, GetUpdateRegion() in OnPaint event handler is not ignored
#define wxPG_GUTTER_DIV 3 // gutter is max(iconwidth/gutter_div,gutter_min)
#define wxPG_GUTTER_MIN 3 // gutter before and after image of [+] or [-]
#define wxPG_YSPACING_MIN 1
#define wxPG_DEFAULT_VSPACING 2 // This matches .NET propertygrid's value,
// but causes normal combobox to spill out under MSW
-#define wxPG_OPTIMAL_WIDTH 200 // Arbitrary
+//#define wxPG_OPTIMAL_WIDTH 200 // Arbitrary
-#define wxPG_MIN_SCROLLBAR_WIDTH 10 // Smallest scrollbar width on any platform
+//#define wxPG_MIN_SCROLLBAR_WIDTH 10 // Smallest scrollbar width on any platform
// Must be larger than largest control border
// width * 2.
//#define wxPG_NAT_CHOICE_BORDER_ANY 0
-#define wxPG_HIDER_BUTTON_HEIGHT 25
+//#define wxPG_HIDER_BUTTON_HEIGHT 25
#define wxPG_PIXELS_PER_UNIT m_lineHeight
#define m_iconHeight m_iconWidth
#endif
-#define wxPG_TOOLTIP_DELAY 1000
+//#define wxPG_TOOLTIP_DELAY 1000
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
-const wxChar *wxPropertyGridNameStr = wxT("wxPropertyGrid");
+const char wxPropertyGridNameStr[] = "wxPropertyGrid";
// -----------------------------------------------------------------------
// Statics in one class for easy destruction.
-// NB: We prefer to use wxModule, as it offers more consistent behavior
-// across platforms. However, for those rare problem situations, we
-// also need to offer option to use simpler approach.
// -----------------------------------------------------------------------
-#ifndef wxPG_USE_WXMODULE
- #define wxPG_USE_WXMODULE 1
-#endif
-
-#if wxPG_USE_WXMODULE
-
-#include <wx/module.h>
+#include "wx/module.h"
class wxPGGlobalVarsClassManager : public wxModule
{
IMPLEMENT_DYNAMIC_CLASS(wxPGGlobalVarsClassManager, wxModule)
-#else // !wxPG_USE_WXMODULE
-
-class wxPGGlobalVarsClassManager
-{
-public:
- wxPGGlobalVarsClassManager() {}
- ~wxPGGlobalVarsClassManager() { delete wxPGGlobalVars; }
-};
-
-static wxPGGlobalVarsClassManager gs_pgGlobalVarsClassManager;
-
-#endif
-
-wxPGGlobalVarsClass* wxPGGlobalVars = (wxPGGlobalVarsClass*) NULL;
+wxPGGlobalVarsClass* wxPGGlobalVars = NULL;
wxPGGlobalVarsClass::wxPGGlobalVarsClass()
m_boolChoices.Add(_("False"));
m_boolChoices.Add(_("True"));
- m_fontFamilyChoices = (wxPGChoices*) NULL;
+ m_fontFamilyChoices = NULL;
m_defaultRenderer = new wxPGDefaultRenderer();
delete wxPGProperty::sm_wxPG_LABEL;
}
-// -----------------------------------------------------------------------
-// wxPGBrush
-// -----------------------------------------------------------------------
-
-//
-// This class is a wxBrush derivative used in the background colour
-// brush cache. It adds wxPG-type colour-in-long to the class.
-// JMS: Yes I know wxBrush doesn't actually hold the value (refcounted
-// object does), but this is simpler implementation and equally
-// effective.
-//
-
-class wxPGBrush : public wxBrush
-{
-public:
- wxPGBrush( const wxColour& colour );
- wxPGBrush();
- virtual ~wxPGBrush() { }
- void SetColour2( const wxColour& colour );
- inline long GetColourAsLong() const { return m_colAsLong; }
-private:
- long m_colAsLong;
-};
-
-
-void wxPGBrush::SetColour2( const wxColour& colour )
-{
- wxBrush::SetColour(colour);
- m_colAsLong = wxPG_COLOUR(colour.Red(),colour.Green(),colour.Blue());
-}
-
-
-wxPGBrush::wxPGBrush() : wxBrush()
-{
- m_colAsLong = 0;
-}
-
-
-wxPGBrush::wxPGBrush( const wxColour& colour ) : wxBrush(colour)
-{
- m_colAsLong = wxPG_COLOUR(colour.Red(),colour.Green(),colour.Blue());
-}
-
-
-// -----------------------------------------------------------------------
-// wxPGColour
-// -----------------------------------------------------------------------
-
-//
-// Same as wxPGBrush, but for wxColour instead.
-//
-
-class wxPGColour : public wxColour
-{
-public:
- wxPGColour( const wxColour& colour );
- wxPGColour();
- virtual ~wxPGColour() { }
- void SetColour2( const wxColour& colour );
- inline long GetColourAsLong() const { return m_colAsLong; }
-private:
- long m_colAsLong;
-};
-
-
-void wxPGColour::SetColour2( const wxColour& colour )
-{
- *this = colour;
- m_colAsLong = wxPG_COLOUR(colour.Red(),colour.Green(),colour.Blue());
-}
-
-
-wxPGColour::wxPGColour() : wxColour()
-{
- m_colAsLong = 0;
-}
-
-
-wxPGColour::wxPGColour( const wxColour& colour ) : wxColour(colour)
+void wxPropertyGridInitGlobalsIfNeeded()
{
- m_colAsLong = wxPG_COLOUR(colour.Red(),colour.Green(),colour.Blue());
}
-
// -----------------------------------------------------------------------
// wxPGTLWHandler
// Intercepts Close-events sent to wxPropertyGrid's top-level parent,
pg->OnKey( event );
}
- void OnKeyUp( wxKeyEvent& event )
- {
- wxPropertyGrid* pg = wxStaticCast(GetParent(), wxPropertyGrid);
- pg->OnKeyUp( event );
- }
+ void OnPaint( wxPaintEvent& event );
- void OnNavigationKey( wxNavigationKeyEvent& event )
- {
- wxPropertyGrid* pg = wxStaticCast(GetParent(), wxPropertyGrid);
- pg->OnNavigationKey( event );
- }
+ // Always be focussable, even with child windows
+ virtual void SetCanFocus(bool WXUNUSED(canFocus))
+ { wxPanel::SetCanFocus(true); }
- void OnPaint( wxPaintEvent& event );
private:
DECLARE_EVENT_TABLE()
+ DECLARE_ABSTRACT_CLASS(wxPGCanvas)
};
+IMPLEMENT_ABSTRACT_CLASS(wxPGCanvas,wxPanel)
+
BEGIN_EVENT_TABLE(wxPGCanvas, wxPanel)
EVT_MOTION(wxPGCanvas::OnMouseMove)
EVT_PAINT(wxPGCanvas::OnPaint)
EVT_RIGHT_UP(wxPGCanvas::OnMouseRightClick)
EVT_LEFT_DCLICK(wxPGCanvas::OnMouseDoubleClick)
EVT_KEY_DOWN(wxPGCanvas::OnKey)
- EVT_KEY_UP(wxPGCanvas::OnKeyUp)
- EVT_CHAR(wxPGCanvas::OnKey)
- EVT_NAVIGATION_KEY(wxPGCanvas::OnNavigationKey)
END_EVENT_TABLE()
EVT_CHILD_FOCUS(wxPropertyGrid::OnChildFocusEvent)
EVT_SET_FOCUS(wxPropertyGrid::OnFocusEvent)
EVT_KILL_FOCUS(wxPropertyGrid::OnFocusEvent)
- EVT_TEXT_ENTER(wxPG_SUBID1,wxPropertyGrid::OnCustomEditorEvent)
EVT_SYS_COLOUR_CHANGED(wxPropertyGrid::OnSysColourChanged)
END_EVENT_TABLE()
const wxPoint& pos,
const wxSize& size,
long style,
- const wxChar* name )
+ const wxString& name )
: wxScrolledWindow()
{
Init1();
const wxPoint& pos,
const wxSize& size,
long style,
- const wxChar* name )
+ const wxString& name )
{
if ( !(style&wxBORDER_MASK) )
style |= wxVSCROLL;
-#ifdef __WXMSW__
- // This prevents crash under Win2K, but still
- // enables keyboard navigation
- if ( style & wxTAB_TRAVERSAL )
- {
- style &= ~(wxTAB_TRAVERSAL);
- style |= wxWANTS_CHARS;
- }
-#else
- if ( style & wxTAB_TRAVERSAL )
- style |= wxWANTS_CHARS;
-#endif
+ // Filter out wxTAB_TRAVERSAL - we will handle TABs manually
+ style &= ~(wxTAB_TRAVERSAL);
+ style |= wxWANTS_CHARS;
wxScrolledWindow::Create(parent,id,pos,size,style,name);
//
void wxPropertyGrid::Init1()
{
-#if !wxPG_USE_WXMODULE
- if ( !wxPGGlobalVars )
- wxPGGlobalVars = new wxPGGlobalVarsClass();
-#endif
-
// Register editor classes, if necessary.
if ( wxPGGlobalVars->m_mapEditorClasses.empty() )
- RegisterDefaultEditors();
+ wxPropertyGrid::RegisterDefaultEditors();
m_iFlags = 0;
- m_pState = (wxPropertyGridPageState*) NULL;
- m_wndEditor = m_wndEditor2 = (wxWindow*) NULL;
- m_selected = (wxPGProperty*) NULL;
+ m_pState = NULL;
+ m_wndEditor = m_wndEditor2 = NULL;
+ m_selected = NULL;
m_selColumn = -1;
- m_propHover = (wxPGProperty*) NULL;
+ m_propHover = NULL;
m_eventObject = this;
- m_curFocused = (wxWindow*) NULL;
+ m_curFocused = NULL;
m_tlwHandler = NULL;
+ m_sortFunction = NULL;
m_inDoPropertyChanged = 0;
m_inCommitChangesFromEditor = 0;
m_inDoSelectProperty = 0;
AddActionTrigger( wxPG_ACTION_EXPAND_PROPERTY, WXK_RIGHT);
AddActionTrigger( wxPG_ACTION_COLLAPSE_PROPERTY, WXK_LEFT);
AddActionTrigger( wxPG_ACTION_CANCEL_EDIT, WXK_ESCAPE );
- AddActionTrigger( wxPG_ACTION_CUT, 'X', wxMOD_CONTROL );
- AddActionTrigger( wxPG_ACTION_CUT, WXK_DELETE, wxMOD_SHIFT );
- AddActionTrigger( wxPG_ACTION_COPY, 'C', wxMOD_CONTROL);
- AddActionTrigger( wxPG_ACTION_COPY, WXK_INSERT, wxMOD_CONTROL );
- AddActionTrigger( wxPG_ACTION_PASTE, 'V', wxMOD_CONTROL );
- AddActionTrigger( wxPG_ACTION_PASTE, WXK_INSERT, wxMOD_SHIFT );
+ AddActionTrigger( wxPG_ACTION_PRESS_BUTTON, WXK_DOWN, wxMOD_ALT );
+ AddActionTrigger( wxPG_ACTION_PRESS_BUTTON, WXK_F4 );
m_coloursCustomized = 0;
m_frozen = 0;
m_canvas = NULL;
#if wxPG_DOUBLE_BUFFER
- m_doubleBuffer = (wxBitmap*) NULL;
+ m_doubleBuffer = NULL;
#endif
- m_windowsToDelete = NULL;
-
#ifndef wxPG_ICON_WIDTH
m_expandbmp = NULL;
m_collbmp = NULL;
m_width = m_height = 0;
- SetButtonShortcut(0);
-
- m_keyComboConsumed = 0;
-
m_commonValues.push_back(new wxPGCommonValue(_("Unspecified"), wxPGGlobalVars->m_defaultRenderer) );
m_cvUnspecified = 0;
#ifdef __WXMAC__
// Smaller controls on Mac
SetWindowVariant(wxWINDOW_VARIANT_SMALL);
-#endif
+#endif
// Now create state, if one didn't exist already
// (wxPropertyGridManager might have created it for us).
wxScrolledWindow::SetOwnFont( useFont );
}
else
+ {
// This should be otherwise called by SetOwnFont
CalculateFontAndBitmapStuff( wxPG_DEFAULT_VSPACING );
+ }
- // Add base brush item
- m_arrBgBrushes.Add((void*)new wxPGBrush());
-
- // Add base colour items
- m_arrFgCols.Add((void*)new wxPGColour());
- m_arrFgCols.Add((void*)new wxPGColour());
+ // Allocate cell datas indirectly by calling setter
+ m_propertyDefaultCell.SetBgCol(*wxBLACK);
+ m_categoryDefaultCell.SetBgCol(*wxBLACK);
RegainColours();
m_canvas = new wxPGCanvas();
m_canvas->Create(this, 1, wxPoint(0, 0), GetClientSize(),
- (GetWindowStyle() & wxTAB_TRAVERSAL) | wxWANTS_CHARS | wxCLIP_CHILDREN);
+ wxWANTS_CHARS | wxCLIP_CHILDREN);
m_canvas->SetBackgroundStyle( wxBG_STYLE_CUSTOM );
m_iFlags |= wxPG_FL_INITIALIZED;
delete m_doubleBuffer;
#endif
- delete m_windowsToDelete;
-
- //m_selected = (wxPGProperty*) NULL;
+ //m_selected = NULL;
if ( m_iFlags & wxPG_FL_CREATEDSTATE )
delete m_pState;
delete m_collbmp;
#endif
- // Delete cached text colours.
- for ( i=0; i<m_arrFgCols.size(); i++ )
- {
- delete (wxPGColour*)m_arrFgCols.Item(i);
- }
-
- // Delete cached brushes.
- for ( i=0; i<m_arrBgBrushes.size(); i++ )
- {
- delete (wxPGBrush*)m_arrBgBrushes.Item(i);
- }
-
// Delete common value records
for ( i=0; i<m_commonValues.size(); i++ )
{
//
// Tooltips disabled
//
- m_canvas->SetToolTip( (wxToolTip*) NULL );
+ m_canvas->SetToolTip( NULL );
}
#endif
}
void wxPropertyGrid::RegainColours()
{
- wxColour def_bgcol = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
-
if ( !(m_coloursCustomized & 0x0002) )
{
wxColour col = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
m_colCapBack = wxPGAdjustColour(col,-colDec);
else
m_colCapBack = col;
+ m_categoryDefaultCell.GetData()->SetBgCol(m_colCapBack);
}
if ( !(m_coloursCustomized & 0x0001) )
#endif
wxColour capForeCol = wxPGAdjustColour(m_colCapBack,colDec,5000,5000,true);
m_colCapFore = capForeCol;
-
- // Set the cached colour as well.
- ((wxPGColour*)m_arrFgCols.Item(1))->SetColour2(capForeCol);
+ m_categoryDefaultCell.GetData()->SetFgCol(capForeCol);
}
if ( !(m_coloursCustomized & 0x0008) )
{
wxColour bgCol = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
m_colPropBack = bgCol;
-
- // Set the cached brush as well.
- ((wxPGBrush*)m_arrBgBrushes.Item(0))->SetColour2(bgCol);
+ m_propertyDefaultCell.GetData()->SetBgCol(bgCol);
}
if ( !(m_coloursCustomized & 0x0010) )
{
wxColour fgCol = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
m_colPropFore = fgCol;
-
- // Set the cached colour as well.
- ((wxPGColour*)m_arrFgCols.Item(0))->SetColour2(fgCol);
+ m_propertyDefaultCell.GetData()->SetFgCol(fgCol);
}
if ( !(m_coloursCustomized & 0x0020) )
bool wxPropertyGrid::SetFont( const wxFont& font )
{
// Must disable active editor.
- if ( m_selected )
- {
- bool selRes = ClearSelection();
- wxPG_CHECK_MSG_DBG( selRes,
- false,
- wxT("failed to deselect a property (editor probably had invalid value)") );
- }
+ ClearSelection(false);
// TODO: Following code is disabled with wxMac because
// it is reported to fail. I (JMS) cannot debug it
// personally right now.
-#if !defined(__WXMAC__)
+ // CS: should be fixed now, leaving old code in just in case, TODO: REMOVE
+#if 1 // !defined(__WXMAC__)
bool res = wxScrolledWindow::SetFont( font );
if ( res )
{
m_colPropBack = col;
m_coloursCustomized |= 0x08;
- // Set the cached brush as well.
- ((wxPGBrush*)m_arrBgBrushes.Item(0))->SetColour2(col);
+ m_propertyDefaultCell.GetData()->SetBgCol(col);
Refresh();
}
m_colPropFore = col;
m_coloursCustomized |= 0x10;
- // Set the cached colour as well.
- ((wxPGColour*)m_arrFgCols.Item(0))->SetColour2(col);
+ m_propertyDefaultCell.GetData()->SetFgCol(col);
Refresh();
}
{
m_colCapBack = col;
m_coloursCustomized |= 0x02;
+
+ m_categoryDefaultCell.GetData()->SetBgCol(col);
+
Refresh();
}
m_colCapFore = col;
m_coloursCustomized |= 0x04;
- // Set the cached colour as well.
- ((wxPGColour*)m_arrFgCols.Item(1))->SetColour2(col);
+ m_categoryDefaultCell.GetData()->SetFgCol(col);
Refresh();
}
-// -----------------------------------------------------------------------
-
-void wxPropertyGrid::SetBackgroundColourIndex( wxPGProperty* p, int index )
-{
- unsigned char ind = index;
-
- p->m_bgColIndex = ind;
-
- unsigned int i;
- for ( i=0; i<p->GetChildCount(); i++ )
- SetBackgroundColourIndex(p->Item(i),index);
-}
-
-// -----------------------------------------------------------------------
-
-void wxPropertyGrid::SetPropertyBackgroundColour( wxPGPropArg id, const wxColour& colour )
-{
- wxPG_PROP_ARG_CALL_PROLOG()
-
- size_t i;
- int colInd = -1;
-
- long colAsLong = wxPG_COLOUR(colour.Red(),colour.Green(),colour.Blue());
-
- // As it is most likely that the previous colour is used, start comparison
- // from the end.
- for ( i=(m_arrBgBrushes.size()-1); i>0; i-- )
- {
- if ( ((wxPGBrush*)m_arrBgBrushes.Item(i))->GetColourAsLong() == colAsLong )
- {
- colInd = i;
- break;
- }
- }
-
- if ( colInd < 0 )
- {
- colInd = m_arrBgBrushes.size();
- wxCHECK_RET( colInd < 256, wxT("wxPropertyGrid: Warning - Only 255 different property background colours allowed.") );
- m_arrBgBrushes.Add( (void*)new wxPGBrush(colour) );
- }
-
- // Set indexes
- SetBackgroundColourIndex(p,colInd);
-
- // If this was on a visible grid, then draw it.
- DrawItemAndChildren(p);
-}
-
-// -----------------------------------------------------------------------
-
-wxColour wxPropertyGrid::GetPropertyBackgroundColour( wxPGPropArg id ) const
-{
- wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxColour())
-
- return ((wxPGBrush*)m_arrBgBrushes.Item(p->m_bgColIndex))->GetColour();
-}
-
-// -----------------------------------------------------------------------
-
-void wxPropertyGrid::SetTextColourIndex( wxPGProperty* p, int index, int flags )
-{
- unsigned char ind = index;
-
- p->m_fgColIndex = ind;
-
- if ( p->GetChildCount() && (flags & wxPG_RECURSE) )
- {
- unsigned int i;
- for ( i=0; i<p->GetChildCount(); i++ )
- SetTextColourIndex( p->Item(i), index, flags );
- }
-}
-
-// -----------------------------------------------------------------------
-
-int wxPropertyGrid::CacheColour( const wxColour& colour )
-{
- unsigned int i;
- int colInd = -1;
-
- long colAsLong = wxPG_COLOUR(colour.Red(),colour.Green(),colour.Blue());
-
- // As it is most likely that the previous colour is used, start comparison
- // from the end.
- for ( i=(m_arrFgCols.size()-1); i>0; i-- )
- {
- if ( ((wxPGColour*)m_arrFgCols.Item(i))->GetColourAsLong() == colAsLong )
- {
- colInd = i;
- break;
- }
- }
-
- if ( colInd < 0 )
- {
- colInd = m_arrFgCols.size();
- wxCHECK_MSG( colInd < 256, 0, wxT("wxPropertyGrid: Warning - Only 255 different property foreground colours allowed.") );
- m_arrFgCols.Add( (void*)new wxPGColour(colour) );
- }
-
- return colInd;
-}
-
-// -----------------------------------------------------------------------
-
-void wxPropertyGrid::SetPropertyTextColour( wxPGPropArg id, const wxColour& colour,
- bool recursively )
-{
- wxPG_PROP_ARG_CALL_PROLOG()
-
- if ( p->IsCategory() )
- {
- wxPropertyCategory* cat = (wxPropertyCategory*) p;
- cat->SetTextColIndex(CacheColour(colour));
- }
-
- // Set indexes
- int flags = 0;
- if ( recursively )
- flags |= wxPG_RECURSE;
- SetTextColourIndex(p, CacheColour(colour), flags);
-
- DrawItemAndChildren(p);
-}
-
-// -----------------------------------------------------------------------
-
-wxColour wxPropertyGrid::GetPropertyTextColour( wxPGPropArg id ) const
-{
- wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxColour())
-
- return wxColour(*((wxPGColour*)m_arrFgCols.Item(p->m_fgColIndex)));
-}
-
-void wxPropertyGrid::SetPropertyColoursToDefault( wxPGPropArg id )
-{
- wxPG_PROP_ARG_CALL_PROLOG()
-
- SetBackgroundColourIndex( p, 0 );
- SetTextColourIndex( p, 0, wxPG_RECURSE );
-
- if ( p->IsCategory() )
- {
- wxPropertyCategory* cat = (wxPropertyCategory*) p;
- cat->SetTextColIndex(1);
- }
-}
-
// -----------------------------------------------------------------------
// wxPropertyGrid property adding and removal
// -----------------------------------------------------------------------
m_pState->m_itemsAdded = 0;
if ( m_windowStyle & wxPG_AUTO_SORT )
- Sort();
+ Sort(wxPG_SORT_TOP_LEVEL_ONLY);
RecalculateVirtualSize();
}
-// -----------------------------------------------------------------------
-// wxPropertyGrid property value setting and getting
-// -----------------------------------------------------------------------
-
-void wxPropertyGrid::DoSetPropertyValueUnspecified( wxPGProperty* p )
-{
- m_pState->DoSetPropertyValueUnspecified(p);
- DrawItemAndChildren(p);
-
- wxPGProperty* parent = p->GetParent();
- while ( (parent->GetFlags() & wxPG_PROP_PARENTAL_FLAGS) == wxPG_PROP_MISC_PARENT )
- {
- DrawItem(parent);
- parent = parent->GetParent();
- }
-}
-
// -----------------------------------------------------------------------
// wxPropertyGrid property operations
// -----------------------------------------------------------------------
-void wxPropertyGrid::DoSetPropertyName( wxPGProperty* p, const wxString& newname )
-{
- wxCHECK_RET( p, wxT("invalid property id") );
-
- if ( p->GetBaseName().Len() ) m_pState->m_dictName.erase( p->GetBaseName() );
- if ( newname.Len() ) m_pState->m_dictName[newname] = (void*) p;
-
- p->DoSetName(newname);
-}
-
-// -----------------------------------------------------------------------
-
bool wxPropertyGrid::EnsureVisible( wxPGPropArg id )
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
dst_str.clear();
- for ( ; i != src_str.end(); i++ )
+ for ( ; i != src_str.end(); ++i )
{
wxUniChar a = *i;
dst_str.clear();
- for ( ; i != src_str.end(); i++ )
+ for ( ; i != src_str.end(); ++i )
{
wxChar a = *i;
{
// Outside?
if ( y < 0 )
- return (wxPGProperty*) NULL;
+ return NULL;
unsigned int a = 0;
return m_pState->m_properties->GetItemAtY(y, m_lineHeight, &a);
//
// clipRect conversion
- if ( clipRect )
- {
- cr2 = *clipRect;
- cr2.x -= xRelMod;
- cr2.y -= yRelMod;
- clipRect = &cr2;
- }
+ cr2 = *clipRect;
+ cr2.x -= xRelMod;
+ cr2.y -= yRelMod;
+ clipRect = &cr2;
firstItemTopY -= yRelMod;
lastItemBottomY -= yRelMod;
}
const wxFont& normalfont = m_font;
- bool reallyFocused = (m_iFlags & wxPG_FL_FOCUSED) ? true : false;
+ bool reallyFocused = (m_iFlags & wxPG_FL_FOCUSED) != 0;
bool isEnabled = IsEnabled();
int rowHeight = m_fontHeight+(m_spacingy*2)+1;
int textMarginHere = x;
- int renderFlags = wxPGCellRenderer::Control;
+ int renderFlags = 0;
int greyDepth = m_marginWidth;
if ( !(windowStyle & wxPG_HIDE_CATEGORIES) )
dc.DrawLine( greyDepthX, y2-1, gridWidth-xRelMod, y2-1 );
- if ( p == selected )
- {
- renderFlags |= wxPGCellRenderer::Selected;
-#if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
- wasSelectedPainted = true;
-#endif
- }
-
- wxColour rowBgCol;
+ //
+ // Need to override row colours?
wxColour rowFgCol;
- wxBrush rowBgBrush;
+ wxColour rowBgCol;
- if ( p->IsCategory() )
- {
- if ( p->m_fgColIndex == 0 )
- rowFgCol = m_colCapFore;
- else
- rowFgCol = *(wxPGColour*)m_arrFgCols[p->m_fgColIndex];
- rowBgBrush = wxBrush(m_colCapBack);
- }
- else if ( p != selected )
+ if ( p != selected )
{
// Disabled may get different colour.
if ( !p->IsEnabled() )
+ {
+ renderFlags |= wxPGCellRenderer::Disabled |
+ wxPGCellRenderer::DontUseCellFgCol;
rowFgCol = m_colDisPropFore;
- else
- rowFgCol = *(wxPGColour*)m_arrFgCols[p->m_fgColIndex];
-
- rowBgBrush = *(wxPGBrush*)m_arrBgBrushes[p->m_bgColIndex];
+ }
}
else
{
- // Selected gets different colour.
- if ( reallyFocused )
- {
- rowFgCol = m_colSelFore;
- rowBgBrush = wxBrush(m_colSelBack);
- }
- else if ( isEnabled )
+ renderFlags |= wxPGCellRenderer::Selected;
+
+ if ( !p->IsCategory() )
{
- rowFgCol = *(wxPGColour*)m_arrFgCols[p->m_fgColIndex];
- rowBgBrush = marginBrush;
+ renderFlags |= wxPGCellRenderer::DontUseCellFgCol |
+ wxPGCellRenderer::DontUseCellBgCol;
+
+#if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
+ wasSelectedPainted = true;
+#endif
+
+ // Selected gets different colour.
+ if ( reallyFocused )
+ {
+ rowFgCol = m_colSelFore;
+ rowBgCol = m_colSelBack;
+ }
+ else if ( isEnabled )
+ {
+ rowFgCol = m_colPropFore;
+ rowBgCol = m_colMargin;
+ }
+ else
+ {
+ rowFgCol = m_colDisPropFore;
+ rowBgCol = m_colSelBack;
+ }
}
- else
+ }
+
+ wxBrush rowBgBrush;
+
+ if ( rowBgCol.IsOk() )
+ rowBgBrush = wxBrush(rowBgCol);
+
+ if ( HasInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL) )
+ renderFlags = renderFlags & ~wxPGCellRenderer::DontUseCellColours;
+
+ //
+ // Fill additional margin area with background colour of first cell
+ if ( greyDepthX < textMarginHere )
+ {
+ if ( !(renderFlags & wxPGCellRenderer::DontUseCellBgCol) )
{
- rowFgCol = m_colDisPropFore;
- rowBgBrush = wxBrush(m_colSelBack);
+ wxPGCell& cell = p->GetCell(0);
+ rowBgCol = cell.GetBgCol();
+ rowBgBrush = wxBrush(rowBgCol);
}
+ dc.SetBrush(rowBgBrush);
+ dc.SetPen(rowBgCol);
+ dc.DrawRectangle(greyDepthX+1, y,
+ textMarginHere-greyDepthX, lh-1);
}
bool fontChanged = false;
+ // Expander button rectangle
wxRect butRect( ((p->m_depth - 1) * m_subgroup_extramargin) - xRelMod,
y,
m_marginWidth,
if ( p->IsCategory() )
{
- // Captions are all cells merged as one
+ // Captions have their cell areas merged as one
dc.SetFont(m_captionFont);
fontChanged = true;
wxRect cellRect(greyDepthX, y, gridWidth - greyDepth + 2, rowHeight-1 );
- dc.SetBrush(rowBgBrush);
- dc.SetPen(rowBgBrush.GetColour());
- dc.SetTextForeground(rowFgCol);
+ if ( renderFlags & wxPGCellRenderer::DontUseCellBgCol )
+ {
+ dc.SetBrush(rowBgBrush);
+ dc.SetPen(rowBgCol);
+ }
- dc.DrawRectangle(cellRect);
+ if ( renderFlags & wxPGCellRenderer::DontUseCellFgCol )
+ {
+ dc.SetTextForeground(rowFgCol);
+ }
- // Foreground
wxPGCellRenderer* renderer = p->GetCellRenderer(0);
renderer->Render( dc, cellRect, this, p, 0, -1, renderFlags );
unsigned int ci;
int cellX = x + 1;
- int nextCellWidth = state->m_colWidths[0];
+ int nextCellWidth = state->m_colWidths[0] -
+ (greyDepthX - m_marginWidth);
wxRect cellRect(greyDepthX+1, y, 0, rowHeight-1);
int textXAdd = textMarginHere - greyDepthX;
cellRect.width = nextCellWidth - 1;
bool ctrlCell = false;
+ int cellRenderFlags = renderFlags;
+
+ // Tree Item Button
+ if ( ci == 0 && !HasFlag(wxPG_HIDE_MARGIN) && p->HasVisibleChildren() )
+ DrawExpanderButton( dc, butRect, p );
// Background
if ( p == selected && m_wndEditor && ci == 1 )
dc.SetBrush(editorBgCol);
dc.SetPen(editorBgCol);
dc.SetTextForeground(m_colPropFore);
+ dc.DrawRectangle(cellRect);
if ( m_dragStatus == 0 && !(m_iFlags & wxPG_FL_CUR_USES_CUSTOM_IMAGE) )
ctrlCell = true;
}
else
{
- dc.SetBrush(rowBgBrush);
- dc.SetPen(rowBgBrush.GetColour());
- dc.SetTextForeground(rowFgCol);
- }
-
- dc.DrawRectangle(cellRect);
+ if ( renderFlags & wxPGCellRenderer::DontUseCellBgCol )
+ {
+ dc.SetBrush(rowBgBrush);
+ dc.SetPen(rowBgCol);
+ }
- // Tree Item Button
- if ( ci == 0 && !HasFlag(wxPG_HIDE_MARGIN) && p->HasVisibleChildren() )
- DrawExpanderButton( dc, butRect, p );
+ if ( renderFlags & wxPGCellRenderer::DontUseCellFgCol )
+ {
+ dc.SetTextForeground(rowFgCol);
+ }
+ }
dc.SetClippingRegion(cellRect);
if ( cmnVal == -1 || ci != 1 )
{
renderer = p->GetCellRenderer(ci);
- renderer->Render( dc, cellRect, this, p, ci, -1, renderFlags );
+ renderer->Render( dc, cellRect, this, p, ci, -1,
+ cellRenderFlags );
}
else
{
renderer = GetCommonValue(cmnVal)->GetRenderer();
- renderer->Render( dc, cellRect, this, p, ci, -1, renderFlags );
+ renderer->Render( dc, cellRect, this, p, ci, -1,
+ cellRenderFlags );
}
}
cellX += state->m_colWidths[ci];
if ( ci < (state->m_colWidths.size()-1) )
nextCellWidth = state->m_colWidths[ci+1];
- cellRect.x = cellX;
+ cellRect.x = cellX;
dc.DestroyClippingRegion(); // Is this really necessary?
textXAdd = 0;
}
if ( m_width < 10 || m_height < 10 ||
!m_pState->m_properties->GetChildCount() ||
- p1 == (wxPGProperty*) NULL )
+ p1 == NULL )
return wxRect(0,0,0,0);
int vy = 0;
if ( m_pState->m_itemsAdded || m_frozen )
return;
- wxWindow* wndPrimary = GetEditorControl();
-
// Update child control.
if ( m_selected && m_selected->GetParent() == p )
- m_selected->UpdateControl(wndPrimary);
+ RefreshEditor();
const wxPGProperty* lastDrawn = p->GetLastVisibleSubItem();
void wxPropertyGrid::Clear()
{
- if ( m_selected )
- {
- bool selRes = DoSelectProperty(NULL, wxPG_SEL_DELETING); // This must be before state clear
- wxPG_CHECK_RET_DBG( selRes,
- wxT("failed to deselect a property (editor probably had invalid value)") );
- }
+ ClearSelection(false);
m_pState->DoClear();
bool wxPropertyGrid::EnableCategories( bool enable )
{
- if ( !ClearSelection() )
- return false;
+ ClearSelection(false);
if ( enable )
{
wxPGProperty* oldSelection = m_selected;
- // Deselect
- if ( m_selected )
- {
- bool selRes = ClearSelection();
- wxPG_CHECK_RET_DBG( selRes,
- wxT("failed to deselect a property (editor probably had invalid value)") );
- }
+ ClearSelection(false);
m_pState->m_selected = oldSelection;
pNewState->OnClientWidthChange( pgWidth, pgWidth - pNewState->m_width );
}
- m_propHover = (wxPGProperty*) NULL;
+ m_propHover = NULL;
// If necessary, convert state to correct mode.
if ( orig_mode != new_state_mode )
else if ( !m_frozen )
{
// Refresh, if not frozen.
- if ( m_pState->m_itemsAdded )
- PrepareAfterItemsAdded();
+ m_pState->PrepareAfterItemsAdded();
// Reselect
if ( m_pState->m_selected )
// -----------------------------------------------------------------------
-void wxPropertyGrid::SortChildren( wxPGPropArg id )
-{
- wxPG_PROP_ARG_CALL_PROLOG()
-
- m_pState->SortChildren( p );
-}
-
-// -----------------------------------------------------------------------
-
-void wxPropertyGrid::Sort()
-{
- bool selRes = ClearSelection(); // This must be before state clear
- wxPG_CHECK_RET_DBG( selRes,
- wxT("failed to deselect a property (editor probably had invalid value)") );
-
- m_pState->Sort();
-}
-
-// -----------------------------------------------------------------------
-
// Call to SetSplitterPosition will always disable splitter auto-centering
// if parent window is shown.
void wxPropertyGrid::DoSetSplitterPosition_( int newxpos, bool refresh, int splitterIndex, bool allPages )
}
-// -----------------------------------------------------------------------
-
-void wxPropertyGrid::SetButtonShortcut( int keycode, bool ctrlDown, bool altDown )
-{
- if ( keycode )
- {
- m_pushButKeyCode = keycode;
- m_pushButKeyCodeNeedsCtrl = ctrlDown ? 1 : 0;
- m_pushButKeyCodeNeedsAlt = altDown ? 1 : 0;
- }
- else
- {
- m_pushButKeyCode = WXK_DOWN;
- m_pushButKeyCodeNeedsCtrl = 0;
- m_pushButKeyCodeNeedsAlt = 1;
- }
-}
-
// -----------------------------------------------------------------------
// Methods related to change in value, value modification and sending events
// -----------------------------------------------------------------------
// Don't do this if already processing editor event. It might
// induce recursive dialogs and crap like that.
- if ( m_iFlags & wxPG_FL_IN_ONCUSTOMEDITOREVENT )
+ if ( m_iFlags & wxPG_FL_IN_HANDLECUSTOMEDITOREVENT )
{
if ( m_inDoPropertyChanged )
return true;
// -----------------------------------------------------------------------
-bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue )
+bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue,
+ int flags )
{
//
// Runs all validation functionality.
wxVariant evtChangingValue = value;
- // FIXME: After proper ValueToString()s added, remove
- // this. It is just a temporary fix, as evt_changing
- // will simply not work for wxPG_PROP_COMPOSED_VALUE
- // (unless it is selected, and textctrl editor is open).
- if ( changedProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) )
+ if ( flags & SendEvtChanging )
{
- evtChangingProperty = baseChangedProperty;
- if ( evtChangingProperty != p )
- {
- evtChangingProperty->AdaptListToValue( bcpPendingList, &evtChangingValue );
- }
- else
+ // FIXME: After proper ValueToString()s added, remove
+ // this. It is just a temporary fix, as evt_changing
+ // will simply not work for wxPG_PROP_COMPOSED_VALUE
+ // (unless it is selected, and textctrl editor is open).
+ if ( changedProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) )
{
- evtChangingValue = pendingValue;
+ evtChangingProperty = baseChangedProperty;
+ if ( evtChangingProperty != p )
+ {
+ evtChangingProperty->AdaptListToValue( bcpPendingList, &evtChangingValue );
+ }
+ else
+ {
+ evtChangingValue = pendingValue;
+ }
}
- }
- if ( evtChangingProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) )
- {
- if ( changedProperty == m_selected )
- {
- wxASSERT( m_wndEditor->IsKindOf(CLASSINFO(wxTextCtrl)) );
- evtChangingValue = ((wxTextCtrl*)m_wndEditor)->GetValue();
- }
- else
+ if ( evtChangingProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) )
{
- wxLogDebug(wxT("WARNING: wxEVT_PG_CHANGING is about to happen with old value."));
+ if ( changedProperty == m_selected )
+ {
+ wxWindow* editor = GetEditorControl();
+ wxASSERT( editor->IsKindOf(CLASSINFO(wxTextCtrl)) );
+ evtChangingValue = wxStaticCast(editor, wxTextCtrl)->GetValue();
+ }
+ else
+ {
+ wxLogDebug(wxT("WARNING: wxEVT_PG_CHANGING is about to happen with old value."));
+ }
}
}
return false;
}
- // SendEvent returns true if event was vetoed
- if ( SendEvent( wxEVT_PG_CHANGING, evtChangingProperty, &evtChangingValue, 0 ) )
- return false;
+ if ( flags & SendEvtChanging )
+ {
+ // SendEvent returns true if event was vetoed
+ if ( SendEvent( wxEVT_PG_CHANGING, evtChangingProperty, &evtChangingValue, 0 ) )
+ return false;
+ }
+
+ if ( flags & IsStandaloneValidation )
+ {
+ // If called in 'generic' context, we need to reset
+ // m_chgInfo_changedProperty and write back translated value.
+ m_chgInfo_changedProperty = NULL;
+ pendingValue = value;
+ }
return true;
}
// -----------------------------------------------------------------------
+bool wxPropertyGrid::OnValidationFailure( wxPGProperty* property,
+ wxVariant& invalidValue )
+{
+ wxWindow* editor = GetEditorControl();
+
+ // First call property's handler
+ property->OnValidationFailure(invalidValue);
+
+ bool res = DoOnValidationFailure(property, invalidValue);
+
+ //
+ // For non-wxTextCtrl editors, we do need to revert the value
+ if ( !editor->IsKindOf(CLASSINFO(wxTextCtrl)) &&
+ property == m_selected )
+ {
+ property->GetEditorClass()->UpdateControl(property, editor);
+ }
+
+ property->SetFlag(wxPG_PROP_INVALID_VALUE);
+
+ return res;
+}
+
bool wxPropertyGrid::DoOnValidationFailure( wxPGProperty* property, wxVariant& WXUNUSED(invalidValue) )
{
int vfb = m_validationInfo.m_failureBehavior;
if ( (vfb & wxPG_VFB_MARK_CELL) &&
!property->HasFlag(wxPG_PROP_INVALID_VALUE) )
{
- wxASSERT_MSG( !property->GetCell(0) && !property->GetCell(1),
- wxT("Currently wxPG_VFB_MARK_CELL only works with properties with standard first two cells") );
+ unsigned int colCount = m_pState->GetColumnCount();
+
+ // We need backup marked property's cells
+ m_propCellsBackup = property->m_cells;
- if ( !property->GetCell(0) && !property->GetCell(1) )
+ wxColour vfbFg = *wxWHITE;
+ wxColour vfbBg = *wxRED;
+
+ property->EnsureCells(colCount);
+
+ for ( unsigned int i=0; i<colCount; i++ )
{
- wxColour vfbFg = *wxWHITE;
- wxColour vfbBg = *wxRED;
- property->SetCell(0, new wxPGCell(property->GetLabel(), wxNullBitmap, vfbFg, vfbBg));
- property->SetCell(1, new wxPGCell(property->GetDisplayedString(), wxNullBitmap, vfbFg, vfbBg));
+ wxPGCell& cell = property->m_cells[i];
+ cell.SetFgCol(vfbFg);
+ cell.SetBgCol(vfbBg);
+ }
- DrawItemAndChildren(property);
+ DrawItemAndChildren(property);
- if ( property == m_selected )
- {
- SetInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL);
+ if ( property == m_selected )
+ {
+ SetInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL);
- wxWindow* editor = GetEditorControl();
- if ( editor )
- {
- editor->SetForegroundColour(vfbFg);
- editor->SetBackgroundColour(vfbBg);
- }
+ wxWindow* editor = GetEditorControl();
+ if ( editor )
+ {
+ editor->SetForegroundColour(vfbFg);
+ editor->SetBackgroundColour(vfbBg);
}
}
}
if ( vfb & wxPG_VFB_MARK_CELL )
{
- property->SetCell(0, NULL);
- property->SetCell(1, NULL);
+ // Revert cells
+ property->m_cells = m_propCellsBackup;
ClearInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL);
// control.
if ( selFlags & wxPG_SEL_DIALOGVAL )
{
- if ( editor )
- p->GetEditorClass()->UpdateControl(p, editor);
+ RefreshEditor();
}
else
{
// -----------------------------------------------------------------------
-// Runs wxValidator for the selected property
-bool wxPropertyGrid::DoEditorValidate()
+wxVariant wxPropertyGrid::GetUncommittedPropertyValue()
{
-#if wxUSE_VALIDATORS
- // With traditional validator style, we dont need to more
- if ( !(GetExtraStyle() & wxPG_EX_LEGACY_VALIDATORS) )
- return true;
+ wxPGProperty* prop = GetSelectedProperty();
- if ( m_iFlags & wxPG_FL_VALIDATION_FAILED )
- {
- return false;
- }
+ if ( !prop )
+ return wxNullVariant;
- wxWindow* wnd = GetEditorControl();
+ wxTextCtrl* tc = GetEditorTextCtrl();
+ wxVariant value = prop->GetValue();
- wxValidator* validator = m_selected->GetValidator();
- if ( validator && wnd )
- {
- // Use TextCtrl of ODComboBox instead
- if ( wnd->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) )
- {
- wnd = ((wxOwnerDrawnComboBox*)wnd)->GetTextCtrl();
+ if ( !tc || !IsEditorsValueModified() )
+ return value;
- if ( !wnd )
- return true;
- }
+ if ( !prop->StringToValue(value, tc->GetValue()) )
+ return value;
- validator->SetWindow(wnd);
+ if ( !PerformValidation(prop, value, IsStandaloneValidation) )
+ return prop->GetValue();
- // Instead setting the flag after the failure, we set
- // it before checking and then clear afterwards if things
- // went fine. This trick is necessary since focus events
- // may be triggered while in Validate.
- m_iFlags |= wxPG_FL_VALIDATION_FAILED;
- if ( !validator->Validate(this) )
- {
- // If you dpm't want to display message multiple times per change,
- // comment the following line.
- m_iFlags &= ~(wxPG_FL_VALIDATION_FAILED);
- return false;
- }
- m_iFlags &= ~(wxPG_FL_VALIDATION_FAILED);
- }
-#endif
- return true;
+ return value;
}
// -----------------------------------------------------------------------
-bool wxPropertyGrid::ProcessEvent(wxEvent& event)
+// Runs wxValidator for the selected property
+bool wxPropertyGrid::DoEditorValidate()
{
- wxWindow* wnd = (wxWindow*) event.GetEventObject();
- if ( wnd && wnd->IsKindOf(CLASSINFO(wxWindow)) )
- {
- wxWindow* parent = wnd->GetParent();
-
- if ( parent &&
- (parent == m_canvas ||
- parent->GetParent() == m_canvas) )
- {
- OnCustomEditorEvent((wxCommandEvent&)event);
- return true;
- }
- }
- return wxPanel::ProcessEvent(event);
+ return true;
}
// -----------------------------------------------------------------------
-// NB: It may really not be wxCommandEvent - must check if necessary
-// (usually not).
-void wxPropertyGrid::OnCustomEditorEvent( wxCommandEvent &event )
+void wxPropertyGrid::HandleCustomEditorEvent( wxEvent &event )
{
wxPGProperty* selected = m_selected;
- //
// Somehow, event is handled after property has been deselected.
// Possibly, but very rare.
if ( !selected )
return;
- if ( m_iFlags & wxPG_FL_IN_ONCUSTOMEDITOREVENT )
+ if ( m_iFlags & wxPG_FL_IN_HANDLECUSTOMEDITOREVENT )
return;
wxVariant pendingValue(selected->GetValueRef());
m_prevTcValue = newTcValue;
}
- SetInternalFlag(wxPG_FL_IN_ONCUSTOMEDITOREVENT);
+ SetInternalFlag(wxPG_FL_IN_HANDLECUSTOMEDITOREVENT);
bool validationFailure = false;
bool buttonWasHandled = false;
}
}
- if ( wnd && !buttonWasHandled )
+ if ( !buttonWasHandled )
{
- // First call editor class' event handler.
- const wxPGEditor* editor = selected->GetEditorClass();
-
- if ( editor->OnEvent( this, selected, wnd, event ) )
+ if ( wnd )
{
- // If changes, validate them
- if ( DoEditorValidate() )
- {
- if ( editor->GetValueFromControl( pendingValue, m_selected, wnd ) )
- valueIsPending = true;
- }
- else
+ // First call editor class' event handler.
+ const wxPGEditor* editor = selected->GetEditorClass();
+
+ if ( editor->OnEvent( this, selected, wnd, event ) )
{
- validationFailure = true;
+ // If changes, validate them
+ if ( DoEditorValidate() )
+ {
+ if ( editor->GetValueFromControl( pendingValue, m_selected, wnd ) )
+ valueIsPending = true;
+ }
+ else
+ {
+ validationFailure = true;
+ }
}
}
if ( !PerformValidation(m_selected, pendingValue) )
validationFailure = true;
- if ( validationFailure )
+ if ( validationFailure)
{
OnValidationFailure(selected, pendingValue);
}
DoPropertyChanged(selected, selFlags);
EditorsValueWasNotModified();
+
+ // Regardless of editor type, unfocus editor on
+ // text-editing related enter press.
+ if ( event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER )
+ {
+ SetFocusOnCanvas();
+ }
}
else
{
// No value after all
+ // Regardless of editor type, unfocus editor on
+ // text-editing related enter press.
+ if ( event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER )
+ {
+ SetFocusOnCanvas();
+ }
+
// Let unhandled button click events go to the parent
if ( !buttonWasHandled && event.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED )
{
}
}
- ClearInternalFlag(wxPG_FL_IN_ONCUSTOMEDITOREVENT);
+ ClearInternalFlag(wxPG_FL_IN_HANDLECUSTOMEDITOREVENT);
}
// -----------------------------------------------------------------------
wxSize cis = p->OnMeasureImage(item);
- int choiceCount = p->GetChoiceCount();
+ int choiceCount = p->m_choices.GetCount();
int comVals = p->GetDisplayedCommonValueCount();
if ( item >= choiceCount && comVals > 0 )
{
}
// -----------------------------------------------------------------------
-// wxPropertyGrid property selection
+// wxPropertyGrid property selection, editor creation
// -----------------------------------------------------------------------
-#define CONNECT_CHILD(EVT,FUNCTYPE,FUNC) \
- wnd->Connect(id, EVT, \
- (wxObjectEventFunction) (wxEventFunction) \
- FUNCTYPE (&wxPropertyGrid::FUNC), \
- NULL, this );
-
-// Setups event handling for child control
-void wxPropertyGrid::SetupEventHandling( wxWindow* argWnd, int id )
+//
+// This class forwards events from property editor controls to wxPropertyGrid.
+class wxPropertyGridEditorEventForwarder : public wxEvtHandler
{
- wxWindow* wnd = argWnd;
+public:
+ wxPropertyGridEditorEventForwarder( wxPropertyGrid* propGrid )
+ : wxEvtHandler(), m_propGrid(propGrid)
+ {
+ }
- if ( argWnd == m_wndEditor )
+ virtual ~wxPropertyGridEditorEventForwarder()
{
- CONNECT_CHILD(wxEVT_MOTION,(wxMouseEventFunction),OnMouseMoveChild)
- CONNECT_CHILD(wxEVT_LEFT_UP,(wxMouseEventFunction),OnMouseUpChild)
- CONNECT_CHILD(wxEVT_LEFT_DOWN,(wxMouseEventFunction),OnMouseClickChild)
- CONNECT_CHILD(wxEVT_RIGHT_UP,(wxMouseEventFunction),OnMouseRightClickChild)
- CONNECT_CHILD(wxEVT_ENTER_WINDOW,(wxMouseEventFunction),OnMouseEntry)
- CONNECT_CHILD(wxEVT_LEAVE_WINDOW,(wxMouseEventFunction),OnMouseEntry)
}
- else
+
+private:
+ bool ProcessEvent( wxEvent& event )
{
- CONNECT_CHILD(wxEVT_NAVIGATION_KEY,(wxNavigationKeyEventFunction),OnNavigationKey)
+ // Always skip
+ event.Skip();
+
+ m_propGrid->HandleCustomEditorEvent(event);
+
+ return wxEvtHandler::ProcessEvent(event);
}
- CONNECT_CHILD(wxEVT_KEY_DOWN,(wxCharEventFunction),OnChildKeyDown)
- CONNECT_CHILD(wxEVT_KEY_UP,(wxCharEventFunction),OnChildKeyUp)
- CONNECT_CHILD(wxEVT_KILL_FOCUS,(wxFocusEventFunction),OnFocusEvent)
+
+ wxPropertyGrid* m_propGrid;
+};
+
+// Setups event handling for child control
+void wxPropertyGrid::SetupChildEventHandling( wxWindow* argWnd )
+{
+ wxWindowID id = argWnd->GetId();
+
+ if ( argWnd == m_wndEditor )
+ {
+ argWnd->Connect(id, wxEVT_MOTION,
+ wxMouseEventHandler(wxPropertyGrid::OnMouseMoveChild),
+ NULL, this);
+ argWnd->Connect(id, wxEVT_LEFT_UP,
+ wxMouseEventHandler(wxPropertyGrid::OnMouseUpChild),
+ NULL, this);
+ argWnd->Connect(id, wxEVT_LEFT_DOWN,
+ wxMouseEventHandler(wxPropertyGrid::OnMouseClickChild),
+ NULL, this);
+ argWnd->Connect(id, wxEVT_RIGHT_UP,
+ wxMouseEventHandler(wxPropertyGrid::OnMouseRightClickChild),
+ NULL, this);
+ argWnd->Connect(id, wxEVT_ENTER_WINDOW,
+ wxMouseEventHandler(wxPropertyGrid::OnMouseEntry),
+ NULL, this);
+ argWnd->Connect(id, wxEVT_LEAVE_WINDOW,
+ wxMouseEventHandler(wxPropertyGrid::OnMouseEntry),
+ NULL, this);
+ }
+
+ wxPropertyGridEditorEventForwarder* forwarder;
+ forwarder = new wxPropertyGridEditorEventForwarder(this);
+ argWnd->PushEventHandler(forwarder);
+
+ argWnd->Connect(id, wxEVT_KEY_DOWN,
+ wxCharEventHandler(wxPropertyGrid::OnChildKeyDown),
+ NULL, this);
}
void wxPropertyGrid::FreeEditors()
{
- // Do not free editors immediately if processing events
- if ( !m_windowsToDelete )
- m_windowsToDelete = new wxArrayPtrVoid;
+ //
+ // Return focus back to canvas from children (this is required at least for
+ // GTK+, which, unlike Windows, clears focus when control is destroyed
+ // instead of moving it to closest parent).
+ wxWindow* focus = wxWindow::FindFocus();
+ if ( focus )
+ {
+ wxWindow* parent = focus->GetParent();
+ while ( parent )
+ {
+ if ( parent == m_canvas )
+ {
+ SetFocusOnCanvas();
+ break;
+ }
+ parent = parent->GetParent();
+ }
+ }
+ // Do not free editors immediately if processing events
if ( m_wndEditor2 )
{
- m_windowsToDelete->push_back(m_wndEditor2);
+ wxEvtHandler* handler = m_wndEditor2->PopEventHandler(false);
m_wndEditor2->Hide();
- m_wndEditor2 = (wxWindow*) NULL;
+ wxPendingDelete.Append( handler );
+ wxPendingDelete.Append( m_wndEditor2 );
+ m_wndEditor2 = NULL;
}
if ( m_wndEditor )
{
- m_windowsToDelete->push_back(m_wndEditor);
+ wxEvtHandler* handler = m_wndEditor->PopEventHandler(false);
m_wndEditor->Hide();
- m_wndEditor = (wxWindow*) NULL;
+ wxPendingDelete.Append( handler );
+ wxPendingDelete.Append( m_wndEditor );
+ m_wndEditor = NULL;
}
}
// Call with NULL to de-select property
bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
{
- wxPanel* canvas = GetPanel();
-
/*
if (p)
wxLogDebug(wxT("SelectProperty( %s (%s[%i]) )"),p->m_label.c_str(),
wxPGProperty* prev = m_selected;
- //
- // Delete windows pending for deletion
- if ( m_windowsToDelete && !m_inDoPropertyChanged && m_windowsToDelete->size() )
- {
- unsigned int i;
-
- for ( i=0; i<m_windowsToDelete->size(); i++ )
- delete ((wxWindow*)((*m_windowsToDelete)[i]));
-
- m_windowsToDelete->clear();
- }
-
if ( !m_pState )
{
m_inDoSelectProperty = 0;
return false;
}
- //
+/*
+ if (m_selected)
+ wxPrintf( "Selected %s\n", m_selected->GetClassInfo()->GetClassName() );
+ else
+ wxPrintf( "None selected\n" );
+
+ if (p)
+ wxPrintf( "P = %s\n", p->GetClassInfo()->GetClassName() );
+ else
+ wxPrintf( "P = NULL\n" );
+*/
+
// If we are frozen, then just set the values.
if ( m_frozen )
{
FreeEditors();
// Prevent any further selection measures in this call
- p = (wxPGProperty*) NULL;
+ p = NULL;
}
else
{
FreeEditors();
m_selColumn = -1;
- m_selected = (wxPGProperty*) NULL;
- m_pState->m_selected = (wxPGProperty*) NULL;
+ m_selected = NULL;
+ m_pState->m_selected = NULL;
// We need to always fully refresh the grid here
Refresh(false);
if ( p != prev )
m_iFlags &= ~(wxPG_FL_VALIDATION_FAILED);
- wxASSERT( m_wndEditor == (wxWindow*) NULL );
-
- // Do we need OnMeasureCalls?
- wxSize imsz = p->OnMeasureImage();
+ wxASSERT( m_wndEditor == NULL );
//
// Only create editor for non-disabled non-caption
m_wndEditor = wndList.m_primary;
m_wndEditor2 = wndList.m_secondary;
+ wxWindow* primaryCtrl = GetEditorControl();
+
+ //
+ // Essentially, primaryCtrl == m_wndEditor
+ //
// NOTE: It is allowed for m_wndEditor to be NULL - in this case
// value is drawn as normal, and m_wndEditor2 is assumed
- // to be a right-aligned button that triggers a separate editor
+ // to be a right-aligned button that triggers a separate editorCtrl
// window.
if ( m_wndEditor )
{
- wxASSERT_MSG( m_wndEditor->GetParent() == canvas,
+ wxASSERT_MSG( m_wndEditor->GetParent() == GetPanel(),
wxT("CreateControls must use result of wxPropertyGrid::GetPanel() as parent of controls.") );
// Set validator, if any
#if wxUSE_VALIDATORS
- if ( !(GetExtraStyle() & wxPG_EX_LEGACY_VALIDATORS) )
- {
- wxValidator* validator = p->GetValidator();
- if ( validator )
- m_wndEditor->SetValidator(*validator);
- }
+ wxValidator* validator = p->GetValidator();
+ if ( validator )
+ primaryCtrl->SetValidator(*validator);
#endif
if ( m_wndEditor->GetSize().y > (m_lineHeight+6) )
// Fix TextCtrl indentation
#if defined(__WXMSW__) && !defined(__WXWINCE__)
wxTextCtrl* tc = NULL;
- if ( m_wndEditor->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) )
- tc = ((wxOwnerDrawnComboBox*)m_wndEditor)->GetTextCtrl();
+ if ( primaryCtrl->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) )
+ tc = ((wxOwnerDrawnComboBox*)primaryCtrl)->GetTextCtrl();
else
- tc = wxDynamicCast(m_wndEditor, wxTextCtrl);
+ tc = wxDynamicCast(primaryCtrl, wxTextCtrl);
if ( tc )
::SendMessage(GetHwndOf(tc), EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0));
#endif
m_wndEditor->Move( goodPos );
#endif
- wxWindow* primaryCtrl = GetEditorControl();
- SetupEventHandling(primaryCtrl, wxPG_SUBID1);
+ SetupChildEventHandling(primaryCtrl);
// Focus and select all (wxTextCtrl, wxComboBox etc)
if ( flags & wxPG_SEL_FOCUS )
if ( m_wndEditor2 )
{
- wxASSERT_MSG( m_wndEditor2->GetParent() == canvas,
+ wxASSERT_MSG( m_wndEditor2->GetParent() == GetPanel(),
wxT("CreateControls must use result of wxPropertyGrid::GetPanel() as parent of controls.") );
// Get proper id for wndSecondary
#endif
m_wndEditor2->Show();
- SetupEventHandling(m_wndEditor2,wxPG_SUBID2);
+ SetupChildEventHandling(m_wndEditor2);
// If no primary editor, focus to button to allow
// it to interprete ENTER etc.
if ( !(GetExtraStyle() & wxPG_EX_HELP_AS_TOOLTIPS) )
{
- wxStatusBar* statusbar = (wxStatusBar*) NULL;
+ wxStatusBar* statusbar = NULL;
if ( !(m_iFlags & wxPG_FL_NOSTATUSBARHELP) )
{
wxFrame* frame = wxDynamicCast(::wxGetTopLevelParent(this),wxFrame);
// -----------------------------------------------------------------------
+void wxPropertyGrid::RefreshEditor()
+{
+ wxPGProperty* p = m_selected;
+ if ( !p )
+ return;
+
+ wxWindow* wnd = GetEditorControl();
+ if ( !wnd )
+ return;
+
+ // Set editor font boldness - must do this before
+ // calling UpdateControl().
+ if ( HasFlag(wxPG_BOLD_MODIFIED) )
+ {
+ if ( p->HasFlag(wxPG_PROP_MODIFIED) )
+ wnd->SetFont(GetCaptionFont());
+ else
+ wnd->SetFont(GetFont());
+ }
+
+ const wxPGEditor* editorClass = p->GetEditorClass();
+
+ editorClass->UpdateControl(p, wnd);
+
+ if ( p->IsValueUnspecified() )
+ editorClass ->SetValueToUnspecified(p, wnd);
+}
+
+// -----------------------------------------------------------------------
+
// This method is not inline because it called dozens of times
// (i.e. two-arg function calls create smaller code size).
bool wxPropertyGrid::DoClearSelection()
{
- return DoSelectProperty((wxPGProperty*)NULL);
+ return DoSelectProperty(NULL);
}
// -----------------------------------------------------------------------
wxPGProperty* pwc = wxStaticCast(p, wxPGProperty);
// If active editor was inside collapsed section, then disable it
- if ( m_selected && m_selected->IsSomeParent (p) )
+ if ( m_selected && m_selected->IsSomeParent(p) )
{
- if ( !ClearSelection() )
- return false;
+ ClearSelection(false);
}
// Store dont-center-splitter flag 'cause we need to temporarily set it
}
// Clear dont-center-splitter flag if it wasn't set
- m_iFlags = m_iFlags & ~(wxPG_FL_DONT_CENTER_SPLITTER) | old_flag;
+ m_iFlags = (m_iFlags & ~wxPG_FL_DONT_CENTER_SPLITTER) | old_flag;
return res;
}
( m_selected == p || m_selected->IsSomeParent(p) )
)
{
- if ( !ClearSelection() )
- return false;
+ ClearSelection(false);
}
m_pState->DoHideProperty(p, hide, flags);
if ( by1 != by2 )
{
wxString s = wxString::Format(wxT("VirtualHeight=%i, ActualVirtualHeight=%i, should match!"), by1, by2);
- wxASSERT_MSG( false,
- s.c_str() );
+ wxFAIL_MSG(s.c_str());
wxLogDebug(s);
}
#endif
m_pState->SetVirtualWidth( width );
}
+void wxPropertyGrid::SetFocusOnCanvas()
+{
+ m_canvas->SetFocusIgnoringChildren();
+ m_editorFocused = 0;
+}
+
// -----------------------------------------------------------------------
// wxPropertyGrid mouse event handling
// -----------------------------------------------------------------------
int curPropHoverY = y - (y % ih);
// On which item it hovers
- if ( ( !m_propHover )
+ if ( !m_propHover
||
- ( m_propHover && ( sy < m_propHoverY || sy >= (m_propHoverY+ih) ) )
+ ( sy < m_propHoverY || sy >= (m_propHoverY+ih) )
)
{
// Mouse moves on another property
// (also not if we were dragging and its started
// outside the splitter region)
- if ( m_propHover &&
- !m_propHover->IsCategory() &&
+ if ( !m_propHover->IsCategory() &&
!event.Dragging() )
{
int ux = event.m_x;
int uy = event.m_y;
- wxWindow* wnd = m_wndEditor;
+ wxWindow* wnd = GetEditorControl();
// Hide popup on clicks
if ( event.GetEventType() != wxEVT_MOTION )
if ( wnd && wnd->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) )
{
- ((wxOwnerDrawnComboBox*)m_wndEditor)->HidePopup();
+ ((wxOwnerDrawnComboBox*)wnd)->HidePopup();
}
wxRect r;
if ( wnd )
r = wnd->GetRect();
- if ( wnd == (wxWindow*) NULL || m_dragStatus ||
+ if ( wnd == NULL || m_dragStatus ||
(
ux <= (splitterX + wxPG_SPLITTERX_DETECTMARGIN2) ||
ux >= (r.x+r.width) ||
int x, y;
event.GetPosition(&x,&y);
- AdjustPosForClipperWindow( topCtrlWnd, &x, &y );
-
int splitterX = GetSplitterPosition();
wxRect r = topCtrlWnd->GetRect();
// wxPropertyGrid keyboard event handling
// -----------------------------------------------------------------------
-void wxPropertyGrid::SendNavigationKeyEvent( int dir )
-{
- wxNavigationKeyEvent evt;
- evt.SetFlags(wxNavigationKeyEvent::FromTab|
- (dir?wxNavigationKeyEvent::IsForward:
- wxNavigationKeyEvent::IsBackward));
- evt.SetEventObject(this);
- m_canvas->GetEventHandler()->AddPendingEvent(evt);
-}
-
-
int wxPropertyGrid::KeyEventToActions(wxKeyEvent &event, int* pSecond) const
{
// Translates wxKeyEvent to wxPG_ACTION_XXX
{
wxPGHashMapI2I::iterator it;
- for ( it = m_actionTriggers.begin(); it != m_actionTriggers.end(); it++ )
+ for ( it = m_actionTriggers.begin(); it != m_actionTriggers.end(); ++it )
{
if ( it->second == action )
{
}
}
-static void CopyTextToClipboard( const wxString& text )
-{
- if ( wxTheClipboard->Open() )
- {
- // This data objects are held by the clipboard,
- // so do not delete them in the app.
- wxTheClipboard->SetData( new wxTextDataObject(text) );
- wxTheClipboard->Close();
- }
-}
-
-void wxPropertyGrid::HandleKeyEvent(wxKeyEvent &event)
+void wxPropertyGrid::HandleKeyEvent( wxKeyEvent &event, bool fromChild )
{
//
// Handles key event when editor control is not focused.
//
- wxASSERT( !m_frozen );
- if ( m_frozen )
- return;
+ wxCHECK2(!m_frozen, return);
// Travelsal between items, collapsing/expanding, etc.
int keycode = event.GetKeyCode();
+ bool editorFocused = IsEditorFocused();
if ( keycode == WXK_TAB )
{
- SendNavigationKeyEvent( event.ShiftDown()?0:1 );
- return;
- }
-
- // Ignore Alt and Control when they are down alone
- if ( keycode == WXK_ALT ||
- keycode == WXK_CONTROL )
- {
- event.Skip();
- return;
- }
-
- int secondAction;
- int action = KeyEventToActions(event, &secondAction);
-
- if ( m_selected )
- {
-
- // Show dialog?
- if ( ButtonTriggerKeyTest(event) )
- return;
+ wxWindow* mainControl;
- wxPGProperty* p = m_selected;
+ if ( HasInternalFlag(wxPG_FL_IN_MANAGER) )
+ mainControl = GetParent();
+ else
+ mainControl = this;
- if ( action == wxPG_ACTION_COPY )
+ if ( !event.ShiftDown() )
{
- CopyTextToClipboard(p->GetDisplayedString());
+ if ( !editorFocused && m_wndEditor )
+ {
+ DoSelectProperty( m_selected, wxPG_SEL_FOCUS );
+ }
+ else
+ {
+ // Tab traversal workaround for platforms on which
+ // wxWindow::Navigate() may navigate into first child
+ // instead of next sibling. Does not work perfectly
+ // in every scenario (for instance, when property grid
+ // is either first or last control).
+ #if defined(__WXGTK__)
+ wxWindow* sibling = mainControl->GetNextSibling();
+ if ( sibling )
+ sibling->SetFocusFromKbd();
+ #else
+ Navigate(wxNavigationKeyEvent::IsForward);
+ #endif
+ }
}
else
{
- // Travel and expand/collapse
- int selectDir = -2;
-
- if ( p->GetChildCount() &&
- !(p->m_flags & wxPG_PROP_DISABLED)
- )
+ if ( editorFocused )
{
- if ( action == wxPG_ACTION_COLLAPSE_PROPERTY || secondAction == wxPG_ACTION_COLLAPSE_PROPERTY )
- {
- if ( (m_windowStyle & wxPG_HIDE_MARGIN) || Collapse(p) )
- keycode = 0;
- }
- else if ( action == wxPG_ACTION_EXPAND_PROPERTY || secondAction == wxPG_ACTION_EXPAND_PROPERTY )
- {
- if ( (m_windowStyle & wxPG_HIDE_MARGIN) || Expand(p) )
- keycode = 0;
- }
+ UnfocusEditor();
}
-
- if ( keycode )
- {
- if ( action == wxPG_ACTION_PREV_PROPERTY || secondAction == wxPG_ACTION_PREV_PROPERTY )
- {
- selectDir = -1;
- }
- else if ( action == wxPG_ACTION_NEXT_PROPERTY || secondAction == wxPG_ACTION_NEXT_PROPERTY )
- {
- selectDir = 1;
- }
- else
- {
- event.Skip();
- }
-
- }
-
- if ( selectDir >= -1 )
+ else
{
- p = wxPropertyGridIterator::OneStep( m_pState, wxPG_ITERATE_VISIBLE, p, selectDir );
- if ( p )
- DoSelectProperty(p);
+ #if defined(__WXGTK__)
+ wxWindow* sibling = mainControl->GetPrevSibling();
+ if ( sibling )
+ sibling->SetFocusFromKbd();
+ #else
+ Navigate(wxNavigationKeyEvent::IsBackward);
+ #endif
}
}
- }
- else
- {
- // If nothing was selected, select the first item now
- // (or navigate out of tab).
- if ( action != wxPG_ACTION_CANCEL_EDIT && secondAction != wxPG_ACTION_CANCEL_EDIT )
- {
- wxPGProperty* p = wxPropertyGridInterface::GetFirst();
- if ( p ) DoSelectProperty(p);
- }
- }
-}
-
-// -----------------------------------------------------------------------
-// Potentially handles a keyboard event for editor controls.
-// Returns false if event should *not* be skipped (on true it can
-// be optionally skipped).
-// Basicly, false means that SelectProperty was called (or was about
-// to be called, if canDestroy was false).
-bool wxPropertyGrid::HandleChildKey( wxKeyEvent& event )
-{
- bool res = true;
+ return;
+ }
- if ( !m_selected || !m_wndEditor )
+ // Ignore Alt and Control when they are down alone
+ if ( keycode == WXK_ALT ||
+ keycode == WXK_CONTROL )
{
- return true;
+ event.Skip();
+ return;
}
- int action = KeyEventToAction(event);
+ int secondAction;
+ int action = KeyEventToActions(event, &secondAction);
- // Unfocus?
- if ( action == wxPG_ACTION_CANCEL_EDIT )
+ if ( editorFocused && action == wxPG_ACTION_CANCEL_EDIT )
{
//
// Esc cancels any changes
// Update the control as well
m_selected->GetEditorClass()->SetControlStringValue( m_selected,
- m_wndEditor,
+ GetEditorControl(),
m_selected->GetDisplayedString() );
}
OnValidationFailureReset(m_selected);
- res = false;
-
UnfocusEditor();
+ return;
}
- else if ( action == wxPG_ACTION_COPY )
- {
- // NB: There is some problem with getting native cut-copy-paste keys to go through
- // for embedded editor wxTextCtrl. This is why we emulate.
- //
- wxTextCtrl* tc = GetEditorTextCtrl();
- if ( tc )
- {
- wxString sel = tc->GetStringSelection();
- if ( sel.length() )
- CopyTextToClipboard(sel);
- }
- else
- {
- CopyTextToClipboard(m_selected->GetDisplayedString());
- }
- }
- else if ( action == wxPG_ACTION_CUT )
- {
- wxTextCtrl* tc = GetEditorTextCtrl();
- if ( tc )
- {
- long from, to;
- tc->GetSelection(&from, &to);
- if ( from < to )
- {
- CopyTextToClipboard(tc->GetStringSelection());
- tc->Remove(from, to);
- }
- }
- }
- else if ( action == wxPG_ACTION_PASTE )
- {
- wxTextCtrl* tc = GetEditorTextCtrl();
- if ( tc )
- {
- if (wxTheClipboard->Open())
- {
- if (wxTheClipboard->IsSupported( wxDF_TEXT ))
- {
- wxTextDataObject data;
- wxTheClipboard->GetData( data );
- long from, to;
- tc->GetSelection(&from, &to);
- if ( from < to )
- {
- tc->Remove(from, to);
- tc->WriteText(data.GetText());
- }
- else
- {
- tc->WriteText(data.GetText());
- }
- }
- wxTheClipboard->Close();
- }
- }
- }
-
- return res;
-}
-
-// -----------------------------------------------------------------------
-
-void wxPropertyGrid::OnKey( wxKeyEvent &event )
-{
-
- //
- // Events to editor controls should get relayed here.
- //
- wxWindow* focused = wxWindow::FindFocus();
-
- wxWindow* primaryCtrl = GetEditorControl();
-
- if ( primaryCtrl &&
- (focused==primaryCtrl
- || m_editorFocused) )
- {
- // Child key must be processed here, since it can
- // destroy the control which is referred by its own
- // event handling.
- HandleChildKey( event );
- }
- else
- HandleKeyEvent( event );
-}
-
-// -----------------------------------------------------------------------
-
-void wxPropertyGrid::OnKeyUp(wxKeyEvent &event)
-{
- m_keyComboConsumed = 0;
-
- event.Skip();
-}
-// -----------------------------------------------------------------------
-
-void wxPropertyGrid::OnNavigationKey( wxNavigationKeyEvent& event )
-{
- // Ignore events that occur very close to focus set
- if ( m_iFlags & wxPG_FL_IGNORE_NEXT_NAVKEY )
+ // Except for TAB and ESC, handle child control events in child control
+ if ( fromChild )
{
- m_iFlags &= ~(wxPG_FL_IGNORE_NEXT_NAVKEY);
event.Skip();
return;
}
- wxPGProperty* next = (wxPGProperty*) NULL;
-
- int dir = event.GetDirection()?1:-1;
+ bool wasHandled = false;
if ( m_selected )
{
- if ( dir == 1 && (m_wndEditor || m_wndEditor2) )
- {
- wxWindow* focused = wxWindow::FindFocus();
+ // Show dialog?
+ if ( ButtonTriggerKeyTest(action, event) )
+ return;
- wxWindow* wndToCheck = GetEditorControl();
+ wxPGProperty* p = m_selected;
- // ODComboBox focus goes to its text ctrl, so we need to use it instead
- if ( wndToCheck && wndToCheck->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) )
- {
- wxTextCtrl* comboTextCtrl = ((wxOwnerDrawnComboBox*)wndToCheck)->GetTextCtrl();
- if ( comboTextCtrl )
- wndToCheck = comboTextCtrl;
- }
+ // Travel and expand/collapse
+ int selectDir = -2;
- /*
- // Because of problems navigating from wxButton, do not go to it.
- if ( !wndToCheck )
+ if ( p->GetChildCount() &&
+ !(p->m_flags & wxPG_PROP_DISABLED)
+ )
+ {
+ if ( action == wxPG_ACTION_COLLAPSE_PROPERTY || secondAction == wxPG_ACTION_COLLAPSE_PROPERTY )
{
- // No primary, use secondary
- wndToCheck = m_wndEditor2;
+ if ( (m_windowStyle & wxPG_HIDE_MARGIN) || Collapse(p) )
+ wasHandled = true;
}
- // If it has editor button, focus to it after the primary editor.
- // NB: Doesn't work since wxButton on wxMSW doesn't seem to propagate
- // key events (yes, I'm using wxWANTS_CHARS with it, and yes I
- // have somewhat debugged in window.cpp itself).
- else if ( focused == wndToCheck &&
- m_wndEditor2 &&
- !(GetExtraStyle() & wxPG_EX_NO_TAB_TO_BUTTON) )
+ else if ( action == wxPG_ACTION_EXPAND_PROPERTY || secondAction == wxPG_ACTION_EXPAND_PROPERTY )
{
- wndToCheck = m_wndEditor2;
- wxLogDebug(wxT("Exp1"));
+ if ( (m_windowStyle & wxPG_HIDE_MARGIN) || Expand(p) )
+ wasHandled = true;
}
- */
+ }
- if ( focused != wndToCheck &&
- wndToCheck )
+ if ( !wasHandled )
+ {
+ if ( action == wxPG_ACTION_PREV_PROPERTY || secondAction == wxPG_ACTION_PREV_PROPERTY )
{
- wndToCheck->SetFocus();
-
- // Select all text in wxTextCtrl etc.
- if ( m_wndEditor && wndToCheck == m_wndEditor )
- m_selected->GetEditorClass()->OnFocus(m_selected,wndToCheck);
-
- m_editorFocused = 1;
- next = m_selected;
+ selectDir = -1;
+ }
+ else if ( action == wxPG_ACTION_NEXT_PROPERTY || secondAction == wxPG_ACTION_NEXT_PROPERTY )
+ {
+ selectDir = 1;
}
}
- if ( !next )
+ if ( selectDir >= -1 )
{
- next = wxPropertyGridIterator::OneStep(m_pState, wxPG_ITERATE_VISIBLE, m_selected, dir);
-
- if ( next )
- {
- // This allows preventing NavigateOut to occur
- DoSelectProperty( next, wxPG_SEL_FOCUS );
- }
+ p = wxPropertyGridIterator::OneStep( m_pState, wxPG_ITERATE_VISIBLE, p, selectDir );
+ if ( p )
+ DoSelectProperty(p);
+ wasHandled = true;
+ }
+ }
+ else
+ {
+ // If nothing was selected, select the first item now
+ // (or navigate out of tab).
+ if ( action != wxPG_ACTION_CANCEL_EDIT && secondAction != wxPG_ACTION_CANCEL_EDIT )
+ {
+ wxPGProperty* p = wxPropertyGridInterface::GetFirst();
+ if ( p ) DoSelectProperty(p);
+ wasHandled = true;
}
}
- if ( !next )
+ if ( !wasHandled )
event.Skip();
}
// -----------------------------------------------------------------------
-bool wxPropertyGrid::ButtonTriggerKeyTest( wxKeyEvent &event )
+void wxPropertyGrid::OnKey( wxKeyEvent &event )
{
- int keycode = event.GetKeyCode();
+ HandleKeyEvent(event, false);
+}
- // Does the keycode trigger button?
- if ( keycode == m_pushButKeyCode &&
- m_wndEditor2 &&
- (!m_pushButKeyCodeNeedsAlt || event.AltDown()) &&
- (!m_pushButKeyCodeNeedsCtrl || event.ControlDown()) )
+// -----------------------------------------------------------------------
+
+bool wxPropertyGrid::ButtonTriggerKeyTest( int action, wxKeyEvent& event )
+{
+ if ( action == -1 )
{
- m_keyComboConsumed = 1;
+ int secondAction;
+ action = KeyEventToActions(event, &secondAction);
+ }
- wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED,m_wndEditor2->GetId());
+ // Does the keycode trigger button?
+ if ( action == wxPG_ACTION_PRESS_BUTTON &&
+ m_wndEditor2 )
+ {
+ wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, m_wndEditor2->GetId());
GetEventHandler()->AddPendingEvent(evt);
return true;
}
void wxPropertyGrid::OnChildKeyDown( wxKeyEvent &event )
{
- int keycode = event.GetKeyCode();
-
- // Ignore Alt and Control when they are down alone
- if ( keycode == WXK_ALT ||
- keycode == WXK_CONTROL )
- {
- event.Skip();
- return;
- }
-
- if ( ButtonTriggerKeyTest(event) )
- return;
-
- if ( HandleChildKey(event) == true )
- event.Skip();
-
- GetEventHandler()->AddPendingEvent(event);
-}
-
-void wxPropertyGrid::OnChildKeyUp( wxKeyEvent &event )
-{
- m_keyComboConsumed = 0;
-
- GetEventHandler()->AddPendingEvent(event);
-
- event.Skip();
+ HandleKeyEvent(event, true);
}
// -----------------------------------------------------------------------
HandleFocusChange( newFocused );
}
+bool wxPropertyGrid::IsEditorFocused() const
+{
+ wxWindow* focus = wxWindow::FindFocus();
+
+ if ( focus == m_wndEditor || focus == m_wndEditor2 ||
+ focus == GetEditorControl() )
+ return true;
+
+ return false;
+}
+
// Called by focus event handlers. newFocused is the window that becomes focused.
void wxPropertyGrid::HandleFocusChange( wxWindow* newFocused )
{
if ( (m_iFlags & wxPG_FL_FOCUSED) !=
(oldFlags & wxPG_FL_FOCUSED) )
{
- // On each focus kill, mark the next nav key event
- // to be ignored (can't do on set focus since the
- // event would occur before it).
if ( !(m_iFlags & wxPG_FL_FOCUSED) )
{
- m_iFlags |= wxPG_FL_IGNORE_NEXT_NAVKEY;
-
// Need to store changed value
CommitChangesFromEditor();
}
}
*/
-
- m_iFlags &= ~(wxPG_FL_IGNORE_NEXT_NAVKEY);
}
// Redraw selected
// -----------------------------------------------------------------------
// noDefCheck = true prevents infinite recursion.
-wxPGEditor* wxPropertyGrid::RegisterEditorClass( wxPGEditor* editorclass,
- const wxString& name,
+wxPGEditor* wxPropertyGrid::RegisterEditorClass( wxPGEditor* editorClass,
bool noDefCheck )
{
- wxASSERT( editorclass );
+ wxASSERT( editorClass );
if ( !noDefCheck && wxPGGlobalVars->m_mapEditorClasses.empty() )
RegisterDefaultEditors();
- wxPGGlobalVars->m_mapEditorClasses[name] = (void*)editorclass;
+ wxString name = editorClass->GetName();
+
+ // Existing editor under this name?
+ wxPGHashMapS2P::iterator vt_it = wxPGGlobalVars->m_mapEditorClasses.find(name);
+
+ if ( vt_it != wxPGGlobalVars->m_mapEditorClasses.end() )
+ {
+ // If this name was already used, try class name.
+ name = editorClass->GetClassInfo()->GetClassName();
+ vt_it = wxPGGlobalVars->m_mapEditorClasses.find(name);
+ }
- return editorclass;
+ wxCHECK_MSG( vt_it == wxPGGlobalVars->m_mapEditorClasses.end(),
+ (wxPGEditor*) vt_it->second,
+ "Editor with given name was already registered" );
+
+ wxPGGlobalVars->m_mapEditorClasses[name] = (void*)editorClass;
+
+ return editorClass;
}
+// Use this in RegisterDefaultEditors.
+#define wxPGRegisterDefaultEditorClass(EDITOR) \
+ if ( wxPGEditor_##EDITOR == NULL ) \
+ { \
+ wxPGEditor_##EDITOR = wxPropertyGrid::RegisterEditorClass( \
+ new wxPG##EDITOR##Editor, true ); \
+ }
+
// Registers all default editor classes
void wxPropertyGrid::RegisterDefaultEditors()
{
}
else
{
- i++;
+ ++i;
m_curPos = i;
return true;
}
prev_a = wxT('\0');
}
}
- i++;
+ ++i;
}
m_curPos = str.end();
{
}
-wxPGChoiceEntry::wxPGChoiceEntry( const wxPGChoiceEntry& entry )
- : wxPGCell( entry.GetText(), entry.GetBitmap(),
- entry.GetFgCol(), entry.GetBgCol() ), m_value(entry.GetValue())
-{
-}
-
// -----------------------------------------------------------------------
// wxPGChoicesData
// -----------------------------------------------------------------------
void wxPGChoicesData::Clear()
{
- unsigned int i;
-
- for ( i=0; i<m_items.size(); i++ )
- {
- delete Item(i);
- }
-
-#if wxUSE_STL
- m_items.resize(0);
-#else
- m_items.Empty();
-#endif
+ m_items.clear();
}
void wxPGChoicesData::CopyDataFrom( wxPGChoicesData* data )
{
wxASSERT( m_items.size() == 0 );
- unsigned int i;
+ m_items = data->m_items;
+}
+
+wxPGChoiceEntry& wxPGChoicesData::Insert( int index,
+ const wxPGChoiceEntry& item )
+{
+ wxVector<wxPGChoiceEntry>::iterator it;
+ if ( index == -1 )
+ {
+ it = m_items.end();
+ index = (int) m_items.size();
+ }
+ else
+ {
+ it = m_items.begin() + index;
+ }
+
+ m_items.insert(it, item);
+
+ wxPGChoiceEntry& ownEntry = m_items[index];
+
+ // Need to fix value?
+ if ( ownEntry.GetValue() == wxPG_INVALID_VALUE )
+ ownEntry.SetValue(index);
- for ( i=0; i<data->GetCount(); i++ )
- m_items.push_back( new wxPGChoiceEntry(*data->Item(i)) );
+ return ownEntry;
}
// -----------------------------------------------------------------------
{
EnsureData();
- wxPGChoiceEntry* p = new wxPGChoiceEntry(label, value);
- m_data->Insert( -1, p );
- return *p;
+ wxPGChoiceEntry entry(label, value);
+ return m_data->Insert( -1, entry );
}
// -----------------------------------------------------------------------
{
EnsureData();
- wxPGChoiceEntry* p = new wxPGChoiceEntry(label, value);
- p->SetBitmap(bitmap);
- m_data->Insert( -1, p );
- return *p;
+ wxPGChoiceEntry entry(label, value);
+ entry.SetBitmap(bitmap);
+ return m_data->Insert( -1, entry );
}
// -----------------------------------------------------------------------
wxPGChoiceEntry& wxPGChoices::Insert( const wxPGChoiceEntry& entry, int index )
{
EnsureData();
-
- wxPGChoiceEntry* p = new wxPGChoiceEntry(entry);
- m_data->Insert(index, p);
- return *p;
+ return m_data->Insert( index, entry );
}
// -----------------------------------------------------------------------
{
EnsureData();
- wxPGChoiceEntry* p = new wxPGChoiceEntry(label, value);
- m_data->Insert( index, p );
- return *p;
+ wxPGChoiceEntry entry(label, value);
+ return m_data->Insert( index, entry );
}
// -----------------------------------------------------------------------
index++;
}
- wxPGChoiceEntry* p = new wxPGChoiceEntry(label, value);
- m_data->Insert( index, p );
- return *p;
+ wxPGChoiceEntry entry(label, value);
+ return m_data->Insert( index, entry );
}
// -----------------------------------------------------------------------
unsigned int i;
for ( i = 0; i < itemcount; i++ )
{
- int value = wxPG_INVALID_VALUE;
- if ( values )
- value = values[i];
- m_data->Insert( -1, new wxPGChoiceEntry(labels[i], value) );
- }
-}
-
-// -----------------------------------------------------------------------
-
-void wxPGChoices::Add( const wxArrayString& arr, const ValArrItem* values )
-{
- EnsureData();
-
- unsigned int i;
- unsigned int itemcount = arr.size();
-
- for ( i = 0; i < itemcount; i++ )
- {
- int value = wxPG_INVALID_VALUE;
+ int value = i;
if ( values )
value = values[i];
- m_data->Insert( -1, new wxPGChoiceEntry(arr[i], value) );
+ wxPGChoiceEntry entry(labels[i], value);
+ m_data->Insert( i, entry );
}
}
for ( i = 0; i < itemcount; i++ )
{
- int value = wxPG_INVALID_VALUE;
+ int value = i;
if ( &arrint && arrint.size() )
value = arrint[i];
- m_data->Insert( -1, new wxPGChoiceEntry(arr[i], value) );
+ wxPGChoiceEntry entry(arr[i], value);
+ m_data->Insert( i, entry );
}
}
void wxPGChoices::RemoveAt(size_t nIndex, size_t count)
{
wxASSERT( m_data->m_refCount != 0xFFFFFFF );
- unsigned int i;
- for ( i=nIndex; i<(nIndex+count); i++)
- delete m_data->Item(i);
- m_data->m_items.RemoveAt(nIndex, count);
+ m_data->m_items.erase(m_data->m_items.begin()+nIndex,
+ m_data->m_items.begin()+nIndex+count);
}
// -----------------------------------------------------------------------
unsigned int i;
for ( i=0; i< m_data->GetCount(); i++ )
{
- if ( m_data->Item(i)->GetText() == str )
+ const wxPGChoiceEntry& entry = m_data->Item(i);
+ if ( entry.HasText() && entry.GetText() == str )
return i;
}
}
unsigned int i;
for ( i=0; i< m_data->GetCount(); i++ )
{
- if ( m_data->Item(i)->GetValue() == val )
+ const wxPGChoiceEntry& entry = m_data->Item(i);
+ if ( entry.GetValue() == val )
return i;
}
}
// -----------------------------------------------------------------------
-bool wxPGChoices::HasValues() const
-{
- return true;
-}
-
-// -----------------------------------------------------------------------
-
wxArrayInt wxPGChoices::GetValuesForStrings( const wxArrayString& strings ) const
{
wxArrayInt arr;
// -----------------------------------------------------------------------
-wxArrayInt wxPGChoices::GetIndicesForStrings( const wxArrayString& strings,
+wxArrayInt wxPGChoices::GetIndicesForStrings( const wxArrayString& strings,
wxArrayString* unmatched ) const
{
wxArrayInt arr;
IMPLEMENT_DYNAMIC_CLASS(wxPropertyGridEvent, wxCommandEvent)
-DEFINE_EVENT_TYPE( wxEVT_PG_SELECTED )
-DEFINE_EVENT_TYPE( wxEVT_PG_CHANGING )
-DEFINE_EVENT_TYPE( wxEVT_PG_CHANGED )
-DEFINE_EVENT_TYPE( wxEVT_PG_HIGHLIGHTED )
-DEFINE_EVENT_TYPE( wxEVT_PG_RIGHT_CLICK )
-DEFINE_EVENT_TYPE( wxEVT_PG_PAGE_CHANGED )
-DEFINE_EVENT_TYPE( wxEVT_PG_ITEM_EXPANDED )
-DEFINE_EVENT_TYPE( wxEVT_PG_ITEM_COLLAPSED )
-DEFINE_EVENT_TYPE( wxEVT_PG_DOUBLE_CLICK )
+wxDEFINE_EVENT( wxEVT_PG_SELECTED, wxPropertyGridEvent )
+wxDEFINE_EVENT( wxEVT_PG_CHANGING, wxPropertyGridEvent )
+wxDEFINE_EVENT( wxEVT_PG_CHANGED, wxPropertyGridEvent )
+wxDEFINE_EVENT( wxEVT_PG_HIGHLIGHTED, wxPropertyGridEvent )
+wxDEFINE_EVENT( wxEVT_PG_RIGHT_CLICK, wxPropertyGridEvent )
+wxDEFINE_EVENT( wxEVT_PG_PAGE_CHANGED, wxPropertyGridEvent )
+wxDEFINE_EVENT( wxEVT_PG_ITEM_EXPANDED, wxPropertyGridEvent )
+wxDEFINE_EVENT( wxEVT_PG_ITEM_COLLAPSED, wxPropertyGridEvent )
+wxDEFINE_EVENT( wxEVT_PG_DOUBLE_CLICK, wxPropertyGridEvent )
// -----------------------------------------------------------------------
return new wxPropertyGridEvent( *this );
}
-void wxPropertyGrid::SetPropertyAttributeAll( const wxString& attrName, wxVariant value )
-{
- DoSetPropertyAttribute(GetRoot(), attrName, value, wxPG_RECURSE);
-}
-
// -----------------------------------------------------------------------
// wxPropertyGridPopulator
// -----------------------------------------------------------------------
m_state->DoInsert(parent, -1, property);
if ( propValue )
- property->SetValueFromString( *propValue, wxPG_FULL_VALUE );
+ property->SetValueFromString( *propValue, wxPG_FULL_VALUE|
+ wxPG_PROGRAMMATIC_VALUE );
return property;
}
int state = 0;
bool labelValid = false;
- for ( ; it != choicesString.end(); it++ )
+ for ( ; it != choicesString.end(); ++it )
{
wxChar c = *it;