I'm redoing UI for an editor. The editor has it's tools and commands. I was wondering if there is some sort of property widget for wxPropertyWindow which can controll key/mouse binding? I need to create a prop window that can be used to set up key binding/shortcuts/input keys
Would appreciate if anyone can give me a link to an example or if someone helps with proper code for that
Best regards!
Any wxPropertyKeyBinder exist?
-
- Earned a small fee
- Posts: 15
- Joined: Sat Mar 12, 2022 8:46 pm
Re: Any wxPropertyKeyBinder exist?
I don't think that anything like this already exists, and you'll probably have to implement it yourself.
Do you want something where the user presses the key combination and the app detects it automatically, or just a GUI where you have checkboxes for Control, Shift, Alt- state and a wxChoice for the keys?
Do you want something where the user presses the key combination and the app detects it automatically, or just a GUI where you have checkboxes for Control, Shift, Alt- state and a wxChoice for the keys?
Use the source, Luke!
-
- Earned a small fee
- Posts: 15
- Joined: Sat Mar 12, 2022 8:46 pm
Re: Any wxPropertyKeyBinder exist?
The first variant is what I'm targeted. User presses key combination then and app detects it. After that key combination should be displayed in text ctrl like "Ctrl+Shift+D"doublemax wrote: ↑Sun Mar 13, 2022 12:54 am I don't think that anything like this already exists, and you'll probably have to implement it yourself.
Do you want something where the user presses the key combination and the app detects it automatically, or just a GUI where you have checkboxes for Control, Shift, Alt- state and a wxChoice for the keys?
Re: Any wxPropertyKeyBinder exist?
Check the "keyboard" sample that comes with wxWidgets. It contains everything you need for this.
Use the source, Luke!
-
- Earned a small fee
- Posts: 15
- Joined: Sat Mar 12, 2022 8:46 pm
Re: Any wxPropertyKeyBinder exist?
Here is the raw code of what I came up with for our editor project
Sorry if the code is messy, but I'm the only coder in the project, don't have much time for housekeeping
Again. Just posting it for whoever it might be helpfull to get an idea. The code needs refactoring and probably a better implementation, but our team make a non comercial project, so i'm the only coder and do not have that much of time for housekeeping
P.S. Some of the virtual funcs were not virtual in the parent class in wxWidgets. They need to be changed by coder to be virtual in order to make this code work and override needed funcs in wxWidgets native prop classes
That is actually a question to the wxWidgets devs, why wouldnt be all functions virtual under "protected" specifier?
Sorry if the code is messy, but I'm the only coder in the project, don't have much time for housekeeping
Code: Select all
/// ----------------------- Header
class wxKeyBindProperty;
class wxKeyBindTextCtrl : public wxTextCtrl
{
public:
wxKeyBindTextCtrl() : wxTextCtrl() {}
wxKeyBindTextCtrl(wxKeyBindProperty* prop, wxWindow* parent, wxWindowID id,
const wxString& value = wxEmptyString,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = 0,
const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxASCII_STR(wxTextCtrlNameStr)) : wxTextCtrl(parent, id, value, pos, size, style, validator, name)
{
m_OwningProp = prop;
}
void OnKeyDown(wxKeyEvent& event);
wxKeyBindProperty* m_OwningProp;
wxDECLARE_EVENT_TABLE();
};
WX_PG_DECLARE_VARIANT_DATA(xr_shortcut)
class wxKeyBindProperty : public wxPGProperty
{
WX_PG_DECLARE_PROPERTY_CLASS(wxKeyBindProperty)
public:
wxKeyBindProperty() : wxPGProperty(wxPG_LABEL, wxPG_LABEL) {};
wxKeyBindProperty(const wxString& label, const wxString& name, xr_shortcut& val);
virtual ~wxKeyBindProperty();
virtual wxString ValueToString(wxVariant& value, int argFlags = 0) const;
virtual void OnAfterAppendToPropertyGrid(wxPropertyGrid* pg);
virtual void Refresh() wxOVERRIDE;
virtual void OnFocused() wxOVERRIDE;
virtual void OnUnfocused() wxOVERRIDE;
void XRSetValue(const xr_shortcut& val);
void OnSetNewValue(u32 key, bool has_ctrl, bool has_alt, bool has_shift, bool send_event);
public:
xr_shortcut m_shortcut;
wxKeyBindTextCtrl* m_UIKeyInputCTRL;
};
class wxPGNullEditor : public wxPGEditor
{
wxDECLARE_DYNAMIC_CLASS(wxPGNullEditor);
public:
wxPGNullEditor() {}
virtual ~wxPGNullEditor() {};
virtual wxPGWindowList CreateControls(wxPropertyGrid* propGrid, wxPGProperty* property, const wxPoint& pos, const wxSize& sz) const wxOVERRIDE;
virtual bool OnEvent(wxPropertyGrid* propGrid, wxPGProperty* property, wxWindow* ctrl, wxEvent& event) const wxOVERRIDE;
virtual void UpdateControl(wxPGProperty* property, wxWindow* ctrl) const;
virtual bool GetValueFromControl(wxVariant& variant, wxPGProperty* property, wxWindow* ctrl) const;
};
extern wxPGEditor* wxPGEditor_Null;
// ------------------------ Source cpp
shared_str GetKeyBindingText(u32 key, bool has_ctrl, bool has_alt, bool has_shift)
{
string256 str;
str[0] = 0;
string64 key_name;
if (has_ctrl)
{
key_name[0] = 0;
UINT scanCode = MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC);
GetKeyNameTextA(scanCode << 16, key_name, 64);
xr_sprintf(str, "%s + ", key_name);
}
if (has_alt)
{
key_name[0] = 0;
UINT scanCode = MapVirtualKey(VK_MENU, MAPVK_VK_TO_VSC);
GetKeyNameTextA(scanCode << 16, key_name, 64);
xr_sprintf(str, "%s%s + ", str, key_name);
}
if (has_shift)
{
key_name[0] = 0;
UINT scanCode = MapVirtualKey(VK_SHIFT, MAPVK_VK_TO_VSC);
GetKeyNameTextA(scanCode << 16, key_name, 64);
xr_sprintf(str, "%s%s + ", str, key_name);
}
key_name[0] = 0;
UINT scanCode = MapVirtualKey(key, MAPVK_VK_TO_VSC);
GetKeyNameTextA(scanCode << 16, key_name, 64);
xr_sprintf(str, "%s%s", str, key_name);
return str;
}
wxBEGIN_EVENT_TABLE(wxKeyBindTextCtrl, wxTextCtrl)
EVT_KEY_DOWN(wxKeyBindTextCtrl::OnKeyDown)
wxEND_EVENT_TABLE()
void wxKeyBindTextCtrl::OnKeyDown(wxKeyEvent& event)
{
// ESC reserved for closing dialog
if (event.GetRawKeyCode() == VK_ESCAPE)
{
wxBell();
return;
}
if (event.GetModifiers() != wxMOD_NONE && (event.GetRawKeyCode() == VK_SHIFT || event.GetRawKeyCode() == VK_CONTROL || event.GetRawKeyCode() == VK_MENU))
{
// rafa: No need to do anything if only modifiers are pressed
}
else if(event.GetRawKeyCode() == VK_BACK)
{
SetValue("");
m_OwningProp->OnSetNewValue(0, false, false, false, true);
}
else
{
shared_str str = GetKeyBindingText(event.GetRawKeyCode(), event.GetModifiers() & wxMOD_CONTROL, event.GetModifiers() & wxMOD_ALT, event.GetModifiers() & wxMOD_SHIFT);
SetValue(str.c_str());
m_OwningProp->OnSetNewValue(event.GetRawKeyCode(), event.GetModifiers() & wxMOD_CONTROL, event.GetModifiers() & wxMOD_ALT, event.GetModifiers() & wxMOD_SHIFT, true);
}
}
WX_PG_IMPLEMENT_VARIANT_DATA_DUMMY_EQ(xr_shortcut)
wxPG_IMPLEMENT_PROPERTY_CLASS(wxKeyBindProperty, wxPGProperty, Null)
wxKeyBindProperty::wxKeyBindProperty(const wxString& label, const wxString& name, xr_shortcut& val) : wxPGProperty(label, name)
{
m_shortcut = val;
}
wxKeyBindProperty::~wxKeyBindProperty()
{
delete(m_UIKeyInputCTRL);
}
wxString wxKeyBindProperty::ValueToString(wxVariant& WXUNUSED(value), int argFlags) const
{
return "";
}
void wxKeyBindProperty::Refresh()
{
wxPGProperty::Refresh();
wxPropertyGrid* pg = GetGrid();
if (pg && m_UIKeyInputCTRL)
{
wxRect grect = pg->GetEditorWidgetRect(this, 1);
wxPoint pos = grect.GetPosition();
m_UIKeyInputCTRL->SetMaxSize(wxSize(grect.GetSize().x, grect.GetSize().y - 4));
m_UIKeyInputCTRL->SetSize(wxSize(grect.GetSize().x, grect.GetSize().y - 4));
m_UIKeyInputCTRL->SetPosition(wxPoint(pos.x, pos.y + 2));
m_UIKeyInputCTRL->Show(IsVisible());
}
}
void wxKeyBindProperty::OnFocused()
{
if (GetGrid() && m_UIKeyInputCTRL)
m_UIKeyInputCTRL->SetBackgroundColour(*wxWHITE);
}
void wxKeyBindProperty::OnUnfocused()
{
if (GetGrid() && m_UIKeyInputCTRL)
m_UIKeyInputCTRL->SetBackgroundColour(GetGrid()->GetCellBackgroundColour());
}
void wxKeyBindProperty::OnAfterAppendToPropertyGrid(wxPropertyGrid* pg)
{
wxRect grect = pg->GetEditorWidgetRect(this, 1);
wxPoint pos = grect.GetPosition();
m_UIKeyInputCTRL = new wxKeyBindTextCtrl(this, pg->GetPanel(), wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER | wxBORDER_NONE);
m_UIKeyInputCTRL->SetPosition(pos);
m_UIKeyInputCTRL->Show(true);
m_UIKeyInputCTRL->SetBackgroundColour(pg->GetCellBackgroundColour());
m_UIKeyInputCTRL->SetForegroundColour(pg->GetCellTextColour());
shared_str str = GetKeyBindingText(m_shortcut.key, !!m_shortcut.ext.test(xr_shortcut::flCtrl), !!m_shortcut.ext.test(xr_shortcut::flAlt), !!m_shortcut.ext.test(xr_shortcut::flShift));
m_UIKeyInputCTRL->SetValue(str.c_str());
}
void wxKeyBindProperty::XRSetValue(const xr_shortcut& val)
{
m_shortcut = val;
shared_str str = GetKeyBindingText(m_shortcut.key, !!m_shortcut.ext.test(xr_shortcut::flCtrl), !!m_shortcut.ext.test(xr_shortcut::flAlt), !!m_shortcut.ext.test(xr_shortcut::flShift));
m_UIKeyInputCTRL->SetValue(str.c_str());
}
void wxKeyBindProperty::OnSetNewValue(u32 key, bool has_ctrl, bool has_alt, bool has_shift, bool send_event)
{
xr_shortcut new_val;
new_val.ext.set(xr_shortcut::flCtrl, has_ctrl);
new_val.ext.set(xr_shortcut::flAlt, has_alt);
new_val.ext.set(xr_shortcut::flShift, has_shift);
new_val.key = key;
if(send_event)
GetGrid()->ChangePropertyValue(this, WXVARIANT(new_val));
else
GetGrid()->SetPropertyValue(this, WXVARIANT(new_val));
}
// -----------------------------------------------------------------------
// Оставил как затычку чтобы выдать нулевой едитор. Без этого будут глитчи и краши. Ебаное говно жить.
wxPGEditor* wxPGEditor_Null = NULL;
wxIMPLEMENT_DYNAMIC_CLASS(wxPGNullEditor, wxPGEditor);
void wxPGNullEditor::UpdateControl(wxPGProperty* property, wxWindow* ctrl) const
{
wxTextCtrl* tc = wxDynamicCast(ctrl, wxTextCtrl);
if (!tc) return;
wxString s;
if (tc->HasFlag(wxTE_PASSWORD))
s = property->GetValueAsString(wxPG_FULL_VALUE);
else
s = property->GetDisplayedString();
wxPropertyGrid* pg = property->GetGrid();
pg->SetupTextCtrlValue(s);
tc->SetValue(s);
//
// Fix indentation, just in case (change in font boldness is one good
// reason).
tc->SetMargins(0);
}
wxPGWindowList wxPGNullEditor::CreateControls(wxPropertyGrid* propGrid, wxPGProperty* property, const wxPoint& pos, const wxSize& sz) const
{
return nullptr;
}
bool wxPGNullEditor::OnEvent(wxPropertyGrid* propGrid, wxPGProperty* property, wxWindow* ctrl, wxEvent& event) const
{
wxButtonsProperty* btn_prop = dynamic_cast<wxButtonsProperty*>(property);
if (event.GetEventType() == wxEVT_BUTTON)
{
property->SetValue(event.GetId());
return true;
}
return false;
}
bool wxPGNullEditor::GetValueFromControl(wxVariant& variant, wxPGProperty* property, wxWindow* ctrl) const
{
return property->IntToValue(variant, property->GetValue().GetLong(), wxPG_PROPERTY_SPECIFIC);
}
// -------------------------- Appending
wxPGProperty* CUIPropertyWindow::AppendKeyBindValue(PropItem* prop, wxPropertyCategory* category, LPCSTR name, LPCSTR full_path)
{
ShortcutValue* prop_val = dynamic_cast<ShortcutValue*>(prop->GetFrontValue());
R_ASSERT(prop_val);
xr_shortcut* val = prop_val->value;
wxKeyBindProperty* prop_ui = new wxKeyBindProperty(name, full_path, *val);
m_UIProperyGrid->SetPropertyEditor(prop_ui, wxPGEditor_Null);
return prop_ui;
}
// -------------------------- Change Event
void CUIPropertyWindow::OnPropertyGridValueChange(wxPropertyGridEvent& event)
{
xr_shortcut new_val;
new_val << event.GetValue();
}
// ------------------------ XR Shortcut class from sources of GSC XRay Engine (Not allowed for comercial use)
#pragma pack (push,1)
struct XRCORE_API xr_shortcut{
enum{
flShift = 0x20,
flCtrl = 0x40,
flAlt = 0x80,
};
union{
struct{
u8 key;
Flags8 ext;
};
u16 hotkey;
};
xr_shortcut (u8 k, BOOL a, BOOL c, BOOL s):key(k){ext.assign(u8((a?flAlt:0)|(c?flCtrl:0)|(s?flShift:0)));}
xr_shortcut (){ext.zero();key=0;}
bool similar (const xr_shortcut& v)const{return ext.equal(v.ext)&&(key==v.key);}
};
#pragma pack (pop)
Again. Just posting it for whoever it might be helpfull to get an idea. The code needs refactoring and probably a better implementation, but our team make a non comercial project, so i'm the only coder and do not have that much of time for housekeeping
P.S. Some of the virtual funcs were not virtual in the parent class in wxWidgets. They need to be changed by coder to be virtual in order to make this code work and override needed funcs in wxWidgets native prop classes
That is actually a question to the wxWidgets devs, why wouldnt be all functions virtual under "protected" specifier?
Re: Any wxPropertyKeyBinder exist?
Hi,
You should send an email to the wx-users mailing list.
This forum is for users by users of the library - no wx core devs are coming here.
Thank you.
You should send an email to the wx-users mailing list.
This forum is for users by users of the library - no wx core devs are coming here.
Thank you.