kicad-developers team mailing list archive
-
kicad-developers team
-
Mailing list archive
-
Message #22527
Re: Final? version of hotkeys patch
Looks like the text overflow was actually a wx bug - it insisted on
computing the size of the wxStaticText based on the smaller default font
instead of the larger one I had set.
Easily solved by just not setting a larger font. Still looks fine.
Patch attached.
On Mon, Jan 11, 2016 at 03:32:00PM -0500, Wayne Stambaugh wrote:
> It seems like this may be one of those issues where we have to
> compromise on the design. Once you figure out the hotkey entry dialog
> text overflow issues I'm fine with committing the changes. Everything
> else seems to work as expected.
>
> On 1/11/2016 3:00 PM, Chris Pavlina wrote:
> > Well, yes, that would be why it was selected. I don't like the idea of
> > limiting ourselves so much (must be wxListCtrl, must be an otherwise
> > mostly empty dialog) just because of a quirk of the way wx processes
> > events, though, and IMO the dialog method isn't all that bad. Nice and
> > clean with the way events are handled and received (except for the few
> > weird quirks I ranted about earlier, but those are nicely isolated now).
> > We can put that in any control in any layout we want without
> > restriction.
> >
> > Also I'd argue that just accepting the hotkeys directly in the dialog is
> > rather poor UI design /anyway/. It disables the normal navigation keys,
> > such that a user cannot operate the hotkeys list with the keyboard the
> > way he can operate the other controls, and works in a unique way to any
> > other programs, making it non-obvious. Pretty much everything I've seen
> > uses something different from that.
> >
> > The one I _really_ like is KDE, which places a button /in/ the list
> > control under the selected item. You click the button, and then as far
> > as I can tell the button receives the event. I tried. wx makes this
> > almost impossible. :(
> >
> >
> > On Mon, Jan 11, 2016 at 02:51:26PM -0500, Wayne Stambaugh wrote:
> >> On 1/11/2016 2:16 PM, Chris Pavlina wrote:
> >>> Had to change the capture method for both reasons. The old wxListCtrl
> >>> (IIRC) was the _only_ widget that captured them correctly.
> >>
> >> Maybe that's why the person who design the original hotkey dialog end up
> >> using wxListCtrl. It's certainly something to consider. I know it
> >> doesn't layout as nice as the tree control.
> >>
> >>>
> >>> I'm not completely a fan of the dialog either, but it's not all _that_
> >>> bad, and we're not the only ones doing it that way. At very least the
> >>> XFCE settings dialog does that, as well as a few others I tested (that I
> >>> don't remember right away). It's a pretty reliable way to make sure
> >>> you're the only thing receiving an event.
> >>>
> >>> I'll look at the labels - they weren't truncated in my Windows builds,
> >>> but maybe I changed something and didn't realize it.
> >>
> >> Thanks.
> >>
> >>>
> >>> On Mon, Jan 11, 2016 at 02:11:36PM -0500, Wayne Stambaugh wrote:
> >>>> Chris,
> >>>>
> >>>> I just finished testing this and I'm not sure about using a dialog to
> >>>> capture the hotkey press. Did you have to do this to overcome using the
> >>>> tabbed dialog or was it due to changing the control to a tree control?
> >>>> If it's the tabbed dialog design, it might be worth leaving the hotkey
> >>>> assignment dialog as a separate dialog. If not, I guess I can live
> >>>> with it but it wasn't necessary with the previous hotkey dialog. One
> >>>> other thing, you might want to avoid is using bold characters in the
> >>>> hotkey capture dialog. They are getting truncated on my windows builds.
> >>>> The longer the description, the worse the truncation.
> >>>>
> >>>> Cheers,
> >>>>
> >>>> Wayne
> >>>>
> >>>> On 1/8/2016 1:16 PM, Chris Pavlina wrote:
> >>>>> Hi,
> >>>>>
> >>>>> Jesus, here be dragons. Finally got the hotkeys stuff working properly
> >>>>> on all platforms - this has been tested on Linux, Win10, and OSX. Thanks
> >>>>> to JP for a push in the right direction (and even that required more
> >>>>> work!).
> >>>>>
> >>>>> Quick summary of the problems:
> >>>>>
> >>>>> - On Windows, there is a bug/quirk somewhere, where if a Tab
> >>>>> keypress occurs in a dialog with nothing in the tab order, this
> >>>>> must NOT generate the corresponding wxEVT_CHAR. If this happens,
> >>>>> the entire application freezes solid. This has nothing to do with
> >>>>> wxTAB_TRAVERSAL, so disabling this style property does not help.
> >>>>>
> >>>>> - wxEVT_CHAR_HOOK can be used to catch this event early and block
> >>>>> the tab bug. It also has the benefit of catching other 'special'
> >>>>> keys that wxEVT_CHAR misses (again, on Windows. wxEVT_CHAR has no
> >>>>> problem receiving them on Linux).
> >>>>>
> >>>>> - .../however/, wxEVT_CHAR_HOOK reports some keys incorrectly. Any
> >>>>> shifted symbol keys are reported as shift+(the unshifted key), so
> >>>>> on a US keyboard for example, when you type <?>, it sees
> >>>>> <Shift>+</>. There's no easy way to map these to the "correct"
> >>>>> keys, particularly considering international keyboards.
> >>>>>
> >>>>> - When wxEvent::DoAllowNextEvent() is called (see below),
> >>>>> wxEvent::Skip MUST be called on Linux and OSX, and must NOT be
> >>>>> called on Windows. No... I don't know why.
> >>>>>
> >>>>> In the end, I implemented separate OnChar and OnCharHook handlers.
> >>>>> OnCharHook does the following:
> >>>>>
> >>>>> 1. If the keypress is a pure modifier (wxEVT_CHAR_HOOK generates
> >>>>> events for things like Ctrl by itself), do nothing.
> >>>>>
> >>>>> 2. If the keypress is for a printable character **that is not
> >>>>> whitespace** (to avoid tripping the Tab bug), call
> >>>>> wxEvent::DoAllowNextEvent to cause the wxEVT_CHAR for the same key
> >>>>> to be generated. Call or do not call wxEvent::Skip depending on
> >>>>> platform, as above. This causes the "correct" key to be looked up
> >>>>> (e.g. <?> instead of <Shift></>) and this progresses to the OnChar
> >>>>> handler.
> >>>>>
> >>>>> 3. For all other keys, do not allow the wxEVT_CHAR to be generated,
> >>>>> but instead pass the event object directly to OnChar.
> >>>>>
> >>>>>
> >>>>> Then OnChar handles returning the keycode to caller.
> >>>>>
> >>>>> Please, help me test this. Wayne, if this works, and you don't mind, I'd
> >>>>> really like to get it merged. Even if there are still minor GUI quirks
> >>>>> and whatnot, the current top of the devel branch has the hotkey bugs
> >>>>> from earlier that I'd like to get fixed. Any further minor issues can be
> >>>>> resolved in further minor commits.
> >>>>>
> >>>>> --
> >>>>> Exasperatedly,
> >>>>> Chris
> >>>>>
> >>>>>
> >>>>>
> >>>>> _______________________________________________
> >>>>> Mailing list: https://launchpad.net/~kicad-developers
> >>>>> Post to : kicad-developers@xxxxxxxxxxxxxxxxxxx
> >>>>> Unsubscribe : https://launchpad.net/~kicad-developers
> >>>>> More help : https://help.launchpad.net/ListHelp
> >>>>>
> >>>>
> >>>>
> >>>> _______________________________________________
> >>>> Mailing list: https://launchpad.net/~kicad-developers
> >>>> Post to : kicad-developers@xxxxxxxxxxxxxxxxxxx
> >>>> Unsubscribe : https://launchpad.net/~kicad-developers
> >>>> More help : https://help.launchpad.net/ListHelp
> >>>
> >>> _______________________________________________
> >>> Mailing list: https://launchpad.net/~kicad-developers
> >>> Post to : kicad-developers@xxxxxxxxxxxxxxxxxxx
> >>> Unsubscribe : https://launchpad.net/~kicad-developers
> >>> More help : https://help.launchpad.net/ListHelp
> >>>
> >>
> >> _______________________________________________
> >> Mailing list: https://launchpad.net/~kicad-developers
> >> Post to : kicad-developers@xxxxxxxxxxxxxxxxxxx
> >> Unsubscribe : https://launchpad.net/~kicad-developers
> >> More help : https://help.launchpad.net/ListHelp
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index cf66392..1b51e9f 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -1,6 +1,7 @@
include_directories( BEFORE ${INC_BEFORE} )
include_directories(
./dialogs
+ ./widgets
./dialog_about
${CAIRO_INCLUDE_DIR}
${GLEW_INCLUDE_DIR}
@@ -138,6 +139,9 @@ set( COMMON_ABOUT_DLG_SRCS
dialog_about/AboutDialog_main.cpp
dialog_about/dialog_about.cpp
dialog_about/dialog_about_base.cpp
+ )
+
+set( COMMON_DLG_SRCS
dialogs/dialog_display_info_HTML_base.cpp
dialogs/dialog_exit_base.cpp
dialogs/dialog_image_editor.cpp
@@ -154,6 +158,10 @@ set( COMMON_ABOUT_DLG_SRCS
dialogs/wx_html_report_panel.cpp
)
+set( COMMON_WIDGET_SRCS
+ widgets/widget_hotkey_list.cpp
+ )
+
set( COMMON_PAGE_LAYOUT_SRCS
page_layout/title_block_shapes.cpp
page_layout/class_worksheet_dataitem.cpp
@@ -167,6 +175,8 @@ set( COMMON_PAGE_LAYOUT_SRCS
set( COMMON_SRCS
${LIB_KICAD_SRCS}
${COMMON_ABOUT_DLG_SRCS}
+ ${COMMON_DLG_SRCS}
+ ${COMMON_WIDGET_SRCS}
${COMMON_PAGE_LAYOUT_SRCS}
base_struct.cpp
basicframe.cpp
diff --git a/common/dialogs/dialog_hotkeys_editor.cpp b/common/dialogs/dialog_hotkeys_editor.cpp
index ad0952e..96a8d3b 100644
--- a/common/dialogs/dialog_hotkeys_editor.cpp
+++ b/common/dialogs/dialog_hotkeys_editor.cpp
@@ -21,320 +21,14 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
-#include <algorithm>
-
-#include <fctsys.h>
-#include <pgm_base.h>
-#include <common.h>
-#include <confirm.h>
-
#include <dialog_hotkeys_editor.h>
-
-class DIALOG_HOTKEY_CLIENT_DATA : public wxClientData
-{
- EDA_HOTKEY m_hotkey;
- wxString m_section_tag;
-
-public:
- DIALOG_HOTKEY_CLIENT_DATA( const EDA_HOTKEY& aHotkey, const wxString& aSectionTag )
- : m_hotkey( aHotkey ), m_section_tag( aSectionTag ) {}
-
- EDA_HOTKEY& GetHotkey() { return m_hotkey; }
- wxString GetSectionTag() const { return m_section_tag; }
-};
-
-
-HOTKEY_LIST_CTRL::HOTKEY_LIST_CTRL( wxWindow *aParent, const HOTKEYS_SECTIONS& aSections ) :
- wxTreeListCtrl( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTL_SINGLE ),
- m_sections( aSections )
-{
- AppendColumn( _( "Command" ) );
- AppendColumn( _( "Hotkey" ) );
-
- SetColumnWidth( 1, 100 );
-
- Bind( wxEVT_CHAR, &HOTKEY_LIST_CTRL::OnChar, this );
-}
-
-
-void HOTKEY_LIST_CTRL::DeselectRow( int aRow )
-{
- wxASSERT( aRow >= 0 && aRow < (int)m_items.size() );
- Unselect( m_items[aRow] );
-}
-
-
-void HOTKEY_LIST_CTRL::OnChar( wxKeyEvent& aEvent )
-{
- DIALOG_HOTKEY_CLIENT_DATA* data = GetSelHKClientData();
-
- if( data )
- {
- long key = aEvent.GetKeyCode();
-
- switch( key )
- {
- case WXK_ESCAPE:
- UnselectAll();
- break;
-
- default:
- if( key >= 'a' && key <= 'z' ) // convert to uppercase
- key = key + ('A' - 'a');
-
- // Remap Ctrl A (=1+GR_KB_CTRL) to Ctrl Z(=26+GR_KB_CTRL)
- // to GR_KB_CTRL+'A' .. GR_KB_CTRL+'Z'
- if( aEvent.ControlDown() && key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z )
- key += 'A' - 1;
-
- /* Disallow shift for keys that have two keycodes on them (e.g. number and
- * punctuation keys) leaving only the "letter keys" of A-Z.
- * Then, you can have, e.g. Ctrl-5 and Ctrl-% (GB layout)
- * and Ctrl-( and Ctrl-5 (FR layout).
- * Otherwise, you'd have to have to say Ctrl-Shift-5 on a FR layout
- */
- bool keyIsLetter = key >= 'A' && key <= 'Z';
-
- if( aEvent.ShiftDown() && ( keyIsLetter || key > 256 ) )
- key |= GR_KB_SHIFT;
-
- if( aEvent.ControlDown() )
- key |= GR_KB_CTRL;
-
- if( aEvent.AltDown() )
- key |= GR_KB_ALT;
-
- // See if this key code is handled in hotkeys names list
- bool exists;
- KeyNameFromKeyCode( key, &exists );
-
- if( exists && data->GetHotkey().m_KeyCode != key )
- {
- wxString tag = data->GetSectionTag();
- bool canUpdate = ResolveKeyConflicts( key, tag );
-
- if( canUpdate )
- {
- data->GetHotkey().m_KeyCode = key;
- }
-
- // Remove selection
- UnselectAll();
- }
- }
- }
- UpdateFromClientData();
-}
-
-
-DIALOG_HOTKEY_CLIENT_DATA* HOTKEY_LIST_CTRL::GetSelHKClientData()
-{
- return GetHKClientData( GetSelection() );
-}
-
-
-DIALOG_HOTKEY_CLIENT_DATA* HOTKEY_LIST_CTRL::GetHKClientData( wxTreeListItem aItem )
-{
- if( aItem.IsOk() )
- {
- wxClientData* data = GetItemData( aItem );
- if( !data )
- return NULL;
-
- DIALOG_HOTKEY_CLIENT_DATA* hkdata = static_cast<DIALOG_HOTKEY_CLIENT_DATA*>( data );
- return hkdata;
- }
- else
- {
- return NULL;
- }
-}
-
-
-void HOTKEY_LIST_CTRL::LoadSection( struct EDA_HOTKEY_CONFIG* aSection )
-{
- HOTKEY_LIST list;
- EDA_HOTKEY** info_ptr;
-
- for( info_ptr = aSection->m_HK_InfoList; *info_ptr; info_ptr++ )
- {
- EDA_HOTKEY info = **info_ptr;
- list.push_back( info );
- }
-
- m_hotkeys.push_back( list );
-}
-
-
-void HOTKEY_LIST_CTRL::UpdateFromClientData()
-{
- for( wxTreeListItem i = GetFirstItem(); i.IsOk(); i = GetNextItem( i ) )
- {
- DIALOG_HOTKEY_CLIENT_DATA* hkdata = GetHKClientData( i );
- if( !hkdata )
- continue;
-
- EDA_HOTKEY& hk = hkdata->GetHotkey();
-
- wxString name = wxGetTranslation( hk.m_InfoMsg );
- wxString key = KeyNameFromKeyCode( hk.m_KeyCode );
-
- SetItemText( i, 0, name );
- SetItemText( i, 1, key );
- }
-}
-
-
-bool HOTKEY_LIST_CTRL::TransferDataToControl()
-{
- Freeze();
- DeleteAllItems();
- m_items.clear();
- m_hotkeys.clear();
-
- HOTKEYS_SECTIONS::iterator sec_it;
- size_t sec_index = 0;
- for( sec_it = m_sections.begin(); sec_it != m_sections.end(); ++sec_it, ++sec_index )
- {
- LoadSection( sec_it->second );
- wxString section_tag = *( sec_it->second->m_SectionTag );
-
- // Create parent item
- wxTreeListItem parent = AppendItem( GetRootItem(), sec_it->first );
-
- HOTKEY_LIST& each_list = m_hotkeys[sec_index];
- HOTKEY_LIST::iterator hk_it;
- for( hk_it = each_list.begin(); hk_it != each_list.end(); ++hk_it )
- {
- wxTreeListItem item = AppendItem( parent, wxEmptyString );
- SetItemData( item, new DIALOG_HOTKEY_CLIENT_DATA( &*hk_it, section_tag ) );
- m_items.push_back( item );
- }
-
- Expand( parent );
- }
-
- UpdateFromClientData();
- Thaw();
-
- return true;
-}
-
-
-bool HOTKEY_LIST_CTRL::TransferDataFromControl()
-{
- for( size_t i_sec = 0; i_sec < m_sections.size(); ++i_sec )
- {
- struct EDA_HOTKEY_CONFIG* section = m_sections[i_sec].second;
- for( EDA_HOTKEY** info_ptr = section->m_HK_InfoList; *info_ptr; ++info_ptr )
- {
- EDA_HOTKEY* info = *info_ptr;
- for( wxTreeListItem item = GetFirstItem(); item.IsOk(); item = GetNextItem( item ) )
- {
- DIALOG_HOTKEY_CLIENT_DATA* hkdata = GetHKClientData( item );
- if( !hkdata )
- continue;
-
- EDA_HOTKEY& hk = hkdata->GetHotkey();
- if( hk.m_Idcommand == info->m_Idcommand )
- {
- info->m_KeyCode = hk.m_KeyCode;
- break;
- }
- }
- }
- }
- return true;
-}
-
-
-bool HOTKEY_LIST_CTRL::ResolveKeyConflicts( long aKey, const wxString& aSectionTag )
-{
- EDA_HOTKEY* conflictingKey = NULL;
- EDA_HOTKEY_CONFIG* conflictingSection = NULL;
-
- CheckKeyConflicts( aKey, aSectionTag, &conflictingKey, &conflictingSection );
-
- if( conflictingKey != NULL )
- {
- wxString info = wxGetTranslation( conflictingKey->m_InfoMsg );
- wxString msg = wxString::Format(
- _( "<%s> is already assigned to \"%s\" in section \"%s\". Are you sure you want "
- "to change its assignment?" ),
- KeyNameFromKeyCode( aKey ), GetChars( info ),
- *(conflictingSection->m_Title) );
-
- wxMessageDialog dlg( m_parent, msg, _( "Confirm change" ), wxYES_NO | wxNO_DEFAULT );
-
- if( dlg.ShowModal() == wxID_YES )
- {
- conflictingKey->m_KeyCode = 0;
- UpdateFromClientData();
- return true;
- }
- else
- {
- return false;
- }
- }
-
- return true;
-}
-
-
-bool HOTKEY_LIST_CTRL::CheckKeyConflicts( long aKey, const wxString& aSectionTag,
- EDA_HOTKEY** aConfKey, EDA_HOTKEY_CONFIG** aConfSect )
-{
- EDA_HOTKEY* conflictingKey = NULL;
- struct EDA_HOTKEY_CONFIG* conflictingSection = NULL;
-
- for( wxTreeListItem item = GetFirstItem(); item.IsOk(); item = GetNextItem( item ) )
- {
- DIALOG_HOTKEY_CLIENT_DATA* hkdata = GetHKClientData( item );
- if( !hkdata )
- continue;
-
- EDA_HOTKEY& hk = hkdata->GetHotkey();
- wxString tag = hkdata->GetSectionTag();
-
- if( aSectionTag != g_CommonSectionTag
- && tag != g_CommonSectionTag
- && tag != aSectionTag )
- continue;
-
- if( aKey == hk.m_KeyCode )
- {
- conflictingKey = &hk;
-
- // Find the section
- HOTKEYS_SECTIONS::iterator it;
- for( it = m_sections.begin(); it != m_sections.end(); ++it )
- {
- if( *it->second->m_SectionTag == tag )
- {
- conflictingSection = it->second;
- break;
- }
- }
- }
- }
-
- if( aConfKey )
- *aConfKey = conflictingKey;
-
- if( aConfSect )
- *aConfSect = conflictingSection;
-
- return conflictingKey == NULL;
-}
-
-
void InstallHotkeyFrame( EDA_BASE_FRAME* aParent, EDA_HOTKEY_CONFIG* aHotkeys )
{
HOTKEYS_EDITOR_DIALOG dialog( aParent, aHotkeys );
int diag = dialog.ShowModal();
+
if( diag == wxID_OK )
{
aParent->ReCreateMenuBar();
@@ -343,26 +37,18 @@ void InstallHotkeyFrame( EDA_BASE_FRAME* aParent, EDA_HOTKEY_CONFIG* aHotkeys )
}
-HOTKEYS_EDITOR_DIALOG::HOTKEYS_EDITOR_DIALOG( EDA_BASE_FRAME* aParent,
- EDA_HOTKEY_CONFIG* aHotkeys ) :
+HOTKEYS_EDITOR_DIALOG::HOTKEYS_EDITOR_DIALOG( EDA_BASE_FRAME* aParent,
+ EDA_HOTKEY_CONFIG* aHotkeys ) :
HOTKEYS_EDITOR_DIALOG_BASE( aParent ),
- m_parent( aParent ),
m_hotkeys( aHotkeys )
{
- EDA_HOTKEY_CONFIG* section;
+ m_hotkeyListCtrl = new WIDGET_HOTKEY_LIST( m_panelHotkeys,
+ WIDGET_HOTKEY_LIST::GenSections( aHotkeys ) );
+ m_hotkeyListCtrl->InstallOnPanel( m_panelHotkeys );
- HOTKEYS_SECTIONS sections;
- for( section = m_hotkeys; section->m_HK_InfoList; section++ )
- {
- HOTKEYS_SECTION sec( wxGetTranslation( *section->m_Title ), section );
- sections.push_back( sec );
- }
+ m_sdbSizerOK->SetDefault();
- m_hotkeyListCtrl = new HOTKEY_LIST_CTRL( this, sections );
- m_mainSizer->Insert( 1, m_hotkeyListCtrl, wxSizerFlags( 1 ).Expand().Border( wxALL, 5 ) );
Layout();
-
- m_sdbSizerOK->SetDefault();
Center();
}
@@ -388,7 +74,7 @@ bool HOTKEYS_EDITOR_DIALOG::TransferDataFromWindow()
return false;
// save the hotkeys
- m_parent->WriteHotkeyConfig( m_hotkeys );
+ GetParent()->WriteHotkeyConfig( m_hotkeys );
return true;
}
@@ -398,4 +84,3 @@ void HOTKEYS_EDITOR_DIALOG::ResetClicked( wxCommandEvent& aEvent )
{
m_hotkeyListCtrl->TransferDataToControl();
}
-
diff --git a/common/dialogs/dialog_hotkeys_editor_base.cpp b/common/dialogs/dialog_hotkeys_editor_base.cpp
index 1293cb4..5373ac5 100644
--- a/common/dialogs/dialog_hotkeys_editor_base.cpp
+++ b/common/dialogs/dialog_hotkeys_editor_base.cpp
@@ -15,10 +15,13 @@ HOTKEYS_EDITOR_DIALOG_BASE::HOTKEYS_EDITOR_DIALOG_BASE( wxWindow* parent, wxWind
m_mainSizer = new wxBoxSizer( wxVERTICAL );
- m_staticText1 = new wxStaticText( this, wxID_ANY, _("Select a row and press a new key combination to alter the binding."), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText1 = new wxStaticText( this, wxID_ANY, _("Double-click to edit"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText1->Wrap( 400 );
m_mainSizer->Add( m_staticText1, 0, wxALL|wxEXPAND, 5 );
+ m_panelHotkeys = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+ m_mainSizer->Add( m_panelHotkeys, 1, wxEXPAND | wxALL, 5 );
+
wxBoxSizer* b_buttonsSizer;
b_buttonsSizer = new wxBoxSizer( wxHORIZONTAL );
diff --git a/common/dialogs/dialog_hotkeys_editor_base.fbp b/common/dialogs/dialog_hotkeys_editor_base.fbp
index 814b3ac..6a096fa 100644
--- a/common/dialogs/dialog_hotkeys_editor_base.fbp
+++ b/common/dialogs/dialog_hotkeys_editor_base.fbp
@@ -125,7 +125,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
- <property name="label">Select a row and press a new key combination to alter the binding.</property>
+ <property name="label">Double-click to edit</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
@@ -178,6 +178,86 @@
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
+ <property name="flag">wxEXPAND | wxALL</property>
+ <property name="proportion">1</property>
+ <object class="wxPanel" expanded="1">
+ <property name="BottomDockable">1</property>
+ <property name="LeftDockable">1</property>
+ <property name="RightDockable">1</property>
+ <property name="TopDockable">1</property>
+ <property name="aui_layer"></property>
+ <property name="aui_name"></property>
+ <property name="aui_position"></property>
+ <property name="aui_row"></property>
+ <property name="best_size"></property>
+ <property name="bg"></property>
+ <property name="caption"></property>
+ <property name="caption_visible">1</property>
+ <property name="center_pane">0</property>
+ <property name="close_button">1</property>
+ <property name="context_help"></property>
+ <property name="context_menu">1</property>
+ <property name="default_pane">0</property>
+ <property name="dock">Dock</property>
+ <property name="dock_fixed">0</property>
+ <property name="docking">Left</property>
+ <property name="enabled">1</property>
+ <property name="fg"></property>
+ <property name="floatable">1</property>
+ <property name="font"></property>
+ <property name="gripper">0</property>
+ <property name="hidden">0</property>
+ <property name="id">wxID_ANY</property>
+ <property name="max_size"></property>
+ <property name="maximize_button">0</property>
+ <property name="maximum_size"></property>
+ <property name="min_size"></property>
+ <property name="minimize_button">0</property>
+ <property name="minimum_size"></property>
+ <property name="moveable">1</property>
+ <property name="name">m_panelHotkeys</property>
+ <property name="pane_border">1</property>
+ <property name="pane_position"></property>
+ <property name="pane_size"></property>
+ <property name="permission">protected</property>
+ <property name="pin_button">1</property>
+ <property name="pos"></property>
+ <property name="resize">Resizable</property>
+ <property name="show">1</property>
+ <property name="size"></property>
+ <property name="subclass"></property>
+ <property name="toolbar_pane">0</property>
+ <property name="tooltip"></property>
+ <property name="window_extra_style"></property>
+ <property name="window_name"></property>
+ <property name="window_style">wxTAB_TRAVERSAL</property>
+ <event name="OnChar"></event>
+ <event name="OnEnterWindow"></event>
+ <event name="OnEraseBackground"></event>
+ <event name="OnKeyDown"></event>
+ <event name="OnKeyUp"></event>
+ <event name="OnKillFocus"></event>
+ <event name="OnLeaveWindow"></event>
+ <event name="OnLeftDClick"></event>
+ <event name="OnLeftDown"></event>
+ <event name="OnLeftUp"></event>
+ <event name="OnMiddleDClick"></event>
+ <event name="OnMiddleDown"></event>
+ <event name="OnMiddleUp"></event>
+ <event name="OnMotion"></event>
+ <event name="OnMouseEvents"></event>
+ <event name="OnMouseWheel"></event>
+ <event name="OnPaint"></event>
+ <event name="OnRightDClick"></event>
+ <event name="OnRightDown"></event>
+ <event name="OnRightUp"></event>
+ <event name="OnSetFocus"></event>
+ <event name="OnSize"></event>
+ <event name="OnUpdateUI"></event>
+ </object>
+ </object>
+ <object class="sizeritem" expanded="1">
+ <property name="border">5</property>
<property name="flag">wxALIGN_RIGHT|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
diff --git a/common/dialogs/dialog_hotkeys_editor_base.h b/common/dialogs/dialog_hotkeys_editor_base.h
index 9c58421..a59f560 100644
--- a/common/dialogs/dialog_hotkeys_editor_base.h
+++ b/common/dialogs/dialog_hotkeys_editor_base.h
@@ -20,6 +20,7 @@ class DIALOG_SHIM;
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
+#include <wx/panel.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/dialog.h>
@@ -37,6 +38,7 @@ class HOTKEYS_EDITOR_DIALOG_BASE : public DIALOG_SHIM
protected:
wxBoxSizer* m_mainSizer;
wxStaticText* m_staticText1;
+ wxPanel* m_panelHotkeys;
wxButton* m_resetButton;
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
diff --git a/common/widgets/widget_hotkey_list.cpp b/common/widgets/widget_hotkey_list.cpp
new file mode 100644
index 0000000..3813670
--- /dev/null
+++ b/common/widgets/widget_hotkey_list.cpp
@@ -0,0 +1,674 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2016 Chris Pavlina <pavlina.chris@xxxxxxxxx>
+ * Copyright (C) 2016 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <cctype>
+
+#include <widgets/widget_hotkey_list.h>
+
+#include <wx/dataview.h>
+#include <wx/statline.h>
+
+#include <draw_frame.h>
+#include <dialog_shim.h>
+
+
+/**
+ * Minimum width of the hotkey column
+ */
+static const int HOTKEY_MIN_WIDTH = 100;
+
+
+/**
+ * Extra margin to compensate for vertical scrollbar
+ */
+static const int HORIZ_MARGIN = 30;
+
+
+/**
+ * Menu IDs for the hotkey context menu
+ */
+enum ID_WHKL_MENU_IDS
+{
+ ID_EDIT = 2001,
+ ID_RESET,
+ ID_RESET_ALL,
+};
+
+
+/**
+ * Class WIDGET_HOTKEY_CLIENT_DATA
+ * Stores the hotkey and section tag associated with each row. To change a
+ * hotkey, edit it in the row's client data, then call WIDGET_HOTKEY_LIST::UpdateFromClientData().
+ */
+class WIDGET_HOTKEY_CLIENT_DATA : public wxClientData
+{
+ EDA_HOTKEY m_hotkey;
+ wxString m_section_tag;
+
+public:
+ WIDGET_HOTKEY_CLIENT_DATA( const EDA_HOTKEY& aHotkey, const wxString& aSectionTag )
+ : m_hotkey( aHotkey ), m_section_tag( aSectionTag )
+ {}
+
+
+ EDA_HOTKEY& GetHotkey() { return m_hotkey; }
+ const wxString& GetSectionTag() const { return m_section_tag; }
+};
+
+
+/**
+ * Class HK_PROMPT_DIALOG
+ * Dialog to prompt the user to enter a key.
+ */
+class HK_PROMPT_DIALOG : public DIALOG_SHIM
+{
+ wxKeyEvent m_event;
+
+public:
+ HK_PROMPT_DIALOG( wxWindow* aParent, wxWindowID aId, const wxString& aTitle,
+ const wxString& aName, const wxString& aCurrentKey )
+ : DIALOG_SHIM( aParent, aId, aTitle, wxDefaultPosition, wxDefaultSize )
+ {
+ wxPanel* panel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize );
+ wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
+
+ /* Dialog layout:
+ *
+ * inst_label........................
+ * ----------------------------------
+ *
+ * cmd_label_0 cmd_label_1 \
+ * | fgsizer
+ * key_label_0 key_label_1 /
+ */
+
+ wxStaticText* inst_label = new wxStaticText( panel, wxID_ANY, wxEmptyString,
+ wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL );
+
+ inst_label->SetLabelText( _( "Press a new hotkey, or press Esc to cancel..." ) );
+ sizer->Add( inst_label, 0, wxALL, 5 );
+
+ sizer->Add( new wxStaticLine( panel ), 0, wxALL | wxEXPAND, 2 );
+
+ wxFlexGridSizer* fgsizer = new wxFlexGridSizer( 2 );
+
+ wxStaticText* cmd_label_0 = new wxStaticText( panel, wxID_ANY, _( "Command:" ) );
+ fgsizer->Add( cmd_label_0, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
+
+ wxStaticText* cmd_label_1 = new wxStaticText( panel, wxID_ANY, wxEmptyString );
+ cmd_label_1->SetFont( cmd_label_1->GetFont().Bold() );
+ cmd_label_1->SetLabel( aName );
+ fgsizer->Add( cmd_label_1, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
+
+ wxStaticText* key_label_0 = new wxStaticText( panel, wxID_ANY, _( "Current key:" ) );
+ fgsizer->Add( key_label_0, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
+
+ wxStaticText* key_label_1 = new wxStaticText( panel, wxID_ANY, wxEmptyString );
+ key_label_1->SetFont( key_label_1->GetFont().Bold() );
+ key_label_1->SetLabel( aCurrentKey );
+ fgsizer->Add( key_label_1, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
+
+ sizer->Add( fgsizer, 1, wxEXPAND );
+
+ // Wrap the sizer in a second to give a larger border around the whole dialog
+ wxBoxSizer* outer_sizer = new wxBoxSizer( wxVERTICAL );
+ outer_sizer->Add( sizer, 0, wxALL | wxEXPAND, 10 );
+ panel->SetSizer( outer_sizer );
+
+ Layout();
+ outer_sizer->Fit( this );
+ Center();
+
+ SetMinClientSize( GetClientSize() );
+
+ // Binding both EVT_CHAR and EVT_CHAR_HOOK ensures that all key events,
+ // including specials like Tab and Return, are received, particularly
+ // on MSW.
+ panel->Bind( wxEVT_CHAR, &HK_PROMPT_DIALOG::OnChar, this );
+ panel->Bind( wxEVT_CHAR_HOOK, &HK_PROMPT_DIALOG::OnCharHook, this );
+ }
+
+
+ void OnCharHook( wxKeyEvent& aEvent )
+ {
+ // On certain platforms, EVT_CHAR_HOOK is the only handler that receives
+ // certain "special" keys. However, it doesn't always receive "normal"
+ // keys correctly. For example, with a US keyboard, it sees ? as shift+/.
+ //
+ // Untangling these incorrect keys would be too much trouble, so we bind
+ // both events, and simply skip the EVT_CHAR_HOOK if it receives a
+ // "normal" key.
+
+ const enum wxKeyCode skipped_keys[] =
+ {
+ WXK_NONE, WXK_SHIFT, WXK_ALT, WXK_CONTROL, WXK_CAPITAL,
+ WXK_NUMLOCK, WXK_SCROLL, WXK_RAW_CONTROL
+ };
+
+ int key = aEvent.GetKeyCode();
+
+ for( size_t i = 0; i < sizeof( skipped_keys ) / sizeof( skipped_keys[0] ); ++i )
+ {
+ if( key == skipped_keys[i] )
+ return;
+ }
+
+ if( key <= 255 && isprint( key ) && !isspace( key ) )
+ {
+ // Let EVT_CHAR handle this one
+ aEvent.DoAllowNextEvent();
+
+ // On Windows, wxEvent::Skip must NOT be called.
+ // On Linux and OSX, wxEvent::Skip MUST be called.
+ // No, I don't know why.
+#ifndef __WXMSW__
+ aEvent.Skip();
+#endif
+ }
+ else
+ {
+ OnChar( aEvent );
+ }
+ }
+
+
+ void OnChar( wxKeyEvent& aEvent )
+ {
+ m_event = aEvent;
+ EndFlexible( wxID_OK );
+ }
+
+
+ /**
+ * End the dialog whether modal or quasimodal
+ */
+ void EndFlexible( int aRtnCode )
+ {
+ if( IsQuasiModal() )
+ EndQuasiModal( aRtnCode );
+ else
+ EndModal( aRtnCode );
+ }
+
+
+ static wxKeyEvent PromptForKey( wxWindow* aParent, const wxString& aName,
+ const wxString& aCurrentKey )
+ {
+ HK_PROMPT_DIALOG dialog( aParent, wxID_ANY, _( "Set Hotkey" ), aName, aCurrentKey );
+
+ if( dialog.ShowModal() == wxID_OK )
+ {
+ return dialog.m_event;
+ }
+ else
+ {
+ wxKeyEvent dummy;
+ return dummy;
+ }
+ }
+};
+
+
+WIDGET_HOTKEY_CLIENT_DATA* WIDGET_HOTKEY_LIST::GetHKClientData( wxTreeListItem aItem )
+{
+ if( aItem.IsOk() )
+ {
+ wxClientData* data = GetItemData( aItem );
+
+ if( !data )
+ {
+ return NULL;
+ }
+ else
+ {
+ return static_cast<WIDGET_HOTKEY_CLIENT_DATA*>( data );
+ }
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+WIDGET_HOTKEY_CLIENT_DATA* WIDGET_HOTKEY_LIST::GetSelHKClientData()
+{
+ return GetHKClientData( GetSelection() );
+}
+
+
+void WIDGET_HOTKEY_LIST::UpdateFromClientData()
+{
+ for( wxTreeListItem i = GetFirstItem(); i.IsOk(); i = GetNextItem( i ) )
+ {
+ WIDGET_HOTKEY_CLIENT_DATA* hkdata = GetHKClientData( i );
+
+ if( hkdata )
+ {
+ EDA_HOTKEY& hk = hkdata->GetHotkey();
+
+ SetItemText( i, 0, wxGetTranslation( hk.m_InfoMsg ) );
+ SetItemText( i, 1, KeyNameFromKeyCode( hk.m_KeyCode ) );
+ }
+ }
+}
+
+
+void WIDGET_HOTKEY_LIST::LoadSection( EDA_HOTKEY_CONFIG* aSection )
+{
+ HOTKEY_LIST list;
+
+ for( EDA_HOTKEY** info_ptr = aSection->m_HK_InfoList; *info_ptr; ++info_ptr )
+ {
+ list.push_back( **info_ptr );
+ }
+
+ m_hotkeys.push_back( list );
+}
+
+
+void WIDGET_HOTKEY_LIST::EditItem( wxTreeListItem aItem )
+{
+ WIDGET_HOTKEY_CLIENT_DATA* hkdata = GetHKClientData( aItem );
+
+ if( !hkdata )
+ {
+ // Activated item was not a hotkey row
+ return;
+ }
+
+ wxString name = GetItemText( aItem, 0 );
+ wxString current_key = GetItemText( aItem, 1 );
+
+ wxKeyEvent key_event = HK_PROMPT_DIALOG::PromptForKey( GetParent(), name, current_key );
+ long key = MapKeypressToKeycode( key_event );
+
+ if( hkdata && key )
+ {
+ // See if this key code is handled in hotkeys names list
+ bool exists;
+ KeyNameFromKeyCode( key, &exists );
+
+ if( exists && hkdata->GetHotkey().m_KeyCode != key )
+ {
+ wxString tag = hkdata->GetSectionTag();
+ bool canUpdate = ResolveKeyConflicts( key, tag );
+
+ if( canUpdate )
+ {
+ hkdata->GetHotkey().m_KeyCode = key;
+ }
+ }
+
+ UpdateFromClientData();
+ }
+}
+
+
+void WIDGET_HOTKEY_LIST::ResetItem( wxTreeListItem aItem )
+{
+ WIDGET_HOTKEY_CLIENT_DATA* hkdata = GetHKClientData( aItem );
+ EDA_HOTKEY* hk = &hkdata->GetHotkey();
+
+ for( size_t sec_index = 0; sec_index < m_sections.size(); ++sec_index )
+ {
+ wxString& section_tag = *( m_sections[sec_index].m_section->m_SectionTag );
+
+ if( section_tag != hkdata->GetSectionTag() )
+ continue;
+
+ HOTKEY_LIST& each_list = m_hotkeys[sec_index];
+ HOTKEY_LIST::iterator hk_it;
+
+ for( hk_it = each_list.begin(); hk_it != each_list.end(); ++hk_it )
+ {
+ if( hk_it->m_Idcommand == hk->m_Idcommand )
+ {
+ hk->m_KeyCode = hk_it->m_KeyCode;
+ break;
+ }
+ }
+ }
+
+ UpdateFromClientData();
+}
+
+
+void WIDGET_HOTKEY_LIST::OnActivated( wxTreeListEvent& aEvent )
+{
+ EditItem( aEvent.GetItem() );
+}
+
+
+void WIDGET_HOTKEY_LIST::OnContextMenu( wxTreeListEvent& aEvent )
+{
+ // Save the active event for use in OnMenu
+ m_context_menu_item = aEvent.GetItem();
+
+ wxMenu menu;
+
+ menu.Append( ID_EDIT, _( "Edit..." ) );
+ menu.Append( ID_RESET, _( "Reset" ) );
+ menu.Append( wxID_SEPARATOR );
+ menu.Append( ID_RESET_ALL, _( "Reset all" ) );
+
+ PopupMenu( &menu );
+}
+
+
+void WIDGET_HOTKEY_LIST::OnMenu( wxCommandEvent& aEvent )
+{
+ switch( aEvent.GetId() )
+ {
+ case ID_EDIT:
+ EditItem( m_context_menu_item );
+ break;
+
+ case ID_RESET:
+ ResetItem( m_context_menu_item );
+ break;
+
+ case ID_RESET_ALL:
+ TransferDataToControl();
+ break;
+
+ default:
+ wxFAIL_MSG( wxT( "Unknown ID in context menu event" ) );
+ }
+}
+
+
+void WIDGET_HOTKEY_LIST::OnSize( wxSizeEvent& aEvent )
+{
+ // Handle this manually - wxTreeListCtrl screws up the width of the first column
+ wxDataViewCtrl* view = GetDataView();
+
+ if( !view )
+ return;
+
+ wxRect rect = GetClientRect();
+ view->SetSize( rect );
+
+#ifdef wxHAS_GENERIC_DATAVIEWCTRL
+ {
+ wxWindow* view = GetView();
+ view->Refresh();
+ view->Update();
+ }
+#endif
+
+ // Find the maximum width of the hotkey column
+ int hk_column_width = 0;
+
+ for( wxTreeListItem item = GetFirstItem(); item.IsOk(); item = GetNextItem( item ) )
+ {
+ const wxString& text = GetItemText( item, 1 );
+ int width = WidthFor( text );
+
+ if( width > hk_column_width )
+ hk_column_width = width;
+ }
+
+ if( hk_column_width < HOTKEY_MIN_WIDTH )
+ hk_column_width = HOTKEY_MIN_WIDTH;
+
+ SetColumnWidth( 1, hk_column_width );
+ SetColumnWidth( 0, rect.width - hk_column_width - HORIZ_MARGIN );
+}
+
+
+bool WIDGET_HOTKEY_LIST::CheckKeyConflicts( long aKey, const wxString& aSectionTag,
+ EDA_HOTKEY** aConfKey, EDA_HOTKEY_CONFIG** aConfSect )
+{
+ EDA_HOTKEY* conflicting_key = NULL;
+ struct EDA_HOTKEY_CONFIG* conflicting_section = NULL;
+
+ for( wxTreeListItem item = GetFirstItem(); item.IsOk(); item = GetNextItem( item ) )
+ {
+ WIDGET_HOTKEY_CLIENT_DATA* hkdata = GetHKClientData( item );
+
+ if( !hkdata )
+ continue;
+
+ EDA_HOTKEY& hk = hkdata->GetHotkey();
+ wxString tag = hkdata->GetSectionTag();
+
+ if( aSectionTag != g_CommonSectionTag
+ && tag != g_CommonSectionTag
+ && tag != aSectionTag )
+ {
+ // This key and its conflict candidate are in orthogonal sections, so skip.
+ continue;
+ }
+
+ if( aKey == hk.m_KeyCode )
+ {
+ conflicting_key = &hk;
+
+ // Find the section
+ HOTKEY_SECTIONS::iterator it;
+
+ for( it = m_sections.begin(); it != m_sections.end(); ++it )
+ {
+ if( *it->m_section->m_SectionTag == tag )
+ {
+ conflicting_section = it->m_section;
+ break;
+ }
+ }
+ }
+ }
+
+ // Write the outparams
+ if( aConfKey )
+ *aConfKey = conflicting_key;
+
+ if( aConfSect )
+ *aConfSect = conflicting_section;
+
+ return conflicting_key == NULL;
+}
+
+
+bool WIDGET_HOTKEY_LIST::ResolveKeyConflicts( long aKey, const wxString& aSectionTag )
+{
+ EDA_HOTKEY* conflicting_key = NULL;
+ EDA_HOTKEY_CONFIG* conflicting_section = NULL;
+
+ CheckKeyConflicts( aKey, aSectionTag, &conflicting_key, &conflicting_section );
+
+ if( conflicting_key != NULL )
+ {
+ wxString info = wxGetTranslation( conflicting_key->m_InfoMsg );
+ wxString msg = wxString::Format(
+ _( "<%s> is already assigned to \"%s\" in section \"%s\". Are you sure you want "
+ "to change its assignment?" ),
+ KeyNameFromKeyCode( aKey ), GetChars( info ),
+ *(conflicting_section->m_Title) );
+
+ wxMessageDialog dlg( GetParent(), msg, _( "Confirm change" ), wxYES_NO | wxNO_DEFAULT );
+
+ if( dlg.ShowModal() == wxID_YES )
+ {
+ conflicting_key->m_KeyCode = 0;
+ UpdateFromClientData();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return true;
+ }
+}
+
+
+WIDGET_HOTKEY_LIST::WIDGET_HOTKEY_LIST( wxWindow* aParent, const HOTKEY_SECTIONS& aSections )
+ : wxTreeListCtrl( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTL_SINGLE ),
+ m_sections( aSections )
+{
+ AppendColumn( _( "Command" ) );
+ AppendColumn( _( "Hotkey" ) );
+
+ Bind( wxEVT_TREELIST_ITEM_ACTIVATED, &WIDGET_HOTKEY_LIST::OnActivated, this );
+ Bind( wxEVT_TREELIST_ITEM_CONTEXT_MENU, &WIDGET_HOTKEY_LIST::OnContextMenu, this );
+ Bind( wxEVT_MENU, &WIDGET_HOTKEY_LIST::OnMenu, this );
+ Bind( wxEVT_SIZE, &WIDGET_HOTKEY_LIST::OnSize, this );
+}
+
+
+HOTKEY_SECTIONS WIDGET_HOTKEY_LIST::GenSections( EDA_HOTKEY_CONFIG* aHotkeys )
+{
+ HOTKEY_SECTIONS sections;
+
+ for( EDA_HOTKEY_CONFIG* section = aHotkeys; section->m_HK_InfoList; ++section )
+ {
+ HOTKEY_SECTION sec;
+ sec.m_name = wxGetTranslation( *section->m_Title );
+ sec.m_section = section;
+ sections.push_back( sec );
+ }
+
+ return sections;
+}
+
+
+void WIDGET_HOTKEY_LIST::InstallOnPanel( wxPanel* aPanel )
+{
+ wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
+
+ sizer->Add( this, 1, wxALL | wxEXPAND, 0 );
+ aPanel->SetSizer( sizer );
+}
+
+
+bool WIDGET_HOTKEY_LIST::TransferDataToControl()
+{
+ Freeze();
+ DeleteAllItems();
+ m_hotkeys.clear();
+
+ for( size_t sec_index = 0; sec_index < m_sections.size(); ++sec_index )
+ {
+ // LoadSection pushes into m_hotkeys
+ LoadSection( m_sections[sec_index].m_section );
+ wxASSERT( m_hotkeys.size() == sec_index + 1 );
+
+ wxString section_tag = *( m_sections[sec_index].m_section->m_SectionTag );
+
+ // Create parent tree item
+ wxTreeListItem parent = AppendItem( GetRootItem(), m_sections[sec_index].m_name );
+
+ HOTKEY_LIST& each_list = m_hotkeys[sec_index];
+ HOTKEY_LIST::iterator hk_it;
+
+ for( hk_it = each_list.begin(); hk_it != each_list.end(); ++hk_it )
+ {
+ wxTreeListItem item = AppendItem( parent, wxEmptyString );
+ SetItemData( item, new WIDGET_HOTKEY_CLIENT_DATA( &*hk_it, section_tag ) );
+ }
+
+ Expand( parent );
+ }
+
+ UpdateFromClientData();
+ Thaw();
+
+ return true;
+}
+
+
+bool WIDGET_HOTKEY_LIST::TransferDataFromControl()
+{
+ for( size_t sec_index = 0; sec_index < m_sections.size(); ++sec_index )
+ {
+ EDA_HOTKEY_CONFIG* section = m_sections[sec_index].m_section;
+
+ for( EDA_HOTKEY** info_ptr = section->m_HK_InfoList; *info_ptr; ++info_ptr )
+ {
+ EDA_HOTKEY* info = *info_ptr;
+
+ for( wxTreeListItem item = GetFirstItem(); item.IsOk(); item = GetNextItem( item ) )
+ {
+ WIDGET_HOTKEY_CLIENT_DATA* hkdata = GetHKClientData( item );
+
+ if( !hkdata )
+ continue;
+
+ EDA_HOTKEY& hk = hkdata->GetHotkey();
+
+ if( hk.m_Idcommand == info->m_Idcommand )
+ {
+ info->m_KeyCode = hk.m_KeyCode;
+ break;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+
+long WIDGET_HOTKEY_LIST::MapKeypressToKeycode( const wxKeyEvent& aEvent )
+{
+ long key = aEvent.GetKeyCode();
+
+ if( key == WXK_ESCAPE )
+ {
+ return 0;
+ }
+ else
+ {
+ if( key >= 'a' && key <= 'z' ) // convert to uppercase
+ key = key + ('A' - 'a');
+
+ // Remap Ctrl A (=1+GR_KB_CTRL) to Ctrl Z(=26+GR_KB_CTRL)
+ // to GR_KB_CTRL+'A' .. GR_KB_CTRL+'Z'
+ if( aEvent.ControlDown() && key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z )
+ key += 'A' - 1;
+
+ /* Disallow shift for keys that have two keycodes on them (e.g. number and
+ * punctuation keys) leaving only the "letter keys" of A-Z.
+ * Then, you can have, e.g. Ctrl-5 and Ctrl-% (GB layout)
+ * and Ctrl-( and Ctrl-5 (FR layout).
+ * Otherwise, you'd have to have to say Ctrl-Shift-5 on a FR layout
+ */
+ bool keyIsLetter = key >= 'A' && key <= 'Z';
+
+ if( aEvent.ShiftDown() && ( keyIsLetter || key > 256 ) )
+ key |= GR_KB_SHIFT;
+
+ if( aEvent.ControlDown() )
+ key |= GR_KB_CTRL;
+
+ if( aEvent.AltDown() )
+ key |= GR_KB_ALT;
+
+ return key;
+ }
+}
diff --git a/eeschema/dialogs/dialog_eeschema_options.cpp b/eeschema/dialogs/dialog_eeschema_options.cpp
index c6b0f34..5ce1477 100644
--- a/eeschema/dialogs/dialog_eeschema_options.cpp
+++ b/eeschema/dialogs/dialog_eeschema_options.cpp
@@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2009 Wayne Stambaugh <stambaughw@xxxxxxxxxxx>
- * Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -30,10 +30,14 @@
#include <class_base_screen.h>
#include <dialog_eeschema_options.h>
+#include <widgets/widget_hotkey_list.h>
+#include <schframe.h>
+#include <hotkeys.h>
-#include "wx/settings.h"
+#include <wx/settings.h>
-DIALOG_EESCHEMA_OPTIONS::DIALOG_EESCHEMA_OPTIONS( wxWindow* parent ) :
+
+DIALOG_EESCHEMA_OPTIONS::DIALOG_EESCHEMA_OPTIONS( SCH_EDIT_FRAME* parent ) :
DIALOG_EESCHEMA_OPTIONS_BASE( parent )
{
m_choiceUnits->SetFocus();
@@ -50,9 +54,29 @@ DIALOG_EESCHEMA_OPTIONS::DIALOG_EESCHEMA_OPTIONS( wxWindow* parent ) :
m_fieldGrid->AutoSizeColLabelSize( i );
}
+ // Embed the hotkeys list
+ HOTKEY_SECTIONS sections = WIDGET_HOTKEY_LIST::GenSections( g_Eeschema_Hokeys_Descr );
+ m_hotkeyListCtrl = new WIDGET_HOTKEY_LIST( m_panelHotkeys, sections );
+ m_hotkeyListCtrl->InstallOnPanel( m_panelHotkeys );
+
// Make sure we select the first tab of the options tab page
m_notebook->SetSelection( 0 );
+ // Lay out all child pages
+ // No, I don't know why this->Layout() doesn't propagate through to these,
+ // but at least on MSW, it does not.
+ for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
+ {
+ m_notebook->GetPage( i )->Layout();
+ }
+
+ Layout();
+}
+
+
+SCH_EDIT_FRAME* DIALOG_EESCHEMA_OPTIONS::GetParent()
+{
+ return static_cast<SCH_EDIT_FRAME*>( DIALOG_EESCHEMA_OPTIONS_BASE::GetParent() );
}
@@ -147,11 +171,13 @@ void DIALOG_EESCHEMA_OPTIONS::OnAddButtonClick( wxCommandEvent& event )
for( int row = 0; row < m_fieldGrid->GetNumberRows(); ++row )
{
bool this_row_selected = false;
+
for( int col = 0; col < m_fieldGrid->GetNumberCols(); ++col )
{
if( m_fieldGrid->IsInSelection( row, col ) )
this_row_selected = true;
}
+
if( this_row_selected )
{
selected_row = row;
@@ -198,10 +224,12 @@ void DIALOG_EESCHEMA_OPTIONS::OnDeleteButtonClick( wxCommandEvent& event )
TransferDataFromWindow();
int n_rows = m_fieldGrid->GetNumberRows();
+
for( int count = 0; count < n_rows; ++count )
{
// Iterate backwards, unsigned-friendly way for future
int row = n_rows - count - 1;
+
if( rows_to_delete[row] )
{
templateFields.erase( templateFields.begin() + row );
@@ -217,9 +245,14 @@ bool DIALOG_EESCHEMA_OPTIONS::TransferDataToWindow()
if( !wxDialog::TransferDataToWindow() )
return false;
+ if( !m_hotkeyListCtrl->TransferDataToControl() )
+ return false;
+
m_fieldGrid->Freeze();
+
if( m_fieldGrid->GetNumberRows() )
m_fieldGrid->DeleteRows( 0, m_fieldGrid->GetNumberRows() );
+
m_fieldGrid->AppendRows( templateFields.size() );
for( int row = 0; row < m_fieldGrid->GetNumberRows(); ++row )
@@ -238,21 +271,34 @@ bool DIALOG_EESCHEMA_OPTIONS::TransferDataToWindow()
m_fieldGrid->SetCellRenderer( row, 2, new wxGridCellBoolRenderer() );
m_fieldGrid->SetCellAlignment( row, 2, wxALIGN_CENTRE, wxALIGN_CENTRE );
}
+
m_fieldGrid->AutoSizeRows();
m_fieldGrid->Thaw();
+ Layout();
return true;
}
bool DIALOG_EESCHEMA_OPTIONS::TransferDataFromWindow()
{
+ if( !wxDialog::TransferDataFromWindow() )
+ return false;
+
+ if( !m_hotkeyListCtrl->TransferDataFromControl() )
+ return false;
+
+ // Refresh hotkeys
+ GetParent()->ReCreateMenuBar();
+ GetParent()->Refresh();
+
for( int row = 0; row < m_fieldGrid->GetNumberRows(); ++row )
{
- templateFields[row].m_Name = m_fieldGrid->GetCellValue( row, 0 );
+ templateFields[row].m_Name = m_fieldGrid->GetCellValue( row, 0 );
templateFields[row].m_Value = m_fieldGrid->GetCellValue( row, 1 );
templateFields[row].m_Visible = ( m_fieldGrid->GetCellValue( row, 2 ) != wxEmptyString );
}
+
return true;
}
@@ -271,4 +317,3 @@ TEMPLATE_FIELDNAMES DIALOG_EESCHEMA_OPTIONS::GetTemplateFields( void )
{
return templateFields;
}
-
diff --git a/eeschema/dialogs/dialog_eeschema_options.h b/eeschema/dialogs/dialog_eeschema_options.h
index 828d1b0..d5daca2 100644
--- a/eeschema/dialogs/dialog_eeschema_options.h
+++ b/eeschema/dialogs/dialog_eeschema_options.h
@@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2009 Wayne Stambaugh <stambaughw@xxxxxxxxxxx>
- * Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -34,9 +34,14 @@
#include <dialog_eeschema_options_base.h>
#include <template_fieldnames.h>
+class WIDGET_HOTKEY_LIST;
+class SCH_EDIT_FRAME;
+
class DIALOG_EESCHEMA_OPTIONS : public DIALOG_EESCHEMA_OPTIONS_BASE
{
protected:
+ WIDGET_HOTKEY_LIST* m_hotkeyListCtrl;
+
/** @brief The template fieldnames for this dialog */
TEMPLATE_FIELDNAMES templateFields;
@@ -80,7 +85,9 @@ public:
*
* @param parent The dialog's parent
*/
- DIALOG_EESCHEMA_OPTIONS( wxWindow* parent );
+ DIALOG_EESCHEMA_OPTIONS( SCH_EDIT_FRAME* parent );
+
+ virtual SCH_EDIT_FRAME* GetParent();
/**
* Function GetUnitsSelection
diff --git a/eeschema/dialogs/dialog_eeschema_options_base.cpp b/eeschema/dialogs/dialog_eeschema_options_base.cpp
index b744d8d..9c85f9d 100644
--- a/eeschema/dialogs/dialog_eeschema_options_base.cpp
+++ b/eeschema/dialogs/dialog_eeschema_options_base.cpp
@@ -233,7 +233,7 @@ DIALOG_EESCHEMA_OPTIONS_BASE::DIALOG_EESCHEMA_OPTIONS_BASE( wxWindow* parent, wx
m_panel3->Layout();
bSizer8->Fit( m_panel3 );
m_notebook->AddPage( m_panel3, _("Editing"), false );
- m_panel4 = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+ m_controlsPanel = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer81;
bSizer81 = new wxBoxSizer( wxVERTICAL );
@@ -248,35 +248,51 @@ DIALOG_EESCHEMA_OPTIONS_BASE::DIALOG_EESCHEMA_OPTIONS_BASE( wxWindow* parent, wx
bSizer81->Add( fgSizer31, 0, wxALL|wxEXPAND, 5 );
- wxBoxSizer* bSizer91;
- bSizer91 = new wxBoxSizer( wxVERTICAL );
+ m_controlsSizer = new wxBoxSizer( wxVERTICAL );
- m_checkEnableZoomCenter = new wxCheckBox( m_panel4, wxID_ANY, _("Cen&ter and warp cursor on zoom"), wxDefaultPosition, wxDefaultSize, 0 );
+ wxBoxSizer* bSizer13;
+ bSizer13 = new wxBoxSizer( wxHORIZONTAL );
+
+ m_staticText20 = new wxStaticText( m_controlsPanel, wxID_ANY, _("Hotkeys:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText20->Wrap( -1 );
+ bSizer13->Add( m_staticText20, 1, wxALL, 5 );
+
+ m_staticText21 = new wxStaticText( m_controlsPanel, wxID_ANY, _("Double-click to edit"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText21->Wrap( -1 );
+ bSizer13->Add( m_staticText21, 0, wxALL, 5 );
+
+
+ m_controlsSizer->Add( bSizer13, 0, wxEXPAND, 5 );
+
+ m_panelHotkeys = new wxPanel( m_controlsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+ m_controlsSizer->Add( m_panelHotkeys, 1, wxEXPAND | wxALL, 5 );
+
+ m_checkEnableZoomCenter = new wxCheckBox( m_controlsPanel, wxID_ANY, _("Cen&ter and warp cursor on zoom"), wxDefaultPosition, wxDefaultSize, 0 );
m_checkEnableZoomCenter->SetToolTip( _("Keep the cursor at its current location when zooming") );
- bSizer91->Add( m_checkEnableZoomCenter, 0, wxTOP|wxRIGHT|wxLEFT, 3 );
+ m_controlsSizer->Add( m_checkEnableZoomCenter, 0, wxTOP|wxRIGHT|wxLEFT, 3 );
- m_checkEnableMiddleButtonPan = new wxCheckBox( m_panel4, xwID_ANY, _("&Use middle mouse button to pan"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_checkEnableMiddleButtonPan = new wxCheckBox( m_controlsPanel, xwID_ANY, _("&Use middle mouse button to pan"), wxDefaultPosition, wxDefaultSize, 0 );
m_checkEnableMiddleButtonPan->SetToolTip( _("Use middle mouse button dragging to pan") );
- bSizer91->Add( m_checkEnableMiddleButtonPan, 0, wxTOP|wxRIGHT|wxLEFT, 3 );
+ m_controlsSizer->Add( m_checkEnableMiddleButtonPan, 0, wxTOP|wxRIGHT|wxLEFT, 3 );
- m_checkMiddleButtonPanLimited = new wxCheckBox( m_panel4, wxID_ANY, _("&Limit panning to scroll size"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_checkMiddleButtonPanLimited = new wxCheckBox( m_controlsPanel, wxID_ANY, _("&Limit panning to scroll size"), wxDefaultPosition, wxDefaultSize, 0 );
m_checkMiddleButtonPanLimited->SetToolTip( _("Middle mouse button panning limited by current scrollbar size") );
- bSizer91->Add( m_checkMiddleButtonPanLimited, 0, wxTOP|wxRIGHT|wxLEFT, 3 );
+ m_controlsSizer->Add( m_checkMiddleButtonPanLimited, 0, wxTOP|wxRIGHT|wxLEFT, 3 );
- m_checkAutoPan = new wxCheckBox( m_panel4, wxID_ANY, _("&Pan while moving object"), wxDefaultPosition, wxDefaultSize, 0 );
- bSizer91->Add( m_checkAutoPan, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 3 );
+ m_checkAutoPan = new wxCheckBox( m_controlsPanel, wxID_ANY, _("&Pan while moving object"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_controlsSizer->Add( m_checkAutoPan, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 3 );
- bSizer81->Add( bSizer91, 0, wxALL|wxEXPAND, 5 );
+ bSizer81->Add( m_controlsSizer, 1, wxALL|wxEXPAND, 5 );
- m_panel4->SetSizer( bSizer81 );
- m_panel4->Layout();
- bSizer81->Fit( m_panel4 );
- m_notebook->AddPage( m_panel4, _("Co&ntrols"), false );
+ m_controlsPanel->SetSizer( bSizer81 );
+ m_controlsPanel->Layout();
+ bSizer81->Fit( m_controlsPanel );
+ m_notebook->AddPage( m_controlsPanel, _("Controls"), false );
m_panel2 = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_panel2->SetToolTip( _("User defined field names for schematic components. ") );
@@ -342,10 +358,13 @@ DIALOG_EESCHEMA_OPTIONS_BASE::DIALOG_EESCHEMA_OPTIONS_BASE( wxWindow* parent, wx
m_panel2->SetSizer( bSizer6 );
m_panel2->Layout();
bSizer6->Fit( m_panel2 );
- m_notebook->AddPage( m_panel2, _("Default &Fields"), false );
+ m_notebook->AddPage( m_panel2, _("Default Fields"), false );
bOptionsSizer->Add( m_notebook, 1, wxALL|wxEXPAND, 5 );
+ wxBoxSizer* bSizer12;
+ bSizer12 = new wxBoxSizer( wxHORIZONTAL );
+
m_sdbSizer = new wxStdDialogButtonSizer();
m_sdbSizerOK = new wxButton( this, wxID_OK );
m_sdbSizer->AddButton( m_sdbSizerOK );
@@ -353,7 +372,10 @@ DIALOG_EESCHEMA_OPTIONS_BASE::DIALOG_EESCHEMA_OPTIONS_BASE( wxWindow* parent, wx
m_sdbSizer->AddButton( m_sdbSizerCancel );
m_sdbSizer->Realize();
- bOptionsSizer->Add( m_sdbSizer, 0, wxALL|wxEXPAND, 6 );
+ bSizer12->Add( m_sdbSizer, 1, wxALL|wxEXPAND, 5 );
+
+
+ bOptionsSizer->Add( bSizer12, 0, wxBOTTOM|wxEXPAND, 5 );
mainSizer->Add( bOptionsSizer, 1, wxEXPAND, 12 );
diff --git a/eeschema/dialogs/dialog_eeschema_options_base.fbp b/eeschema/dialogs/dialog_eeschema_options_base.fbp
index 7a24be7..668ac9f 100644
--- a/eeschema/dialogs/dialog_eeschema_options_base.fbp
+++ b/eeschema/dialogs/dialog_eeschema_options_base.fbp
@@ -184,11 +184,11 @@
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
- <object class="notebookpage" expanded="1">
+ <object class="notebookpage" expanded="0">
<property name="bitmap"></property>
<property name="label">Display</property>
<property name="select">1</property>
- <object class="wxPanel" expanded="1">
+ <object class="wxPanel" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@@ -262,16 +262,16 @@
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
- <object class="wxBoxSizer" expanded="1">
+ <object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">bSizer82</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
- <object class="sizeritem" expanded="1">
+ <object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property>
- <object class="wxFlexGridSizer" expanded="1">
+ <object class="wxFlexGridSizer" expanded="0">
<property name="cols">3</property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols">0,1,2</property>
@@ -1675,11 +1675,11 @@
</object>
</object>
</object>
- <object class="notebookpage" expanded="1">
+ <object class="notebookpage" expanded="0">
<property name="bitmap"></property>
<property name="label">Editing</property>
<property name="select">0</property>
- <object class="wxPanel" expanded="1">
+ <object class="wxPanel" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@@ -1753,16 +1753,16 @@
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
- <object class="wxBoxSizer" expanded="1">
+ <object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">bSizer8</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
- <object class="sizeritem" expanded="1">
+ <object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property>
- <object class="wxFlexGridSizer" expanded="1">
+ <object class="wxFlexGridSizer" expanded="0">
<property name="cols">3</property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols">0,1,2</property>
@@ -3069,11 +3069,11 @@
<event name="OnUpdateUI"></event>
</object>
</object>
- <object class="sizeritem" expanded="1">
+ <object class="sizeritem" expanded="0">
<property name="border">3</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT</property>
<property name="proportion">0</property>
- <object class="wxStaticText" expanded="1">
+ <object class="wxStaticText" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@@ -3769,7 +3769,7 @@
</object>
<object class="notebookpage" expanded="1">
<property name="bitmap"></property>
- <property name="label">Co&ntrols</property>
+ <property name="label">Controls</property>
<property name="select">0</property>
<object class="wxPanel" expanded="1">
<property name="BottomDockable">1</property>
@@ -3806,7 +3806,7 @@
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
- <property name="name">m_panel4</property>
+ <property name="name">m_controlsPanel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
@@ -3850,11 +3850,11 @@
<property name="name">bSizer81</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
- <object class="sizeritem" expanded="1">
+ <object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property>
- <object class="wxFlexGridSizer" expanded="1">
+ <object class="wxFlexGridSizer" expanded="0">
<property name="cols">3</property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols">0,1,2</property>
@@ -3868,15 +3868,272 @@
<property name="vgap">0</property>
</object>
</object>
- <object class="sizeritem" expanded="0">
+ <object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
- <property name="proportion">0</property>
- <object class="wxBoxSizer" expanded="0">
+ <property name="proportion">1</property>
+ <object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
- <property name="name">bSizer91</property>
+ <property name="name">m_controlsSizer</property>
<property name="orient">wxVERTICAL</property>
- <property name="permission">none</property>
+ <property name="permission">protected</property>
+ <object class="sizeritem" expanded="1">
+ <property name="border">5</property>
+ <property name="flag">wxEXPAND</property>
+ <property name="proportion">0</property>
+ <object class="wxBoxSizer" expanded="1">
+ <property name="minimum_size"></property>
+ <property name="name">bSizer13</property>
+ <property name="orient">wxHORIZONTAL</property>
+ <property name="permission">none</property>
+ <object class="sizeritem" expanded="0">
+ <property name="border">5</property>
+ <property name="flag">wxALL</property>
+ <property name="proportion">1</property>
+ <object class="wxStaticText" expanded="0">
+ <property name="BottomDockable">1</property>
+ <property name="LeftDockable">1</property>
+ <property name="RightDockable">1</property>
+ <property name="TopDockable">1</property>
+ <property name="aui_layer"></property>
+ <property name="aui_name"></property>
+ <property name="aui_position"></property>
+ <property name="aui_row"></property>
+ <property name="best_size"></property>
+ <property name="bg"></property>
+ <property name="caption"></property>
+ <property name="caption_visible">1</property>
+ <property name="center_pane">0</property>
+ <property name="close_button">1</property>
+ <property name="context_help"></property>
+ <property name="context_menu">1</property>
+ <property name="default_pane">0</property>
+ <property name="dock">Dock</property>
+ <property name="dock_fixed">0</property>
+ <property name="docking">Left</property>
+ <property name="enabled">1</property>
+ <property name="fg"></property>
+ <property name="floatable">1</property>
+ <property name="font"></property>
+ <property name="gripper">0</property>
+ <property name="hidden">0</property>
+ <property name="id">wxID_ANY</property>
+ <property name="label">Hotkeys:</property>
+ <property name="max_size"></property>
+ <property name="maximize_button">0</property>
+ <property name="maximum_size"></property>
+ <property name="min_size"></property>
+ <property name="minimize_button">0</property>
+ <property name="minimum_size"></property>
+ <property name="moveable">1</property>
+ <property name="name">m_staticText20</property>
+ <property name="pane_border">1</property>
+ <property name="pane_position"></property>
+ <property name="pane_size"></property>
+ <property name="permission">protected</property>
+ <property name="pin_button">1</property>
+ <property name="pos"></property>
+ <property name="resize">Resizable</property>
+ <property name="show">1</property>
+ <property name="size"></property>
+ <property name="style"></property>
+ <property name="subclass"></property>
+ <property name="toolbar_pane">0</property>
+ <property name="tooltip"></property>
+ <property name="window_extra_style"></property>
+ <property name="window_name"></property>
+ <property name="window_style"></property>
+ <property name="wrap">-1</property>
+ <event name="OnChar"></event>
+ <event name="OnEnterWindow"></event>
+ <event name="OnEraseBackground"></event>
+ <event name="OnKeyDown"></event>
+ <event name="OnKeyUp"></event>
+ <event name="OnKillFocus"></event>
+ <event name="OnLeaveWindow"></event>
+ <event name="OnLeftDClick"></event>
+ <event name="OnLeftDown"></event>
+ <event name="OnLeftUp"></event>
+ <event name="OnMiddleDClick"></event>
+ <event name="OnMiddleDown"></event>
+ <event name="OnMiddleUp"></event>
+ <event name="OnMotion"></event>
+ <event name="OnMouseEvents"></event>
+ <event name="OnMouseWheel"></event>
+ <event name="OnPaint"></event>
+ <event name="OnRightDClick"></event>
+ <event name="OnRightDown"></event>
+ <event name="OnRightUp"></event>
+ <event name="OnSetFocus"></event>
+ <event name="OnSize"></event>
+ <event name="OnUpdateUI"></event>
+ </object>
+ </object>
+ <object class="sizeritem" expanded="0">
+ <property name="border">5</property>
+ <property name="flag">wxALL</property>
+ <property name="proportion">0</property>
+ <object class="wxStaticText" expanded="0">
+ <property name="BottomDockable">1</property>
+ <property name="LeftDockable">1</property>
+ <property name="RightDockable">1</property>
+ <property name="TopDockable">1</property>
+ <property name="aui_layer"></property>
+ <property name="aui_name"></property>
+ <property name="aui_position"></property>
+ <property name="aui_row"></property>
+ <property name="best_size"></property>
+ <property name="bg"></property>
+ <property name="caption"></property>
+ <property name="caption_visible">1</property>
+ <property name="center_pane">0</property>
+ <property name="close_button">1</property>
+ <property name="context_help"></property>
+ <property name="context_menu">1</property>
+ <property name="default_pane">0</property>
+ <property name="dock">Dock</property>
+ <property name="dock_fixed">0</property>
+ <property name="docking">Left</property>
+ <property name="enabled">1</property>
+ <property name="fg"></property>
+ <property name="floatable">1</property>
+ <property name="font"></property>
+ <property name="gripper">0</property>
+ <property name="hidden">0</property>
+ <property name="id">wxID_ANY</property>
+ <property name="label">Double-click to edit</property>
+ <property name="max_size"></property>
+ <property name="maximize_button">0</property>
+ <property name="maximum_size"></property>
+ <property name="min_size"></property>
+ <property name="minimize_button">0</property>
+ <property name="minimum_size"></property>
+ <property name="moveable">1</property>
+ <property name="name">m_staticText21</property>
+ <property name="pane_border">1</property>
+ <property name="pane_position"></property>
+ <property name="pane_size"></property>
+ <property name="permission">protected</property>
+ <property name="pin_button">1</property>
+ <property name="pos"></property>
+ <property name="resize">Resizable</property>
+ <property name="show">1</property>
+ <property name="size"></property>
+ <property name="style"></property>
+ <property name="subclass"></property>
+ <property name="toolbar_pane">0</property>
+ <property name="tooltip"></property>
+ <property name="window_extra_style"></property>
+ <property name="window_name"></property>
+ <property name="window_style"></property>
+ <property name="wrap">-1</property>
+ <event name="OnChar"></event>
+ <event name="OnEnterWindow"></event>
+ <event name="OnEraseBackground"></event>
+ <event name="OnKeyDown"></event>
+ <event name="OnKeyUp"></event>
+ <event name="OnKillFocus"></event>
+ <event name="OnLeaveWindow"></event>
+ <event name="OnLeftDClick"></event>
+ <event name="OnLeftDown"></event>
+ <event name="OnLeftUp"></event>
+ <event name="OnMiddleDClick"></event>
+ <event name="OnMiddleDown"></event>
+ <event name="OnMiddleUp"></event>
+ <event name="OnMotion"></event>
+ <event name="OnMouseEvents"></event>
+ <event name="OnMouseWheel"></event>
+ <event name="OnPaint"></event>
+ <event name="OnRightDClick"></event>
+ <event name="OnRightDown"></event>
+ <event name="OnRightUp"></event>
+ <event name="OnSetFocus"></event>
+ <event name="OnSize"></event>
+ <event name="OnUpdateUI"></event>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="sizeritem" expanded="1">
+ <property name="border">5</property>
+ <property name="flag">wxEXPAND | wxALL</property>
+ <property name="proportion">1</property>
+ <object class="wxPanel" expanded="1">
+ <property name="BottomDockable">1</property>
+ <property name="LeftDockable">1</property>
+ <property name="RightDockable">1</property>
+ <property name="TopDockable">1</property>
+ <property name="aui_layer"></property>
+ <property name="aui_name"></property>
+ <property name="aui_position"></property>
+ <property name="aui_row"></property>
+ <property name="best_size"></property>
+ <property name="bg"></property>
+ <property name="caption"></property>
+ <property name="caption_visible">1</property>
+ <property name="center_pane">0</property>
+ <property name="close_button">1</property>
+ <property name="context_help"></property>
+ <property name="context_menu">1</property>
+ <property name="default_pane">0</property>
+ <property name="dock">Dock</property>
+ <property name="dock_fixed">0</property>
+ <property name="docking">Left</property>
+ <property name="enabled">1</property>
+ <property name="fg"></property>
+ <property name="floatable">1</property>
+ <property name="font"></property>
+ <property name="gripper">0</property>
+ <property name="hidden">0</property>
+ <property name="id">wxID_ANY</property>
+ <property name="max_size"></property>
+ <property name="maximize_button">0</property>
+ <property name="maximum_size"></property>
+ <property name="min_size"></property>
+ <property name="minimize_button">0</property>
+ <property name="minimum_size"></property>
+ <property name="moveable">1</property>
+ <property name="name">m_panelHotkeys</property>
+ <property name="pane_border">1</property>
+ <property name="pane_position"></property>
+ <property name="pane_size"></property>
+ <property name="permission">protected</property>
+ <property name="pin_button">1</property>
+ <property name="pos"></property>
+ <property name="resize">Resizable</property>
+ <property name="show">1</property>
+ <property name="size"></property>
+ <property name="subclass"></property>
+ <property name="toolbar_pane">0</property>
+ <property name="tooltip"></property>
+ <property name="window_extra_style"></property>
+ <property name="window_name"></property>
+ <property name="window_style">wxTAB_TRAVERSAL</property>
+ <event name="OnChar"></event>
+ <event name="OnEnterWindow"></event>
+ <event name="OnEraseBackground"></event>
+ <event name="OnKeyDown"></event>
+ <event name="OnKeyUp"></event>
+ <event name="OnKillFocus"></event>
+ <event name="OnLeaveWindow"></event>
+ <event name="OnLeftDClick"></event>
+ <event name="OnLeftDown"></event>
+ <event name="OnLeftUp"></event>
+ <event name="OnMiddleDClick"></event>
+ <event name="OnMiddleDown"></event>
+ <event name="OnMiddleUp"></event>
+ <event name="OnMotion"></event>
+ <event name="OnMouseEvents"></event>
+ <event name="OnMouseWheel"></event>
+ <event name="OnPaint"></event>
+ <event name="OnRightDClick"></event>
+ <event name="OnRightDown"></event>
+ <event name="OnRightUp"></event>
+ <event name="OnSetFocus"></event>
+ <event name="OnSize"></event>
+ <event name="OnUpdateUI"></event>
+ </object>
+ </object>
<object class="sizeritem" expanded="0">
<property name="border">3</property>
<property name="flag">wxTOP|wxRIGHT|wxLEFT</property>
@@ -4234,11 +4491,11 @@
</object>
</object>
</object>
- <object class="notebookpage" expanded="1">
+ <object class="notebookpage" expanded="0">
<property name="bitmap"></property>
- <property name="label">Default &Fields</property>
+ <property name="label">Default Fields</property>
<property name="select">0</property>
- <object class="wxPanel" expanded="1">
+ <object class="wxPanel" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@@ -4312,25 +4569,25 @@
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
- <object class="wxBoxSizer" expanded="1">
+ <object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">bSizer6</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
- <object class="sizeritem" expanded="1">
+ <object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
- <object class="wxBoxSizer" expanded="1">
+ <object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">bSizer11</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
- <object class="sizeritem" expanded="1">
+ <object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">1</property>
- <object class="wxGrid" expanded="1">
+ <object class="wxGrid" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@@ -4471,7 +4728,7 @@
</object>
</object>
</object>
- <object class="sizeritem" expanded="1">
+ <object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
@@ -4673,30 +4930,41 @@
</object>
</object>
</object>
- <object class="sizeritem" expanded="0">
- <property name="border">6</property>
- <property name="flag">wxALL|wxEXPAND</property>
+ <object class="sizeritem" expanded="1">
+ <property name="border">5</property>
+ <property name="flag">wxBOTTOM|wxEXPAND</property>
<property name="proportion">0</property>
- <object class="wxStdDialogButtonSizer" expanded="0">
- <property name="Apply">0</property>
- <property name="Cancel">1</property>
- <property name="ContextHelp">0</property>
- <property name="Help">0</property>
- <property name="No">0</property>
- <property name="OK">1</property>
- <property name="Save">0</property>
- <property name="Yes">0</property>
+ <object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
- <property name="name">m_sdbSizer</property>
- <property name="permission">protected</property>
- <event name="OnApplyButtonClick"></event>
- <event name="OnCancelButtonClick"></event>
- <event name="OnContextHelpButtonClick"></event>
- <event name="OnHelpButtonClick"></event>
- <event name="OnNoButtonClick"></event>
- <event name="OnOKButtonClick"></event>
- <event name="OnSaveButtonClick"></event>
- <event name="OnYesButtonClick"></event>
+ <property name="name">bSizer12</property>
+ <property name="orient">wxHORIZONTAL</property>
+ <property name="permission">none</property>
+ <object class="sizeritem" expanded="0">
+ <property name="border">5</property>
+ <property name="flag">wxALL|wxEXPAND</property>
+ <property name="proportion">1</property>
+ <object class="wxStdDialogButtonSizer" expanded="0">
+ <property name="Apply">0</property>
+ <property name="Cancel">1</property>
+ <property name="ContextHelp">0</property>
+ <property name="Help">0</property>
+ <property name="No">0</property>
+ <property name="OK">1</property>
+ <property name="Save">0</property>
+ <property name="Yes">0</property>
+ <property name="minimum_size"></property>
+ <property name="name">m_sdbSizer</property>
+ <property name="permission">protected</property>
+ <event name="OnApplyButtonClick"></event>
+ <event name="OnCancelButtonClick"></event>
+ <event name="OnContextHelpButtonClick"></event>
+ <event name="OnHelpButtonClick"></event>
+ <event name="OnNoButtonClick"></event>
+ <event name="OnOKButtonClick"></event>
+ <event name="OnSaveButtonClick"></event>
+ <event name="OnYesButtonClick"></event>
+ </object>
+ </object>
</object>
</object>
</object>
diff --git a/eeschema/dialogs/dialog_eeschema_options_base.h b/eeschema/dialogs/dialog_eeschema_options_base.h
index 585d442..5b20e1c 100644
--- a/eeschema/dialogs/dialog_eeschema_options_base.h
+++ b/eeschema/dialogs/dialog_eeschema_options_base.h
@@ -103,7 +103,11 @@ class DIALOG_EESCHEMA_OPTIONS_BASE : public DIALOG_SHIM
wxCheckBox* m_checkAutoplaceFields;
wxCheckBox* m_checkAutoplaceJustify;
wxCheckBox* m_checkAutoplaceAlign;
- wxPanel* m_panel4;
+ wxPanel* m_controlsPanel;
+ wxBoxSizer* m_controlsSizer;
+ wxStaticText* m_staticText20;
+ wxStaticText* m_staticText21;
+ wxPanel* m_panelHotkeys;
wxCheckBox* m_checkEnableZoomCenter;
wxCheckBox* m_checkEnableMiddleButtonPan;
wxCheckBox* m_checkMiddleButtonPanLimited;
diff --git a/eeschema/menubar.cpp b/eeschema/menubar.cpp
index 0baaa1e..2e8047d 100644
--- a/eeschema/menubar.cpp
+++ b/eeschema/menubar.cpp
@@ -3,7 +3,7 @@
*
* Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2009-2014 Wayne Stambaugh <stambaughw@xxxxxxxxxxx>
- * Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -398,23 +398,38 @@ void SCH_EDIT_FRAME::ReCreateMenuBar()
// Language submenu
Pgm().AddMenuLanguageList( preferencesMenu );
- // Hotkey submenu
- AddHotkeyConfigMenu( preferencesMenu );
+ // Import/export
+ wxMenu* importExportSubmenu = new wxMenu();
- // Separator
- preferencesMenu->AppendSeparator();
-
- AddMenuItem( preferencesMenu,
+ AddMenuItem( importExportSubmenu,
ID_CONFIG_SAVE,
_( "&Save Preferences" ),
_( "Save application preferences" ),
- KiBitmap( save_setup_xpm ) );
+ wxNullBitmap );
- AddMenuItem( preferencesMenu,
+ AddMenuItem( importExportSubmenu,
ID_CONFIG_READ,
_( "Load Prefe&rences" ),
_( "Load application preferences" ),
- KiBitmap( read_setup_xpm ) );
+ wxNullBitmap );
+
+ AddMenuItem( importExportSubmenu,
+ ID_PREFERENCES_HOTKEY_EXPORT_CONFIG,
+ _( "E&xport Hotkeys" ),
+ _( "Create a hotkey configuration file to export the current hotkeys" ),
+ wxNullBitmap );
+
+ AddMenuItem( importExportSubmenu,
+ ID_PREFERENCES_HOTKEY_IMPORT_CONFIG,
+ _( "&Import Hotkeys" ),
+ _( "Load an existing hotkey configuration file" ),
+ wxNullBitmap );
+
+ AddMenuItem( preferencesMenu, importExportSubmenu,
+ wxID_ANY,
+ _( "&Import and export" ),
+ _( "Import and export settings" ),
+ KiBitmap( save_setup_xpm ) );
// Menu Tools:
wxMenu* toolsMenu = new wxMenu;
diff --git a/include/dialog_hotkeys_editor.h b/include/dialog_hotkeys_editor.h
index c0da682..801bea9 100644
--- a/include/dialog_hotkeys_editor.h
+++ b/include/dialog_hotkeys_editor.h
@@ -5,7 +5,7 @@
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
+ * as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
@@ -28,151 +28,9 @@
#ifndef __dialog_hotkeys_editor__
#define __dialog_hotkeys_editor__
-#include <wx/intl.h>
-
-#include <wx/string.h>
-#include <wx/choice.h>
-#include <wx/gdicmn.h>
-#include <wx/font.h>
-#include <wx/settings.h>
-#include <wx/textctrl.h>
-#include <wx/stattext.h>
-#include <wx/button.h>
-#include <wx/treelist.h>
-#include <wx/dialog.h>
-#include <wx/grid.h>
-
-#include <vector>
-#include <utility>
-
#include <hotkeys_basic.h>
-#include <draw_frame.h>
#include <../common/dialogs/dialog_hotkeys_editor_base.h>
-
-typedef std::pair<wxString, struct EDA_HOTKEY_CONFIG*> HOTKEYS_SECTION;
-typedef std::vector<HOTKEYS_SECTION> HOTKEYS_SECTIONS;
-
-typedef std::vector<EDA_HOTKEY> HOTKEY_LIST;
-
-class HOTKEYS_EDITOR_DIALOG;
-class DIALOG_HOTKEY_CLIENT_DATA;
-
-/**
- * Class HOTKEY_LIST_CTRL
- * is a class to contain the contents of a hotkey editor tab page.
- */
-class HOTKEY_LIST_CTRL : public wxTreeListCtrl
-{
-public:
- HOTKEY_LIST_CTRL( wxWindow* aParent, const HOTKEYS_SECTIONS& aSections );
- ~HOTKEY_LIST_CTRL() {};
-
- /**
- * Function DeselectRow
- * Deselect the given row
- *
- * @param aRow is the row to deselect
- */
- void DeselectRow( int aRow );
-
- /**
- * Function TransferDataToControl
- * Load the hotkey data into the control.
- * @return true iff the operation was successful
- */
- bool TransferDataToControl();
-
- /**
- * Function TransferDataFromControl
- * Save the hotkey data from the control.
- * @return true iff the operation was successful
- */
- bool TransferDataFromControl();
-
- /**
- * Function ResolveKeyConflicts
- * Check if we can set a hotkey, this will prompt the user if there
- * is a conflict between keys. The key code should have already been
- * checked that it's not for the same entry as its currently in or else
- * it'll prompt the change on itself.
- * The function will do conflict detection depending on aSectionTag.
- * g_CommonSectionTag means the key code must be checked with all sections.
- * While other tags means the key code only must be checked with the aSectionTag
- * section and g_CommonSectionTag section.
- *
- * @param aKey is the key code that wants to be set
- * @param aSectionTag is the section tag that the key code came from
- *
- * @return True if the user accepted the overwrite or no conflict existed
- */
- bool ResolveKeyConflicts( long aKey, const wxString& aSectionTag );
-
-
- /**
- * Function CheckKeyConflicts
- * Check whether the given key conflicts with anything in this HOTKEY_LIST_CTRL.
- *
- * @param aKey - key to check
- * @param aSectionTag - section tag of the key
- * @param aConfKey - if not NULL, outparam holding the key this one conflicts with
- * @param aConfSect - if not NULL, outparam holding the section this one conflicts with
- */
- bool CheckKeyConflicts( long aKey, const wxString& aSectionTag,
- EDA_HOTKEY** aConfKey, EDA_HOTKEY_CONFIG** aConfSect );
-
- /**
- * Function UpdateFromClientData
- * Update all visible items from the data stored in their client data objects.
- */
- void UpdateFromClientData();
-
-private:
- HOTKEYS_SECTIONS m_sections;
- std::vector< HOTKEY_LIST > m_hotkeys;
- std::vector< wxTreeListItem > m_items;
-
- /**
- * Function GetSelHKClientData
- * Return the DIALOG_HOTKEY_CLIENT_DATA for the item being edited, or NULL if none is selected.
- */
- DIALOG_HOTKEY_CLIENT_DATA* GetSelHKClientData();
-
- /**
- * Function GetHKClientData
- * Return the DIALOG_HOTKEY_CLIENT_DATA for the given item, or NULL if invalid.
- */
- DIALOG_HOTKEY_CLIENT_DATA* GetHKClientData( wxTreeListItem aItem );
-
-protected:
- /**
- * Function LoadSection
- * Generates a HOTKEY_LIST from the given hotkey configuration array and
- * pushes it to m_hotkeys.
- *
- * @param aSection is a pointer to the hotkey configuration array
- */
- void LoadSection( struct EDA_HOTKEY_CONFIG* aSection );
-
- /**
- * Function OnGetItemText
- * Returns the requested row, column data to the list control.
- *
- * @param aRow is the row of the data which matches our hotkeys vector as a index
- * @param aColumn is the column of the data which is either Command(0) or KeyCode(1)
- *
- * @return String containing the text for the specified row, column combination
- */
- wxString OnGetItemText( long aRow, long aColumn ) const;
-
- /**
- * Function OnChar
- * Decoded key press handler which is used to set key codes in the list control
- *
- * @param aEvent is the key press event, the keycode is retrieved from it
- */
- void OnChar( wxKeyEvent& aEvent );
-};
-
+#include <widgets/widget_hotkey_list.h>
/**
* Class HOTKEYS_EDITOR_DIALOG
@@ -182,14 +40,18 @@ protected:
class HOTKEYS_EDITOR_DIALOG : public HOTKEYS_EDITOR_DIALOG_BASE
{
protected:
- EDA_BASE_FRAME* m_parent;
struct EDA_HOTKEY_CONFIG* m_hotkeys;
- HOTKEY_LIST_CTRL* m_hotkeyListCtrl;
+ WIDGET_HOTKEY_LIST* m_hotkeyListCtrl;
bool TransferDataToWindow();
bool TransferDataFromWindow();
+ virtual EDA_BASE_FRAME* GetParent()
+ {
+ return static_cast<EDA_BASE_FRAME*>( HOTKEYS_EDITOR_DIALOG_BASE::GetParent() );
+ }
+
public:
HOTKEYS_EDITOR_DIALOG( EDA_BASE_FRAME* aParent, EDA_HOTKEY_CONFIG* aHotkeys );
diff --git a/include/hotkeys_basic.h b/include/hotkeys_basic.h
index a2dc773..089fcce 100644
--- a/include/hotkeys_basic.h
+++ b/include/hotkeys_basic.h
@@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
- * Copyright (C) 2004-2011 KiCad Developers, see change_log.txt for contributors.
+ * Copyright (C) 2004-2016 KiCad Developers, see change_log.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -29,6 +29,8 @@
#ifndef HOTKEYS_BASIC_H
#define HOTKEYS_BASIC_H
+#include <common.h>
+
#define DEFAULT_HOTKEY_FILENAME_EXT wxT( "hotkeys" )
// A define to allow translation of Hot Key message Info in hotkey help menu
diff --git a/include/widgets/widget_hotkey_list.h b/include/widgets/widget_hotkey_list.h
new file mode 100644
index 0000000..bfaf010
--- /dev/null
+++ b/include/widgets/widget_hotkey_list.h
@@ -0,0 +1,202 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2016 Chris Pavlina <pavlina.chris@xxxxxxxxx>
+ * Copyright (C) 2016 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file widget_hotkey_list
+ */
+
+#ifndef __widget_hotkey_list__
+#define __widget_hotkey_list__
+
+#include <utility>
+#include <vector>
+
+#include <wx/treelist.h>
+
+#include <hotkeys_basic.h>
+
+/**
+ * struct HOTKEY_SECTION
+ * Associates a hotkey configuration with a name.
+ */
+struct HOTKEY_SECTION
+{
+ wxString m_name;
+ EDA_HOTKEY_CONFIG* m_section;
+};
+
+typedef std::vector<HOTKEY_SECTION> HOTKEY_SECTIONS;
+typedef std::vector<EDA_HOTKEY> HOTKEY_LIST;
+
+class WIDGET_HOTKEY_CLIENT_DATA;
+
+class WIDGET_HOTKEY_LIST : public wxTreeListCtrl
+{
+ HOTKEY_SECTIONS m_sections;
+ std::vector<HOTKEY_LIST> m_hotkeys;
+ wxTreeListItem m_context_menu_item;
+
+ /**
+ * Method GetHKClientData
+ * Return the WIDGET_HOTKEY_CLIENT_DATA for the given item, or NULL if the
+ * item is invalid.
+ */
+ WIDGET_HOTKEY_CLIENT_DATA* GetHKClientData( wxTreeListItem aItem );
+
+ /**
+ * Method GetSelHKClientData
+ * Return the WIDGET_HOTKEY_CLIENT_DATA for the item being edited, or NULL if
+ * none is selected.
+ */
+ WIDGET_HOTKEY_CLIENT_DATA* GetSelHKClientData();
+
+ /**
+ * Method UpdateFromClientData
+ * Refresh the visible text on the widget from the rows' client data objects.
+ */
+ void UpdateFromClientData();
+
+protected:
+ /**
+ * Method LoadSection
+ * Generates a HOTKEY_LIST from the given hotkey configuration array and pushes
+ * it to m_hotkeys.
+ */
+ void LoadSection( EDA_HOTKEY_CONFIG* aSection );
+
+ /**
+ * Method EditItem
+ * Prompt the user for a new hotkey given a list item.
+ */
+ void EditItem( wxTreeListItem aItem );
+
+ /**
+ * Method ResetItem
+ * Reset the item to the original from the dialog was created.
+ */
+ void ResetItem( wxTreeListItem aItem );
+
+ /**
+ * Method OnActivated
+ * Handle activation of a row.
+ */
+ void OnActivated( wxTreeListEvent& aEvent );
+
+ /**
+ * Method OnContextMenu
+ * Handle right-click on a row.
+ */
+ void OnContextMenu( wxTreeListEvent& aEvent );
+
+ /**
+ * Method OnMenu
+ * Handle activation of a context menu item.
+ */
+ void OnMenu( wxCommandEvent& aEvent );
+
+ /**
+ * Function OnSize
+ * Handle resizing of the control. Overrides the buggy wxTreeListCtrl::OnSize.
+ */
+ void OnSize( wxSizeEvent& aEvent );
+
+ /**
+ * Method CheckKeyConflicts
+ * Check whether the given key conflicts with anything in this WIDGET_HOTKEY_LIST.
+ *
+ * @param aKey - key to check
+ * @param aSectionTag - section tag into which the key is proposed to be installed
+ * @param aConfKey - if not NULL, outparam getting the key this one conflicts with
+ * @param aConfSect - if not NULL, outparam getting the section this one conflicts with
+ */
+ bool CheckKeyConflicts( long aKey, const wxString& aSectionTag,
+ EDA_HOTKEY** aConfKey, EDA_HOTKEY_CONFIG** aConfSect );
+
+ /**
+ * Method ResolveKeyConflicts
+ * Check if we can set a hotkey, and prompt the user if there is a conflict between
+ * keys. The key code should already have been checked that it's not for the same
+ * entry as it's current in, or else this method will prompt for the self-change.
+ *
+ * The method will do conflict resolution depending on aSectionTag.
+ * g_CommonSectionTag means the key code must only be checkd with the aSectionTag
+ * section and g_CommonSectionTag section.
+ *
+ * @param aKey - key to check
+ * @param aSectionTag - section tag into which the key is proposed to be installed
+ *
+ * @return true iff the user accepted the overwrite or no conflict existed
+ */
+ bool ResolveKeyConflicts( long aKey, const wxString& aSectionTag );
+
+public:
+ /**
+ * Constructor WIDGET_HOTKEY_LIST
+ * Create a WIDGET_HOTKEY_LIST.
+ *
+ * @param aParent - parent widget
+ * @param aSections - list of the hotkey sections to display and their names.
+ * See WIDGET_HOTKEY_LIST::GenSections for a way to generate these easily
+ * from an EDA_HOTKEY_CONFIG*.
+ */
+ WIDGET_HOTKEY_LIST( wxWindow* aParent, const HOTKEY_SECTIONS& aSections );
+
+ /**
+ * Static method GenSections
+ * Generate a list of sections and names from an EDA_HOTKEY_CONFIG*. Titles
+ * will be looked up from translations.
+ */
+ static HOTKEY_SECTIONS GenSections( EDA_HOTKEY_CONFIG* aHotkeys );
+
+ /**
+ * Method InstallOnPanel
+ * Install this WIDGET_HOTKEY_LIST onto an empty panel. This is useful
+ * when combining with wxFormBuilder, as an empty panel can be left as a
+ * placeholder in the layout.
+ */
+ void InstallOnPanel( wxPanel* aPanel );
+
+ /**
+ * Method TransferDataToControl
+ * Load the hotkey data into the control. It is safe to call this multiple times,
+ * for example to reset the control.
+ * @return true iff the operation was successful
+ */
+ bool TransferDataToControl();
+
+ /**
+ * Method TransferDataFromControl
+ * Save the hotkey data from the control.
+ * @return true iff the operation was successful
+ */
+ bool TransferDataFromControl();
+
+ /**
+ * Static method MapKeypressToKeycode
+ * Map a keypress event to the correct key code for use as a hotkey.
+ */
+ static long MapKeypressToKeycode( const wxKeyEvent& aEvent );
+};
+
+#endif // __widget_hotkey_list__
Follow ups
References