diff --git a/src/lay/lay/KeyBindingsConfigPage.ui b/src/lay/lay/KeyBindingsConfigPage.ui index 4cd5e3d6d..c9822895c 100644 --- a/src/lay/lay/KeyBindingsConfigPage.ui +++ b/src/lay/lay/KeyBindingsConfigPage.ui @@ -1,7 +1,8 @@ - + + KeyBindingsConfigPage - - + + 0 0 @@ -9,78 +10,92 @@ 495 - - - 5 - 7 + + 0 1 - + Settings - - - 9 - - + + 6 + + 9 + + + 9 + + + 9 + + + 9 + - - - - 7 - 7 + + + 1 0 - + true - + Path - + Title - + Shortcut - - + + QFrame::NoFrame - + QFrame::Raised - - + + + 6 + + 9 - - 6 + + 9 + + + 9 + + + 9 - + Qt::Vertical - + QSizePolicy::Fixed - + 20 40 @@ -89,24 +104,24 @@ - - + + Keyboard Shortcut - + - + Qt::Vertical - + QSizePolicy::Fixed - + 20 10 @@ -115,30 +130,30 @@ - - + + Examples: - - "Ctrl+A" - - "Shift+F2" - - "M" + - "Ctrl+A" + - "Shift+F2" + - "M" For special keys: - - "PgUp" - - "Left" - - "Enter" - - "Esc" or "Escape" - - "Ins" or "Insert" - - "Backspace" + - "PgUp" + - "Left" + - "Enter" + - "Esc" or "Escape" + - "Ins" or "Insert" + - "Backspace" - + Qt::Vertical - + 20 40 @@ -147,8 +162,8 @@ For special keys: - - + + Reset To Default @@ -158,7 +173,14 @@ For special keys: - + + + + lay::DecoratedLineEdit + QLineEdit +
layWidgets.h
+
+
diff --git a/src/lay/lay/layMacroController.cc b/src/lay/lay/layMacroController.cc index f84d8f4e9..b708fc15c 100644 --- a/src/lay/lay/layMacroController.cc +++ b/src/lay/lay/layMacroController.cc @@ -202,21 +202,9 @@ MacroController::uninitialize (lay::PluginRoot * /*root*/) bool MacroController::configure (const std::string &key, const std::string &value) { - if (key == cfg_key_bindings && mp_mw) { - - // Update the shortcuts of the menu item if they have been edited in the configuration editor - std::vector > key_bindings = unpack_key_binding (value); - for (std::vector >::const_iterator kb = key_bindings.begin (); kb != key_bindings.end (); ++kb) { - if (mp_mw->menu ()->is_valid (kb->first)) { - lay::Action a = mp_mw->menu ()->action (kb->first); - if (m_action_to_macro.find (a.qaction ()) != m_action_to_macro.end ()) { - m_action_to_macro [a.qaction ()]->set_shortcut (kb->second); - } - } - } - + if (key == cfg_key_bindings) { + m_key_bindings = unpack_key_binding (value); } - return false; } @@ -639,7 +627,7 @@ static std::string menu_name (std::set &used_names, const std::stri } void -MacroController::add_macro_items_to_menu (lym::MacroCollection &collection, std::set &used_names, std::set &groups, const lay::Technology *tech, std::vector > *key_bindings) +MacroController::add_macro_items_to_menu (lym::MacroCollection &collection, std::set &used_names, std::set &groups, const lay::Technology *tech) { for (lym::MacroCollection::child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) { @@ -655,7 +643,7 @@ MacroController::add_macro_items_to_menu (lym::MacroCollection &collection, std: } if (consider) { - add_macro_items_to_menu (*c->second, used_names, groups, 0 /*don't check 2nd level and below*/, key_bindings); + add_macro_items_to_menu (*c->second, used_names, groups, 0 /*don't check 2nd level and below*/); } } @@ -686,7 +674,7 @@ MacroController::add_macro_items_to_menu (lym::MacroCollection &collection, std: } else { a.set_title (c->second->description ()); } - a.set_shortcut (sc); + a.set_default_shortcut (sc); m_macro_actions.push_back (a); mp_mw->menu ()->insert_item (mp, menu_name (used_names, c->second->name ()), a); @@ -695,11 +683,6 @@ MacroController::add_macro_items_to_menu (lym::MacroCollection &collection, std: lym::MacroSignalAdaptor *adaptor = new lym::MacroSignalAdaptor (a.qaction (), c->second); QObject::connect (a.qaction (), SIGNAL (triggered ()), adaptor, SLOT (run ())); - // store the key bindings in the array - if (!sc.empty () && key_bindings) { - key_bindings->push_back (std::make_pair (mp, sc)); - } - } else if (! sc.empty ()) { // Create actions for shortcut-only actions too and add them to the main window @@ -772,19 +755,6 @@ MacroController::do_update_menu_with_macros () tech = lay::TechnologyController::instance ()->active_technology (); } - std::vector > key_bindings = unpack_key_binding (mp_mw->config_get (cfg_key_bindings)); - std::sort (key_bindings.begin (), key_bindings.end ()); - - std::vector > new_key_bindings; - for (std::vector >::const_iterator kb = key_bindings.begin (); kb != key_bindings.end (); ++kb) { - if (mp_mw->menu ()->is_valid (kb->first)) { - lay::Action a = mp_mw->menu ()->action (kb->first); - if (m_action_to_macro.find (a.qaction ()) == m_action_to_macro.end ()) { - new_key_bindings.push_back (*kb); - } - } - } - // delete all existing items for (std::vector::iterator a = m_macro_actions.begin (); a != m_macro_actions.end (); ++a) { mp_mw->menu ()->delete_items (*a); @@ -794,13 +764,15 @@ MacroController::do_update_menu_with_macros () std::set groups; std::set used_names; - add_macro_items_to_menu (m_temp_macros, used_names, groups, tech, 0); - add_macro_items_to_menu (lym::MacroCollection::root (), used_names, groups, tech, &new_key_bindings); + add_macro_items_to_menu (m_temp_macros, used_names, groups, tech); + add_macro_items_to_menu (lym::MacroCollection::root (), used_names, groups, tech); - // update the key bindings if required - std::sort (new_key_bindings.begin (), new_key_bindings.end ()); - if (new_key_bindings != key_bindings) { - mp_mw->config_set (cfg_key_bindings, pack_key_binding (new_key_bindings)); + // apply the custom keyboard shortcuts + for (std::vector >::const_iterator kb = m_key_bindings.begin (); kb != m_key_bindings.end (); ++kb) { + if (mp_mw->menu ()->is_valid (kb->first)) { + lay::Action a = mp_mw->menu ()->action (kb->first); + a.set_shortcut (kb->second); + } } } diff --git a/src/lay/lay/layMacroController.h b/src/lay/lay/layMacroController.h index 49881a5b2..29f8f70f0 100644 --- a/src/lay/lay/layMacroController.h +++ b/src/lay/lay/layMacroController.h @@ -246,9 +246,10 @@ private: tl::DeferredMethod dm_do_sync_with_external_sources; tl::DeferredMethod dm_sync_file_watcher; tl::DeferredMethod dm_sync_files; + std::vector > m_key_bindings; void sync_implicit_macros (bool ask_before_autorun); - void add_macro_items_to_menu (lym::MacroCollection &collection, std::set &used_names, std::set &groups, const lay::Technology *tech, std::vector > *key_bindings); + void add_macro_items_to_menu (lym::MacroCollection &collection, std::set &used_names, std::set &groups, const lay::Technology *tech); void do_update_menu_with_macros (); void do_sync_with_external_sources (); void sync_file_watcher (); diff --git a/src/lay/lay/layMainConfigPages.cc b/src/lay/lay/layMainConfigPages.cc index d09abe1bf..081e0fe2f 100644 --- a/src/lay/lay/layMainConfigPages.cc +++ b/src/lay/lay/layMainConfigPages.cc @@ -369,6 +369,8 @@ KeyBindingsConfigPage::KeyBindingsConfigPage (QWidget *parent) connect (mp_ui->reset_pb, SIGNAL (clicked ()), this, SLOT (reset_clicked ())); mp_ui->binding_le->setEnabled (false); + mp_ui->binding_le->set_clear_button_enabled (true); + connect (mp_ui->binding_le, SIGNAL (textChanged (QString)), this, SLOT (text_changed ())); } KeyBindingsConfigPage::~KeyBindingsConfigPage () @@ -377,43 +379,34 @@ KeyBindingsConfigPage::~KeyBindingsConfigPage () mp_ui = 0; } -static void fill_paths (const lay::AbstractMenu &menu, const std::string &root, std::map &bindings) +static void fill_paths (const lay::AbstractMenu &menu, const std::string &root, std::map &bindings, bool with_defaults) { std::vector items = menu.items (root); for (std::vector::const_iterator i = items.begin (); i != items.end (); ++i) { if (i->size () > 0) { if (menu.is_valid (*i) && menu.action (*i).is_visible ()) { if (menu.is_menu (*i)) { - fill_paths (menu, *i, bindings); + fill_paths (menu, *i, bindings, with_defaults); } else if (! menu.is_separator (*i)) { - bindings.insert (std::make_pair (*i, menu.action (*i).get_shortcut ())); + bindings.insert (std::make_pair (*i, with_defaults ? menu.action (*i).get_default_shortcut () : menu.action (*i).get_shortcut ())); } } } } } -std::vector > KeyBindingsConfigPage::m_default_bindings; - -void -KeyBindingsConfigPage::set_default () -{ - std::map bm; - fill_paths (*lay::MainWindow::instance ()->menu (), std::string (), bm); - - m_default_bindings.clear (); - m_default_bindings.insert (m_default_bindings.begin (), bm.begin (), bm.end ()); -} - void KeyBindingsConfigPage::reset_clicked () { if (QMessageBox::question (this, + QObject::tr ("Confirm Reset"), QObject::tr ("Are you sure to reset the key bindings?\nThis operation will clear all custom settings."), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) { - apply (m_default_bindings); + + apply (std::vector > ()); + } } @@ -426,15 +419,23 @@ KeyBindingsConfigPage::apply (const std::vectormenu (), std::string (), m_current_bindings); + fill_paths (*lay::MainWindow::instance ()->menu (), std::string (), m_current_bindings, false); + + // get the default bindings + std::map default_bindings; + fill_paths (*lay::MainWindow::instance ()->menu (), std::string (), default_bindings, true); m_enable_event = false; - // overwrite with the given ones - for (std::vector >::const_iterator kb = key_bindings.begin (); kb != key_bindings.end (); ++kb) { - std::map::iterator cb = m_current_bindings.find (kb->first); - if (cb != m_current_bindings.end ()) { - cb->second = kb->second; + // clear bindings and initialize with the given ones + std::map b; + b.insert (key_bindings.begin (), key_bindings.end ()); + for (std::map::iterator kb = m_current_bindings.begin (); kb != m_current_bindings.end (); ++kb) { + std::map::iterator bb = b.find (kb->first); + if (bb != b.end ()) { + kb->second = bb->second; + } else { + kb->second.clear (); } } @@ -454,9 +455,19 @@ KeyBindingsConfigPage::apply (const std::vector::const_iterator cb = m_current_bindings.begin (); cb != m_current_bindings.end (); ++cb) { - std::string tl_menu; + std::map::const_iterator db = default_bindings.find (cb->first); + bool is_default = false; + + std::string sc = cb->second; + if (sc.empty () && db != default_bindings.end ()) { + sc = db->second; + is_default = true; + } + const std::string &path = cb->first; - std::string rem_path = path; + + std::string tl_menu; + std::string rem_path = path; if (path.find ("@") == 0) { size_t n = path.find ("."); if (n != std::string::npos) { @@ -470,7 +481,8 @@ KeyBindingsConfigPage::apply (const std::vectormenu ()->action (cb->first); item->setData (0, Qt::DisplayRole, tl::to_qstring (rem_path)); item->setData (1, Qt::DisplayRole, tl::to_qstring (action.get_title ())); - item->setData (2, Qt::DisplayRole, tl::to_qstring (cb->second)); + item->setData (2, Qt::DisplayRole, tl::to_qstring (sc)); + item->setData (2, Qt::ForegroundRole, palette ().color (is_default ? QPalette::Disabled : QPalette::Normal, QPalette::Text)); item->setData (0, Qt::UserRole, tl::to_qstring (path)); m_item_for_path[path] = item; if (action.qaction ()) { @@ -484,6 +496,7 @@ KeyBindingsConfigPage::apply (const std::vectorbinding_le->setText (QString ()); + mp_ui->binding_le->setPlaceholderText (QString ()); mp_ui->binding_le->setEnabled (false); m_enable_event = true; @@ -527,6 +540,54 @@ KeyBindingsConfigPage::commit (lay::PluginRoot *root) root->config_set (cfg_key_bindings, packed_key_bindings); } +void +KeyBindingsConfigPage::text_changed () +{ + if (m_enable_event) { + update_list_item (mp_ui->bindings_list->currentItem ()); + } +} + +void +KeyBindingsConfigPage::update_list_item (QTreeWidgetItem *item) +{ + if (! item || ! mp_ui->binding_le->isEnabled ()) { + return; + } + + std::string path = tl::to_string (item->data (0, Qt::UserRole).toString ()); + std::string shortcut = tl::to_string (mp_ui->binding_le->text ().simplified ()); + m_current_bindings[path] = shortcut; + + bool is_default = false; + std::string eff_shortcut = shortcut; + if (shortcut.empty ()) { + lay::Action a = lay::MainWindow::instance ()->menu ()->action (path); + eff_shortcut = a.get_default_shortcut (); + is_default = true; + } + + item->setData (2, Qt::DisplayRole, tl::to_qstring (eff_shortcut)); + item->setData (2, Qt::ForegroundRole, palette ().color (is_default ? QPalette::Disabled : QPalette::Normal, QPalette::Text)); + + // Set the aliases too + const lay::AbstractMenu &menu = *lay::MainWindow::instance ()->menu (); + if (menu.is_valid (path)) { + QAction *qaction = menu.action (path).qaction (); + std::map >::const_iterator a = m_paths_for_action.find (qaction); + if (a != m_paths_for_action.end ()) { + for (std::vector::const_iterator p = a->second.begin (); p != a->second.end (); ++p) { + m_current_bindings[*p] = shortcut; + std::map::const_iterator i = m_item_for_path.find (*p); + if (i != m_item_for_path.end ()) { + i->second->setData (2, Qt::DisplayRole, tl::to_qstring (eff_shortcut)); + i->second->setData (2, Qt::ForegroundRole, palette ().color (is_default ? QPalette::Disabled : QPalette::Normal, QPalette::Text)); + } + } + } + } +} + void KeyBindingsConfigPage::current_changed (QTreeWidgetItem *current, QTreeWidgetItem *previous) { @@ -534,41 +595,29 @@ KeyBindingsConfigPage::current_changed (QTreeWidgetItem *current, QTreeWidgetIte return; } - if (previous && mp_ui->binding_le->isEnabled ()) { + update_list_item (previous); - QKeySequence key_sequence (mp_ui->binding_le->text ()); - previous->setData (2, Qt::DisplayRole, key_sequence.toString ()); - - std::string path = tl::to_string (previous->data (0, Qt::UserRole).toString ()); - std::string shortcut = tl::to_string (previous->data (2, Qt::DisplayRole).toString ()); - - m_current_bindings[path] = shortcut; - - // Set the aliases too - const lay::AbstractMenu &menu = *lay::MainWindow::instance ()->menu (); - if (menu.is_valid (path)) { - QAction *qaction = menu.action (path).qaction (); - std::map >::const_iterator a = m_paths_for_action.find (qaction); - if (a != m_paths_for_action.end ()) { - for (std::vector::const_iterator p = a->second.begin (); p != a->second.end (); ++p) { - m_current_bindings[*p] = shortcut; - std::map::const_iterator i = m_item_for_path.find (*p); - if (i != m_item_for_path.end ()) { - i->second->setData (2, Qt::DisplayRole, tl::to_qstring (shortcut)); - } - } - } - } - - } + m_enable_event = false; if (current && !current->data (0, Qt::UserRole).isNull ()) { - mp_ui->binding_le->setText (current->data (2, Qt::DisplayRole).toString ()); + + std::string path = tl::to_string (current->data (0, Qt::UserRole).toString ()); + std::string shortcut = m_current_bindings[path]; + + lay::Action a = lay::MainWindow::instance ()->menu ()->action (path); + std::string def_shortcut = a.get_default_shortcut (); + + mp_ui->binding_le->setText (tl::to_qstring (shortcut)); + mp_ui->binding_le->setPlaceholderText (tl::to_qstring (def_shortcut)); mp_ui->binding_le->setEnabled (true); + } else { mp_ui->binding_le->setText (QString ()); + mp_ui->binding_le->setPlaceholderText (QString ()); mp_ui->binding_le->setEnabled (false); } + + m_enable_event = true; } } diff --git a/src/lay/lay/layMainConfigPages.h b/src/lay/lay/layMainConfigPages.h index da1e0037d..21c3719ef 100644 --- a/src/lay/lay/layMainConfigPages.h +++ b/src/lay/lay/layMainConfigPages.h @@ -184,10 +184,9 @@ public: virtual void setup (lay::PluginRoot *root); virtual void commit (lay::PluginRoot *root); - static void set_default (); - -public slots: +private slots: void current_changed (QTreeWidgetItem *current, QTreeWidgetItem *previous); + void text_changed (); void reset_clicked (); private: @@ -196,9 +195,9 @@ private: std::map m_item_for_path; std::map > m_paths_for_action; bool m_enable_event; - static std::vector > m_default_bindings; void apply (const std::vector > &bindings); + void update_list_item (QTreeWidgetItem *item); }; } diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index 7e5a9f17a..6fccaaa52 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -1032,7 +1032,7 @@ MainWindow::init_menu () title = tab + 1; } - Action action (AbstractMenu::create_action (title)); + Action action (title); action.set_checkable (true); action.qaction ()->setData (QVariant (mode_id)); action.add_to_exclusive_group (mp_menu, "mouse_mode_exclusive_group"); @@ -1078,9 +1078,6 @@ MainWindow::init_menu () for (std::vector::const_iterator g = view_mode_grp.begin (); g != view_mode_grp.end (); ++g) { mp_menu->action (*g).set_visible (view_mode); } - - // get and store the initial (default) key bindings for restore in the setup dialog - KeyBindingsConfigPage::set_default (); } void @@ -4930,7 +4927,7 @@ MainWindow::action_for_slot (const char *slot) if (a != m_actions_for_slot.end ()) { return a->second; } else { - Action a (new ActionHandle (this)); + Action a = Action::create_free_action (this); gtf::action_connect (a.qaction (), SIGNAL (triggered ()), this, slot); return m_actions_for_slot.insert (std::make_pair (std::string (slot), a)).first->second; } diff --git a/src/laybasic/laybasic/layAbstractMenu.cc b/src/laybasic/laybasic/layAbstractMenu.cc index c11c199b1..c1338f9b1 100644 --- a/src/laybasic/laybasic/layAbstractMenu.cc +++ b/src/laybasic/laybasic/layAbstractMenu.cc @@ -239,7 +239,9 @@ public: ActionHandle::ActionHandle (QWidget *parent) : mp_action (new ActionObject (parent)), m_ref_count (0), - m_owned (true) + m_owned (true), + m_visible (true), + m_hidden (false) { if (! sp_actionHandles) { sp_actionHandles = new std::set (); @@ -253,7 +255,9 @@ ActionHandle::ActionHandle (QWidget *parent) ActionHandle::ActionHandle (QAction *action, bool owned) : mp_action (action), m_ref_count (0), - m_owned (owned) + m_owned (owned), + m_visible (true), + m_hidden (false) { if (! sp_actionHandles) { sp_actionHandles = new std::set (); @@ -310,6 +314,89 @@ ActionHandle::destroyed (QObject * /*obj*/) m_owned = false; } +void +ActionHandle::set_visible (bool v) +{ + if (m_visible != v) { + m_visible = v; + if (mp_action) { + mp_action->setVisible (is_effective_visible ()); + } + } +} + +void +ActionHandle::set_hidden (bool h) +{ + if (m_hidden != h) { + m_hidden = h; + if (mp_action) { + mp_action->setVisible (is_effective_visible ()); + } + } +} + +bool +ActionHandle::is_visible () const +{ + return m_visible; +} + +bool +ActionHandle::is_hidden () const +{ + return m_hidden; +} + +bool +ActionHandle::is_effective_visible () const +{ + return m_visible && !m_hidden; +} + +void +ActionHandle::set_default_shortcut (const QKeySequence &sc) +{ + if (m_default_shortcut != sc) { + m_default_shortcut = sc; + if (mp_action) { + mp_action->setShortcut (get_effective_shortcut ()); + } + } +} + +void +ActionHandle::set_shortcut (const QKeySequence &sc) +{ + if (m_shortcut != sc) { + m_shortcut = sc; + if (mp_action) { + mp_action->setShortcut (get_effective_shortcut ()); + } + } +} + +const QKeySequence & +ActionHandle::get_default_shortcut () const +{ + return m_default_shortcut; +} + +const QKeySequence & +ActionHandle::get_shortcut () const +{ + return m_shortcut; +} + +QKeySequence +ActionHandle::get_effective_shortcut () const +{ + if (m_shortcut.isEmpty ()) { + return m_default_shortcut; + } else { + return m_shortcut; + } +} // --------------------------------------------------------------- // Action implementation @@ -338,6 +425,12 @@ Action::Action (ActionHandle *handle) mp_handle->add_ref (); } +Action +Action::create_free_action (QWidget *parent) +{ + return Action (new ActionHandle (parent)); +} + Action::Action (const Action &action) : QObject () { @@ -422,24 +515,56 @@ Action::get_title () const void Action::set_shortcut (const QKeySequence &s) { - if (qaction ()) { - qaction ()->setShortcut (s); + if (mp_handle) { + mp_handle->set_shortcut (s); } } -void +void +Action::set_default_shortcut (const QKeySequence &s) +{ + if (mp_handle) { + mp_handle->set_default_shortcut (s); + } +} + +void Action::set_shortcut (const std::string &s) { - if (qaction () && s != get_shortcut ()) { - qaction ()->setShortcut (QKeySequence (tl::to_qstring (s))); + set_shortcut (QKeySequence (tl::to_qstring (s))); +} + +void +Action::set_default_shortcut (const std::string &s) +{ + set_default_shortcut (QKeySequence (tl::to_qstring (s))); +} + +std::string +Action::get_effective_shortcut () const +{ + if (mp_handle) { + return tl::to_string (mp_handle->get_effective_shortcut ().toString ()); + } else { + return std::string (); } } -std::string +std::string Action::get_shortcut () const { - if (qaction ()) { - return tl::to_string (qaction ()->shortcut ().toString ()); + if (mp_handle) { + return tl::to_string (mp_handle->get_shortcut ().toString ()); + } else { + return std::string (); + } +} + +std::string +Action::get_default_shortcut () const +{ + if (mp_handle) { + return tl::to_string (mp_handle->get_default_shortcut ().toString ()); } else { return std::string (); } @@ -478,7 +603,19 @@ Action::is_enabled () const bool Action::is_visible () const { - return qaction () && qaction ()->isVisible (); + return mp_handle && mp_handle->is_visible (); +} + +bool +Action::is_hidden () const +{ + return mp_handle && mp_handle->is_hidden (); +} + +bool +Action::is_effective_visible () const +{ + return mp_handle && mp_handle->is_effective_visible (); } bool @@ -498,8 +635,16 @@ Action::set_enabled (bool b) void Action::set_visible (bool v) { - if (qaction ()) { - qaction ()->setVisible (v); + if (mp_handle) { + mp_handle->set_visible (v); + } +} + +void +Action::set_hidden (bool h) +{ + if (mp_handle) { + mp_handle->set_hidden (h); } } @@ -705,7 +850,7 @@ AbstractMenu::create_action (const std::string &s) } if (! shortcut.empty ()) { - ah->ptr ()->setShortcut (QKeySequence (tl::to_qstring (shortcut))); + ah->set_default_shortcut (QKeySequence (tl::to_qstring (shortcut))); } return ah; @@ -1036,7 +1181,7 @@ AbstractMenu::insert_menu (const std::string &p, const std::string &name, const void AbstractMenu::insert_menu (const std::string &path, const std::string &name, const std::string &title) { - insert_menu (path, name, Action (create_action (title))); + insert_menu (path, name, create_action (title)); } void @@ -1324,7 +1469,7 @@ AbstractMenu::transfer (const MenuLayoutEntry *layout, AbstractMenuItem &item) a.set_title (title); if (! shortcut.empty ()) { - a.set_shortcut (QKeySequence (tl::to_qstring (shortcut))); + a.set_default_shortcut (shortcut); } if (! tool_tip.empty ()) { diff --git a/src/laybasic/laybasic/layAbstractMenu.h b/src/laybasic/laybasic/layAbstractMenu.h index 171b70982..e5ece7024 100644 --- a/src/laybasic/laybasic/layAbstractMenu.h +++ b/src/laybasic/laybasic/layAbstractMenu.h @@ -57,7 +57,7 @@ class PluginRoot; /** * @brief A helper class that does reference counting for the QAction object */ -class LAYBASIC_PUBLIC ActionHandle +class ActionHandle : public QObject { Q_OBJECT @@ -70,6 +70,18 @@ public: void remove_ref (); QAction *ptr () const; + void set_visible (bool v); + void set_hidden (bool h); + bool is_visible () const; + bool is_hidden () const; + bool is_effective_visible () const; + + void set_default_shortcut (const QKeySequence &sc); + void set_shortcut (const QKeySequence &sc); + const QKeySequence &get_default_shortcut () const; + const QKeySequence &get_shortcut () const; + QKeySequence get_effective_shortcut () const; + protected slots: void destroyed (QObject *obj); @@ -77,6 +89,10 @@ private: QAction *mp_action; int m_ref_count; bool m_owned; + bool m_visible; + bool m_hidden; + QKeySequence m_default_shortcut; + QKeySequence m_shortcut; // no copying ActionHandle (const ActionHandle &); @@ -125,20 +141,18 @@ public: */ Action (const std::string &title); + /** + * @brief Creates a new free action + * This constructor wil create a new action with it's own QAction object + * under the given parent. + */ + static Action create_free_action (QWidget *parent); + /** * @brief Assignement */ Action &operator= (const Action &action); - /** - * @brief The proxy constructor - * - * This constructor takes a QAction object that it will refer to. - * If the Action is copied, the copy will refer to the same QAction. - * The QAction object is deleted if the last Action referring to QAction is deleted. - */ - Action (ActionHandle *action); - /** * @brief The destructor */ @@ -155,20 +169,48 @@ public: std::string get_title () const; /** - * @brief Set the keyboard shortcut (as a QKeySequence object) + * @brief Sets the keyboard shortcut (as a QKeySequence object) + * If no shortcut is set, the default shortcut will be taken. */ void set_shortcut (const QKeySequence &s); /** - * @brief Set the keyboard shortcut + * @brief Sets the keyboard shortcut + * If no shortcut is set, the default shortcut will be taken. */ void set_shortcut (const std::string &s); /** - * @brief Get the keyboard shortcut + * @brief Gets the keyboard shortcut + * To get the effective shortcut (combination of default shortcut and shortcut), + * use "get_effective_shortcut". */ std::string get_shortcut () const; + /** + * @brief Sets the default keyboard shortcut (as a QKeySequence object) + * This shortcut is used when no specific shortcut is set. + */ + void set_default_shortcut (const QKeySequence &s); + + /** + * @brief Sets the default keyboard shortcut + * This shortcut is used when no specific shortcut is set. + */ + void set_default_shortcut (const std::string &s); + + /** + * @brief Gets the default keyboard shortcut + * To get the effective shortcut (combination of default shortcut and shortcut), + * use "get_effective_shortcut". + */ + std::string get_default_shortcut () const; + + /** + * @brief Gets the effective shortcut + */ + std::string get_effective_shortcut () const; + /** * @brief "is_checkable" attribute */ @@ -189,6 +231,20 @@ public: */ bool is_visible () const; + /** + * @brief Gets a value indicating whether the action is intentionally hidden + * This flag combines with the visibility. "is_effective_visible" is false + * if hidden is true. This feature allows implementation of the menu configuration + * feature where users can deliberately switch off and on menu items. + */ + bool is_hidden () const; + + /** + * @brief Gets the effective visibility + * See "is_hidden" for details. + */ + bool is_effective_visible () const; + /** * @brief "is_separator" attribute */ @@ -204,6 +260,12 @@ public: */ void set_visible (bool v); + /** + * @brief Sets a value indicating whether the menu item is hidden + * See "is_hidden" for details. + */ + void set_hidden (bool h); + /** * @brief Make checkable or not */ @@ -295,7 +357,18 @@ public slots: void triggered_slot (); private: + friend class AbstractMenu; + ActionHandle *mp_handle; + + /** + * @brief The proxy constructor + * + * This constructor takes a QAction object that it will refer to. + * If the Action is copied, the copy will refer to the same QAction. + * The QAction object is deleted if the last Action referring to QAction is deleted. + */ + Action (ActionHandle *action); }; /** @@ -738,17 +811,6 @@ public: */ QMenu *detached_menu (const std::string &name); - /** - * @brief Create a action from a string - * - * The format of the string is: ["("shortcut")"]["<"icon-resource">"] - * - * @param s The title, key and icon resource string in the format given above - * @param parent The widget to which to attach the QAction object - * @return The ActionHandle object created - */ - static ActionHandle *create_action (const std::string &s); - /** * @brief Creates a new exclusive action group * @@ -772,7 +834,9 @@ signals: */ void changed (); -private: +private: + friend class Action; + std::vector::iterator> > find_item (const std::string &path); const AbstractMenuItem *find_item_exact (const std::string &path) const; AbstractMenuItem *find_item_exact (const std::string &path); @@ -782,6 +846,17 @@ private: void collect_group (std::vector &grp, const std::string &name, const AbstractMenuItem &item) const; void reset_menu_objects (AbstractMenuItem &item); + /** + * @brief Create a action from a string + * + * The format of the string is: ["("shortcut")"]["<"icon-resource">"] + * + * @param s The title, key and icon resource string in the format given above + * @param parent The widget to which to attach the QAction object + * @return The ActionHandle object created + */ + static ActionHandle *create_action (const std::string &s); + AbstractMenuProvider *mp_provider; AbstractMenuItem m_root; tl::stable_vector m_helper_menu_items; diff --git a/src/laybasic/laybasic/layPlugin.cc b/src/laybasic/laybasic/layPlugin.cc index 15660e123..173ddb089 100644 --- a/src/laybasic/laybasic/layPlugin.cc +++ b/src/laybasic/laybasic/layPlugin.cc @@ -139,7 +139,7 @@ PluginDeclaration::init_menu () title = tab + 1; } - m_editable_mode_action = AbstractMenu::create_action (title); + m_editable_mode_action = Action (title); gtf::action_connect (m_editable_mode_action.qaction (), SIGNAL (triggered ()), this, SLOT (toggle_editable_enabled ())); m_editable_mode_action.qaction ()->setData (id ()); m_editable_mode_action.set_checkable (true); @@ -163,7 +163,7 @@ PluginDeclaration::init_menu () menu.insert_menu (m->insert_pos, m->menu_name, m->title); } else { - Action action (AbstractMenu::create_action (m->title)); + Action action (m->title); action.qaction ()->setData (QVariant (tl::to_qstring (m->symbol))); gtf::action_connect (action.qaction (), SIGNAL (triggered ()), this, SLOT (generic_menu ())); menu.insert_item (m->insert_pos, m->menu_name, action); @@ -189,7 +189,7 @@ PluginDeclaration::init_menu () title = std::string (tab + 1); } - m_mouse_mode_action = AbstractMenu::create_action (title); + m_mouse_mode_action = Action (title); m_mouse_mode_action.add_to_exclusive_group (&menu, "mouse_mode_exclusive_group"); m_mouse_mode_action.set_checkable (true);