Commit 24106102 authored by tomasz.'s avatar tomasz.

Added core tool framework files + boost::context assembly stuff (initial, very...

Added core tool framework files + boost::context assembly stuff (initial, very buggy and unfinished work).
parent bd182aad
......@@ -144,11 +144,23 @@ set(COMMON_SRCS
zoom.cpp
)
enable_language(C CXX ASM)
set_source_files_properties(system/fcontext.s PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp")
set(COMMON_SRCS
${COMMON_SRCS}
view/view.cpp
view/view_item.cpp
)
system/fcontext.s
tool/tool_base.cpp
tool/tool_manager.cpp
tool/tool_dispatcher.cpp
tool/tool_event.cpp
tool/tool_interactive.cpp
tool/context_menu.cpp
)
add_library(common STATIC ${COMMON_SRCS})
......
/*
Boost::Context assembly wrapper - done to avoid compiling the whole boost binary library
which may be unpleasant, in particular under Windows (we don't support VC++, while boost::context
does not support mingw */
#if __i386__
#include "jump_i386_sysv_elf_gas.S"
#include "make_i386_sysv_elf_gas.S"
#ifdef __WIN32__
#include "jump_i386_pe_gas.S"
#include "make_i386_pe_gas.S"
#endif
#elif __x86_64__
#include "jump_x86_64_sysv_elf_gas.S"
#include "make_x86_64_sysv_elf_gas.S"
#endif
/* Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
.text
.globl jump_fcontext
.align 2
.type jump_fcontext,@function
jump_fcontext:
mov 0x4(%esp),%ecx
mov %edi,(%ecx)
mov %esi,0x4(%ecx)
mov %ebx,0x8(%ecx)
mov %ebp,0xc(%ecx)
mov %fs:0x18,%edx
mov (%edx),%eax
mov %eax,0x24(%ecx)
mov 0x4(%edx),%eax
mov %eax,0x18(%ecx)
mov 0x8(%edx),%eax
mov %eax,0x20(%ecx)
mov 0x10(%edx),%eax
mov %eax,0x28(%ecx)
lea 0x4(%esp),%eax
mov %eax,0x10(%ecx)
mov (%esp),%eax
mov %eax,0x14(%ecx)
mov 0x8(%esp),%edx
mov (%edx),%edi
mov 0x4(%edx),%esi
mov 0x8(%edx),%ebx
mov 0xc(%edx),%ebp
mov 0x10(%esp),%eax
test %eax,%eax
je jump_fcontext+0x5f
stmxcsr 0x2c(%ecx)
fnstcw 0x30(%ecx)
ldmxcsr 0x2c(%edx)
fldcw 0x30(%edx)
mov %edx,%ecx
mov %fs:0x18,%edx
mov 0x24(%ecx),%eax
mov %eax,(%edx)
mov 0x18(%ecx),%eax
mov %eax,0x4(%edx)
mov 0x20(%ecx),%eax
mov %eax,0x8(%edx)
mov 0x28(%ecx),%eax
mov %eax,0x10(%edx)
mov 0xc(%esp),%eax
mov 0x10(%ecx),%esp
mov %eax,0x4(%esp)
mov 0x14(%ecx),%ecx
jmp *%ecx
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/********************************************************************
* *
* -------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | *
* -------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | *
* -------------------------------------------------------------- *
* | EDI | ESI | EBX | EBP | ESP | EIP | *
* -------------------------------------------------------------- *
* -------------------------------------------------------------- *
* | 6 | 7 | | *
* -------------------------------------------------------------- *
* | 0x18 | 0x1c | | *
* -------------------------------------------------------------- *
* | sp | size | | *
* -------------------------------------------------------------- *
* -------------------------------------------------------------- *
* | 8 | 9 | | *
* -------------------------------------------------------------- *
* | 0x20 | 0x24 | | *
* -------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| | *
* -------------------------------------------------------------- *
* *
* *****************************************************************/
.text
.globl jump_fcontext
.align 2
.type jump_fcontext,@function
jump_fcontext:
movl 0x4(%esp), %ecx /* load address of the first fcontext_t arg */
movl %edi, (%ecx) /* save EDI */
movl %esi, 0x4(%ecx) /* save ESI */
movl %ebx, 0x8(%ecx) /* save EBX */
movl %ebp, 0xc(%ecx) /* save EBP */
leal 0x4(%esp), %eax /* exclude the return address */
movl %eax, 0x10(%ecx) /* save as stack pointer */
movl (%esp), %eax /* load return address */
movl %eax, 0x14(%ecx) /* save return address */
movl 0x8(%esp), %edx /* load address of the second fcontext_t arg */
movl (%edx), %edi /* restore EDI */
movl 0x4(%edx), %esi /* restore ESI */
movl 0x8(%edx), %ebx /* restore EBX */
movl 0xc(%edx), %ebp /* restore EBP */
movl 0x10(%esp), %eax /* check if fpu enve preserving was requested */
test %eax, %eax
je 1f
stmxcsr 0x20(%ecx) /* save MMX control and status word */
fnstcw 0x24(%ecx) /* save x87 control word */
ldmxcsr 0x20(%edx) /* restore MMX control and status word */
fldcw 0x24(%edx) /* restore x87 control word */
1:
movl 0xc(%esp), %eax /* use third arg as return value after jump */
movl 0x10(%edx), %esp /* restore ESP */
movl %eax, 0x4(%esp) /* use third arg as first arg in context function */
movl 0x14(%edx), %edx /* fetch the address to return to */
jmp *%edx /* indirect jump to context */
.size jump_fcontext,.-jump_fcontext
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/****************************************************************************************
* *
* ---------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
* | RBX | R12 | R13 | R14 | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | *
* ---------------------------------------------------------------------------------- *
* | R15 | RBP | RSP | RIP | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 16 | 17 | 18 | 19 | | *
* ---------------------------------------------------------------------------------- *
* | 0x40 | 0x44 | 0x48 | 0x4c | | *
* ---------------------------------------------------------------------------------- *
* | sp | size | | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 20 | 21 | | *
* ---------------------------------------------------------------------------------- *
* | 0x50 | 0x54 | | *
* ---------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| | *
* ---------------------------------------------------------------------------------- *
* *
* **************************************************************************************/
.text
.globl jump_fcontext
.type jump_fcontext,@function
.align 16
jump_fcontext:
movq %rbx, (%rdi) /* save RBX */
movq %r12, 0x8(%rdi) /* save R12 */
movq %r13, 0x10(%rdi) /* save R13 */
movq %r14, 0x18(%rdi) /* save R14 */
movq %r15, 0x20(%rdi) /* save R15 */
movq %rbp, 0x28(%rdi) /* save RBP */
cmp $0, %rcx
je 1f
stmxcsr 0x50(%rdi) /* save MMX control and status word */
fnstcw 0x54(%rdi) /* save x87 control word */
ldmxcsr 0x50(%rsi) /* restore MMX control and status word */
fldcw 0x54(%rsi) /* restore x87 control word */
1:
leaq 0x8(%rsp), %rax /* exclude the return address and save as stack pointer */
movq %rax, 0x30(%rdi) /* save as stack pointer */
movq (%rsp), %rax /* save return address */
movq %rax, 0x38(%rdi) /* save return address as RIP */
movq (%rsi), %rbx /* restore RBX */
movq 0x8(%rsi), %r12 /* restore R12 */
movq 0x10(%rsi), %r13 /* restore R13 */
movq 0x18(%rsi), %r14 /* restore R14 */
movq 0x20(%rsi), %r15 /* restore R15 */
movq 0x28(%rsi), %rbp /* restore RBP */
movq 0x30(%rsi), %rsp /* restore RSP */
movq 0x38(%rsi), %rcx /* fetch the address to return to */
movq %rdx, %rax /* use third arg as return value after jump */
movq %rdx, %rdi /* use third arg as first arg in context function */
jmp *%rcx /* indirect jump to context */
.size jump_fcontext,.-jump_fcontext
/* Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
.text
.globl make_fcontext
.align 2
.type make_fcontext,@function
make_fcontext:
mov 0x4(%esp),%eax
lea -0x34(%eax),%eax
and $0xfffffff0,%eax
mov 0x4(%esp),%ecx
mov %ecx,0x18(%eax)
mov 0x8(%esp),%edx
mov %edx,0x1c(%eax)
neg %edx
lea (%edx,%ecx,1),%ecx
mov %ecx,0x20(%eax)
mov 0xc(%esp),%ecx
mov %ecx,0x14(%eax)
stmxcsr 0x2c(%eax)
fnstcw 0x30(%eax)
lea -0x1c(%eax),%edx
mov %edx,0x10(%eax)
mov $0x0,%ecx
mov %ecx,(%edx)
mov %fs:0x18,%ecx
mov (%ecx),%edx
inc %edx
je make_fcontext+0x4c // <_make_fcontext+0x4c>
dec %edx
xchg %edx,%ecx
jmp make_fcontext+0x42 // <_make_fcontext+0x42>
mov 0x4(%ecx),%ecx
mov 0x10(%eax),%edx
mov %ecx,0x18(%edx)
mov $0xffffffff,%ecx
mov %ecx,0x14(%edx)
lea 0x14(%edx),%ecx
mov %ecx,0x24(%eax)
ret
finish:
xor %eax,%eax
mov %eax,(%esp)
call finish+0xa
hlt
.size make_fcontext,.-make_fcontext
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/********************************************************************
* *
* -------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | *
* -------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | *
* -------------------------------------------------------------- *
* | EDI | ESI | EBX | EBP | ESP | EIP | *
* -------------------------------------------------------------- *
* -------------------------------------------------------------- *
* | 6 | 7 | | *
* -------------------------------------------------------------- *
* | 0x18 | 0x1c | | *
* -------------------------------------------------------------- *
* | sp | size | | *
* -------------------------------------------------------------- *
* -------------------------------------------------------------- *
* | 8 | 9 | | *
* -------------------------------------------------------------- *
* | 0x20 | 0x24 | | *
* -------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| | *
* -------------------------------------------------------------- *
* *
* *****************************************************************/
.text
.globl make_fcontext
.align 2
.type make_fcontext,@function
make_fcontext:
movl 0x4(%esp), %eax /* load 1. arg of make_fcontext, pointer to context stack (base) */
leal -0x28(%eax), %eax /* reserve space for fcontext_t at top of context stack */
/* shift address in EAX to lower 16 byte boundary */
/* == pointer to fcontext_t and address of context stack */
andl $-16, %eax
movl 0x4(%esp), %edx /* load 1. arg of make_fcontext, pointer to context stack (base) */
movl %edx, 0x18(%eax) /* save address of context stack (base) in fcontext_t */
movl 0x8(%esp), %edx /* load 2. arg of make_fcontext, context stack size */
movl %edx, 0x1c(%eax) /* save stack size in fcontext_t */
movl 0xc(%esp), %edx /* load 3. arg of make_fcontext, pointer to context function */
movl %edx, 0x14(%eax) /* save address of context function in fcontext_t */
stmxcsr 0x20(%eax) /* save MMX control and status word */
fnstcw 0x24(%eax) /* save x87 control word */
leal -0x8(%eax), %edx /* reserve space for the last frame on context stack; (ESP - 0x4) % 16 == 0 */
movl %edx, 0x10(%eax) /* save address in EDX as stack pointer for context function */
call 1f
1: popl %ecx /* address of label 2 */
addl $finish-1b, %ecx /* compute abs address of label finish */
movl %ecx, (%edx) /* save address of finish as return address for context functions */
/* entered after context function returns */
ret
finish:
/* ESP points to same address as ESP on entry of context function + 0x4 */
call 2f
2: popl %ebx /* address of label 3 */
addl $_GLOBAL_OFFSET_TABLE_+[.-2b], %ebx /* compute address of GOT and store it in EBX */
xorl %eax, %eax
movl %eax, (%esp) /* exit code is zero */
call _exit@PLT /* exit application */
hlt
.size make_fcontext,.-make_fcontext
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/****************************************************************************************
* *
* ---------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
* | RBX | R12 | R13 | R14 | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | *
* ---------------------------------------------------------------------------------- *
* | R15 | RBP | RSP | RIP | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 16 | 17 | 18 | 19 | | *
* ---------------------------------------------------------------------------------- *
* | 0x40 | 0x44 | 0x48 | 0x4c | | *
* ---------------------------------------------------------------------------------- *
* | sp | size | | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 20 | 21 | | *
* ---------------------------------------------------------------------------------- *
* | 0x50 | 0x54 | | *
* ---------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| | *
* ---------------------------------------------------------------------------------- *
* *
* **************************************************************************************/
.text
.globl make_fcontext
.type make_fcontext,@function
.align 16
make_fcontext:
leaq -0x58(%rdi), %rax /* reserve space for fcontext_t at top of context stack */
/* shift address in RAX to lower 16 byte boundary */
/* == pointer to fcontext_t and address of context stack */
andq $-16, %rax
movq %rdi, 0x40(%rax) /* save address of context stack pointer (base) in fcontext_t */
movq %rsi, 0x48(%rax) /* save context stack size in fcontext_t */
movq %rdx, 0x38(%rax) /* save address of context function in fcontext_t */
stmxcsr 0x50(%rax) /* save MMX control and status word */
fnstcw 0x54(%rax) /* save x87 control word */
leaq -0x8(%rax), %rdx /* reserve space for the return address on context stack, (RSP - 0x8) % 16 == 0 */
movq %rdx, 0x30(%rax) /* save address in RDX as stack pointer for context function */
leaq finish(%rip), %rcx /* compute abs address of label finish */
movq %rcx, (%rdx) /* save address of finish as return address for context function */
/* entered after context function returns */
ret /* return pointer to fcontext_t placed on context stack */
finish:
/* RSP points to same address as RSP on entry of context function + 0x8 */
xorq %rdi, %rdi /* exit code is zero */
call _exit@PLT /* exit application */
hlt
.size make_fcontext,.-make_fcontext
#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>
class CONTEXT_MENU::CMEventHandler : public wxEvtHandler
{
public:
CMEventHandler( CONTEXT_MENU *aMenu ):
m_menu(aMenu) {};
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() );
m_menu->m_tool->GetManager()->ProcessEvent(evt);
}
private:
CONTEXT_MENU *m_menu;
};
CONTEXT_MENU::CONTEXT_MENU ( )
{
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_titleSet = false;
}
CONTEXT_MENU::~CONTEXT_MENU ( )
{
delete m_menu;
delete m_handler;
}
void CONTEXT_MENU::SetTitle( const wxString& aTitle )
{
if(m_titleSet)
{
m_menu->Delete(m_menu->FindItemByPosition(0)); // fixme: this is LAME!
m_menu->Delete(m_menu->FindItemByPosition(0));
}
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& aItem, int aId )
{
m_menu->Append( new wxMenuItem( m_menu, aId, aItem, wxEmptyString, wxITEM_NORMAL ) );
}
void CONTEXT_MENU::Clear()
{
m_titleSet = false;
}
\ No newline at end of file
#include <tool/tool_event.h>
#include <tool/tool_manager.h>
KiGfx::VIEW *TOOL_BASE::getView()
{
return m_toolMgr->GetView();
}
KiGfx::VIEW_CONTROLS *TOOL_BASE::getViewControls()
{
return m_toolMgr->GetViewControls();
}
wxWindow * TOOL_BASE::getEditFrameInt()
{
return m_toolMgr->GetEditFrame();
}
EDA_ITEM * TOOL_BASE::getModelInt()
{
return m_toolMgr->GetModel();
}
\ No newline at end of file
#include <wx/wx.h>
#include <wx/event.h>
#include <wxPcbStruct.h>
#include <wxBasePcbFrame.h>
#include <tool/tool_manager.h>
#include <tool/tool_dispatcher.h>
#include <view/view.h>
#include <class_drawpanel_gal.h>
#include <pcbnew_id.h>
#include <boost/optional.hpp>
#include <boost/foreach.hpp>
using boost::optional;
struct TOOL_DISPATCHER::ButtonState
{
ButtonState (TOOL_MouseButtons aButton, const wxEventType& aDownEvent, const wxEventType & aUpEvent, bool aTriggerMenu = false) :
button(aButton),
downEvent(aDownEvent),
upEvent(aUpEvent),
triggerContextMenu(aTriggerMenu)
{};
bool dragging;
bool pressed;
VECTOR2D dragOrigin;
double dragMaxDelta;
TOOL_MouseButtons button;
wxEventType downEvent;
wxEventType upEvent;
bool triggerContextMenu;
wxLongLong downTimestamp;
void Reset()
{
dragging = false;
pressed = false;
}
};
TOOL_DISPATCHER::TOOL_DISPATCHER( TOOL_MANAGER *aToolMgr, PCB_BASE_FRAME *aEditFrame ):
m_toolMgr(aToolMgr),
m_editFrame(aEditFrame)
{
m_buttons.push_back(new ButtonState(MB_Left, wxEVT_LEFT_DOWN, wxEVT_LEFT_UP));
m_buttons.push_back(new ButtonState(MB_Right, wxEVT_RIGHT_DOWN, wxEVT_RIGHT_UP, true));
m_buttons.push_back(new ButtonState(MB_Middle, wxEVT_MIDDLE_DOWN, wxEVT_MIDDLE_UP));
ResetState();
};
TOOL_DISPATCHER::~TOOL_DISPATCHER()
{
BOOST_FOREACH(ButtonState *st, m_buttons)
delete st;
}
void TOOL_DISPATCHER::ResetState()
{
BOOST_FOREACH(ButtonState *st, m_buttons)
st->Reset();
}
KiGfx::VIEW* TOOL_DISPATCHER::getView()
{
return m_editFrame->GetGalCanvas()->GetView();
}
int TOOL_DISPATCHER::decodeModifiers( wxEvent& aEvent )
{
wxMouseEvent *me = static_cast<wxMouseEvent*> (&aEvent);
int mods = 0;
if(me->ControlDown())
mods |= MB_ModCtrl;
if(me->AltDown())
mods |= MB_ModAlt;
if(me->ShiftDown())
mods |= MB_ModShift;
return mods;
}
bool TOOL_DISPATCHER::handleMouseButton ( wxEvent& aEvent, int aIndex, bool aMotion )
{
ButtonState *st = m_buttons[aIndex];
wxEventType type = aEvent.GetEventType();
optional<TOOL_EVENT> evt;
bool up = type == st->upEvent;
bool down = type == st->downEvent;
int mods = decodeModifiers(aEvent);
int args = st->button | mods;
if(down)
{
st->downTimestamp = wxGetLocalTimeMillis();
st->dragOrigin = m_lastMousePos;
st->dragMaxDelta = 0;
st->pressed = true;
evt = TOOL_EVENT (TC_Mouse, TA_MouseDown, args );
} else if (up)
{
bool isClick = false;
st->pressed = false;
if(st->dragging)
{
wxLongLong t = wxGetLocalTimeMillis();
if( t - st->downTimestamp < DragTimeThreshold && st->dragMaxDelta < DragDistanceThreshold )
isClick = true;
else
evt = TOOL_EVENT (TC_Mouse, TA_MouseUp, args );
} else
isClick = true;
if(isClick)
{
if(st -> triggerContextMenu && !mods)
{}
// evt = TOOL_EVENT (TC_Command, TA_ContextMenu );
else
evt = TOOL_EVENT (TC_Mouse, TA_MouseClick, args );
}
st->dragging = false;
}
if(st->pressed && aMotion)
{
st->dragging = true;
double dragPixelDistance = getView()->ToScreen(m_lastMousePos - st->dragOrigin, false).EuclideanNorm();
st->dragMaxDelta = std::max(st->dragMaxDelta, dragPixelDistance);
wxLongLong t = wxGetLocalTimeMillis();
if( t - st->downTimestamp > DragTimeThreshold || st->dragMaxDelta > DragDistanceThreshold )
{
evt = TOOL_EVENT (TC_Mouse, TA_MouseDrag, args );
evt->SetMouseDragOrigin(st->dragOrigin);
evt->SetMouseDelta(m_lastMousePos - st->dragOrigin);
}
}
if(evt)
{
evt->SetMousePosition(m_lastMousePos);
m_toolMgr->ProcessEvent( *evt );
return true;
}
return false;
}
void TOOL_DISPATCHER::DispatchWxEvent(wxEvent &aEvent)
{
bool motion = false, buttonEvents = false;
VECTOR2D pos;
optional<TOOL_EVENT> evt;
int type = aEvent.GetEventType();
if( type == wxEVT_MOTION )
{
wxMouseEvent *me = static_cast<wxMouseEvent*> (&aEvent);
pos = getView()->ToWorld ( VECTOR2D( me->GetX(), me->GetY() ));
if(pos != m_lastMousePos)
{
motion = true;
m_lastMousePos = pos;
}
}
for(unsigned int i = 0; i < m_buttons.size(); i++)
buttonEvents |= handleMouseButton(aEvent, i, motion);
if(!buttonEvents && motion)
{
evt = TOOL_EVENT (TC_Mouse, TA_MouseMotion );
evt->SetMousePosition(pos);
}
if(evt)
m_toolMgr->ProcessEvent( *evt );
aEvent.Skip();
}
void TOOL_DISPATCHER::DispatchWxCommand(wxCommandEvent &aEvent)
{
bool activateTool = false;
std::string toolName;
switch (aEvent.GetId())
{
case ID_SELECTION_TOOL:
toolName = "pcbnew.InteractiveSelection";
activateTool = true;
break;
}
if(activateTool)
{
TOOL_EVENT evt ( TC_Command, TA_ActivateTool, toolName );
m_toolMgr->ProcessEvent(evt);
}
}
\ No newline at end of file
#include <cstring>
#include <string>
#include <base_struct.h>
#include <tool/tool_event.h>
#include <tool/tool_manager.h>
#include <boost/foreach.hpp>
using namespace std;
struct FlagString {
int flag;
std::string str;
};
static const std::string flag2string(int flag, const FlagString *exps)
{
std::string rv;
for(int i = 0; exps[i].str.length(); i++)
if(exps[i].flag & flag)
rv+=exps[i].str+" ";
return rv;
}
const std::string TOOL_EVENT::Format() const
{
std::string ev;
const FlagString categories[] = {
{TC_Mouse, "mouse"},
{TC_Command, "command"},
{TC_Message, "message"},
{TC_View, "view"},
{0, ""}
};
const FlagString actions[] = {
{TA_MouseClick, "click"},
{TA_MouseUp, "button-up"},
{TA_MouseDown, "button-down"},
{TA_MouseDrag, "drag"},
{TA_MouseMotion, "motion"},
{TA_MouseWheel, "wheel"},
{TA_ViewRefresh, "view-refresh"},
{TA_ViewZoom, "view-zoom"},
{TA_ViewPan, "view-pan"},
{TA_ViewDirty, "view-dirty"},
{TA_ChangeLayer, "change-layer"},
{TA_CancelTool, "cancel-tool"},
{TA_ActivateTool, "activate-tool"},
{TA_ContextMenuUpdate, "context-menu-update"},
{TA_ContextMenuChoice, "context-menu-choice"},
{0, ""}
};
const FlagString buttons[] = {
{MB_None, "none"},
{MB_Left, "left"},
{MB_Right, "right"},
{MB_Middle, "middle"},
{MB_ModShift, "shift"},
{MB_ModCtrl, "ctrl"},
{MB_ModAlt, "alt"},
{0, ""}
};
ev = "category: ";
ev += flag2string(m_category, categories);
ev +=" action: ";
ev += flag2string(m_actions, actions);
if(m_actions & TA_Mouse)
{
ev +=" btns: ";
ev += flag2string(m_mouseButtons, buttons);
};
if(m_commandId)
{
char tmp[128];
sprintf(tmp,"cmd-id: %d", *m_commandId);
ev += tmp;
}
if(m_commandStr)
ev += "cmd-str: " + (*m_commandStr);
return ev;
}
const std::string TOOL_EVENT_LIST::Format() const
{
string s;
BOOST_FOREACH(TOOL_EVENT e, m_events)
s+=e.Format()+" ";
return s;
}
#include <string>
#include <tool/tool_event.h>
#include <tool/tool_manager.h>
#include <tool/tool_interactive.h>
#include <tool/context_menu.h>
TOOL_INTERACTIVE::TOOL_INTERACTIVE( TOOL_ID aId, const std::string& aName ):
TOOL_BASE(TOOL_Interactive, aId, aName)
{};
TOOL_INTERACTIVE::TOOL_INTERACTIVE( const std::string& aName ):
TOOL_BASE(TOOL_Interactive, TOOL_MANAGER::MakeToolId(aName), aName)
{};
TOOL_INTERACTIVE::~TOOL_INTERACTIVE()
{
}
OPT_TOOL_EVENT TOOL_INTERACTIVE::Wait ( const TOOL_EVENT_LIST & aEventList )
{
return m_toolMgr->ScheduleWait(this, aEventList);
}
void TOOL_INTERACTIVE::goInternal( TOOL_STATE_FUNC& aState, const TOOL_EVENT_LIST& aConditions )
{
m_toolMgr->ScheduleNextState(this, aState, aConditions);
}
void TOOL_INTERACTIVE::Reset()
{
}
void TOOL_INTERACTIVE::SetContextMenu( CONTEXT_MENU *aMenu, TOOL_ContextMenuTrigger aTrigger )
{
aMenu->setTool(this);
m_toolMgr->ScheduleContextMenu(this, aMenu, aTrigger);
}
#include <map>
#include <deque>
#include <boost/foreach.hpp>
#include <boost/optional.hpp>
#include <boost/range/adaptor/map.hpp>
#include <wx/event.h>
#include <view/view.h>
#include <tool/tool_base.h>
#include <tool/tool_interactive.h>
#include <tool/tool_manager.h>
#include <tool/context_menu.h>
#include <tool/coroutine.h>
#include <wxPcbStruct.h>
#include <class_drawpanel_gal.h>
using boost::optional;
using namespace std;
struct TOOL_MANAGER::ToolState
{
TOOL_BASE *theTool;
bool idle;
bool pendingWait;
bool pendingContextMenu;
CONTEXT_MENU *contextMenu;
TOOL_ContextMenuTrigger contextMenuTrigger;
COROUTINE<int, TOOL_EVENT&> *cofunc;
TOOL_EVENT wakeupEvent;
TOOL_EVENT_LIST waitEvents;
std::vector<Transition> transitions;
};
TOOL_MANAGER::TOOL_MANAGER()
{
}
void TOOL_MANAGER::RegisterTool ( TOOL_BASE *aTool )
{
ToolState *st = new ToolState;
st->theTool = aTool;
st->idle = true;
st->pendingWait = false;
st->pendingContextMenu = false;
st->cofunc = NULL;
st->contextMenuTrigger = CMENU_OFF;
m_toolState[ aTool ] = st;
m_toolNameIndex [ aTool->GetName() ] = st;
m_toolIdIndex [ aTool->GetId() ] = st;
aTool->m_toolMgr = this;
if(aTool->GetType() == TOOL_Interactive)
static_cast<TOOL_INTERACTIVE*>(aTool)->Reset();
}
void TOOL_MANAGER::ScheduleNextState( TOOL_BASE *aTool, TOOL_STATE_FUNC& aHandler, const TOOL_EVENT_LIST & aConditions )
{
ToolState *st = m_toolState [aTool];
st->transitions.push_back ( Transition (aConditions, aHandler ));
}
optional<TOOL_EVENT> TOOL_MANAGER::ScheduleWait( TOOL_BASE *aTool, const TOOL_EVENT_LIST & aConditions )
{
ToolState *st = m_toolState [aTool];
st->pendingWait = true;
st->waitEvents = aConditions;
st->cofunc->Yield();
return st->wakeupEvent;
}
void TOOL_MANAGER::dispatchInternal ( TOOL_EVENT& aEvent )
{
// iterate over all registered tools
BOOST_FOREACH(ToolState *st, m_toolState | boost::adaptors::map_values)
{
// the tool state handler is waiting for events (i.e. called Wait() method)
if(st->pendingWait)
{
if( st->waitEvents.Matches(aEvent) )
{
// got matching event? clear wait list and wake up the coroutine
st->wakeupEvent = aEvent;
st->pendingWait = false;
st->waitEvents.clear();
st->cofunc->Resume();
if(!st->cofunc->Running())
delete st->cofunc;
}
} else {
// no state handler in progress - check if there are any transitions (defined by
// Go() method that match the event.
if(st->transitions.size()) {
BOOST_FOREACH(Transition tr, st->transitions)
{
if(tr.first.Matches(aEvent))
{
st->transitions.clear();
if(!st->cofunc)
st->cofunc = new COROUTINE<int, TOOL_EVENT&>( tr.second );
else
st->cofunc->SetEntry( tr.second );
// got match? Run the handler.
st->cofunc->Call(aEvent);
if(!st->cofunc->Running())
delete st->cofunc;
}
}
}
}
}
}
bool TOOL_MANAGER::ProcessEvent (TOOL_EVENT& aEvent)
{
printf("process: %s\n", aEvent.Format().c_str());
dispatchInternal(aEvent);
BOOST_FOREACH(ToolState *st, m_toolState | boost::adaptors::map_values)
{
if(st->contextMenuTrigger == CMENU_NOW)
{
st->pendingWait = true;
st->waitEvents = TOOL_EVENT ( TC_Any, TA_Any );
st->contextMenuTrigger = CMENU_OFF;
GetEditFrame()->PopupMenu( st->contextMenu->GetMenu() );
TOOL_EVENT evt ( TC_Command, TA_ContextMenuChoice );
dispatchInternal( evt );
break;
}
}
if(m_view->IsDirty())
{
PCB_EDIT_FRAME *f = static_cast<PCB_EDIT_FRAME*>(GetEditFrame());
f->GetGalCanvas()->Refresh(); // fixme: ugly hack, provide a method in TOOL_DISPATCHER.
}
return false;
}
void TOOL_MANAGER::ScheduleContextMenu( TOOL_BASE *aTool, CONTEXT_MENU *aMenu, TOOL_ContextMenuTrigger aTrigger )
{
ToolState *st = m_toolState [aTool];
st->contextMenu = aMenu;
st->contextMenuTrigger = aTrigger;
if(aTrigger == CMENU_NOW)
st->cofunc->Yield();
}
TOOL_ID TOOL_MANAGER::MakeToolId( const std::string &aToolName )
{
static int currentId;
return currentId++;
}
void TOOL_MANAGER::SetEnvironment( EDA_ITEM *aModel, KiGfx::VIEW* aView, KiGfx::VIEW_CONTROLS *aViewControls, wxWindow *aFrame )
{
m_model = aModel;
m_view = aView;
m_viewControls = aViewControls;
m_editFrame = aFrame;
// fixme: reset tools after changing environment
}
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@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
*/
#ifndef __CONTEXT_MENU_H
#define __CONTEXT_MENU_H
#include <wx/string.h>
class wxMenu;
class TOOL_INTERACTIVE;
/**
* Class CONTEXT_MENU
*
* Defines the structure of a context (usually right-click) popup menu
* for a given tool.
*/
class CONTEXT_MENU
{
public:
CONTEXT_MENU ( );
~CONTEXT_MENU ( );
void SetTitle( const wxString& aTitle );
void Add ( const wxString& aItem, int aId );
// fixme: unimplemented
// void Add ( const TOOL_ACTION& aAction, int aId = -1 );
void Clear();
wxMenu *GetMenu() const
{
return m_menu;
}
private:
class CMEventHandler;
friend class TOOL_INTERACTIVE;
void setTool ( TOOL_INTERACTIVE *aTool )
{
m_tool = aTool;
}
bool m_titleSet;
wxMenu *m_menu;
CMEventHandler *m_handler;
TOOL_INTERACTIVE *m_tool;
};
#endif
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@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
*/
#ifndef __COROUTINE_H
#define __COROUTINE_H
#include <cstdlib>
#include <boost/context/fcontext.hpp>
#include "delegate.h"
/**
Class COROUNTINE.
Implements a coroutine. Wikipedia has a good explanation:
"Coroutines are computer program components that generalize subroutines to
allow multiple entry points for suspending and resuming execution at certain locations.
Coroutines are well-suited for implementing more familiar program components such as cooperative
tasks, exceptions, event loop, iterators, infinite lists and pipes."
In other words, a coroutine can be considered a lightweight thread - which can be
preempted only when it deliberately yields the control to the caller. This way,
we avoid concurrency problems such as locking / race conditions.
Uses boost::context library to do the actual context switching.
This particular version takes a DELEGATE as an entry point, so it can invoke
methods within a given object as separate coroutines.
See coroutine_example.cpp for sample code.
*/
template<class ReturnType, class ArgType >
class COROUTINE {
public:
COROUTINE ( )
{
m_stackSize = c_defaultStackSize;
m_stack = NULL;
m_saved = NULL;
}
/**
* Constructor
* Creates a coroutine from a member method of an object
*/
template<class T>
COROUTINE ( T* object, ReturnType (T::*ptr)( ArgType ) ) :
m_func (object, ptr),
m_saved(NULL),
m_stack(NULL),
m_stackSize(c_defaultStackSize)
{
}
/**
* Constructor
* Creates a coroutine from a delegate object
*/
COROUTINE( DELEGATE < ReturnType, ArgType > aEntry ) :
m_func(aEntry),
m_saved(NULL),
m_stack(NULL),
m_stackSize(c_defaultStackSize)
{};
~COROUTINE()
{
if(m_saved)
delete m_saved;
if(m_stack)
free(m_stack);
}
/**
* Function Yield()
*
* Stops execution of the coroutine and returns control to the caller.
* After a yield, Call() or Resume() methods invoked by the caller will
* immediately return true, indicating that we are not done yet, just asleep.
*/
void Yield( )
{
jump_fcontext(m_self, m_saved, 0);
}
/**
* Function Yield()
*
* Yield with a value - passes a value of given type to the caller.
* Useful for implementing generator objects.
*/
void Yield( ReturnType& retVal )
{
m_retVal = retVal;
jump_fcontext(m_self, m_saved, 0);
}
/**
* Function SetEntry()
*
* Defines the entry point for the coroutine, if not set in the constructor.
*/
void SetEntry ( DELEGATE < ReturnType, ArgType > aEntry )
{
m_func = aEntry;
}
/* Function Call()
*
* Starts execution of a coroutine, passing args as its arguments.
* @return true, if the coroutine has yielded and false if it has finished its
* execution (returned).
*/
bool Call( ArgType args )
{
// fixme: Clean up stack stuff. Add a guard
m_stack = malloc(c_defaultStackSize);
// align to 16 bytes
void *sp = (void *) ((((ptrdiff_t) m_stack) + m_stackSize - 0xf) & 0xfffffff0);
m_args = &args;
m_self = boost::context::make_fcontext(sp, m_stackSize, callerStub );
m_saved = new boost::context::fcontext_t();
m_running = true;
// off we go!
boost::context::jump_fcontext(m_saved, m_self, reinterpret_cast<intptr_t> (this));
return m_running;
}
/**
* Function Resume()
*
* Resumes execution of a previously yielded coroutine.
* @return true, if the coroutine has yielded again and false if it has finished its
* execution (returned).
*/
bool Resume( )
{
jump_fcontext(m_saved, m_self, 0);
return m_running;
}
/**
* Function ReturnValue()
*
* Returns the yielded value (the argument Yield() was called with)
*/
const ReturnType& ReturnValue() const
{
return m_retVal;
}
/**
* Function Running()
*
* @return true, if the coroutine is active
*/
bool Running() const
{
return m_running;
}
private:
static const int c_defaultStackSize = 2000000;
/* real entry point of the coroutine */
static void callerStub(intptr_t data)
{
// get pointer to self
COROUTINE<ReturnType, ArgType> *cor = reinterpret_cast<COROUTINE<ReturnType, ArgType> *> (data);
// call the coroutine method
cor->m_retVal = cor->m_func(*cor->m_args);
cor->m_running = false;
// go back to wherever we came from.
boost::context::jump_fcontext(cor->m_self, cor->m_saved, 0); //reinterpret_cast<intptr_t> (this));
}
template <typename T> struct strip_ref {
typedef T result;
};
template <typename T> struct strip_ref<T&> {
typedef T result;
};
DELEGATE < ReturnType, ArgType > m_func;
///< pointer to coroutine entry arguments. Stripped of references
///< to avoid compiler errors.
typename strip_ref<ArgType>::result *m_args;
ReturnType m_retVal;
///< saved caller context
boost::context::fcontext_t *m_saved;
///< saved coroutine context
boost::context::fcontext_t *m_self;
///< coroutine stack
void *m_stack;
size_t m_stackSize;
bool m_running;
};
#endif
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@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
*/
#ifndef __DELEGATE_H
#define __DELEGATE_H
/**
* class DELEGATE
* A trivial delegate (pointer to member method of an object) pattern implementation.
* Check delegate_example.cpp for a coding sample.
*/
template<class ReturnType, class Arg>
class DELEGATE {
public:
typedef ReturnType (DELEGATE<ReturnType, Arg>::*MemberPointer)( Arg );
typedef ReturnType _ReturnType;
typedef Arg _ArgType;
DELEGATE ()
{
}
template<class T>
DELEGATE ( T* object, ReturnType (T::*ptr)( Arg ) )
{
m_ptr = reinterpret_cast<MemberPointer>(ptr);
m_object = reinterpret_cast<void *> (object);
};
ReturnType operator()( Arg a ) const
{
DELEGATE<ReturnType, Arg> *casted = reinterpret_cast<DELEGATE<ReturnType, Arg> * >(m_object);
return (casted->*m_ptr)(a);
}
private:
MemberPointer m_ptr;
void *m_object;
};
/**
* Class DELEGATE0
* Same as DELEGATE, but with no arguments.
*/
template<class ReturnType>
class DELEGATE0 {
public:
typedef ReturnType (DELEGATE0<ReturnType>::*MemberPointer)( );
typedef ReturnType _ReturnType;
DELEGATE0 ()
{
}
template<class T>
DELEGATE0 ( T* object, ReturnType (T::*ptr)( ) )
{
m_ptr = reinterpret_cast<MemberPointer>(ptr);
m_object = reinterpret_cast<void *> (object);
};
ReturnType operator()( ) const
{
DELEGATE0<ReturnType> *casted = reinterpret_cast<DELEGATE0<ReturnType> * >(m_object);
return (casted->*m_ptr)();
}
private:
MemberPointer m_ptr;
void *m_object;
};
#endif
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@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
*/
#ifndef __TOOL_BASE_H
#define __TOOL_BASE_H
#include <cassert>
// for KICAD_T.
#include <base_struct.h>
#include <tool/tool_event.h>
#include <tool/delegate.h>
class EDA_ITEM;
class TOOL_MANAGER;
namespace KiGfx {
class VIEW;
class VIEW_CONTROLS;
};
enum TOOL_Type {
TOOL_Interactive = 0x1,
TOOL_Batch = 0x2
};
typedef int TOOL_ID;
typedef DELEGATE<int, TOOL_EVENT&> TOOL_STATE_FUNC;
/**
* Class TOOL_BASE
*
* Base abstract interface for all kinds of tools
*/
class TOOL_BASE
{
public:
TOOL_BASE(TOOL_Type aType, TOOL_ID aId, const std::string& aName = std::string("")) :
m_type(aType),
m_toolId(aId),
m_toolName(aName) {};
virtual ~TOOL_BASE() {};
TOOL_Type GetType() const
{
return m_type;
}
TOOL_ID GetId() const
{
return m_toolId;
}
const std::string& GetName() const
{
return m_toolName;
}
TOOL_MANAGER *GetManager()
{
return m_toolMgr;
}
protected:
friend class TOOL_MANAGER;
/**
* Function attachManager()
*
* Sets the TOOL_MANAGER the tool will belong to.
* Called by TOOL_MANAGER::RegisterTool()
*/
void attachManager( TOOL_MANAGER *aManager );
KiGfx::VIEW *getView();
KiGfx::VIEW_CONTROLS *getViewControls();
/**
* Function getEditFrame()
*
* Returns the application window object, casted to requested user type, possibly with
* run-time type check
*/
template<typename T>
T *getEditFrame()
{
return static_cast<T*> (getEditFrameInt());
}
/**
* Function getModel()
*
* Returns the model object if it matches the requested type.
*/
template<typename T>
T* getModel( KICAD_T modelType )
{
EDA_ITEM *m = getModelInt();
// assert(modelType == m->Type());
return static_cast<T*> (m);
}
protected:
TOOL_Type m_type;
TOOL_ID m_toolId;
std::string m_toolName;
TOOL_MANAGER *m_toolMgr;
private:
// hide the implementation to avoid spreading half of
// kicad and wxWidgets headers to the tools that may not need them at all!
EDA_ITEM *getModelInt();
wxWindow *getEditFrameInt();
};
#endif
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@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
*/
#ifndef __TOOL_DISPATCHER_H
#define __TOOL_DISPATCHER_H
#include <vector>
#include <tool/tool_event.h>
#include <wx/event.h>
class TOOL_MANAGER;
class PCB_BASE_FRAME;
namespace KiGfx {
class VIEW ;
};
/**
* Class TOOL_DISPATCHER
*
* - takes wx events,
* - fixes all wx quirks (mouse warping, etc)
* - translates coordinates to world space
* - low-level input conditioning (drag/click threshold), updating mouse position during view auto-scroll/pan.
* - issues TOOL_EVENTS to the manager
*/
class TOOL_DISPATCHER
{
public:
/**
* Constructor
*
* @param aToolMgr: tool manager instance the events will be sent to
* @param aEditFrame: the frame wx events come from
*/
TOOL_DISPATCHER( TOOL_MANAGER *aToolMgr, PCB_BASE_FRAME *aEditFrame );
~TOOL_DISPATCHER();
virtual void ResetState ();
virtual void DispatchWxEvent(wxEvent &aEvent);
virtual void DispatchWxCommand(wxCommandEvent &aEvent);
private:
static const int MouseButtonCount = 3;
static const int DragTimeThreshold = 300;
static const int DragDistanceThreshold = 8;
bool handleMouseButton ( wxEvent& aEvent, int aIndex, bool aMotion );
bool handleKeys ( wxEvent& aEvent );
bool handlePopupMenu ( wxEvent& aEvent );
int decodeModifiers( wxEvent& aEvent );
KiGfx::VIEW *getView();
struct ButtonState;
TOOL_MANAGER *m_toolMgr;
PCB_BASE_FRAME *m_editFrame;
VECTOR2D m_lastMousePos;
std::vector<ButtonState*> m_buttons;
};
#endif
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@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
*/
#ifndef __TOOL_EVENT_H
#define __TOOL_EVENT_H
#include <cstdio>
#include <deque>
#include <math/vector2d.h>
#include <boost/optional.hpp>
class TOOL_MANAGER;
/**
* Internal (GUI-independent) event definitions.
* Enums are mostly self-explanatory.
*/
enum TOOL_EventCategory {
TC_None = 0x0,
TC_Mouse = 0x1,
TC_Command = 0x2,
TC_Message = 0x4,
TC_View = 0x8,
TC_Any = 0xffffffff
};
enum TOOL_Actions {
TA_None = 0x0,
TA_MouseClick = 0x1,
TA_MouseUp = 0x2,
TA_MouseDown = 0x4,
TA_MouseDrag = 0x8,
TA_MouseMotion = 0x10,
TA_MouseWheel = 0x20,
TA_Mouse = 0x3f,
TA_ViewRefresh = 0x40,
TA_ViewZoom = 0x80,
TA_ViewPan = 0x100,
TA_ViewDirty = 0x200,
TA_ChangeLayer = 0x1000,
// Tool cancel event. Issued automagically when the user hits escape or selects End Tool from the context menu.
TA_CancelTool = 0x2000,
// Tool activation event. Issued by the GUI upon pressing a button/menu selection.
TA_ActivateTool = 0x4000,
// Context menu update. Issued whenever context menu is open and the user hovers the mouse over one of choices.
// Used in dynamic highligting in disambiguation menu
TA_ContextMenuUpdate = 0x8000,
// Context menu choice. Sent if the user picked something from the context menu or closed it without selecting anything.
TA_ContextMenuChoice = 0x10000,
TA_Any = 0xffffffff
};
enum TOOL_MouseButtons {
MB_None = 0x0,
MB_Left = 0x1,
MB_Right = 0x2,
MB_Middle = 0x4,
MB_ButtonMask = MB_Left | MB_Right | MB_Middle,
MB_ModShift = 0x8,
MB_ModCtrl = 0x10,
MB_ModAlt = 0x20,
MB_ModifierMask = MB_ModShift | MB_ModCtrl | MB_ModAlt,
MB_Any = 0xffffffff
};
// Defines when a context menu is opened.
enum TOOL_ContextMenuTrigger {
CMENU_BUTTON = 0, // On the right button
CMENU_NOW, // Right now (after TOOL_INTERACTIVE::SetContxtMenu)
CMENU_OFF // Never
};
/**
* Class TOOL_EVENT
*
* Generic, UI-independent tool event.
*/
class TOOL_EVENT
{
public:
const std::string Format ( ) const;
TOOL_EVENT(TOOL_EventCategory aCategory = TC_None, TOOL_Actions aAction = TA_None ):
m_category (aCategory),
m_actions (aAction),
m_mouseButtons(0) {};
TOOL_EVENT(TOOL_EventCategory aCategory, TOOL_Actions aAction, int aExtraParam ):
m_category (aCategory),
m_actions (aAction)
{
if(aCategory == TC_Mouse)
m_mouseButtons = aExtraParam;
else if (aCategory == TC_Command)
m_commandId = aExtraParam;
};
TOOL_EVENT(TOOL_EventCategory aCategory, TOOL_Actions aAction, const std::string& aExtraParam ):
m_category (aCategory),
m_actions (aAction),
m_mouseButtons(0)
{
if(aCategory == TC_Command)
m_commandStr = aExtraParam;
}
TOOL_EventCategory Category ( ) const
{
return m_category;
}
TOOL_Actions Action ( ) const
{
return m_actions;
}
const VECTOR2D Delta() const
{
return m_mouseDelta;
}
const VECTOR2D& Position() const
{
return m_mousePos;
}
const VECTOR2D& DragOrigin() const
{
return m_mouseDragOrigin;
}
int Buttons() const
{
return m_mouseButtons;
}
bool IsClick ( int aButtonMask = MB_Any ) const
{
return (m_actions == TA_MouseClick) && ((m_mouseButtons & aButtonMask) == aButtonMask);
}
bool IsDrag ( int aButtonMask = MB_Any ) const
{
return (m_actions == TA_MouseDrag) && ((m_mouseButtons & aButtonMask) == aButtonMask);
}
bool IsMouseUp ( int aButtonMask = MB_Any ) const
{
return (m_actions == TA_MouseUp) && ((m_mouseButtons & aButtonMask) == aButtonMask);
}
bool IsMotion ( ) const
{
return (m_actions == TA_MouseMotion);
}
bool IsCancel ( ) const
{
return m_actions == TA_CancelTool;
}
bool Modifier ( int aMask = MB_ModifierMask ) const
{
return (m_mouseButtons & aMask);
}
void Ignore();
void SetMouseDragOrigin( const VECTOR2D &aP )
{
m_mouseDragOrigin = aP;
}
void SetMousePosition( const VECTOR2D& aP )
{
m_mousePos = aP;
}
void SetMouseDelta( const VECTOR2D& aP )
{
m_mouseDelta = aP;
}
bool Matches ( const TOOL_EVENT& aEvent ) const
{
if (! (m_category & aEvent.m_category))
return false;
if (! (m_actions & aEvent.m_actions))
return false;
if( m_category == TC_Command)
{
if(m_commandStr && aEvent.m_commandStr)
return (*m_commandStr == *aEvent.m_commandStr);
if(m_commandId && aEvent.m_commandId)
return (*m_commandId == *aEvent.m_commandId);
}
return true;
}
boost::optional<int> GetCommandId()
{
return m_commandId;
}
private:
friend class TOOL_MANAGER;
TOOL_EventCategory m_category;
TOOL_Actions m_actions;
VECTOR2D m_mouseDelta;
VECTOR2D m_mousePos;
VECTOR2D m_mouseDragOrigin;
int m_mouseButtons;
boost::optional<int> m_commandId;
boost::optional<std::string> m_commandStr;
};
typedef boost::optional<TOOL_EVENT> OPT_TOOL_EVENT;
/**
* Class TOOL_EVENT_LIST
*
* A list of TOOL_EVENTs, with overloaded || operators allowing for
* concatenating TOOL_EVENTs with little code.
*/
class TOOL_EVENT_LIST {
public:
typedef TOOL_EVENT value_type;
typedef std::deque<TOOL_EVENT>::iterator iterator;
typedef std::deque<TOOL_EVENT>::const_iterator const_iterator;
TOOL_EVENT_LIST() {};
TOOL_EVENT_LIST( const TOOL_EVENT& aSingleEvent )
{
m_events.push_back(aSingleEvent);
}
const std::string Format ( ) const;
boost::optional<const TOOL_EVENT&> Matches( const TOOL_EVENT &b ) const
{
for(const_iterator i = m_events.begin(); i != m_events.end(); ++i)
if (i->Matches(b))
return *i;
return boost::optional<const TOOL_EVENT&> ();
}
void Add ( const TOOL_EVENT& aEvent )
{
m_events.push_back(aEvent);
}
iterator begin()
{
return m_events.begin();
}
iterator end()
{
return m_events.end();
}
const_iterator cbegin() const
{
return m_events.begin();
}
const_iterator cend() const
{
return m_events.end();
}
int size() const
{
return m_events.size();
}
void clear()
{
m_events.clear();
}
TOOL_EVENT_LIST& operator=(const TOOL_EVENT_LIST& b)
{
m_events.clear();
for(std::deque<TOOL_EVENT>::const_iterator i = b.m_events.begin(); i != b.m_events.end(); ++i)
m_events.push_back(*i);
return *this;
}
TOOL_EVENT_LIST& operator=(const TOOL_EVENT& b)
{
m_events.clear();
m_events.push_back(b);
return *this;
}
TOOL_EVENT_LIST& operator||(const TOOL_EVENT& b)
{
Add(b);
return *this;
}
TOOL_EVENT_LIST& operator||(const TOOL_EVENT_LIST& b)
{
return *this;
}
private:
std::deque<TOOL_EVENT> m_events;
};
inline const TOOL_EVENT_LIST operator || (const TOOL_EVENT& a, const TOOL_EVENT &b )
{
TOOL_EVENT_LIST l;
l.Add(a);
l.Add(b);
return l;
}
inline const TOOL_EVENT_LIST operator || (const TOOL_EVENT & a, const TOOL_EVENT_LIST &b )
{
TOOL_EVENT_LIST l(b);
l.Add(a);
return l;
}
#endif
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@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
*/
#ifndef __TOOL_INTERACTIVE_H
#define __TOOL_INTERACTIVE_H
#include <string>
#include <tool/tool_event.h>
#include <tool/tool_base.h>
class CONTEXT_MENU;
class TOOL_INTERACTIVE : public TOOL_BASE {
public:
TOOL_INTERACTIVE( TOOL_ID aId, const std::string& aName );
/**
* Constructor
*
* Creates a tool with given name. The name must be unique. */
TOOL_INTERACTIVE( const std::string& aName );
virtual ~TOOL_INTERACTIVE();
/**
* Function Reset()
* Brings the tool to a known, initial state. If the tool claimed anything from the model or the view,
* it must release it when its reset.
*/
virtual void Reset ( ) = 0;
/**
* Function SetContextMenu()
*
* Assigns a context menu and tells when it should be activated
*/
void SetContextMenu( CONTEXT_MENU *aMenu, TOOL_ContextMenuTrigger aTrigger = CMENU_BUTTON );
/**
* Function Go()
*
* Defines which state (aStateFunc) to go when a certain event arrives (aConditions).
* No conditions means any event.
*/
template<class T>
void Go ( int (T::*aStateFunc)( TOOL_EVENT& ), const TOOL_EVENT_LIST & aConditions = TOOL_EVENT( TC_Any, TA_Any ) );
/**
* Function Wait()
*
* Suspends execution of the tool until an event specified in aEventList arrives.
* No parameters means waiting for any event.
*/
OPT_TOOL_EVENT Wait ( const TOOL_EVENT_LIST & aEventList = TOOL_EVENT ( TC_Any, TA_Any ) );
/** functions below are not yet implemented - their interface may change */
template<class Parameters, class ReturnValue>
bool InvokeTool ( const std::string& aToolName, const Parameters& parameters, ReturnValue& returnValue );
template<class Parameters, class ReturnValue>
bool InvokeWindow ( const std::string& aWindowName, const Parameters& parameters, ReturnValue& returnValue );
template<class T>
void Yield ( const T& returnValue );
protected:
/* helper functions for constructing events for Wait() and Go() with
less typing */
const TOOL_EVENT evActivate( std::string aToolName = "" );
const TOOL_EVENT evCommand( int aCommandId = -1 );
const TOOL_EVENT evCommand( std::string aCommandStr = "");
const TOOL_EVENT evMotion();
const TOOL_EVENT evClick(int aButton = MB_Any );
const TOOL_EVENT evDrag(int aButton = MB_Any );
const TOOL_EVENT evButtonUp( int aButton = MB_Any );
const TOOL_EVENT evButtonDown(int aButton = MB_Any );
private:
void goInternal( TOOL_STATE_FUNC& aState, const TOOL_EVENT_LIST& aConditions );
};
// hide TOOL_MANAGER implementation
template<class T>
void TOOL_INTERACTIVE::Go( int (T::*aStateFunc)( TOOL_EVENT& ), const TOOL_EVENT_LIST& aConditions )
{
TOOL_STATE_FUNC sptr (static_cast<T*>(this), aStateFunc);
goInternal( sptr, aConditions );
}
#endif
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@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
*/
#ifndef __TOOL_MANAGER_H
#define __TOOL_MANAGER_H
#include <cstdio>
#include <map>
#include <vector>
#include <deque>
#include <boost/unordered_map.hpp>
#include <math/vector2d.h>
#include <tool/tool_event.h>
#include <tool/tool_base.h>
class TOOL_BASE;
class CONTEXT_MENU;
class wxWindow;
/**
* Class TOOL_MANAGER.
* Master controller class:
* - registers editing tools
* - pumps UI events to tools requesting them
* - manages tool state machines (transitions and wait requests)
*/
class TOOL_MANAGER
{
public:
TOOL_MANAGER();
~TOOL_MANAGER();
/**
* Generates an unique ID from for a tool with given name.
*/
static TOOL_ID MakeToolId( const std::string &aToolName );
/**
* Function RegisterTool()
* Adds a tool to the manager set and sets it up. Called once for
* each tool during application initialization.
* @param aTool: tool to be added. Ownership is transferred.
*/
void RegisterTool(TOOL_BASE *aTool);
/**
* Function InvokeTool()
* Calls a tool by sending a tool activation event to tool of given ID or name.
* An user-defined parameter object can be also passed
*/
void InvokeTool(TOOL_ID aToolId);
void InvokeTool(const std::string& name);
template <class Parameters>
void InvokeTool( const std::string& name, const Parameters& aToolParams);
/**
* Function FindTool()
* Searches for a tool with given name or ID
*/
TOOL_BASE *FindTool(int aId);
TOOL_BASE *FindTool(const std::string& aName);
/**
* Resets the state of a given tool by clearing its wait and
* transition lists and calling tool's internal Reset() method.
*/
void ResetTool( TOOL_BASE *aTool );
/**
* Takes an event from the TOOL_DISPATCHER and propagates it to
* tools that requested events of matching type(s)
*/
bool ProcessEvent (TOOL_EVENT& aEvent);
/**
* Sets the work environment (model, view, view controls and the parent window).
* These are made available to the tool. Called by the parent frame (PCB_EDIT_FRAME)
* when the board is set up
*/
void SetEnvironment( EDA_ITEM *aModel, KiGfx::VIEW* aView, KiGfx::VIEW_CONTROLS *aViewControls, wxWindow *aFrame );
/* Accessors for the environment objects (view, model, etc.) */
KiGfx::VIEW* GetView()
{
return m_view;
}
KiGfx::VIEW_CONTROLS* GetViewControls()
{
return m_viewControls;
}
EDA_ITEM* GetModel()
{
return m_model;
}
wxWindow* GetEditFrame()
{
return m_editFrame;
}
/**
* Defines a state transition - the events that cause a given handler method in the tool
* to be called. Called by TOOL_INTERACTIVE::Go(). May be called from a coroutine context.
*/
void ScheduleNextState( TOOL_BASE *aTool, TOOL_STATE_FUNC& aHandler, const TOOL_EVENT_LIST & aConditions );
/**
* Pauses execution of a given tool until one or more events matching aConditions arrives. The pause/resume
* operation is done through COROUTINE object. Called only from coroutines.
*/
boost::optional<TOOL_EVENT> ScheduleWait( TOOL_BASE *aTool, const TOOL_EVENT_LIST & aConditions );
/**
* Sets behaviour of the tool's context popup menu.
* @param aMenu - the menu structure, defined by the tool
* @param aTrigger - when the menu is activated:
* CMENU_NOW: opens the menu right now
* CMENU_BUTTON: opens the menu when RMB is pressed
* CMENU_OFF: menu is disabled.
* May be called from a coroutine context.
*/
void ScheduleContextMenu( TOOL_BASE *aTool, CONTEXT_MENU *aMenu, TOOL_ContextMenuTrigger aTrigger );
private:
void dispatchInternal ( TOOL_EVENT& aEvent );
struct ToolState;
typedef std::pair<TOOL_EVENT_LIST, TOOL_STATE_FUNC> Transition;
std::map<TOOL_BASE*, ToolState*> m_toolState;
std::map<std::string, ToolState*> m_toolNameIndex;
std::map<TOOL_ID, ToolState*> m_toolIdIndex;
EDA_ITEM *m_model;
KiGfx::VIEW *m_view;
KiGfx::VIEW_CONTROLS *m_viewControls;
wxWindow *m_editFrame;
ToolState *m_currentTool;
};
#endif
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment