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.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 > _______________________________________________ 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