Commit 61066fa6 authored by Maciej Suminski's avatar Maciej Suminski
Browse files

Added functions for handling hotkeys, interface for adding TOOL_ACTIONs to CONTEXT_MENU.

Less objects are allocated dynamically.
CONTEXT_MENU is being run using its copy (it saves a hassle of following the lifetime of object).
parent 7b7a3316
Loading
Loading
Loading
Loading
+82 −52
Original line number Diff line number Diff line
@@ -22,62 +22,45 @@
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

#include <wx/wx.h>
#include <wx/menu.h>

#include <tool/tool_event.h>
#include <tool/tool_manager.h>
#include <tool/tool_interactive.h>

#include <tool/context_menu.h>
#include <cassert>

class CONTEXT_MENU::CMEventHandler : public wxEvtHandler
CONTEXT_MENU::CONTEXT_MENU() :
    m_titleSet( false ), m_handler( this ), m_tool( NULL )
{
public:
	CMEventHandler( CONTEXT_MENU* aMenu ):
		m_menu( aMenu ) {};
	m_menu.Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ),
	                 NULL, &m_handler );
	m_menu.Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CMEventHandler::onEvent ),
	                 NULL, &m_handler );

	void onEvent( wxEvent& aEvent )
	{
		TOOL_EVENT evt;
		wxEventType type = aEvent.GetEventType();

		if( type == wxEVT_MENU_HIGHLIGHT )
			evt = TOOL_EVENT( TC_Command, TA_ContextMenuUpdate, aEvent.GetId() );
		else if( type == wxEVT_COMMAND_MENU_SELECTED )
			evt = TOOL_EVENT( TC_Command, TA_ContextMenuChoice, aEvent.GetId() );
		
		if( m_menu->m_tool )
			m_menu->m_tool->GetManager()->ProcessEvent( evt );
	// Workaround for the case when mouse cursor never reaches menu (it hangs up tools using menu)
	wxMenuEvent menuEvent( wxEVT_MENU_HIGHLIGHT, 0, &m_menu );
	m_menu.AddPendingEvent( menuEvent );
}

private:
	CONTEXT_MENU* m_menu;
};


CONTEXT_MENU::CONTEXT_MENU()
CONTEXT_MENU::CONTEXT_MENU( const CONTEXT_MENU& aMenu ) :
    m_titleSet( aMenu.m_titleSet ), m_handler( this ), m_tool( aMenu.m_tool )
{
	m_tool = NULL;
	m_menu = new wxMenu();
	m_handler = new CMEventHandler( this );
	m_menu->Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ),
	                 NULL, m_handler );
	m_menu->Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CMEventHandler::onEvent ),
	                 NULL, m_handler );
    m_menu.Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ),
                     NULL, &m_handler );
    m_menu.Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CMEventHandler::onEvent ),
                     NULL, &m_handler );

    // Workaround for the case when mouse cursor never reaches menu (it hangs up tools using menu)
	wxMenuEvent menuEvent( wxEVT_MENU_HIGHLIGHT, 0, m_menu );
	m_menu->AddPendingEvent( menuEvent );

	m_titleSet = false;
}

    wxMenuEvent menuEvent( wxEVT_MENU_HIGHLIGHT, 0, &m_menu );
    m_menu.AddPendingEvent( menuEvent );

CONTEXT_MENU::~CONTEXT_MENU()
    // Copy all the menu entries
    for( unsigned i = 0; i < aMenu.m_menu.GetMenuItemCount(); ++i )
    {
	delete m_menu;
	delete m_handler;
        wxMenuItem* item = aMenu.m_menu.FindItemByPosition( i );
        m_menu.Append( new wxMenuItem( &m_menu, item->GetId(), item->GetItemLabel(),
                        wxEmptyString, wxITEM_NORMAL ) );
    }
}


@@ -86,23 +69,70 @@ void CONTEXT_MENU::SetTitle( const wxString& aTitle )
    // Unfortunately wxMenu::SetTitle() does nothing..
	if( m_titleSet )
	{
        m_menu->Delete( m_menu->FindItemByPosition( 0 ) ); // fixme: this is LAME!
        m_menu->Delete( m_menu->FindItemByPosition( 0 ) );
        m_menu.FindItemByPosition( 0 )->SetItemLabel( aTitle );
	}
	
	m_menu->InsertSeparator( 0 );
	m_menu->Insert( 0, new wxMenuItem( m_menu, -1, aTitle, wxEmptyString, wxITEM_NORMAL ) );
	else
	{
        m_menu.InsertSeparator( 0 );
        m_menu.Insert( 0, new wxMenuItem( &m_menu, -1, aTitle, wxEmptyString, wxITEM_NORMAL ) );
        m_titleSet = true;
	}
}


void CONTEXT_MENU::Add( const wxString& aLabel, int aId )
{
	m_menu.Append( new wxMenuItem( &m_menu, aId, aLabel, wxEmptyString, wxITEM_NORMAL ) );
}


void CONTEXT_MENU::Add( const wxString& aItem, int aId )
void CONTEXT_MENU::Add( const TOOL_ACTION& aAction, int aId )
{
	m_menu->Append( new wxMenuItem( m_menu, aId, aItem, wxEmptyString, wxITEM_NORMAL ) );
    m_menu.Append( new wxMenuItem( &m_menu, aId,
                    wxString( aAction.GetDescription() + '\t' + getHotKeyDescription( aAction ) ),
                    wxEmptyString, wxITEM_NORMAL ) );
}


void CONTEXT_MENU::Clear()
{
	m_titleSet = false;

	for( unsigned i = 0; i < m_menu.GetMenuItemCount(); ++i )
	    m_menu.Destroy( m_menu.FindItemByPosition( 0 ) );
}


std::string CONTEXT_MENU::getHotKeyDescription( const TOOL_ACTION& aAction ) const
{
    int hotkey = aAction.GetHotKey();

    std::string description = "";

    if( hotkey & MD_ModAlt )
        description += "ALT+";
    if( hotkey & MD_ModCtrl )
        description += "CTRL+";
    if( hotkey & MD_ModShift )
        description += "SHIFT+";

    // TODO dispatch keys such as Fx, TAB, PG_UP/DN, HOME, END, etc.
    description += char( hotkey & ~MD_ModifierMask );

    return description;
}


void CONTEXT_MENU::CMEventHandler::onEvent( wxEvent& aEvent )
{
    TOOL_EVENT evt;
    wxEventType type = aEvent.GetEventType();

    if( type == wxEVT_MENU_HIGHLIGHT )
        evt = TOOL_EVENT( TC_Command, TA_ContextMenuUpdate, aEvent.GetId() );
    else if( type == wxEVT_COMMAND_MENU_SELECTED )
        evt = TOOL_EVENT( TC_Command, TA_ContextMenuChoice, aEvent.GetId() );

    if( m_menu->m_tool )
        m_menu->m_tool->GetManager()->ProcessEvent( evt );
}
+6 −4
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <deque>

#include <boost/foreach.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/optional.hpp>
#include <boost/range/adaptor/map.hpp>

@@ -387,7 +388,8 @@ bool TOOL_MANAGER::ProcessEvent( TOOL_EVENT& aEvent )
			if( st->contextMenuTrigger == CMENU_NOW )
				st->contextMenuTrigger = CMENU_OFF;

			GetEditFrame()->PopupMenu( st->contextMenu->GetMenu() );
            boost::scoped_ptr<CONTEXT_MENU> menu( new CONTEXT_MENU( *st->contextMenu ) );
            GetEditFrame()->PopupMenu( menu->GetMenu() );

			TOOL_EVENT evt( TC_Command, TA_ContextMenuChoice );
			dispatchInternal( evt );
+27 −11
Original line number Diff line number Diff line
@@ -25,7 +25,8 @@
#ifndef __CONTEXT_MENU_H
#define __CONTEXT_MENU_H

#include <wx/string.h>
#include <wx/menu.h>
#include <tool/tool_action.h>

class wxMenu;
class TOOL_INTERACTIVE;
@@ -41,23 +42,29 @@ class CONTEXT_MENU

public:
	CONTEXT_MENU();
	~CONTEXT_MENU();
	CONTEXT_MENU( const CONTEXT_MENU& aMenu );

	void SetTitle( const wxString& aTitle );
	void Add( const wxString& aItem, int aId );
	
	// fixme: unimplemented
	// void Add ( const TOOL_ACTION& aAction, int aId = -1 );
	
	void Add( const wxString& aLabel, int aId );
	void Add( const TOOL_ACTION& aAction, int aId = -1 );
	void Clear();

	wxMenu* GetMenu() const
	{
		return m_menu;
		return const_cast<wxMenu*>( &m_menu );
	}

private:
	class CMEventHandler;
	class CMEventHandler : public wxEvtHandler
	{
	public:
	    CMEventHandler( CONTEXT_MENU* aMenu ) : m_menu( aMenu ) {};

	    void onEvent( wxEvent& aEvent );

	private:
	    CONTEXT_MENU* m_menu;
	};
	
	friend class TOOL_INTERACTIVE;

@@ -66,10 +73,19 @@ private:
		m_tool = aTool;
	}

	/**
	 * Returns a hot key in the string format accepted by wxMenu.
	 *
	 * @param aAction is the action with hot key to be converted.
	 * @return Hot key in the string format compatible with wxMenu.
	 */
	std::string getHotKeyDescription( const TOOL_ACTION& aAction ) const;

	/// Flag indicating that the menu title was set up
	bool m_titleSet;

	wxMenu* m_menu;
	CMEventHandler* m_handler;
	wxMenu m_menu;
	CMEventHandler m_handler;
	TOOL_INTERACTIVE* m_tool;
};

+40 −9
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@
#define __TOOL_ACTION_H

#include <string>
#include <wx/wx.h>
#include <cassert>

#include <tool/tool_base.h>
#include <tool/action_manager.h>
@@ -38,8 +38,9 @@
class TOOL_ACTION
{
public:
    TOOL_ACTION( const std::string& aName, TOOL_ActionScope aScope = AS_CONTEXT, int aDefaultHotKey = 0,
                 const wxString& aMenuItem = wxT( "" ), const wxString& aMenuDesc = wxT( "" ) ) :
    TOOL_ACTION( const std::string& aName, TOOL_ActionScope aScope = AS_CONTEXT,
                 int aDefaultHotKey = 0, const std::string& aMenuItem = std::string( "" ),
                 const std::string& aMenuDesc = std::string( "" ) ) :
            m_name( aName ), m_scope( aScope ), m_defaultHotKey( aDefaultHotKey ),
                m_currentHotKey( aDefaultHotKey ), m_menuItem( aMenuItem ),
                m_menuDescription( aMenuDesc ), m_id( -1 ), m_actionMgr( NULL )
@@ -86,6 +87,15 @@ public:
        return m_id;
    }

    /**
     * Function GetHotKey()
     * Returns the associated hot key.
     */
    int GetHotKey() const
    {
        return m_currentHotKey;
    }

    /**
     * Function ChangeHotKey()
     * Assigns a new hot key.
@@ -94,8 +104,8 @@ public:
     */
    void ChangeHotKey( int aNewHotKey )
    {
        wxASSERT_MSG( false, wxT( "It is not fully implemented yet") );
        // I mean it has to be changed in the ACTION_MANAGER, or change the implementation
        assert( false );
        // hotkey has to be changed in the ACTION_MANAGER, or change the implementation
        m_currentHotKey = aNewHotKey;
    }

@@ -105,8 +115,8 @@ public:
     */
    void RestoreHotKey()
    {
        wxASSERT_MSG( false, wxT( "It is not fully implemented yet") );
        // I mean it has to be changed in the ACTION_MANAGER, or change the implementation
        assert( false );
        // hotkey has to be changed in the ACTION_MANAGER, or change the implementation
        m_currentHotKey = m_defaultHotKey;
    }

@@ -134,6 +144,26 @@ public:
        return TOOL_EVENT( TC_Command, TA_Action, m_name, m_scope );
    }

    const std::string& GetMenuItem() const
    {
        return m_menuItem;
    }

    void SetMenuItem( const std::string& aItem )
    {
        m_menuItem = aItem;
    }

    const std::string& GetDescription() const
    {
        return m_menuDescription;
    }

    void SetDescription( const std::string& aDescription )
    {
        m_menuDescription = aDescription;
    }

private:
    friend class ACTION_MANAGER;

@@ -162,10 +192,10 @@ private:
    int m_currentHotKey;

    /// Menu entry text
    wxString m_menuItem;
    std::string m_menuItem;

    /// Pop-up help
    wxString m_menuDescription;
    std::string m_menuDescription;

    // Icon for menu entry
    //KiBitmap m_bitmap;
@@ -182,4 +212,5 @@ private:
    /// Originating UI object
//    wxWindow* m_uiOrigin;
};

#endif