KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 <tool/selection.h>
30#include <kiface_base.h>
31#include <widgets/ui_common.h>
32
33
35 ACTION_MENU( true, aTool )
36{
37}
38
39
41{
43 clone->m_entries = m_entries;
44 return clone;
45}
46
47
48void CONDITIONAL_MENU::AddItem( const TOOL_ACTION& aAction, const SELECTION_CONDITION& aCondition,
49 int aOrder )
50{
51 wxASSERT( aAction.GetId() > 0 ); // Check if action was previously registered in ACTION_MANAGER
52 addEntry( ENTRY( &aAction, aCondition, aOrder, false ) );
53}
54
55
57 const SELECTION_CONDITION& aCondition, int aOrder )
58{
59 wxASSERT( aAction.GetId() > 0 ); // Check if action was previously registered in ACTION_MANAGER
60 addEntry( ENTRY( &aAction, aCondition, aOrder, true ) );
61}
62
63
64void CONDITIONAL_MENU::AddItem( int aId, const wxString& aText, const wxString& aTooltip,
65 BITMAPS aIcon, const SELECTION_CONDITION& aCondition,
66 int aOrder )
67{
68 wxMenuItem item( nullptr, aId, aText, aTooltip, wxITEM_NORMAL );
69
70 if( !!aIcon )
71 KIUI::AddBitmapToMenuItem( &item, KiBitmap( aIcon ) );
72
73 addEntry( ENTRY( item, aIcon, aCondition, aOrder, false ) );
74}
75
76
77void CONDITIONAL_MENU::AddCheckItem( int aId, const wxString& aText, const wxString& aTooltip,
78 BITMAPS aIcon, const SELECTION_CONDITION& aCondition,
79 int aOrder )
80{
81 wxMenuItem item( nullptr, aId, aText, aTooltip, wxITEM_CHECK );
82
83 if( !!aIcon )
84 KIUI::AddBitmapToMenuItem( &item, KiBitmap( aIcon ) );
85
86 addEntry( ENTRY( item, aIcon, aCondition, aOrder, true ) );
87}
88
89
91 int aOrder )
92{
93 addEntry( ENTRY( aMenu, aCondition, aOrder ) );
94}
95
96
98{
100}
101
102
103void CONDITIONAL_MENU::AddSeparator( const SELECTION_CONDITION& aCondition, int aOrder )
104{
105 addEntry( ENTRY( aCondition, aOrder ) );
106}
107
108
110
111
113{
115 UpdateAll();
116
118 [] ( ACTION_MENU* aMenu )
119 {
120 CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( aMenu );
121
122 if( conditionalMenu )
123 conditionalMenu->Resolve();
124 } );
125}
126
127
128void CONDITIONAL_MENU::Evaluate( const SELECTION& aSelection )
129{
130 Clear();
131
132 // We try to avoid adding useless separators (when no menuitems between separators)
133 int menu_count = 0; // number of menus since the latest separator
134
135 for( const ENTRY& entry : m_entries )
136 {
137 const SELECTION_CONDITION& cond = entry.Condition();
138 bool result;
139 wxMenuItem* menuItem = nullptr;
140
141 try
142 {
143 result = cond( aSelection );
144 }
145 catch( std::exception& )
146 {
147 continue;
148 }
149
150 if( !result )
151 continue;
152
153 switch( entry.Type() )
154 {
155 case ENTRY::ACTION:
156 Add( *entry.Action(), entry.IsCheckmarkEntry() );
157 menu_count++;
158 break;
159
160 case ENTRY::MENU:
161 entry.Menu()->UpdateTitle();
162 Add( entry.Menu()->Clone() );
163 menu_count++;
164 break;
165
166 case ENTRY::WXITEM:
167 menuItem = new wxMenuItem( this,
168 entry.wxItem()->GetId(),
169 wxGetTranslation( entry.wxItem()->GetItemLabel() ),
170 wxGetTranslation( entry.wxItem()->GetHelp() ),
171 entry.wxItem()->GetKind() );
172
173 if( !!entry.GetIcon() )
174 KIUI::AddBitmapToMenuItem( menuItem, KiBitmap( entry.GetIcon() ) );
175
176 // the wxMenuItem must be append only after the bitmap is set:
177 Append( menuItem );
178
179 menu_count++;
180 break;
181
182 case ENTRY::SEPARATOR:
183 if( menu_count )
184 AppendSeparator();
185
186 menu_count = 0;
187 break;
188
189 default:
190 wxASSERT( false );
191 break;
192 }
193 }
194
195 // Recursively call Evaluate on all the submenus that are CONDITIONAL_MENUs to ensure
196 // they are updated. This is also required on GTK to make sure the menus have the proper
197 // size when created.
199 [&aSelection]( ACTION_MENU* aMenu )
200 {
201 CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( aMenu );
202
203 if( conditionalMenu )
204 conditionalMenu->Evaluate( aSelection );
205 } );
206}
207
208
210{
211 if( aEntry.Order() < 0 ) // Any order, so give it any order number
212 aEntry.SetOrder( m_entries.size() );
213
214 std::list<ENTRY>::iterator it = m_entries.begin();
215
216 // Find the right spot for the entry
217 while( it != m_entries.end() && it->Order() <= aEntry.Order() )
218 ++it;
219
220 m_entries.insert( it, aEntry );
221}
222
223
225{
226 m_type = aEntry.m_type;
227 m_icon = aEntry.m_icon;
228
229 switch( aEntry.m_type )
230 {
231 case ACTION:
232 m_data.action = aEntry.m_data.action;
233 break;
234 case MENU:
235 m_data.menu = aEntry.m_data.menu;
236 break;
237 case WXITEM:
238 // We own the wxItem, so we need to make a new one for the new object
239 m_data.wxItem = new wxMenuItem( nullptr,
240 aEntry.m_data.wxItem->GetId(),
241 aEntry.m_data.wxItem->GetItemLabel(),
242 aEntry.m_data.wxItem->GetHelp(),
243 aEntry.m_data.wxItem->GetKind() );
244 break;
245 case SEPARATOR:
246 break; //No data to copy
247 }
248 m_condition = aEntry.m_condition;
249 m_order = aEntry.m_order;
251}
252
254{
255 if( WXITEM == m_type )
256 delete m_data.wxItem;
257}
258
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:104
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:278
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
SELECTION_CONDITION m_condition
Order number, the higher the number the lower position it takes it is in the menu.
union CONDITIONAL_MENU::ENTRY::@34 m_data
Condition to be fulfilled to show the entry in 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(const 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:269
int GetId() const
Return the unique id of the TOOL_ACTION object.
Definition: tool_action.h:324
SELECTION g_resolveDummySelection
KICOMMON_API void AddBitmapToMenuItem(wxMenuItem *aMenu, const wxBitmapBundle &aImage)
Add a bitmap to a menuitem.
Definition: ui_common.cpp:358
std::function< bool(const SELECTION &)> SELECTION_CONDITION
Functor type that checks a specific condition for selected items.
Functions to provide common constants and other functions to assist in making a consistent UI.