From 2d09237bd767ccd35abb8adb2cefb4e9aabbbe26 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 Aug 2013 16:46:53 +0200 Subject: [PATCH] Added core tool framework files + boost::context assembly stuff (initial, very buggy and unfinished work). --- common/CMakeLists.txt | 14 +- common/system/fcontext.s | 20 ++ common/system/jump_i386_pe_gas.S | 57 ++++ common/system/jump_i386_sysv_elf_gas.S | 72 +++++ common/system/jump_x86_64_sysv_elf_gas.S | 82 +++++ common/system/make_i386_pe_gas.S | 54 ++++ common/system/make_i386_sysv_elf_gas.S | 77 +++++ common/system/make_x86_64_sysv_elf_gas.S | 74 +++++ common/tool/context_menu.cpp | 71 +++++ common/tool/tool_base.cpp | 22 ++ common/tool/tool_dispatcher.cpp | 224 ++++++++++++++ common/tool/tool_event.cpp | 101 ++++++ common/tool/tool_interactive.cpp | 41 +++ common/tool/tool_manager.cpp | 193 ++++++++++++ include/tool/context_menu.h | 78 +++++ include/tool/coroutine.h | 240 +++++++++++++++ include/tool/delegate.h | 99 ++++++ include/tool/tool_base.h | 147 +++++++++ include/tool/tool_dispatcher.h | 90 ++++++ include/tool/tool_event.h | 374 +++++++++++++++++++++++ include/tool/tool_interactive.h | 115 +++++++ include/tool/tool_manager.h | 174 +++++++++++ 22 files changed, 2418 insertions(+), 1 deletion(-) create mode 100644 common/system/fcontext.s create mode 100644 common/system/jump_i386_pe_gas.S create mode 100644 common/system/jump_i386_sysv_elf_gas.S create mode 100644 common/system/jump_x86_64_sysv_elf_gas.S create mode 100644 common/system/make_i386_pe_gas.S create mode 100644 common/system/make_i386_sysv_elf_gas.S create mode 100644 common/system/make_x86_64_sysv_elf_gas.S create mode 100644 common/tool/context_menu.cpp create mode 100644 common/tool/tool_base.cpp create mode 100644 common/tool/tool_dispatcher.cpp create mode 100644 common/tool/tool_event.cpp create mode 100644 common/tool/tool_interactive.cpp create mode 100644 common/tool/tool_manager.cpp create mode 100644 include/tool/context_menu.h create mode 100644 include/tool/coroutine.h create mode 100644 include/tool/delegate.h create mode 100644 include/tool/tool_base.h create mode 100644 include/tool/tool_dispatcher.h create mode 100644 include/tool/tool_event.h create mode 100644 include/tool/tool_interactive.h create mode 100644 include/tool/tool_manager.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 9b7c285168..25357990ca 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -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}) diff --git a/common/system/fcontext.s b/common/system/fcontext.s new file mode 100644 index 0000000000..71055cc9a2 --- /dev/null +++ b/common/system/fcontext.s @@ -0,0 +1,20 @@ +/* + 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 + diff --git a/common/system/jump_i386_pe_gas.S b/common/system/jump_i386_pe_gas.S new file mode 100644 index 0000000000..39db0dec1f --- /dev/null +++ b/common/system/jump_i386_pe_gas.S @@ -0,0 +1,57 @@ +/* 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 diff --git a/common/system/jump_i386_sysv_elf_gas.S b/common/system/jump_i386_sysv_elf_gas.S new file mode 100644 index 0000000000..7b50dfe181 --- /dev/null +++ b/common/system/jump_i386_sysv_elf_gas.S @@ -0,0 +1,72 @@ +/* + 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 diff --git a/common/system/jump_x86_64_sysv_elf_gas.S b/common/system/jump_x86_64_sysv_elf_gas.S new file mode 100644 index 0000000000..40b65d7db6 --- /dev/null +++ b/common/system/jump_x86_64_sysv_elf_gas.S @@ -0,0 +1,82 @@ +/* + 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 diff --git a/common/system/make_i386_pe_gas.S b/common/system/make_i386_pe_gas.S new file mode 100644 index 0000000000..297f8bf54a --- /dev/null +++ b/common/system/make_i386_pe_gas.S @@ -0,0 +1,54 @@ +/* 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 + diff --git a/common/system/make_i386_sysv_elf_gas.S b/common/system/make_i386_sysv_elf_gas.S new file mode 100644 index 0000000000..ef0e1b4086 --- /dev/null +++ b/common/system/make_i386_sysv_elf_gas.S @@ -0,0 +1,77 @@ +/* + 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 diff --git a/common/system/make_x86_64_sysv_elf_gas.S b/common/system/make_x86_64_sysv_elf_gas.S new file mode 100644 index 0000000000..ba040d0519 --- /dev/null +++ b/common/system/make_x86_64_sysv_elf_gas.S @@ -0,0 +1,74 @@ +/* + 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 + diff --git a/common/tool/context_menu.cpp b/common/tool/context_menu.cpp new file mode 100644 index 0000000000..2649b2056e --- /dev/null +++ b/common/tool/context_menu.cpp @@ -0,0 +1,71 @@ +#include +#include + +#include +#include +#include + +#include + +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 diff --git a/common/tool/tool_base.cpp b/common/tool/tool_base.cpp new file mode 100644 index 0000000000..82b1f1ac55 --- /dev/null +++ b/common/tool/tool_base.cpp @@ -0,0 +1,22 @@ +#include +#include + +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 diff --git a/common/tool/tool_dispatcher.cpp b/common/tool/tool_dispatcher.cpp new file mode 100644 index 0000000000..4e114a58c1 --- /dev/null +++ b/common/tool/tool_dispatcher.cpp @@ -0,0 +1,224 @@ +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +#include +#include + +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 (&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 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 evt; + + int type = aEvent.GetEventType(); + + if( type == wxEVT_MOTION ) + { + wxMouseEvent *me = static_cast (&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 diff --git a/common/tool/tool_event.cpp b/common/tool/tool_event.cpp new file mode 100644 index 0000000000..d10822f9c4 --- /dev/null +++ b/common/tool/tool_event.cpp @@ -0,0 +1,101 @@ +#include +#include + +#include + +#include +#include + +#include + +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; +} diff --git a/common/tool/tool_interactive.cpp b/common/tool/tool_interactive.cpp new file mode 100644 index 0000000000..2389c33eed --- /dev/null +++ b/common/tool/tool_interactive.cpp @@ -0,0 +1,41 @@ +#include + +#include +#include +#include +#include + +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); +} diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp new file mode 100644 index 0000000000..2fa4e702e5 --- /dev/null +++ b/common/tool/tool_manager.cpp @@ -0,0 +1,193 @@ +#include +#include + + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +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 *cofunc; + + TOOL_EVENT wakeupEvent; + TOOL_EVENT_LIST waitEvents; + + std::vector 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(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_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( 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(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 +} diff --git a/include/tool/context_menu.h b/include/tool/context_menu.h new file mode 100644 index 0000000000..a8d2f4292a --- /dev/null +++ b/include/tool/context_menu.h @@ -0,0 +1,78 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Tomasz Wlostowski + * + * 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 + +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 diff --git a/include/tool/coroutine.h b/include/tool/coroutine.h new file mode 100644 index 0000000000..be57b97778 --- /dev/null +++ b/include/tool/coroutine.h @@ -0,0 +1,240 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Tomasz Wlostowski + * + * 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 + +#include + +#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 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 + 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 (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 *cor = reinterpret_cast *> (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 (this)); + } + + template struct strip_ref { + typedef T result; + }; + + template struct strip_ref { + typedef T result; + }; + + + DELEGATE < ReturnType, ArgType > m_func; + + ///< pointer to coroutine entry arguments. Stripped of references + ///< to avoid compiler errors. + typename strip_ref::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 diff --git a/include/tool/delegate.h b/include/tool/delegate.h new file mode 100644 index 0000000000..3e48b57ccc --- /dev/null +++ b/include/tool/delegate.h @@ -0,0 +1,99 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Tomasz Wlostowski + * + * 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 DELEGATE { + public: + typedef ReturnType (DELEGATE::*MemberPointer)( Arg ); + typedef ReturnType _ReturnType; + typedef Arg _ArgType; + + DELEGATE () + { + } + + template + DELEGATE ( T* object, ReturnType (T::*ptr)( Arg ) ) + { + m_ptr = reinterpret_cast(ptr); + m_object = reinterpret_cast (object); + }; + + + ReturnType operator()( Arg a ) const + { + DELEGATE *casted = reinterpret_cast * >(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 DELEGATE0 { + public: + typedef ReturnType (DELEGATE0::*MemberPointer)( ); + + typedef ReturnType _ReturnType; + + DELEGATE0 () + { + } + + template + DELEGATE0 ( T* object, ReturnType (T::*ptr)( ) ) + { + m_ptr = reinterpret_cast(ptr); + m_object = reinterpret_cast (object); + }; + + + ReturnType operator()( ) const + { + DELEGATE0 *casted = reinterpret_cast * >(m_object); + return (casted->*m_ptr)(); + } + +private: + MemberPointer m_ptr; + void *m_object; +}; + +#endif diff --git a/include/tool/tool_base.h b/include/tool/tool_base.h new file mode 100644 index 0000000000..fd9658f06b --- /dev/null +++ b/include/tool/tool_base.h @@ -0,0 +1,147 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Tomasz Wlostowski + * + * 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 + +// for KICAD_T. +#include + +#include +#include + +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 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 + T *getEditFrame() + { + return static_cast (getEditFrameInt()); + } + + /** + * Function getModel() + * + * Returns the model object if it matches the requested type. + */ + template + T* getModel( KICAD_T modelType ) + { + EDA_ITEM *m = getModelInt(); +// assert(modelType == m->Type()); + return static_cast (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 diff --git a/include/tool/tool_dispatcher.h b/include/tool/tool_dispatcher.h new file mode 100644 index 0000000000..572d4bc60e --- /dev/null +++ b/include/tool/tool_dispatcher.h @@ -0,0 +1,90 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Tomasz Wlostowski + * + * 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 + +#include + +#include + +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 m_buttons; + +}; + +#endif diff --git a/include/tool/tool_event.h b/include/tool/tool_event.h new file mode 100644 index 0000000000..4811fa1cfb --- /dev/null +++ b/include/tool/tool_event.h @@ -0,0 +1,374 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Tomasz Wlostowski + * + * 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 +#include + +#include + +#include + +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 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 m_commandId; + boost::optional m_commandStr; + + + +}; + +typedef boost::optional 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::iterator iterator; + typedef std::deque::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 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 (); + } + + 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::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 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 diff --git a/include/tool/tool_interactive.h b/include/tool/tool_interactive.h new file mode 100644 index 0000000000..679ab5588e --- /dev/null +++ b/include/tool/tool_interactive.h @@ -0,0 +1,115 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Tomasz Wlostowski + * + * 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 + +#include +#include + +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 + 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 + bool InvokeTool ( const std::string& aToolName, const Parameters& parameters, ReturnValue& returnValue ); + + template + bool InvokeWindow ( const std::string& aWindowName, const Parameters& parameters, ReturnValue& returnValue ); + + template + 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 +void TOOL_INTERACTIVE::Go( int (T::*aStateFunc)( TOOL_EVENT& ), const TOOL_EVENT_LIST& aConditions ) +{ + TOOL_STATE_FUNC sptr (static_cast(this), aStateFunc); + goInternal( sptr, aConditions ); +} + +#endif diff --git a/include/tool/tool_manager.h b/include/tool/tool_manager.h new file mode 100644 index 0000000000..4a70d5048a --- /dev/null +++ b/include/tool/tool_manager.h @@ -0,0 +1,174 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Tomasz Wlostowski + * + * 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 +#include +#include +#include + +#include + +#include + +#include +#include + +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 + 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 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 Transition; + + std::map m_toolState; + std::map m_toolNameIndex; + std::map 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