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