Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions src-ui-wx/shared/utils/xlPropertyGrid.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <set>
#include <wx/propgrid/propgrid.h>
#include <wx/propgrid/propgridiface.h>
#include <wx/combo.h>

// This is to workaround a crash in wxPropertyGrid where doing
Expand All @@ -29,6 +30,17 @@ class xlPropertyGrid : public wxPropertyGrid {
const wxString& name = wxASCII_STR(wxPropertyGridNameStr)) :
wxPropertyGrid(parent, id, pos, size, style, name) {
Connect(wxEVT_IDLE,(wxObjectEventFunction)&xlPropertyGrid::OnIdle, 0, this);
// Tab traversal: stock wxPropertyGrid sends focus to the next sibling
// widget on Tab (via Navigate()), so users have to click their way
// back into the grid to edit the next property. Intercept Tab via
// CHAR_HOOK on the grid and walk to the next/previous visible
// property instead, matching the behavior of every other property
// editor (Excel, Visual Studio properties pane, etc.).
Bind(wxEVT_CHAR_HOOK, &xlPropertyGrid::OnCharHook, this);
// Spin/combo editors capture the mouse wheel and change their value,
// which fires a rebuild that loses the selection. Redirect the wheel
// from the active editor to the grid so scrolling only scrolls.
Bind(wxEVT_PG_SELECTED, &xlPropertyGrid::OnPropertySelected, this);
}
virtual ~xlPropertyGrid() {
}
Expand Down Expand Up @@ -75,5 +87,81 @@ class xlPropertyGrid : public wxPropertyGrid {
}

private:
void OnPropertySelected(wxPropertyGridEvent& event) {
event.Skip();
if (wxWindow* ed = GetEditorControl()) {
ed->Bind(wxEVT_MOUSEWHEEL, &xlPropertyGrid::OnEditorMouseWheel, this);
}
}
void OnEditorMouseWheel(wxMouseEvent& event) {
// Forward to the grid so it scrolls; don't Skip, so the editor never
// consumes the wheel to change its value.
wxMouseEvent fwd(event);
fwd.SetEventObject(this);
ProcessWindowEvent(fwd);
}
void OnCharHook(wxKeyEvent& event) {
Comment thread
heffneil marked this conversation as resolved.
// Only interested in plain Tab / Shift+Tab; Ctrl/Alt+Tab passes through.
if (event.GetKeyCode() != WXK_TAB || event.ControlDown() || event.AltDown()) {
event.Skip();
return;
}
// Nothing selected -> no active editor; let Tab traverse out of the grid.
wxPGProperty* sel = GetSelection();
if (sel == nullptr) {
event.Skip();
return;
}
// Gate on selection rather than editor focus so combo/choice editors
// advance too (IsEditorFocused() is false for them, which used to drop
// focus out of the grid). Skip expanded category headers (descend to
// their first child) but stop on collapsed ones so the user can expand
// them (Right arrow) and Tab again to enter the section.
auto step = [&event](wxPropertyGridIterator& i) {
if (event.ShiftDown()) {
--i;
} else {
++i;
}
};
auto skippable = [](wxPropertyGridIterator& i) {
return (*i)->IsCategory() && (*i)->IsExpanded();
};
wxPropertyGridIterator it = GetIterator(wxPG_ITERATE_VISIBLE, sel);
do {
step(it);
} while (!it.AtEnd() && skippable(it));
if (it.AtEnd()) {
Comment thread
heffneil marked this conversation as resolved.
// Past the last/first stop: wrap to the other end so Tab cycles
// through the grid instead of leaving it.
it = GetIterator(wxPG_ITERATE_VISIBLE, event.ShiftDown() ? wxBOTTOM : wxTOP);
while (!it.AtEnd() && skippable(it)) {
step(it);
}
if (it.AtEnd()) {
event.Skip();
return;
}
}
// Commit the current editor's value, then jump to the next property.
// The commit fires wxEVT_PG_CHANGED, which queues a model reload that
// rebuilds the whole grid and invalidates property pointers. Defer the
// focus shift via CallAfter so it runs once the rebuild has settled,
// and look up the target by name (pointers from before the rebuild
// are dead).
const wxString nextName = (*it)->GetName();
// If validation rejects the value, stay on the current editor so the
// user can fix it rather than silently losing focus to another row.
if (!CommitChangesFromEditor()) {
return;
}
CallAfter([this, nextName]() {
Comment thread
heffneil marked this conversation as resolved.
if (wxPGProperty* p = GetPropertyByName(nextName)) {
SelectProperty(p, true);
EnsureVisible(p);
}
});
}

bool m_hidingComboPopups = false;
};
Loading