Any wxPropertyKeyBinder exist?

Are you writing your own components and need help with how to set them up or have questions about the components you are deriving from ? Ask them here.
Post Reply
tatarinrafa
Earned a small fee
Earned a small fee
Posts: 15
Joined: Sat Mar 12, 2022 8:46 pm

Any wxPropertyKeyBinder exist?

Post by tatarinrafa »

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! :)
User avatar
doublemax
Moderator
Moderator
Posts: 19103
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Any wxPropertyKeyBinder exist?

Post by doublemax »

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?
Use the source, Luke!
tatarinrafa
Earned a small fee
Earned a small fee
Posts: 15
Joined: Sat Mar 12, 2022 8:46 pm

Re: Any wxPropertyKeyBinder exist?

Post by tatarinrafa »

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?
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"
:?
User avatar
doublemax
Moderator
Moderator
Posts: 19103
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Any wxPropertyKeyBinder exist?

Post by doublemax »

Check the "keyboard" sample that comes with wxWidgets. It contains everything you need for this.
Use the source, Luke!
tatarinrafa
Earned a small fee
Earned a small fee
Posts: 15
Joined: Sat Mar 12, 2022 8:46 pm

Re: Any wxPropertyKeyBinder exist?

Post by tatarinrafa »

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

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? :D

:D :wink:
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7449
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Any wxPropertyKeyBinder exist?

Post by ONEEYEMAN »

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.
Post Reply