You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							257 lines
						
					
					
						
							7.7 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							257 lines
						
					
					
						
							7.7 KiB
						
					
					
				| /* | |
|  * This program source code file is part of KiCad, a free EDA CAD application. | |
|  * | |
|  * Copyright (C) 2015-2019 CERN | |
|  * Copyright (C) 2015-2019 KiCad Developers, see CHANGELOG.txt for contributors. | |
|  * @author Maciej Suminski <maciej.suminski@cern.ch> | |
|  * | |
|  * 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, you may find one here: | |
|  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html | |
|  * or you may search the http://www.gnu.org website for the version 2 license, | |
|  * or you may write to the Free Software Foundation, Inc., | |
|  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA | |
|  */ | |
| 
 | |
| #include <bitmaps.h> | |
| #include <tool/conditional_menu.h> | |
| #include <tool/action_menu.h> | |
| #include <menus_helpers.h> | |
| #include <kiface_base.h> | |
|  | |
| 
 | |
| CONDITIONAL_MENU::CONDITIONAL_MENU( TOOL_INTERACTIVE* aTool ) : | |
|         ACTION_MENU( true, aTool ) | |
| { | |
| } | |
| 
 | |
| 
 | |
| ACTION_MENU* CONDITIONAL_MENU::create() const | |
| { | |
|     CONDITIONAL_MENU* clone = new CONDITIONAL_MENU( m_tool ); | |
|     clone->m_entries = m_entries; | |
|     return clone; | |
| } | |
| 
 | |
| 
 | |
| void CONDITIONAL_MENU::AddItem( const TOOL_ACTION& aAction, const SELECTION_CONDITION& aCondition, | |
|                                 int aOrder ) | |
| { | |
|     wxASSERT( aAction.GetId() > 0 ); // Check if action was previously registered in ACTION_MANAGER | |
|     addEntry( ENTRY( &aAction, aCondition, aOrder, false ) ); | |
| } | |
| 
 | |
| 
 | |
| void CONDITIONAL_MENU::AddCheckItem( const TOOL_ACTION& aAction, | |
|                                      const SELECTION_CONDITION& aCondition, int aOrder ) | |
| { | |
|     wxASSERT( aAction.GetId() > 0 ); // Check if action was previously registered in ACTION_MANAGER | |
|     addEntry( ENTRY( &aAction, aCondition, aOrder, true ) ); | |
| } | |
| 
 | |
| 
 | |
| void CONDITIONAL_MENU::AddItem( int aId, const wxString& aText, const wxString& aTooltip, | |
|                                 BITMAPS aIcon, const SELECTION_CONDITION& aCondition, | |
|                                 int aOrder ) | |
| { | |
|     wxMenuItem item( nullptr, aId, aText, aTooltip, wxITEM_NORMAL ); | |
| 
 | |
|     if( !!aIcon ) | |
|         AddBitmapToMenuItem( &item, KiBitmap( aIcon ) ); | |
| 
 | |
|     addEntry( ENTRY( item, aIcon, aCondition, aOrder, false ) ); | |
| } | |
| 
 | |
| 
 | |
| void CONDITIONAL_MENU::AddCheckItem( int aId, const wxString& aText, const wxString& aTooltip, | |
|                                      BITMAPS aIcon, const SELECTION_CONDITION& aCondition, | |
|                                      int aOrder ) | |
| { | |
|     wxMenuItem item( nullptr, aId, aText, aTooltip, wxITEM_CHECK ); | |
| 
 | |
|     if( !!aIcon ) | |
|         AddBitmapToMenuItem( &item, KiBitmap( aIcon ) ); | |
| 
 | |
|     addEntry( ENTRY( item, aIcon, aCondition, aOrder, true ) ); | |
| } | |
| 
 | |
| 
 | |
| void CONDITIONAL_MENU::AddMenu( ACTION_MENU* aMenu, const SELECTION_CONDITION& aCondition, | |
|                                 int aOrder ) | |
| { | |
|     addEntry( ENTRY( aMenu, aCondition, aOrder ) ); | |
| } | |
| 
 | |
| 
 | |
| void CONDITIONAL_MENU::AddSeparator( int aOrder ) | |
| { | |
|     addEntry( ENTRY( SELECTION_CONDITIONS::ShowAlways, aOrder ) ); | |
| } | |
| 
 | |
| 
 | |
| void CONDITIONAL_MENU::AddSeparator( const SELECTION_CONDITION& aCondition, int aOrder ) | |
| { | |
|     addEntry( ENTRY( aCondition, aOrder ) ); | |
| } | |
| 
 | |
| 
 | |
| SELECTION g_resolveDummySelection; | |
| 
 | |
| 
 | |
| void CONDITIONAL_MENU::Resolve() | |
| { | |
|     Evaluate( g_resolveDummySelection ); | |
|     UpdateAll(); | |
| 
 | |
|     runOnSubmenus( | |
|             [] ( ACTION_MENU* aMenu ) | |
|             { | |
|                 CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( aMenu ); | |
| 
 | |
|                 if( conditionalMenu ) | |
|                     conditionalMenu->Resolve(); | |
|             } ); | |
| } | |
| 
 | |
| 
 | |
| void CONDITIONAL_MENU::Evaluate( SELECTION& aSelection ) | |
| { | |
|     Clear(); | |
| 
 | |
|     // We try to avoid adding useless separators (when no menuitems between separators) | |
|     int menu_count = 0;     // number of menus since the latest separator | |
|  | |
|     for( const ENTRY& entry : m_entries ) | |
|     { | |
|         const SELECTION_CONDITION& cond = entry.Condition(); | |
|         bool                       result; | |
|         wxMenuItem*                menuItem = nullptr; | |
| 
 | |
|         try | |
|         { | |
|             result = cond( aSelection ); | |
|         } | |
|         catch( std::exception& ) | |
|         { | |
|             continue; | |
|         } | |
| 
 | |
|         if( !result ) | |
|             continue; | |
| 
 | |
|         switch( entry.Type() ) | |
|         { | |
|             case ENTRY::ACTION: | |
|                 Add( *entry.Action(), entry.IsCheckmarkEntry() ); | |
|                 menu_count++; | |
|                 break; | |
| 
 | |
|             case ENTRY::MENU: | |
|                 entry.Menu()->UpdateTitle(); | |
|                 Add( entry.Menu()->Clone() ); | |
|                 menu_count++; | |
|                 break; | |
| 
 | |
|             case ENTRY::WXITEM: | |
|                 menuItem = new wxMenuItem( this, | |
|                                            entry.wxItem()->GetId(), | |
|                                            wxGetTranslation( entry.wxItem()->GetItemLabel() ), | |
|                                            wxGetTranslation( entry.wxItem()->GetHelp() ), | |
|                                            entry.wxItem()->GetKind() ); | |
| 
 | |
|                 if( !!entry.GetIcon() ) | |
|                     AddBitmapToMenuItem( menuItem, KiBitmap( entry.GetIcon() ) ); | |
| 
 | |
|                 // the wxMenuItem must be append only after the bitmap is set: | |
|                 Append( menuItem ); | |
| 
 | |
|                 menu_count++; | |
|                 break; | |
| 
 | |
|             case ENTRY::SEPARATOR: | |
|                 if( menu_count ) | |
|                     AppendSeparator(); | |
| 
 | |
|                 menu_count = 0; | |
|                 break; | |
| 
 | |
|             default: | |
|                 wxASSERT( false ); | |
|                 break; | |
|         } | |
|     } | |
| 
 | |
|     // Recursively call Evaluate on all the submenus that are CONDITIONAL_MENUs to ensure | |
|     // they are updated. This is also required on GTK to make sure the menus have the proper | |
|     // size when created. | |
|     runOnSubmenus( | |
|             [&aSelection]( ACTION_MENU* aMenu ) | |
|             { | |
|                 CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( aMenu ); | |
| 
 | |
|                 if( conditionalMenu ) | |
|                     conditionalMenu->Evaluate( aSelection ); | |
|             } ); | |
| } | |
| 
 | |
| 
 | |
| void CONDITIONAL_MENU::addEntry( ENTRY aEntry ) | |
| { | |
|     if( aEntry.Order() < 0 )        // Any order, so give it any order number | |
|         aEntry.SetOrder( m_entries.size() ); | |
| 
 | |
|     std::list<ENTRY>::iterator it = m_entries.begin(); | |
| 
 | |
|     // Find the right spot for the entry | |
|     while( it != m_entries.end() && it->Order() <= aEntry.Order() ) | |
|         ++it; | |
| 
 | |
|     m_entries.insert( it, aEntry ); | |
| } | |
| 
 | |
| 
 | |
| CONDITIONAL_MENU::ENTRY::ENTRY( const ENTRY& aEntry ) | |
| { | |
|     m_type = aEntry.m_type; | |
|     m_icon = aEntry.m_icon; | |
| 
 | |
|     switch( aEntry.m_type ) | |
|     { | |
|     case ACTION: | |
|         m_data.action = aEntry.m_data.action; | |
|         break; | |
|     case MENU: | |
|         m_data.menu = aEntry.m_data.menu; | |
|         break; | |
|     case WXITEM: | |
|         // We own the wxItem, so we need to make a new one for the new object | |
|         m_data.wxItem = new wxMenuItem( nullptr, | |
|                                         aEntry.m_data.wxItem->GetId(), | |
|                                         aEntry.m_data.wxItem->GetItemLabel(), | |
|                                         aEntry.m_data.wxItem->GetHelp(), | |
|                                         aEntry.m_data.wxItem->GetKind() ); | |
|         break; | |
|     case SEPARATOR: | |
|         break; //No data to copy | |
|     } | |
|     m_condition        = aEntry.m_condition; | |
|     m_order            = aEntry.m_order; | |
|     m_isCheckmarkEntry = aEntry.m_isCheckmarkEntry; | |
| } | |
| 
 | |
| CONDITIONAL_MENU::ENTRY::~ENTRY() | |
| { | |
|     if( WXITEM == m_type ) | |
|         delete m_data.wxItem; | |
| } | |
| 
 |