KiCad PCB EDA Suite
conditional_menu.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2015-2019 CERN
5 * Copyright (C) 2015-2019 KiCad Developers, see CHANGELOG.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <bitmaps.h>
28#include <tool/action_menu.h>
29#include <menus_helpers.h>
30#include <kiface_base.h>
31
32
34 ACTION_MENU( true, aTool )
35{
36}
37
38
40{
42 clone->m_entries = m_entries;
43 return clone;
44}
45
46
47void CONDITIONAL_MENU::AddItem( const TOOL_ACTION& aAction, const SELECTION_CONDITION& aCondition,
48 int aOrder )
49{
50 wxASSERT( aAction.GetId() > 0 ); // Check if action was previously registered in ACTION_MANAGER
51 addEntry( ENTRY( &aAction, aCondition, aOrder, false ) );
52}
53
54
56 const SELECTION_CONDITION& aCondition, int aOrder )
57{
58 wxASSERT( aAction.GetId() > 0 ); // Check if action was previously registered in ACTION_MANAGER
59 addEntry( ENTRY( &aAction, aCondition, aOrder, true ) );
60}
61
62
63void CONDITIONAL_MENU::AddItem( int aId, const wxString& aText, const wxString& aTooltip,
64 BITMAPS aIcon, const SELECTION_CONDITION& aCondition,
65 int aOrder )
66{
67 wxMenuItem item( nullptr, aId, aText, aTooltip, wxITEM_NORMAL );
68
69 if( !!aIcon )
70 AddBitmapToMenuItem( &item, KiBitmap( aIcon ) );
71
72 addEntry( ENTRY( item, aIcon, aCondition, aOrder, false ) );
73}
74
75
76void CONDITIONAL_MENU::AddCheckItem( int aId, const wxString& aText, const wxString& aTooltip,
77 BITMAPS aIcon, const SELECTION_CONDITION& aCondition,
78 int aOrder )
79{
80 wxMenuItem item( nullptr, aId, aText, aTooltip, wxITEM_CHECK );
81
82 if( !!aIcon )
83 AddBitmapToMenuItem( &item, KiBitmap( aIcon ) );
84
85 addEntry( ENTRY( item, aIcon, aCondition, aOrder, true ) );
86}
87
88
90 int aOrder )
91{
92 addEntry( ENTRY( aMenu, aCondition, aOrder ) );
93}
94
95
97{
99}
100
101
102void CONDITIONAL_MENU::AddSeparator( const SELECTION_CONDITION& aCondition, int aOrder )
103{
104 addEntry( ENTRY( aCondition, aOrder ) );
105}
106
107
109
110
112{
114 UpdateAll();
115
117 [] ( ACTION_MENU* aMenu )
118 {
119 CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( aMenu );
120
121 if( conditionalMenu )
122 conditionalMenu->Resolve();
123 } );
124}
125
126
128{
129 Clear();
130
131 // We try to avoid adding useless separators (when no menuitems between separators)
132 int menu_count = 0; // number of menus since the latest separator
133
134 for( const ENTRY& entry : m_entries )
135 {
136 const SELECTION_CONDITION& cond = entry.Condition();
137 bool result;
138 wxMenuItem* menuItem = nullptr;
139
140 try
141 {
142 result = cond( aSelection );
143 }
144 catch( std::exception& )
145 {
146 continue;
147 }
148
149 if( !result )
150 continue;
151
152 switch( entry.Type() )
153 {
154 case ENTRY::ACTION:
155 Add( *entry.Action(), entry.IsCheckmarkEntry() );
156 menu_count++;
157 break;
158
159 case ENTRY::MENU:
160 entry.Menu()->UpdateTitle();
161 Add( entry.Menu()->Clone() );
162 menu_count++;
163 break;
164
165 case ENTRY::WXITEM:
166 menuItem = new wxMenuItem( this,
167 entry.wxItem()->GetId(),
168 wxGetTranslation( entry.wxItem()->GetItemLabel() ),
169 wxGetTranslation( entry.wxItem()->GetHelp() ),
170 entry.wxItem()->GetKind() );
171
172 if( !!entry.GetIcon() )
173 AddBitmapToMenuItem( menuItem, KiBitmap( entry.GetIcon() ) );
174
175 // the wxMenuItem must be append only after the bitmap is set:
176 Append( menuItem );
177
178 menu_count++;
179 break;
180
181 case ENTRY::SEPARATOR:
182 if( menu_count )
183 AppendSeparator();
184
185 menu_count = 0;
186 break;
187
188 default:
189 wxASSERT( false );
190 break;
191 }
192 }
193
194 // Recursively call Evaluate on all the submenus that are CONDITIONAL_MENUs to ensure
195 // they are updated. This is also required on GTK to make sure the menus have the proper
196 // size when created.
198 [&aSelection]( ACTION_MENU* aMenu )
199 {
200 CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( aMenu );
201
202 if( conditionalMenu )
203 conditionalMenu->Evaluate( aSelection );
204 } );
205}
206
207
209{
210 if( aEntry.Order() < 0 ) // Any order, so give it any order number
211 aEntry.SetOrder( m_entries.size() );
212
213 std::list<ENTRY>::iterator it = m_entries.begin();
214
215 // Find the right spot for the entry
216 while( it != m_entries.end() && it->Order() <= aEntry.Order() )
217 ++it;
218
219 m_entries.insert( it, aEntry );
220}
221
222
224{
225 m_type = aEntry.m_type;
226 m_icon = aEntry.m_icon;
227
228 switch( aEntry.m_type )
229 {
230 case ACTION:
231 m_data.action = aEntry.m_data.action;
232 break;
233 case MENU:
234 m_data.menu = aEntry.m_data.menu;
235 break;
236 case WXITEM:
237 // We own the wxItem, so we need to make a new one for the new object
238 m_data.wxItem = new wxMenuItem( nullptr,
239 aEntry.m_data.wxItem->GetId(),
240 aEntry.m_data.wxItem->GetItemLabel(),
241 aEntry.m_data.wxItem->GetHelp(),
242 aEntry.m_data.wxItem->GetKind() );
243 break;
244 case SEPARATOR:
245 break; //No data to copy
246 }
247 m_condition = aEntry.m_condition;
248 m_order = aEntry.m_order;
250}
251
253{
254 if( WXITEM == m_type )
255 delete m_data.wxItem;
256}
257
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:105
void AddBitmapToMenuItem(wxMenuItem *aMenu, const wxBitmap &aImage)
Add a bitmap to a menuitem.
Definition: bitmap.cpp:251
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
void Clear()
Remove all the entries from the menu (as well as its title).
void UpdateAll()
Run update handlers for the menu and its submenus.
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
TOOL_INTERACTIVE * m_tool
Associates tool actions with menu item IDs. Non-owning.
Definition: action_menu.h:266
void runOnSubmenus(std::function< void(ACTION_MENU *)> aFunction)
Check if any of submenus contains a TOOL_ACTION with a specific ID.
< Helper class to organize menu entries. Inserts the entry, preserving the requested order.
void SetOrder(int aOrder)
ENTRY(const TOOL_ACTION *aAction, SELECTION_CONDITION aCondition, int aOrder, bool aCheckmark)
~ENTRY()
Possible entry types.
const TOOL_ACTION * action
union CONDITIONAL_MENU::ENTRY::@32 m_data
Condition to be fulfilled to show the entry in menu.
SELECTION_CONDITION m_condition
Order number, the higher the number the lower position it takes it is in the menu.
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
void addEntry(ENTRY aEntry)
List of all menu entries.
std::list< ENTRY > m_entries
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
void AddCheckItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a checked menu entry to run a TOOL_ACTION on selected items.
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
void Resolve()
Update the initial contents so that wxWidgets doesn't get its knickers tied in a knot over the menu b...
CONDITIONAL_MENU(TOOL_INTERACTIVE *aTool)
void Evaluate(SELECTION &aSelection)
Update the contents of the menu based on the supplied conditions.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
Represent a single user action.
Definition: tool_action.h:68
int GetId() const
Return the unique id of the TOOL_ACTION object.
Definition: tool_action.h:121
SELECTION g_resolveDummySelection
Macros and inline functions to create menus items in menubars or popup menus.
std::function< bool(const SELECTION &)> SELECTION_CONDITION
< Functor type that checks a specific condition for selected items.