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.ch...@gmail.com> > + * 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 <stambau...@verizon.net> > - * 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 <stambau...@verizon.net> > - * 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 <stambau...@verizon.net> > - * 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.ch...@gmail.com> > + * 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@lists.launchpad.net Unsubscribe : https://launchpad.net/~kicad-developers More help : https://help.launchpad.net/ListHelp