mirror of https://github.com/KLayout/klayout.git
New feature: allow group generation in menu paths.
This commit is contained in:
parent
ba7e9da5a6
commit
4cbfec9c35
|
|
@ -19,15 +19,49 @@
|
|||
|
||||
<p>
|
||||
The menu path specifies the position where the macro shall be put. A macro path is a
|
||||
sequence of symbolic names separated by a dot. For example "edit_menu.end" is the end
|
||||
of the "Edit" menu and "edit_menu.undo" is the "Undo" entry in the "Edit" menu. To obtain
|
||||
a list of the paths available, have a look at the "Key Bindings" page in the "Application"
|
||||
section of the setup dialog ("File/Setup"). The pseudo element "end" denotes the position
|
||||
after the last entry. The same way "begin" indicates the first entry in the menu.
|
||||
The macro will be inserted before the entry indicated by the path. Hence the if a
|
||||
path of "edit_menu.end" is given, the macro will be inserted at the end of the
|
||||
"Edit" menu and "edit_menu.undo" will insert the macro before the "Undo" entry.
|
||||
sequence of symbolic names separated by a dot. For example:
|
||||
</p>
|
||||
|
||||
<li>
|
||||
<ul><tt>edit_menu.end</tt> is the end of the "Edit" menu </ul>
|
||||
<ul><tt>edit_menu.undo</tt> is the "Undo" entry in the "Edit" menu</ul>
|
||||
</li>
|
||||
|
||||
<p>To obtain
|
||||
a list of the paths available, have a look at the "Key Bindings" page in the "Application"
|
||||
section of the setup dialog ("File/Setup").
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The pseudo element "end" denotes the position
|
||||
after the last entry. The same way "begin" indicates the first entry in the menu.
|
||||
The macro will be inserted before the entry indicated by the path. Hence:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><tt>edit_menu.end</tt>: the macro will be inserted at the end of the "Edit" menu</li>
|
||||
<li><tt>edit_menu.undo</tt>: the macro will be inserted before the "Undo" entry.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
If a plus sign follows the macro path element, the new element is inserted <b>after</b>
|
||||
this element. For example:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><tt>edit_menu.undo+</tt>: the macro will be inserted after the "Undo" menu item.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
A special form can be used to generate new groups: if the given element does not exist,
|
||||
the menu generator can be instructed to create it by appending the insert point plus
|
||||
the new text string to the element after a ">" character. For example:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><tt>edit_menu.my_group>end("My Edit Functions").end</tt>: will look for "my_group" and add the new element at the end of this group. If no such
|
||||
group exists, it will be created at the end of the "Edit" menu with the title "My Edit Functions".</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
If no macro path is specified, the macro is inserted in the "Macros" menu.
|
||||
|
|
|
|||
|
|
@ -101,13 +101,13 @@ parse_menu_title (const std::string &s, std::string &title, std::string &shortcu
|
|||
// AbstractMenuItem implementation
|
||||
|
||||
AbstractMenuItem::AbstractMenuItem ()
|
||||
: mp_menu (0), m_has_submenu (false)
|
||||
: mp_menu (0), m_has_submenu (false), m_remove_on_empty (false)
|
||||
{
|
||||
// ... nothing yet ..
|
||||
}
|
||||
|
||||
AbstractMenuItem::AbstractMenuItem (const AbstractMenuItem &)
|
||||
: mp_menu (0), m_has_submenu (false)
|
||||
: mp_menu (0), m_has_submenu (false), m_remove_on_empty (false)
|
||||
{
|
||||
// ... nothing yet ..
|
||||
}
|
||||
|
|
@ -173,7 +173,13 @@ AbstractMenuItem::set_has_submenu ()
|
|||
m_has_submenu = true;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenuItem::set_remove_on_empty ()
|
||||
{
|
||||
m_remove_on_empty = true;
|
||||
}
|
||||
|
||||
void
|
||||
AbstractMenuItem::set_menu (QMenu *menu)
|
||||
{
|
||||
mp_menu = menu;
|
||||
|
|
@ -708,7 +714,7 @@ AbstractMenu::create_action (const std::string &s)
|
|||
AbstractMenu::AbstractMenu (AbstractMenuProvider *provider)
|
||||
: mp_provider (provider)
|
||||
{
|
||||
tl_assert (mp_provider != 0);
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
AbstractMenu::~AbstractMenu ()
|
||||
|
|
@ -777,6 +783,8 @@ AbstractMenu::build_detached (const std::string &name, QMenuBar *mbar)
|
|||
void
|
||||
AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
|
||||
{
|
||||
tl_assert (mp_provider != 0);
|
||||
|
||||
m_helper_menu_items.clear ();
|
||||
mbar->clear ();
|
||||
tbar->clear ();
|
||||
|
|
@ -942,23 +950,27 @@ AbstractMenu::items (const std::string &path) const
|
|||
}
|
||||
|
||||
void
|
||||
AbstractMenu::insert_item (const std::string &path, const std::string &name, const Action &action)
|
||||
AbstractMenu::insert_item (const std::string &p, const std::string &name, const Action &action)
|
||||
{
|
||||
std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator > ins = find_item (path);
|
||||
if (ins.first) {
|
||||
typedef std::vector<std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator > > path_type;
|
||||
path_type path = find_item (p);
|
||||
if (! path.empty ()) {
|
||||
|
||||
AbstractMenuItem *parent = path.back ().first;
|
||||
std::list<AbstractMenuItem>::iterator iter = path.back ().second;
|
||||
|
||||
// insert the new item
|
||||
ins.first->children.insert (ins.second, AbstractMenuItem ());
|
||||
--ins.second;
|
||||
parent->children.insert (iter, AbstractMenuItem ());
|
||||
--iter;
|
||||
|
||||
ins.second->setup_item (ins.first->name (), name, action);
|
||||
iter->setup_item (parent->name (), name, action);
|
||||
|
||||
// find an item with the same name and remove it
|
||||
for (std::list<AbstractMenuItem>::iterator existing = ins.first->children.begin (); existing != ins.first->children.end (); ) {
|
||||
// find any items with the same name and remove them
|
||||
for (std::list<AbstractMenuItem>::iterator existing = parent->children.begin (); existing != parent->children.end (); ) {
|
||||
std::list<AbstractMenuItem>::iterator existing_next = existing;
|
||||
++existing_next;
|
||||
if (existing->name () == ins.second->name () && &*existing != &*ins.second) {
|
||||
ins.first->children.erase (existing);
|
||||
if (existing->name () == iter->name () && existing != iter) {
|
||||
parent->children.erase (existing);
|
||||
}
|
||||
existing = existing_next;
|
||||
}
|
||||
|
|
@ -969,29 +981,55 @@ AbstractMenu::insert_item (const std::string &path, const std::string &name, con
|
|||
}
|
||||
|
||||
void
|
||||
AbstractMenu::insert_separator (const std::string &path, const std::string &name)
|
||||
AbstractMenu::insert_separator (const std::string &p, const std::string &name)
|
||||
{
|
||||
std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator > ins = find_item (path);
|
||||
if (ins.first) {
|
||||
ins.first->children.insert (ins.second, AbstractMenuItem ());
|
||||
--ins.second;
|
||||
tl_assert (mp_provider != 0); // required to get the parent for the new QAction (via ActionHandle)
|
||||
|
||||
typedef std::vector<std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator > > path_type;
|
||||
path_type path = find_item (p);
|
||||
if (! path.empty ()) {
|
||||
|
||||
AbstractMenuItem *parent = path.back ().first;
|
||||
std::list<AbstractMenuItem>::iterator iter = path.back ().second;
|
||||
|
||||
parent->children.insert (iter, AbstractMenuItem ());
|
||||
--iter;
|
||||
Action action (new ActionHandle (mp_provider->menu_parent_widget ()));
|
||||
action.set_separator (true);
|
||||
ins.second->setup_item (ins.first->name (), name, action);
|
||||
iter->setup_item (parent->name (), name, action);
|
||||
|
||||
}
|
||||
|
||||
emit changed ();
|
||||
}
|
||||
|
||||
void
|
||||
AbstractMenu::insert_menu (const std::string &path, const std::string &name, const Action &action)
|
||||
AbstractMenu::insert_menu (const std::string &p, const std::string &name, const Action &action)
|
||||
{
|
||||
std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator > ins = find_item (path);
|
||||
if (ins.first) {
|
||||
ins.first->children.insert (ins.second, AbstractMenuItem ());
|
||||
--ins.second;
|
||||
ins.second->setup_item (ins.first->name (), name, action);
|
||||
ins.second->set_has_submenu ();
|
||||
typedef std::vector<std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator > > path_type;
|
||||
path_type path = find_item (p);
|
||||
if (! path.empty ()) {
|
||||
|
||||
AbstractMenuItem *parent = path.back ().first;
|
||||
std::list<AbstractMenuItem>::iterator iter = path.back ().second;
|
||||
|
||||
parent->children.insert (iter, AbstractMenuItem ());
|
||||
--iter;
|
||||
iter->setup_item (parent->name (), name, action);
|
||||
iter->set_has_submenu ();
|
||||
|
||||
// find any items with the same name and remove them
|
||||
for (std::list<AbstractMenuItem>::iterator existing = parent->children.begin (); existing != parent->children.end (); ) {
|
||||
std::list<AbstractMenuItem>::iterator existing_next = existing;
|
||||
++existing_next;
|
||||
if (existing->name () == iter->name () && existing != iter) {
|
||||
parent->children.erase (existing);
|
||||
}
|
||||
existing = existing_next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
emit changed ();
|
||||
}
|
||||
|
||||
|
|
@ -1002,28 +1040,43 @@ AbstractMenu::insert_menu (const std::string &path, const std::string &name, con
|
|||
}
|
||||
|
||||
void
|
||||
AbstractMenu::delete_item (const std::string &path)
|
||||
AbstractMenu::delete_item (const std::string &p)
|
||||
{
|
||||
std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator > ins = find_item (path);
|
||||
if (ins.first) {
|
||||
if (ins.second == ins.first->children.end ()) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("delete_item cannot delete past-the-end item")));
|
||||
typedef std::vector<std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator > > path_type;
|
||||
path_type path = find_item (p);
|
||||
if (! path.empty ()) {
|
||||
|
||||
for (path_type::const_reverse_iterator p = path.rbegin (); p != path.rend (); ++p) {
|
||||
|
||||
if (p->second == p->first->children.end ()) {
|
||||
break;
|
||||
} else if (p != path.rbegin () && (! p->second->remove_on_empty () || ! p->second->children.empty ())) {
|
||||
// stop on non-empty parent menues
|
||||
break;
|
||||
}
|
||||
|
||||
reset_menu_objects (*p->second);
|
||||
p->first->children.erase (p->second);
|
||||
|
||||
}
|
||||
reset_menu_objects (*ins.second);
|
||||
ins.first->children.erase (ins.second);
|
||||
|
||||
}
|
||||
|
||||
emit changed ();
|
||||
}
|
||||
|
||||
static void do_delete_items (std::list<AbstractMenuItem> &list, const Action &action)
|
||||
static void do_delete_items (AbstractMenuItem &parent, const Action &action)
|
||||
{
|
||||
for (std::list<AbstractMenuItem>::iterator l = list.begin (); l != list.end (); ) {
|
||||
for (std::list<AbstractMenuItem>::iterator l = parent.children.begin (); l != parent.children.end (); ) {
|
||||
std::list<AbstractMenuItem>::iterator ll = l;
|
||||
++ll;
|
||||
if (l->action () == action) {
|
||||
list.erase (l);
|
||||
parent.children.erase (l);
|
||||
} else {
|
||||
do_delete_items (l->children, action);
|
||||
do_delete_items (*l, action);
|
||||
if (l->remove_on_empty () && l->children.empty ()) {
|
||||
parent.children.erase (l);
|
||||
}
|
||||
}
|
||||
l = ll;
|
||||
}
|
||||
|
|
@ -1032,7 +1085,7 @@ static void do_delete_items (std::list<AbstractMenuItem> &list, const Action &ac
|
|||
void
|
||||
AbstractMenu::delete_items (const Action &action)
|
||||
{
|
||||
do_delete_items (m_root.children, action);
|
||||
do_delete_items (m_root, action);
|
||||
emit changed ();
|
||||
}
|
||||
|
||||
|
|
@ -1099,14 +1152,17 @@ AbstractMenu::find_item_exact (const std::string &path)
|
|||
return item;
|
||||
}
|
||||
|
||||
std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator>
|
||||
AbstractMenu::find_item (const std::string &path)
|
||||
std::vector<std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator> >
|
||||
AbstractMenu::find_item (const std::string &p)
|
||||
{
|
||||
tl::Extractor extr (path.c_str ());
|
||||
typedef std::vector<std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator> > path_type;
|
||||
path_type path;
|
||||
|
||||
tl::Extractor extr (p.c_str ());
|
||||
AbstractMenuItem *parent = &m_root;
|
||||
std::list<AbstractMenuItem>::iterator iter = m_root.children.end ();
|
||||
|
||||
while (true) {
|
||||
while (parent && ! extr.at_end ()) {
|
||||
|
||||
if (extr.test ("#")) {
|
||||
|
||||
|
|
@ -1118,70 +1174,119 @@ AbstractMenu::find_item (const std::string &path)
|
|||
++iter;
|
||||
}
|
||||
if (n > 0) {
|
||||
return std::make_pair ((AbstractMenuItem *) 0, m_root.children.end ());
|
||||
return path_type ();
|
||||
}
|
||||
|
||||
} else if (extr.test ("begin")) {
|
||||
|
||||
iter = parent->children.begin ();
|
||||
|
||||
} else if (extr.test ("end")) {
|
||||
|
||||
iter = parent->children.end ();
|
||||
|
||||
} else {
|
||||
|
||||
std::string n;
|
||||
extr.read (n, ".+");
|
||||
std::string n, nn;
|
||||
|
||||
if (n == "begin") {
|
||||
return std::make_pair (parent, parent->children.begin ());
|
||||
} else if (n == "end") {
|
||||
return std::make_pair (parent, parent->children.end ());
|
||||
extr.read (n, ".+>(");
|
||||
|
||||
if (extr.test (">")) {
|
||||
extr.read (nn, ".+>(");
|
||||
}
|
||||
|
||||
std::string name (parent->name ());
|
||||
if (! name.empty ()) {
|
||||
name += ".";
|
||||
}
|
||||
|
||||
std::string nname;
|
||||
nname = name + nn;
|
||||
name += n;
|
||||
|
||||
bool after = extr.test ("+");
|
||||
|
||||
std::string ndesc;
|
||||
if (! nn.empty () && extr.test ("(")) {
|
||||
extr.read_word_or_quoted (ndesc, " _.$");
|
||||
extr.test (")");
|
||||
}
|
||||
|
||||
AbstractMenuItem *p = parent;
|
||||
parent = 0;
|
||||
|
||||
// Look for the next path item
|
||||
for (std::list<AbstractMenuItem>::iterator c = p->children.begin (); c != p->children.end (); ++c) {
|
||||
|
||||
if (c->name () == name) {
|
||||
|
||||
if (after) {
|
||||
if (after && nn.empty ()) {
|
||||
++c;
|
||||
if (c == p->children.end ()) {
|
||||
return std::make_pair (parent, parent->children.end ());
|
||||
}
|
||||
}
|
||||
|
||||
parent = p;
|
||||
iter = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If that's not found, check whether we are supposed to create one:
|
||||
// identify the insert position and create a new entry there.
|
||||
if (! parent && ! nn.empty ()) {
|
||||
|
||||
if (nn == "begin") {
|
||||
parent = p;
|
||||
iter = parent->children.begin ();
|
||||
} else if (nn == "end") {
|
||||
parent = p;
|
||||
iter = parent->children.end ();
|
||||
} else {
|
||||
for (std::list<AbstractMenuItem>::iterator c = p->children.begin (); c != p->children.end (); ++c) {
|
||||
if (c->name () == nname) {
|
||||
if (after) {
|
||||
++c;
|
||||
}
|
||||
parent = p;
|
||||
iter = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
parent->children.insert (iter, AbstractMenuItem ());
|
||||
--iter;
|
||||
iter->setup_item (parent->name (), n, Action ());
|
||||
iter->set_has_submenu ();
|
||||
iter->set_remove_on_empty ();
|
||||
iter->set_action_title (ndesc.empty () ? n : ndesc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! parent) {
|
||||
return std::make_pair ((AbstractMenuItem *) 0, m_root.children.end ());
|
||||
return path_type ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (extr.at_end ()) {
|
||||
return std::make_pair (parent, iter);
|
||||
}
|
||||
path.push_back (std::make_pair (parent, iter));
|
||||
|
||||
extr.test (".");
|
||||
|
||||
parent = &*iter;
|
||||
if (iter == parent->children.end ()) {
|
||||
parent = 0;
|
||||
} else {
|
||||
parent = iter.operator-> ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void
|
||||
AbstractMenu::transfer (const MenuLayoutEntry *layout, AbstractMenuItem &item)
|
||||
{
|
||||
tl_assert (mp_provider != 0);
|
||||
|
||||
while (layout->name) {
|
||||
|
||||
item.children.push_back (AbstractMenuItem ());
|
||||
|
|
|
|||
|
|
@ -505,11 +505,19 @@ struct LAYBASIC_PUBLIC AbstractMenuItem
|
|||
return m_has_submenu;
|
||||
}
|
||||
|
||||
void set_remove_on_empty ();
|
||||
|
||||
bool remove_on_empty () const
|
||||
{
|
||||
return m_remove_on_empty;
|
||||
}
|
||||
|
||||
std::list <AbstractMenuItem> children;
|
||||
|
||||
private:
|
||||
QMenu *mp_menu;
|
||||
bool m_has_submenu;
|
||||
bool m_remove_on_empty;
|
||||
Action m_action;
|
||||
std::string m_name;
|
||||
std::string m_basename;
|
||||
|
|
@ -750,6 +758,14 @@ public:
|
|||
*/
|
||||
QActionGroup *make_exclusive_group (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Gets the root node of the menu
|
||||
*/
|
||||
const AbstractMenuItem &root () const
|
||||
{
|
||||
return m_root;
|
||||
}
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief this signal is emitted whenever something changes on the menu
|
||||
|
|
@ -757,7 +773,7 @@ signals:
|
|||
void changed ();
|
||||
|
||||
private:
|
||||
std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator> find_item (const std::string &path);
|
||||
std::vector<std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::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);
|
||||
void transfer (const MenuLayoutEntry *layout, AbstractMenuItem &item);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,128 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2017 Matthias Koefferlein
|
||||
|
||||
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 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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "layAbstractMenu.h"
|
||||
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
std::string node_to_string (const lay::AbstractMenuItem &item)
|
||||
{
|
||||
std::string s = item.name ();
|
||||
if (! item.children.empty ()) {
|
||||
s += "(";
|
||||
for (std::list<lay::AbstractMenuItem>::const_iterator c = item.children.begin (); c != item.children.end (); ++c) {
|
||||
if (c != item.children.begin ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += node_to_string (*c);
|
||||
}
|
||||
s += ")";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string menu_to_string (const lay::AbstractMenu &menu)
|
||||
{
|
||||
return node_to_string (menu.root ());
|
||||
}
|
||||
|
||||
TEST(1)
|
||||
{
|
||||
lay::AbstractMenu menu (0);
|
||||
EXPECT_EQ (menu_to_string (menu), "");
|
||||
|
||||
try {
|
||||
EXPECT_EQ (menu.action ("n1").get_title (), "");
|
||||
EXPECT_EQ (true, false);
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
EXPECT_EQ (menu.is_valid ("n1"), false);
|
||||
|
||||
menu.insert_menu ("end", "n1", lay::Action ("title:n1"));
|
||||
EXPECT_EQ (menu_to_string (menu), "(n1)");
|
||||
EXPECT_EQ (tl::join (menu.items (""), ","), "n1");
|
||||
EXPECT_EQ (menu.is_menu ("n1"), true);
|
||||
EXPECT_EQ (menu.action ("n1").get_title (), "title:n1");
|
||||
|
||||
EXPECT_EQ (menu.is_valid ("n1"), true);
|
||||
EXPECT_EQ (menu.is_valid ("n2"), false);
|
||||
|
||||
menu.insert_menu ("end", "n2", lay::Action ("title:n2"));
|
||||
EXPECT_EQ (menu_to_string (menu), "(n1,n2)");
|
||||
EXPECT_EQ (tl::join (menu.items (""), ","), "n1,n2");
|
||||
EXPECT_EQ (menu.is_menu ("n2"), true);
|
||||
EXPECT_EQ (menu.action ("n2").get_title (), "title:n2");
|
||||
|
||||
EXPECT_EQ (menu.is_valid ("n2"), true);
|
||||
|
||||
menu.insert_menu ("end", "n1", lay::Action ("title:n1"));
|
||||
EXPECT_EQ (menu_to_string (menu), "(n2,n1)");
|
||||
EXPECT_EQ (menu.is_menu ("n1"), true);
|
||||
EXPECT_EQ (menu.action ("n1").get_title (), "title:n1");
|
||||
|
||||
menu.insert_item ("n1.begin", "c1", lay::Action ("title:c1"));
|
||||
EXPECT_EQ (menu_to_string (menu), "(n2,n1(n1.c1))");
|
||||
EXPECT_EQ (tl::join (menu.items ("n1"), ","), "n1.c1");
|
||||
EXPECT_EQ (menu.action ("n1.c1").get_title (), "title:c1");
|
||||
|
||||
menu.insert_item ("n1.end", "c2", lay::Action ("title:c2"));
|
||||
EXPECT_EQ (menu_to_string (menu), "(n2,n1(n1.c1,n1.c2))");
|
||||
EXPECT_EQ (tl::join (menu.items ("n1"), ","), "n1.c1,n1.c2");
|
||||
EXPECT_EQ (menu.is_menu ("n1.c2"), false);
|
||||
EXPECT_EQ (menu.action ("n1.c2").get_title (), "title:c2");
|
||||
|
||||
menu.insert_item ("n1.begin", "c1", lay::Action ("title:c1a"));
|
||||
EXPECT_EQ (menu_to_string (menu), "(n2,n1(n1.c1,n1.c2))");
|
||||
EXPECT_EQ (tl::join (menu.items ("n1"), ","), "n1.c1,n1.c2");
|
||||
EXPECT_EQ (menu.action ("n1.c1").get_title (), "title:c1a");
|
||||
|
||||
menu.insert_item ("n1.c1", "c3", lay::Action ("title:c3"));
|
||||
EXPECT_EQ (menu_to_string (menu), "(n2,n1(n1.c3,n1.c1,n1.c2))");
|
||||
|
||||
menu.insert_item ("n1.c1+", "c4", lay::Action ("title:c4"));
|
||||
EXPECT_EQ (menu_to_string (menu), "(n2,n1(n1.c3,n1.c1,n1.c4,n1.c2))");
|
||||
EXPECT_EQ (menu.action ("n1.c4").get_title (), "title:c4");
|
||||
|
||||
menu.delete_item ("n1.c1");
|
||||
EXPECT_EQ (menu_to_string (menu), "(n2,n1(n1.c3,n1.c4,n1.c2))");
|
||||
|
||||
menu.delete_item ("n1");
|
||||
EXPECT_EQ (menu_to_string (menu), "(n2)");
|
||||
|
||||
menu.insert_item ("n1>end(title).end", "c1", lay::Action ("title:c1"));
|
||||
EXPECT_EQ (menu_to_string (menu), "(n2,n1(n1.c1))");
|
||||
EXPECT_EQ (menu.action ("n1.c1").get_title (), "title:c1");
|
||||
|
||||
menu.insert_item ("n1>end(title).end", "c2", lay::Action ("title:c2"));
|
||||
EXPECT_EQ (menu_to_string (menu), "(n2,n1(n1.c1,n1.c2))");
|
||||
|
||||
menu.delete_item ("n1.c1");
|
||||
EXPECT_EQ (menu_to_string (menu), "(n2,n1(n1.c2))");
|
||||
|
||||
menu.delete_item ("n1.c1");
|
||||
EXPECT_EQ (menu_to_string (menu), "(n2,n1(n1.c2))");
|
||||
|
||||
menu.delete_item ("n1.c2");
|
||||
EXPECT_EQ (menu_to_string (menu), "(n2)");
|
||||
}
|
||||
|
||||
|
|
@ -14,6 +14,7 @@ SOURCES = \
|
|||
layParsedLayerSource.cc \
|
||||
layRenderer.cc \
|
||||
laySnap.cc \
|
||||
layAbstractMenu.cc
|
||||
|
||||
INCLUDEPATH += $$TL_INC $$LAYBASIC_INC $$DB_INC $$GSI_INC
|
||||
DEPENDPATH += $$TL_INC $$LAYBASIC_INC $$DB_INC $$GSI_INC
|
||||
|
|
|
|||
Loading…
Reference in New Issue