delete ((wxPGEditor*)vt_it->second);
}
+ // Make sure the global pointers have been reset
+ wxASSERT(wxPG_EDITOR(TextCtrl) == NULL);
+ wxASSERT(wxPG_EDITOR(ChoiceAndButton) == NULL);
+
delete wxPGProperty::sm_wxPG_LABEL;
}
// wxPropertyGrid
// -----------------------------------------------------------------------
-IMPLEMENT_DYNAMIC_CLASS(wxPropertyGrid, wxScrolledWindow)
+IMPLEMENT_DYNAMIC_CLASS(wxPropertyGrid, wxControl)
-BEGIN_EVENT_TABLE(wxPropertyGrid, wxScrolledWindow)
+BEGIN_EVENT_TABLE(wxPropertyGrid, wxControl)
EVT_IDLE(wxPropertyGrid::OnIdle)
EVT_PAINT(wxPropertyGrid::OnPaint)
EVT_SIZE(wxPropertyGrid::OnResize)
// -----------------------------------------------------------------------
wxPropertyGrid::wxPropertyGrid()
- : wxScrolledWindow()
+ : wxControl(), wxScrollHelper(this)
{
Init1();
}
const wxSize& size,
long style,
const wxString& name )
- : wxScrolledWindow()
+ : wxControl(), wxScrollHelper(this)
{
Init1();
Create(parent,id,pos,size,style,name);
style &= ~(wxTAB_TRAVERSAL);
style |= wxWANTS_CHARS;
- wxScrolledWindow::Create(parent,id,pos,size,style,name);
+ wxControl::Create(parent, id, pos, size,
+ style | wxScrolledWindowStyle,
+ wxDefaultValidator,
+ name);
Init2();
m_eventObject = this;
m_curFocused = NULL;
m_processedEvent = NULL;
+ m_tlp = NULL;
m_sortFunction = NULL;
m_inDoPropertyChanged = false;
m_inCommitChangesFromEditor = false;
m_coloursCustomized = 0;
m_frozen = 0;
-#if wxPG_DOUBLE_BUFFER
m_doubleBuffer = NULL;
-#endif
#ifndef wxPG_ICON_WIDTH
m_expandbmp = NULL;
SetBackgroundStyle( wxBG_STYLE_CUSTOM );
// Hook the top-level parent
- m_tlp = NULL;
m_tlpClosed = NULL;
m_tlpClosedTime = 0;
m_timeCreated = ::wxGetLocalTimeMillis();
- //m_canvas->Create(this, wxID_ANY, wxPoint(0, 0), GetClientSize(),
- // wxWANTS_CHARS | wxCLIP_CHILDREN);
- SetBackgroundStyle( wxBG_STYLE_CUSTOM );
-
m_iFlags |= wxPG_FL_INITIALIZED;
m_ncWidth = wndsize.GetWidth();
wxS("Close(false).)") );
}
-#if wxPG_DOUBLE_BUFFER
if ( m_doubleBuffer )
delete m_doubleBuffer;
-#endif
if ( m_iFlags & wxPG_FL_CREATEDSTATE )
delete m_pState;
if ( m_iFlags & wxPG_FL_MOUSE_CAPTURED )
ReleaseMouse();
- return wxScrolledWindow::Destroy();
+ return wxControl::Destroy();
}
// -----------------------------------------------------------------------
//
// Tooltips disabled
//
- wxScrolledWindow::SetToolTip( NULL );
+ SetToolTip( NULL );
}
#endif
}
- wxScrolledWindow::SetWindowStyleFlag ( style );
+ wxControl::SetWindowStyleFlag ( style );
if ( m_iFlags & wxPG_FL_INITIALIZED )
{
{
if ( !m_frozen )
{
- wxScrolledWindow::Freeze();
+ wxControl::Freeze();
}
m_frozen++;
}
if ( !m_frozen )
{
- wxScrolledWindow::Thaw();
+ wxControl::Thaw();
RecalculateVirtualSize();
- #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
Refresh();
- #endif
// Force property re-selection
// NB: We must copy the selection.
}
else
{
- #if wxPG_DOUBLE_BUFFER
wxDELETE(m_doubleBuffer);
- #endif
}
}
- wxScrolledWindow::SetExtraStyle( exStyle );
+ wxControl::SetExtraStyle( exStyle );
if ( exStyle & wxPG_EX_INIT_NOCAT )
m_pState->InitNonCatMode();
{
OnTLPChanging((wxWindow*)newParent);
- bool res = wxScrolledWindow::Reparent(newParent);
+ bool res = wxControl::Reparent(newParent);
return res;
}
{
int x = 0, y = 0;
- m_captionFont = wxScrolledWindow::GetFont();
+ m_captionFont = wxControl::GetFont();
GetTextExtent(wxS("jG"), &x, &y, 0, 0, &m_captionFont);
m_subgroup_extramargin = x + (x/2);
// Must disable active editor.
DoClearSelection();
- bool res = wxScrolledWindow::SetFont( font );
+ bool res = wxControl::SetFont( font );
if ( res && GetParent()) // may not have been Create()ed yet if SetFont called from SetWindowVariant
{
CalculateFontAndBitmapStuff( m_vspacing );
wxString& wxPropertyGrid::ExpandEscapeSequences( wxString& dst_str, wxString& src_str )
{
- if ( src_str.length() == 0 )
+ if ( src_str.empty() )
{
dst_str = src_str;
return src_str;
wxString& wxPropertyGrid::CreateEscapeSequences( wxString& dst_str, wxString& src_str )
{
- if ( src_str.length() == 0 )
+ if ( src_str.empty() )
{
dst_str = src_str;
return src_str;
r.x = 0;
r.width = GetClientSize().x;
+ r.y = vy;
+ r.height = GetClientSize().y;
+
// Repaint this rectangle
DrawItems( dc, r.y, r.y + r.height, &r );
void wxPropertyGrid::DrawItems( wxDC& dc,
unsigned int topItemY,
unsigned int bottomItemY,
- const wxRect* drawRect )
+ const wxRect* itemsRect )
{
if ( m_frozen ||
m_height < 1 ||
m_pState->EnsureVirtualHeight();
- wxRect tempDrawRect;
- if ( !drawRect )
+ wxRect tempItemsRect;
+ if ( !itemsRect )
{
- tempDrawRect = wxRect(0, topItemY,
- m_pState->m_width,
- bottomItemY);
- drawRect = &tempDrawRect;
+ tempItemsRect = wxRect(0, topItemY,
+ m_pState->m_width,
+ bottomItemY);
+ itemsRect = &tempItemsRect;
}
+ int vx, vy;
+ GetViewStart(&vx, &vy);
+ vx *= wxPG_PIXELS_PER_UNIT;
+ vy *= wxPG_PIXELS_PER_UNIT;
+
+ // itemRect is in virtual grid space
+ wxRect drawRect(itemsRect->x - vx,
+ itemsRect->y - vy,
+ itemsRect->width,
+ itemsRect->height);
+
// items added check
if ( m_pState->m_itemsAdded ) PrepareAfterItemsAdded();
wxDC* dcPtr = &dc;
bool isBuffered = false;
- #if wxPG_DOUBLE_BUFFER
wxMemoryDC* bufferDC = NULL;
if ( !(GetExtraStyle() & wxPG_EX_NATIVE_DOUBLE_BUFFERING) )
{
if ( !m_doubleBuffer )
{
- paintFinishY = drawRect->y;
+ paintFinishY = itemsRect->y;
dcPtr = NULL;
}
else
isBuffered = true;
}
}
- #endif
if ( dcPtr )
{
- dc.SetClippingRegion( *drawRect );
- paintFinishY = DoDrawItems( *dcPtr, drawRect, isBuffered );
- int drawBottomY = drawRect->y + drawRect->height;
+ // paintFinishY and drawBottomY are in buffer/physical space
+ paintFinishY = DoDrawItems( *dcPtr, itemsRect, isBuffered );
+ int drawBottomY = itemsRect->y + itemsRect->height - vy;
// Clear area beyond last painted property
if ( paintFinishY < drawBottomY )
m_width,
drawBottomY );
}
-
- dc.DestroyClippingRegion();
}
- #if wxPG_DOUBLE_BUFFER
if ( bufferDC )
{
- dc.Blit( drawRect->x, drawRect->y, drawRect->width,
- drawRect->height,
+ dc.Blit( drawRect.x, drawRect.y, drawRect.width,
+ drawRect.height,
bufferDC, 0, 0, wxCOPY );
delete bufferDC;
}
- #endif
}
else
{
// Just clear the area
dc.SetPen(m_colEmptySpace);
dc.SetBrush(m_colEmptySpace);
- dc.DrawRectangle(*drawRect);
+ dc.DrawRectangle(drawRect);
}
}
// -----------------------------------------------------------------------
int wxPropertyGrid::DoDrawItems( wxDC& dc,
- const wxRect* drawRect,
+ const wxRect* itemsRect,
bool isBuffered ) const
{
const wxPGProperty* firstItem;
const wxPGProperty* lastItem;
- firstItem = DoGetItemAtY(drawRect->y);
- lastItem = DoGetItemAtY(drawRect->y+drawRect->height-1);
+ firstItem = DoGetItemAtY(itemsRect->y);
+ lastItem = DoGetItemAtY(itemsRect->y+itemsRect->height-1);
if ( !lastItem )
lastItem = GetLastItem( wxPG_ITERATE_VISIBLE );
if ( m_frozen || m_height < 1 || firstItem == NULL )
- return drawRect->y;
+ return itemsRect->y;
- wxCHECK_MSG( !m_pState->m_itemsAdded, drawRect->y,
+ wxCHECK_MSG( !m_pState->m_itemsAdded, itemsRect->y,
"no items added" );
wxASSERT( m_pState->m_properties->GetChildCount() );
int firstItemTopY;
int lastItemBottomY;
- firstItemTopY = drawRect->y;
- lastItemBottomY = drawRect->y + drawRect->height;
+ firstItemTopY = itemsRect->y;
+ lastItemBottomY = itemsRect->y + itemsRect->height;
// Align y coordinates to item boundaries
firstItemTopY -= firstItemTopY % lh;
// Entire range outside scrolled, visible area?
if ( firstItemTopY >= (int)m_pState->GetVirtualHeight() ||
lastItemBottomY <= 0 )
- return drawRect->y;
+ return itemsRect->y;
wxCHECK_MSG( firstItemTopY < lastItemBottomY,
- drawRect->y,
+ itemsRect->y,
"invalid y values" );
/*
wxLogDebug(" -> DoDrawItems ( \"%s\" -> \"%s\"
- "height=%i (ch=%i), drawRect = 0x%lX )",
+ "height=%i (ch=%i), itemsRect = 0x%lX )",
firstItem->GetLabel().c_str(),
lastItem->GetLabel().c_str(),
(int)(lastItemBottomY - firstItemTopY),
(int)m_height,
- (unsigned long)drawRect );
+ (unsigned long)&itemsRect );
*/
wxRect r;
int xRelMod = 0;
//
- // With wxPG_DOUBLE_BUFFER, do double buffering
- // - buffer's y = 0, so align drawRect and coordinates to that
+ // For now, do some manual calculation for double buffering
+ // - buffer's y = 0, so align itemsRect and coordinates to that
+ //
+ // TODO: In future use wxAutoBufferedPaintDC (for example)
//
-#if wxPG_DOUBLE_BUFFER
int yRelMod = 0;
wxRect cr2;
if ( isBuffered )
{
- xRelMod = drawRect->x;
- yRelMod = drawRect->y;
+ xRelMod = itemsRect->x;
+ yRelMod = itemsRect->y;
//
- // drawRect conversion
- cr2 = *drawRect;
+ // itemsRect conversion
+ cr2 = *itemsRect;
cr2.x -= xRelMod;
cr2.y -= yRelMod;
- drawRect = &cr2;
+ itemsRect = &cr2;
firstItemTopY -= yRelMod;
lastItemBottomY -= yRelMod;
}
-#else
- wxUnusedVar(isBuffered);
-#endif
int x = m_marginWidth - xRelMod;
const wxPropertyGridPageState* state = m_pState;
const wxArrayInt& colWidths = state->m_colWidths;
-#if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
- bool wasSelectedPainted = false;
-#endif
-
// TODO: Only render columns that are within clipping region.
dc.SetFont(normalFont);
}
else
{
-#if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
- if ( p == firstSelected )
- wasSelectedPainted = true;
-#endif
-
renderFlags |= wxPGCellRenderer::Selected;
if ( !p->IsCategory() )
y += rowHeight;
}
- // Refresh editor controls (seems not needed on msw)
- // NOTE: This code is mandatory for GTK!
-#if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
- if ( wasSelectedPainted )
- {
- if ( m_wndEditor )
- m_wndEditor->Refresh();
- if ( m_wndEditor2 )
- m_wndEditor2->Refresh();
- }
-#endif
-
return y;
}
//
// Return rect which encloses the given property range
// (in logical grid coordinates)
- //
+ //
int visTop = p1->GetY();
int visBottom;
void wxPropertyGrid::RefreshProperty( wxPGProperty* p )
{
- if ( m_pState->DoIsPropertySelected(p) )
+ if ( m_pState->DoIsPropertySelected(p) || p->IsChildSelected(true) )
{
// NB: We must copy the selection.
wxArrayPGProperty selection = m_pState->m_selection;
wxWindow::Refresh(false, rect);
-#if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
+#if wxPG_REFRESH_CONTROLS
// I think this really helps only GTK+1.2
if ( m_wndEditor ) m_wndEditor->Refresh();
if ( m_wndEditor2 ) m_wndEditor2->Refresh();
void wxPropertyGrid::DoShowPropertyError( wxPGProperty* WXUNUSED(property), const wxString& msg )
{
- if ( !msg.length() )
+ if ( msg.empty() )
return;
#if wxUSE_STATUSBAR
{
wxString msg = m_validationInfo.m_failureMessage;
- if ( !msg.length() )
+ if ( msg.empty() )
msg = _("You have entered invalid value. Press ESC to cancel editing.");
#if wxUSE_STATUSBAR
}
else
{
-#if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
+#if wxPG_REFRESH_CONTROLS
if ( m_wndEditor ) m_wndEditor->Refresh();
if ( m_wndEditor2 ) m_wndEditor2->Refresh();
#endif
// -----------------------------------------------------------------------
-void wxPropertyGrid::HandleCustomEditorEvent( wxEvent &event )
+bool wxPropertyGrid::HandleCustomEditorEvent( wxEvent &event )
{
+ //
+ // NB: We should return true if the event was recognized as
+ // a dedicated wxPropertyGrid event, and as such was
+ // either properly handled or ignored.
+ //
+
// It is possible that this handler receives event even before
// the control has been properly initialized. Let's skip the
// event handling in that case.
if ( !m_pState )
- return;
+ return false;
// Don't care about the event if it originated from the
// 'label editor'. In this function we only care about the
if ( m_labelEditor && event.GetId() == m_labelEditor->GetId() )
{
event.Skip();
- return;
+ return true;
}
wxPGProperty* selected = GetSelection();
// similar is currently doing something (showing a
// message box, for instance).
m_processedEvent )
- return;
+ return true;
if ( m_iFlags & wxPG_FL_IN_HANDLECUSTOMEDITOREVENT )
- return;
+ return true;
wxVariant pendingValue(selected->GetValueRef());
wxWindow* wnd = GetEditorControl();
wxString newTcValue = tc->GetValue();
if ( m_prevTcValue == newTcValue )
- return;
+ return true;
m_prevTcValue = newTcValue;
}
else if ( wnd->IsKindOf(CLASSINFO(wxComboCtrl)) )
{
+ // In some cases we might stumble unintentionally on
+ // wxComboCtrl's embedded wxTextCtrl's events. Let's
+ // avoid them.
+ if ( editorWnd->IsKindOf(CLASSINFO(wxTextCtrl)) )
+ return false;
+
wxComboCtrl* cc = (wxComboCtrl*) wnd;
wxString newTcValue = cc->GetTextCtrl()->GetValue();
if ( m_prevTcValue == newTcValue )
- return;
+ return true;
m_prevTcValue = newTcValue;
}
}
bool validationFailure = false;
bool buttonWasHandled = false;
+ bool result = false;
//
// Try common button handling
if ( editor->OnEvent( this, selected, editorWnd, event ) )
{
+ result = true;
+
// If changes, validate them
if ( DoEditorValidate() )
{
// Let unhandled button click events go to the parent
if ( !buttonWasHandled && event.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED )
{
+ result = true;
wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED,GetId());
GetEventHandler()->AddPendingEvent(evt);
}
}
ClearInternalFlag(wxPG_FL_IN_HANDLECUSTOMEDITOREVENT);
+
+ return result;
}
// -----------------------------------------------------------------------
m_propGrid->HandleCustomEditorEvent(event);
+ //
+ // NB: We should return true if the event was recognized as
+ // a dedicated wxPropertyGrid event, and as such was
+ // either properly handled or ignored.
+ //
+ if ( m_propGrid->IsMainButtonEvent(event) )
+ return true;
+
//
// NB: On wxMSW, a wxTextCtrl with wxTE_PROCESS_ENTER
// may beep annoyingly if that event is skipped
// 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 == this )
- {
- SetFocusOnCanvas();
- break;
- }
- parent = parent->GetParent();
- }
- }
+ SetFocusOnCanvas();
// Do not free editors immediately if processing events
if ( m_wndEditor2 )
wxStatusBar* statusbar = GetStatusBar();
if ( statusbar )
{
- if ( pHelpString && pHelpString->length() )
+ if ( pHelpString && !pHelpString->empty() )
{
// Set help box text.
statusbar->SetStatusText( *pHelpString );
//
// Show help as a tool tip on the editor control.
//
- if ( pHelpString && pHelpString->length() &&
+ if ( pHelpString && !pHelpString->empty() &&
primaryCtrl )
{
primaryCtrl->SetToolTip(*pHelpString);
SetScrollbars( wxPG_PIXELS_PER_UNIT, wxPG_PIXELS_PER_UNIT,
xAmount, yAmount, xPos, yPos, true );
+ // This may be needed in addition to calling SetScrollbars()
+ // when class inherits from wxScrollHelper instead of
+ // actual wxScrolled<T>.
+ AdjustScrollbars();
+
// Must re-get size now
GetClientSize(&width,&height);
m_width = width;
m_height = height;
-#if wxPG_DOUBLE_BUFFER
if ( !(GetExtraStyle() & wxPG_EX_NATIVE_DOUBLE_BUFFERING) )
{
int dblh = (m_lineHeight*2);
}
}
-#endif
-
m_pState->OnClientWidthChange( width, event.GetSize().x - m_ncWidth, true );
m_ncWidth = event.GetSize().x;
void wxPropertyGrid::SetFocusOnCanvas()
{
- SetFocusIgnoringChildren();
+ // To prevent wxPropertyGrid from stealing focus from other controls,
+ // only move focus to the grid if it was already in one if its child
+ // controls.
+ wxWindow* focus = wxWindow::FindFocus();
+ if ( focus )
+ {
+ wxWindow* parent = focus->GetParent();
+ while ( parent )
+ {
+ if ( parent == this )
+ {
+ SetFocus();
+ break;
+ }
+ parent = parent->GetParent();
+ }
+ }
+
m_editorFocused = 0;
}
else DoExpand( p, true );
}
- res = false;
+ // Do not Skip() the event after selection has been made.
+ // Otherwise default event handling behaviour kicks in
+ // and may revert focus back to the main canvas.
+ res = true;
}
else
{
m_draggedSplitter = splitterHit;
m_dragOffset = splitterHitOffset;
- #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
+ #if wxPG_REFRESH_CONTROLS
// Fixes button disappearance bug
if ( m_wndEditor2 )
m_wndEditor2->Show ( false );
// Disable splitter auto-centering (but only if moved any -
// otherwise we end up disabling auto-center even after a
// recentering double-click).
- int posDiff = abs(m_startingSplitterX -
+ int posDiff = abs(m_startingSplitterX -
GetSplitterPosition(m_draggedSplitter));
if ( posDiff > 1 )
m_wndEditor->Show ( true );
}
- #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
+ #if wxPG_REFRESH_CONTROLS
// Fixes button disappearance bug
if ( m_wndEditor2 )
m_wndEditor2->Show ( true );
int x, y;
if ( OnMouseCommon( event, &x, &y ) )
{
- HandleMouseClick(x,y,event);
+ if ( !HandleMouseClick(x, y, event) )
+ event.Skip();
+ }
+ else
+ {
+ event.Skip();
}
- event.Skip();
}
// -----------------------------------------------------------------------
int x, y;
CalcUnscrolledPosition( event.m_x, event.m_y, &x, &y );
HandleMouseDoubleClick(x,y,event);
- event.Skip();
+
+ // Do not Skip() event here - OnMouseClick() call above
+ // should have already taken care of it.
}
// -----------------------------------------------------------------------
int x, y;
if ( OnMouseCommon( event, &x, &y ) )
{
- HandleMouseUp(x,y,event);
+ if ( !HandleMouseUp(x, y, event) )
+ event.Skip();
+ }
+ else
+ {
+ event.Skip();
}
- event.Skip();
}
// -----------------------------------------------------------------------
wxPGProperty* p = selected;
+ if ( action == wxPG_ACTION_EDIT && !editorFocused )
+ {
+ DoSelectProperty( p, wxPG_SEL_FOCUS );
+ wasHandled = true;
+ }
+
// Travel and expand/collapse
int selectDir = -2;
RegisterDefaultEditors();
wxString name = editorName;
- if ( name.length() == 0 )
+ if ( name.empty() )
name = editorClass->GetName();
// Existing editor under this name?
m_column = 1;
m_canVeto = false;
m_wasVetoed = false;
+ m_pg = NULL;
}
// -----------------------------------------------------------------------
else
{
bool found = false;
- if ( idString.length() )
+ if ( !idString.empty() )
{
wxPGHashMapS2P::iterator it = m_dictIdChoices.find(idString);
if ( it != m_dictIdChoices.end() )
}
// Assign to id
- if ( idString.length() )
+ if ( !idString.empty() )
m_dictIdChoices[idString] = choices.GetData();
}
}
wxString valuel = value.Lower();
wxVariant variant;
- if ( type.length() == 0 )
+ if ( type.empty() )
{
long v;