kicad-developers team mailing list archive
-
kicad-developers team
-
Mailing list archive
-
Message #22474
Re: Final? version of hotkeys patch
Sorry Chris. I've been busy and just didn't get to it yet. I'll try to
take a look at it today or tomorrow.
On 1/10/2016 4:13 PM, Chris Pavlina wrote:
> Just to clarify - Wayne, are you still having a look at this, or were
> you just expecting me to merge my own patch when it's done? I think it's
> ready to go in.
>
> On Fri, Jan 08, 2016 at 01:16:52PM -0500, 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
>
>> diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
>> index 9d8b71f..675c565 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 a3c2742..96a8d3b 100644
>> --- a/common/dialogs/dialog_hotkeys_editor.cpp
>> +++ b/common/dialogs/dialog_hotkeys_editor.cpp
>> @@ -21,321 +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 < 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();
>> - HOTKEYS_EDITOR_DIALOG* parent = static_cast<HOTKEYS_EDITOR_DIALOG*>( m_parent );
>> - 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();
>> @@ -344,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();
>> }
>>
>> @@ -389,7 +74,7 @@ bool HOTKEYS_EDITOR_DIALOG::TransferDataFromWindow()
>> return false;
>>
>> // save the hotkeys
>> - m_parent->WriteHotkeyConfig( m_hotkeys );
>> + GetParent()->WriteHotkeyConfig( m_hotkeys );
>>
>> return true;
>> }
>> @@ -399,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..a188968
>> --- /dev/null
>> +++ b/common/widgets/widget_hotkey_list.cpp
>> @@ -0,0 +1,672 @@
>> +/*
>> + * 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, aName );
>> + cmd_label_1->SetFont( cmd_label_1->GetFont().Bold().MakeLarger() );
>> + 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, aCurrentKey );
>> + key_label_1->SetFont( key_label_1->GetFont().Bold().MakeLarger() );
>> + 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__
>
>
> _______________________________________________
> 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
>
Follow ups
References