Mercurial > hg > orthanc-stone
changeset 880:9953f16c304d am-dev
Merge
author | Alain Mazy <alain@mazy.be> |
---|---|
date | Fri, 05 Jul 2019 15:33:02 +0200 |
parents | 12b591d5d63c (current diff) 4bc8d9609447 (diff) |
children | a8cd3755db21 |
files | Applications/Generic/GuiAdapter.cpp Applications/Generic/GuiAdapter.h Resources/CMake/OrthancStoneConfiguration.cmake |
diffstat | 23 files changed, 1294 insertions(+), 249 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Fri Jul 05 14:52:43 2019 +0200 +++ b/.hgtags Fri Jul 05 15:33:02 2019 +0200 @@ -1,2 +1,6 @@ 90f3a60576a9f08dcf783752a7f67ce0615a5371 rtviewer19 6d15261f9c9965a2f4b64658e318b370933b175e toa2019061901 +ff3559c489c98fad1ed174f7be919df6c20d36a9 toa2019062401 +c71ef52602a00dbb35f2b6bd7bd5ed516f1014fa toa2019062501 +fe96057e97b94eb8a46c1a33ba350c354b5c4afc toa2019062502 +60a403f01c3112249f9d4a1a6149bef1de9766bf toa2019062503
--- a/Applications/Generic/GuiAdapter.cpp Fri Jul 05 14:52:43 2019 +0200 +++ b/Applications/Generic/GuiAdapter.cpp Fri Jul 05 15:33:02 2019 +0200 @@ -44,7 +44,7 @@ std::ostream& operator<<( std::ostream& os, const GuiAdapterKeyboardEvent& event) { - os << "ctrl: " << event.ctrlKey << ", " << + os << "sym: " << event.sym << " (" << (int)(event.sym[0]) << ") ctrl: " << event.ctrlKey << ", " << "shift: " << event.shiftKey << ", " << "alt: " << event.altKey; return os; @@ -112,10 +112,7 @@ //dest.padding = src.padding; } - void ConvertFromPlatform( - GuiAdapterWheelEvent& dest, - int eventType, - const EmscriptenWheelEvent& src) + void ConvertFromPlatform( GuiAdapterWheelEvent& dest, int eventType, const EmscriptenWheelEvent& src) { ConvertFromPlatform(dest.mouse, eventType, src.mouse); dest.deltaX = src.deltaX; @@ -138,15 +135,15 @@ dest.deltaMode = src.deltaMode; } - void ConvertFromPlatform( - GuiAdapterKeyboardEvent& dest, - const EmscriptenKeyboardEvent& src) + void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const EmscriptenKeyboardEvent& src) { + dest.sym[0] = src.key[0]; + dest.sym[1] = 0; dest.ctrlKey = src.ctrlKey; dest.shiftKey = src.shiftKey; dest.altKey = src.altKey; } - + template<typename GenericFunc> struct FuncAdapterPayload { @@ -156,10 +153,10 @@ }; template<typename GenericFunc, - typename GuiAdapterEvent, - typename EmscriptenEvent> - EM_BOOL OnEventAdapterFunc( - int eventType, const EmscriptenEvent* emEvent, void* userData) + typename GuiAdapterEvent, + typename EmscriptenEvent> + EM_BOOL OnEventAdapterFunc( + int eventType, const EmscriptenEvent* emEvent, void* userData) { // userData is OnMouseWheelFuncAdapterPayload @@ -170,7 +167,7 @@ // LOG(INFO) << "eventType: " << eventType << " wheelEvent: " << // (int)wheelEvent << " userData: " << userData << // " payload->userData: " << payload->userData; - + GuiAdapterEvent guiEvent; ConvertFromPlatform(guiEvent, eventType, *emEvent); bool ret = (*(payload->callback))(payload->canvasId, &guiEvent, payload->userData); @@ -186,7 +183,7 @@ // userData is OnMouseWheelFuncAdapterPayload FuncAdapterPayload<GenericFunc>* payload = reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData); - + GuiAdapterEvent guiEvent; ConvertFromPlatform(guiEvent, *wheelEvent); bool ret = (*(payload->callback))(payload->canvasId, &guiEvent, payload->userData); @@ -194,8 +191,8 @@ } template<typename GenericFunc> - EM_BOOL OnEventAdapterFunc3( - double time, void* userData) + EM_BOOL OnEventAdapterFunc3( + double time, void* userData) { // userData is OnMouseWheelFuncAdapterPayload FuncAdapterPayload<GenericFunc>* payload = @@ -207,17 +204,17 @@ // resize: (const char* target, void* userData, EM_BOOL useCapture, em_ui_callback_func callback) template< - typename GenericFunc, - typename GuiAdapterEvent, - typename EmscriptenEvent, + typename GenericFunc, + typename GuiAdapterEvent, + typename EmscriptenEvent, typename EmscriptenSetCallbackFunc> - static void SetCallback( - EmscriptenSetCallbackFunc emFunc, - std::string canvasId, void* userData, bool capture, GenericFunc func) + static void SetCallback( + EmscriptenSetCallbackFunc emFunc, + std::string canvasId, void* userData, bool capture, GenericFunc func) { // TODO: write RemoveCallback with an int id that gets returned from // here - FuncAdapterPayload<GenericFunc>* payload = + FuncAdapterPayload<GenericFunc>* payload = new FuncAdapterPayload<GenericFunc>(); std::auto_ptr<FuncAdapterPayload<GenericFunc> > payloadP(payload); payload->canvasId = canvasId; @@ -397,76 +394,107 @@ #else -// SDL ONLY -void ConvertFromPlatform( - GuiAdapterMouseEvent& dest, - bool ctrlPressed, bool shiftPressed, bool altPressed, - const SDL_Event& source) -{ - memset(&dest, 0, sizeof(GuiAdapterMouseEvent)); - switch (source.type) + // SDL ONLY + void ConvertFromPlatform(GuiAdapterMouseEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source) { - case SDL_MOUSEBUTTONDOWN: - dest.type = GUIADAPTER_EVENT_MOUSEDOWN; - break; - case SDL_MOUSEMOTION: - dest.type = GUIADAPTER_EVENT_MOUSEMOVE; - break; - case SDL_MOUSEBUTTONUP: - dest.type = GUIADAPTER_EVENT_MOUSEUP; - break; - case SDL_MOUSEWHEEL: - dest.type = GUIADAPTER_EVENT_WHEEL; - break; - default: - LOG(ERROR) << "SDL event: " << source.type << " is not supported"; - ORTHANC_ASSERT(false, "Not supported"); + memset(&dest, 0, sizeof(GuiAdapterMouseEvent)); + switch (source.type) + { + case SDL_MOUSEBUTTONDOWN: + dest.type = GUIADAPTER_EVENT_MOUSEDOWN; + break; + case SDL_MOUSEMOTION: + dest.type = GUIADAPTER_EVENT_MOUSEMOVE; + break; + case SDL_MOUSEBUTTONUP: + dest.type = GUIADAPTER_EVENT_MOUSEUP; + break; + case SDL_MOUSEWHEEL: + dest.type = GUIADAPTER_EVENT_WHEEL; + break; + default: + LOG(ERROR) << "SDL event: " << source.type << " is not supported"; + ORTHANC_ASSERT(false, "Not supported"); } - //dest.timestamp = src.timestamp; - //dest.screenX = src.screenX; - //dest.screenY = src.screenY; - //dest.clientX = src.clientX; - //dest.clientY = src.clientY; - dest.ctrlKey = ctrlPressed; - dest.shiftKey = shiftPressed; - dest.altKey = altPressed; - //dest.metaKey = src.metaKey; - switch (source.button.button) - { - case SDL_BUTTON_MIDDLE: - dest.button = GUIADAPTER_MOUSEBUTTON_MIDDLE; - break; + //dest.timestamp = src.timestamp; + //dest.screenX = src.screenX; + //dest.screenY = src.screenY; + //dest.clientX = src.clientX; + //dest.clientY = src.clientY; + dest.ctrlKey = ctrlPressed; + dest.shiftKey = shiftPressed; + dest.altKey = altPressed; + //dest.metaKey = src.metaKey; + switch (source.button.button) + { + case SDL_BUTTON_MIDDLE: + dest.button =GUIADAPTER_MOUSEBUTTON_MIDDLE; + break; - case SDL_BUTTON_RIGHT: - dest.button = GUIADAPTER_MOUSEBUTTON_RIGHT; - break; + case SDL_BUTTON_RIGHT: + dest.button = GUIADAPTER_MOUSEBUTTON_RIGHT; + break; - case SDL_BUTTON_LEFT: - dest.button = GUIADAPTER_MOUSEBUTTON_LEFT; - break; + case SDL_BUTTON_LEFT: + dest.button = GUIADAPTER_MOUSEBUTTON_LEFT; + break; - default: - break; - } - //dest.buttons = src.buttons; - //dest.movementX = src.movementX; - //dest.movementY = src.movementY; - dest.targetX = source.button.x; - dest.targetY = source.button.y; - //dest.canvasX = src.canvasX; - //dest.canvasY = src.canvasY; - //dest.padding = src.padding; + default: + break; + } + //dest.buttons = src.buttons; + //dest.movementX = src.movementX; + //dest.movementY = src.movementY; + dest.targetX = source.button.x; + dest.targetY = source.button.y; + //dest.canvasX = src.canvasX; + //dest.canvasY = src.canvasY; + //dest.padding = src.padding; } -void ConvertFromPlatform( - GuiAdapterWheelEvent& dest, - bool ctrlPressed, bool shiftPressed, bool altPressed, - const SDL_Event& source) -{ - ConvertFromPlatform(dest.mouse, ctrlPressed, shiftPressed, altPressed, source); - dest.deltaX = source.wheel.x; - dest.deltaY = source.wheel.y; -} + void ConvertFromPlatform( + GuiAdapterWheelEvent& dest, + bool ctrlPressed, bool shiftPressed, bool altPressed, + const SDL_Event& source) + { + ConvertFromPlatform(dest.mouse, ctrlPressed, shiftPressed, altPressed, source); + dest.deltaX = source.wheel.x; + dest.deltaY = source.wheel.y; + } + + void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const SDL_Event& src) + { + memset(&dest, 0, sizeof(GuiAdapterMouseEvent)); + switch (src.type) + { + case SDL_KEYDOWN: + dest.type = GUIADAPTER_EVENT_KEYDOWN; + break; + case SDL_KEYUP: + dest.type = GUIADAPTER_EVENT_KEYUP; + break; + default: + LOG(ERROR) << "SDL event: " << src.type << " is not supported"; + ORTHANC_ASSERT(false, "Not supported"); + } + dest.sym[0] = src.key.keysym.sym; + dest.sym[1] = 0; + + if (src.key.keysym.mod & KMOD_CTRL) + dest.ctrlKey = true; + else + dest.ctrlKey = false; + + if (src.key.keysym.mod & KMOD_SHIFT) + dest.shiftKey = true; + else + dest.shiftKey = false; + + if (src.key.keysym.mod & KMOD_ALT) + dest.altKey = true; + else + dest.altKey = false; + } @@ -480,43 +508,44 @@ // SDL ONLY void GuiAdapter::SetMouseDownCallback( std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) - { + { mouseDownHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData)); - } + } // SDL ONLY void GuiAdapter::SetMouseMoveCallback( std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) - { + { mouseMoveHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData)); } // SDL ONLY void GuiAdapter::SetMouseUpCallback( std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) - { + { mouseUpHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData)); } // SDL ONLY void GuiAdapter::SetWheelCallback( - std::string canvasId, void* userData, bool capture, OnMouseWheelFunc func) + std::string canvasId, void* userData, bool capture, OnMouseWheelFunc func) { mouseWheelHandlers_.push_back(EventHandlerData<OnMouseWheelFunc>(canvasId, func, userData)); } // SDL ONLY void GuiAdapter::SetKeyDownCallback( - std::string canvasId, void* userData, bool capture, OnKeyDownFunc func) - { - } + std::string canvasId, void* userData, bool capture, OnKeyDownFunc func) + { + keyDownHandlers_.push_back(EventHandlerData<OnKeyDownFunc>(canvasId, func, userData)); + } // SDL ONLY void GuiAdapter::SetKeyUpCallback( - std::string canvasId, void* userData, bool capture, OnKeyUpFunc func) - { - } - + std::string canvasId, void* userData, bool capture, OnKeyUpFunc func) + { + keyUpHandlers_.push_back(EventHandlerData<OnKeyUpFunc>(canvasId, func, userData)); + } // SDL ONLY void GuiAdapter::OnAnimationFrame() @@ -558,7 +587,7 @@ case GUIADAPTER_EVENT_WHEEL: for (size_t i = 0; i < mouseWheelHandlers_.size(); i++) { - if(mouseWheelHandlers_[i].canvasName == windowTitle) + if (mouseWheelHandlers_[i].canvasName == windowTitle) (*(mouseWheelHandlers_[i].func))(windowTitle, &event, mouseWheelHandlers_[i].userData); } break; @@ -568,14 +597,16 @@ } } - // SDL ONLY - void GuiAdapter::OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& event) + + void GuiAdapter::OnKeyboardEvent(uint32_t windowID, const GuiAdapterKeyboardEvent& event) { - // the SDL window name IS the canvas name ("canvas" is used because this lib - // is designed for Wasm + // only one-letter (ascii) keyboard events supported for now + ORTHANC_ASSERT(event.sym[0] != 0); + ORTHANC_ASSERT(event.sym[1] == 0); + SDL_Window* sdlWindow = SDL_GetWindowFromID(windowID); ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowID << "\" is not a valid SDL window ID!"); - + const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow); ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowID << "\" has a NULL window title!"); @@ -584,42 +615,84 @@ switch (event.type) { - case GUIADAPTER_EVENT_MOUSEDOWN: - for (size_t i = 0; i < mouseDownHandlers_.size(); i++) + case GUIADAPTER_EVENT_KEYDOWN: + for (size_t i = 0; i < keyDownHandlers_.size(); i++) { - if (mouseDownHandlers_[i].canvasName == windowTitle) - (*(mouseDownHandlers_[i].func))(windowTitle, &event, mouseDownHandlers_[i].userData); + (*(keyDownHandlers_[i].func))(windowTitle, &event, keyDownHandlers_[i].userData); } break; - case GUIADAPTER_EVENT_MOUSEMOVE: - for (size_t i = 0; i < mouseMoveHandlers_.size(); i++) + case GUIADAPTER_EVENT_KEYUP: + for (size_t i = 0; i < keyUpHandlers_.size(); i++) { - if (mouseMoveHandlers_[i].canvasName == windowTitle) - (*(mouseMoveHandlers_[i].func))(windowTitle, &event, mouseMoveHandlers_[i].userData); - } - break; - case GUIADAPTER_EVENT_MOUSEUP: - for (size_t i = 0; i < mouseUpHandlers_.size(); i++) - { - if (mouseUpHandlers_[i].canvasName == windowTitle) - (*(mouseUpHandlers_[i].func))(windowTitle, &event, mouseUpHandlers_[i].userData); + (*(keyUpHandlers_[i].func))(windowTitle, &event, keyUpHandlers_[i].userData); } break; default: - ORTHANC_ASSERT(false, "Wrong event.type: " << event.type << " in GuiAdapter::OnMouseEvent(...)"); + ORTHANC_ASSERT(false, "Wrong event.type: " << event.type << " in GuiAdapter::OnKeyboardEvent(...)"); break; } + } - ////boost::shared_ptr<IGuiAdapterWidget> GetWidgetFromWindowId(); - //boost::shared_ptr<IGuiAdapterWidget> foundWidget; - //VisitWidgets([foundWidget, windowID](auto widget) - // { - // if (widget->GetSdlWindowID() == windowID) - // foundWidget = widget; - // }); - //ORTHANC_ASSERT(foundWidget, "WindowID " << windowID << " was not found in the registered widgets!"); - //if(foundWidget) - // foundWidget-> + // SDL ONLY + void GuiAdapter::OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& event) + { + if (windowID == 0) + { + LOG(WARNING) << "GuiAdapter::OnMouseEvent -- windowID == 0 and event won't be routed!"; + } + else + { + // the SDL window name IS the canvas name ("canvas" is used because this lib + // is designed for Wasm + SDL_Window* sdlWindow = SDL_GetWindowFromID(windowID); + + ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowID << "\" is not a valid SDL window ID!"); + + const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow); + ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowID << "\" has a NULL window title!"); + + std::string windowTitle(windowTitleSz); + ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowID << "\" has an empty window title!"); + + switch (event.type) + { + case GUIADAPTER_EVENT_MOUSEDOWN: + for (size_t i = 0; i < mouseDownHandlers_.size(); i++) + { + if (mouseDownHandlers_[i].canvasName == windowTitle) + (*(mouseDownHandlers_[i].func))(windowTitle, &event, mouseDownHandlers_[i].userData); + } + break; + case GUIADAPTER_EVENT_MOUSEMOVE: + for (size_t i = 0; i < mouseMoveHandlers_.size(); i++) + { + if (mouseMoveHandlers_[i].canvasName == windowTitle) + (*(mouseMoveHandlers_[i].func))(windowTitle, &event, mouseMoveHandlers_[i].userData); + } + break; + case GUIADAPTER_EVENT_MOUSEUP: + for (size_t i = 0; i < mouseUpHandlers_.size(); i++) + { + if (mouseUpHandlers_[i].canvasName == windowTitle) + (*(mouseUpHandlers_[i].func))(windowTitle, &event, mouseUpHandlers_[i].userData); + } + break; + default: + ORTHANC_ASSERT(false, "Wrong event.type: " << event.type << " in GuiAdapter::OnMouseEvent(...)"); + break; + } + + ////boost::shared_ptr<IGuiAdapterWidget> GetWidgetFromWindowId(); + //boost::shared_ptr<IGuiAdapterWidget> foundWidget; + //VisitWidgets([foundWidget, windowID](auto widget) + // { + // if (widget->GetSdlWindowID() == windowID) + // foundWidget = widget; + // }); + //ORTHANC_ASSERT(foundWidget, "WindowID " << windowID << " was not found in the registered widgets!"); + //if(foundWidget) + // foundWidget-> + } } // SDL ONLY @@ -637,7 +710,7 @@ GLuint id, GLenum severity, GLsizei length, - const GLchar* message, + const GLchar * message, const void* userParam) { if (severity != GL_DEBUG_SEVERITY_NOTIFICATION) @@ -646,7 +719,7 @@ (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), type, severity, message); } -} + } # endif // SDL ONLY @@ -680,16 +753,16 @@ stop = true; break; } - else if ( (event.type == SDL_MOUSEMOTION) || - (event.type == SDL_MOUSEBUTTONDOWN) || - (event.type == SDL_MOUSEBUTTONUP) ) + else if ((event.type == SDL_MOUSEMOTION) || + (event.type == SDL_MOUSEBUTTONDOWN) || + (event.type == SDL_MOUSEBUTTONUP)) { int scancodeCount = 0; const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount); bool ctrlPressed(false); bool shiftPressed(false); bool altPressed(false); - + if (SDL_SCANCODE_LCTRL < scancodeCount && keyboardState[SDL_SCANCODE_LCTRL]) ctrlPressed = true; if (SDL_SCANCODE_RCTRL < scancodeCount && keyboardState[SDL_SCANCODE_RCTRL]) @@ -700,7 +773,7 @@ shiftPressed = true; if (SDL_SCANCODE_LALT < scancodeCount && keyboardState[SDL_SCANCODE_LALT]) altPressed = true; - + GuiAdapterMouseEvent dest; ConvertFromPlatform(dest, ctrlPressed, shiftPressed, altPressed, event); OnMouseEvent(event.window.windowID, dest); @@ -768,23 +841,14 @@ // window.GetWindow().ToggleMaximize(); //TODO: move to particular handler break; - case SDLK_s: -#if 0 - // TODO: re-enable at application-level!!!! - VisitWidgets( - [](auto value) - { - auto widget = boost::dynamic_pointer_cast<VolumeSlicerWidget() - value->FitContent(); - }); -#endif - break; - case SDLK_q: stop = true; break; default: + GuiAdapterKeyboardEvent dest; + ConvertFromPlatform(dest, event); + OnKeyboardEvent(event.window.windowID, dest); break; } }
--- a/Applications/Generic/GuiAdapter.h Fri Jul 05 14:52:43 2019 +0200 +++ b/Applications/Generic/GuiAdapter.h Fri Jul 05 15:33:02 2019 +0200 @@ -75,12 +75,14 @@ }; - enum GuiAdapterMouseEventType + enum GuiAdapterHidEventType { GUIADAPTER_EVENT_MOUSEDOWN = 1973, GUIADAPTER_EVENT_MOUSEMOVE = 1974, GUIADAPTER_EVENT_MOUSEUP = 1975, - GUIADAPTER_EVENT_WHEEL = 1976 + GUIADAPTER_EVENT_WHEEL = 1976, + GUIADAPTER_EVENT_KEYDOWN = 1977, + GUIADAPTER_EVENT_KEYUP = 1978, }; const unsigned int GUIADAPTER_DELTA_PIXEL = 2973; @@ -124,8 +126,9 @@ #endif #endif - struct GuiAdapterMouseEvent { - GuiAdapterMouseEventType type; + struct GuiAdapterMouseEvent + { + GuiAdapterHidEventType type; //double timestamp; //long screenX; //long screenY; @@ -168,6 +171,8 @@ // EmscriptenKeyboardEvent struct GuiAdapterKeyboardEvent { + GuiAdapterHidEventType type; + char sym[32]; bool ctrlKey; bool shiftKey; bool altKey; @@ -193,37 +198,21 @@ FROM: https://codingrepo.com/javascript/2017/05/19/javascript-difference-mousedown-mouseup-click-events/ */ #if ORTHANC_ENABLE_WASM == 1 - void ConvertFromPlatform( - GuiAdapterUiEvent& dest, - int eventType, - const EmscriptenUiEvent& src); + void ConvertFromPlatform(GuiAdapterUiEvent& dest, int eventType, const EmscriptenUiEvent& src); - void ConvertFromPlatform( - GuiAdapterMouseEvent& dest, - int eventType, - const EmscriptenMouseEvent& src); + void ConvertFromPlatform(GuiAdapterMouseEvent& dest, int eventType, const EmscriptenMouseEvent& src); - void ConvertFromPlatform( - GuiAdapterWheelEvent& dest, - int eventType, - const EmscriptenWheelEvent& src); + void ConvertFromPlatform(GuiAdapterWheelEvent& dest, int eventType, const EmscriptenWheelEvent& src); - void ConvertFromPlatform( - GuiAdapterKeyboardEvent& dest, - const EmscriptenKeyboardEvent& src); - + void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const EmscriptenKeyboardEvent& src); #else # if ORTHANC_ENABLE_SDL == 1 - void ConvertFromPlatform( - GuiAdapterMouseEvent& dest, - bool ctrlPressed, bool shiftPressed, bool altPressed, - const SDL_Event& source); + void ConvertFromPlatform(GuiAdapterMouseEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source); - void ConvertFromPlatform( - GuiAdapterWheelEvent& dest, - bool ctrlPressed, bool shiftPressed, bool altPressed, - const SDL_Event& source); + void ConvertFromPlatform(GuiAdapterWheelEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source); + + void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const SDL_Event& source); # endif @@ -342,14 +331,17 @@ std::vector<EventHandlerData<OnMouseEventFunc > > mouseMoveHandlers_; std::vector<EventHandlerData<OnMouseEventFunc > > mouseUpHandlers_; std::vector<EventHandlerData<OnMouseWheelFunc > > mouseWheelHandlers_; - + std::vector<EventHandlerData<OnKeyDownFunc > > keyDownHandlers_; + std::vector<EventHandlerData<OnKeyUpFunc > > keyUpHandlers_; /** This executes all the registered headers if needed (in wasm, the browser deals with this) */ void OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& event); - + + void OnKeyboardEvent(uint32_t windowID, const GuiAdapterKeyboardEvent& event); + /** Same remark as OnMouseEvent */
--- a/Framework/Scene2D/ScenePoint2D.h Fri Jul 05 14:52:43 2019 +0200 +++ b/Framework/Scene2D/ScenePoint2D.h Fri Jul 05 15:33:02 2019 +0200 @@ -13,7 +13,7 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. **/ @@ -22,7 +22,7 @@ #pragma once #include "../Toolbox/AffineTransform2D.h" - +#include "../Toolbox/LinearAlgebra.h" namespace OrthancStone { @@ -40,7 +40,7 @@ } ScenePoint2D(double x, - double y) : + double y) : x_(x), y_(y) { @@ -63,5 +63,83 @@ t.Apply(x, y); return ScenePoint2D(x, y); } + + const ScenePoint2D operator-(const ScenePoint2D& a) const + { + ScenePoint2D v; + v.x_ = x_ - a.x_; + v.y_ = y_ - a.y_; + + return v; + } + + const ScenePoint2D operator+(const ScenePoint2D& a) const + { + ScenePoint2D v; + v.x_ = x_ + a.x_; + v.y_ = y_ + a.y_; + + return v; + } + + const ScenePoint2D operator*(double a) const + { + ScenePoint2D v; + v.x_ = x_ * a; + v.y_ = y_ * a; + + return v; + } + + static double Dot(const ScenePoint2D& a, const ScenePoint2D& b) + { + return a.x_ * b.x_ + a.y_ * b.y_; + } + + static double SquaredDistancePtPt(const ScenePoint2D& a, const ScenePoint2D& b) + { + ScenePoint2D n = b - a; + return Dot(n, n); + } + + /** + Distance from point p to [a,b] segment + + Rewritten from https://www.randygaul.net/2014/07/23/distance-point-to-line-segment/ + */ + static double SquaredDistancePtSegment(const ScenePoint2D& a, const ScenePoint2D& b, const ScenePoint2D& p) + { + ScenePoint2D n = b - a; + ScenePoint2D pa = a - p; + + double c = Dot(n, pa); + + // Closest point is a + if (c > 0.0) + return Dot(pa, pa); + + ScenePoint2D bp = p - b; + + // Closest point is b + if (Dot(n, bp) > 0.0) + return Dot(bp, bp); + + // if segment length is very short, we approximate distance to the + // distance with a + double nq = Dot(n, n); + if (LinearAlgebra::IsCloseToZero(nq)) + { + // segment is very small: approximate distance from point to segment + // with distance from p to a + return Dot(pa, pa); + } + else + { + // Closest point is between a and b + ScenePoint2D e = pa - n * (c / nq); + return Dot(e, e); + } + } }; } +
--- a/Framework/Scene2DViewport/AngleMeasureTool.cpp Fri Jul 05 14:52:43 2019 +0200 +++ b/Framework/Scene2DViewport/AngleMeasureTool.cpp Fri Jul 05 15:33:02 2019 +0200 @@ -20,6 +20,7 @@ #include "AngleMeasureTool.h" #include "MeasureToolsToolbox.h" +#include "EditAngleMeasureTracker.h" #include "LayerHolder.h" #include <Core/Logging.h> @@ -43,6 +44,7 @@ MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW) : MeasureTool(broker, controllerW) , layerHolder_(boost::make_shared<LayerHolder>(controllerW,1,5)) + , angleHighlightArea_(AngleHighlightArea_None) { } @@ -75,10 +77,109 @@ RefreshScene(); } + void AngleMeasureTool::SetAngleHighlightArea(AngleHighlightArea area) + { + if (angleHighlightArea_ != area) + { + angleHighlightArea_ = area; + RefreshScene(); + } + } + + void AngleMeasureTool::ResetHighlightState() + { + SetAngleHighlightArea(AngleHighlightArea_None); + } + + + boost::shared_ptr<OrthancStone::MeasureToolMemento> AngleMeasureTool::GetMemento() const + { + boost::shared_ptr<AngleMeasureToolMemento> memento(new AngleMeasureToolMemento()); + memento->center_ = center_; + memento->side1End_ = side1End_; + memento->side2End_ = side2End_; + return memento; + } + + void AngleMeasureTool::SetMemento(boost::shared_ptr<MeasureToolMemento> mementoBase) + { + boost::shared_ptr<AngleMeasureToolMemento> memento = boost::dynamic_pointer_cast<AngleMeasureToolMemento>(mementoBase); + ORTHANC_ASSERT(memento.get() != NULL, "Internal error: wrong (or bad) memento"); + center_ = memento->center_; + side1End_ = memento->side1End_; + side2End_ = memento->side2End_; + RefreshScene(); + } + + void AngleMeasureTool::Highlight(ScenePoint2D p) + { + AngleHighlightArea angleHighlightArea = AngleHitTest(p); + SetAngleHighlightArea(angleHighlightArea); + } + + AngleMeasureTool::AngleHighlightArea AngleMeasureTool::AngleHitTest(ScenePoint2D p) const + { + const double pixelToScene = + GetScene()->GetCanvasToSceneTransform().ComputeZoom(); + const double SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD = pixelToScene * HIT_TEST_MAX_DISTANCE_CANVAS_COORD * pixelToScene * HIT_TEST_MAX_DISTANCE_CANVAS_COORD; + + { + const double sqDistanceFromSide1End = ScenePoint2D::SquaredDistancePtPt(p, side1End_); + if (sqDistanceFromSide1End <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD) + return AngleHighlightArea_Side1End; + } + + { + const double sqDistanceFromSide2End = ScenePoint2D::SquaredDistancePtPt(p, side2End_); + if (sqDistanceFromSide2End <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD) + return AngleHighlightArea_Side2End; + } + + { + const double sqDistanceFromCenter = ScenePoint2D::SquaredDistancePtPt(p, center_); + if (sqDistanceFromCenter <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD) + return AngleHighlightArea_Center; + } + + { + const double sqDistanceFromSide1 = ScenePoint2D::SquaredDistancePtSegment(center_, side1End_, p); + if (sqDistanceFromSide1 <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD) + return AngleHighlightArea_Side1; + } + + { + const double sqDistanceFromSide2 = ScenePoint2D::SquaredDistancePtSegment(center_, side2End_, p); + if (sqDistanceFromSide2 <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD) + return AngleHighlightArea_Side2; + } + + return AngleHighlightArea_None; + } bool AngleMeasureTool::HitTest(ScenePoint2D p) const { - throw std::logic_error("The method or operation is not implemented."); + return AngleHitTest(p) != AngleHighlightArea_None; + } + + + boost::shared_ptr<IFlexiblePointerTracker> AngleMeasureTool::CreateEditionTracker(const PointerEvent& e) + { + ScenePoint2D scenePos = e.GetMainPosition().Apply( + GetScene()->GetCanvasToSceneTransform()); + + if (!HitTest(scenePos)) + return boost::shared_ptr<IFlexiblePointerTracker>(); + + /** + new EditLineMeasureTracker( + boost::shared_ptr<LineMeasureTool> measureTool; + MessageBroker & broker, + boost::weak_ptr<ViewportController> controllerW, + const PointerEvent & e); + */ + boost::shared_ptr<EditAngleMeasureTracker> editAngleMeasureTracker( + new EditAngleMeasureTracker(shared_from_this(), GetBroker(), GetController(), e)); + return editAngleMeasureTracker; } void AngleMeasureTool::SetCenter(ScenePoint2D pt) @@ -101,7 +202,8 @@ PolylineSceneLayer* polylineLayer = layerHolder_->GetPolylineLayer(0); polylineLayer->ClearAllChains(); - const Color color(0, 183, 17); + const Color color(TOOL_ANGLE_LINES_COLOR_RED, TOOL_ANGLE_LINES_COLOR_GREEN, TOOL_ANGLE_LINES_COLOR_BLUE); + const Color highlightColor(TOOL_ANGLE_LINES_HL_COLOR_RED, TOOL_ANGLE_LINES_HL_COLOR_GREEN, TOOL_ANGLE_LINES_HL_COLOR_BLUE); // sides { @@ -109,13 +211,20 @@ PolylineSceneLayer::Chain chain; chain.push_back(side1End_); chain.push_back(center_); - polylineLayer->AddChain(chain, false, color); + + if ((angleHighlightArea_ == AngleHighlightArea_Side1) || (angleHighlightArea_ == AngleHighlightArea_Side2)) + polylineLayer->AddChain(chain, false, highlightColor); + else + polylineLayer->AddChain(chain, false, color); } { PolylineSceneLayer::Chain chain; chain.push_back(side2End_); chain.push_back(center_); - polylineLayer->AddChain(chain, false, color); + if ((angleHighlightArea_ == AngleHighlightArea_Side1) || (angleHighlightArea_ == AngleHighlightArea_Side2)) + polylineLayer->AddChain(chain, false, highlightColor); + else + polylineLayer->AddChain(chain, false, color); } } @@ -126,14 +235,23 @@ //TODO: take DPI into account AddSquare(chain, GetScene(), side1End_, GetController()->GetHandleSideLengthS()); - polylineLayer->AddChain(chain, true, color); + + if (angleHighlightArea_ == AngleHighlightArea_Side1End) + polylineLayer->AddChain(chain, true, highlightColor); + else + polylineLayer->AddChain(chain, true, color); + } { PolylineSceneLayer::Chain chain; //TODO: take DPI into account AddSquare(chain, GetScene(), side2End_, GetController()->GetHandleSideLengthS()); - polylineLayer->AddChain(chain, true, color); + + if (angleHighlightArea_ == AngleHighlightArea_Side2End) + polylineLayer->AddChain(chain, true, highlightColor); + else + polylineLayer->AddChain(chain, true, color); } } @@ -143,7 +261,10 @@ AddShortestArc(chain, side1End_, center_, side2End_, controller->GetAngleToolArcRadiusS()); - polylineLayer->AddChain(chain, false, color); + if (angleHighlightArea_ == AngleHighlightArea_Center) + polylineLayer->AddChain(chain, false, highlightColor); + else + polylineLayer->AddChain(chain, false, color); } } {
--- a/Framework/Scene2DViewport/AngleMeasureTool.h Fri Jul 05 14:52:43 2019 +0200 +++ b/Framework/Scene2DViewport/AngleMeasureTool.h Fri Jul 05 15:33:02 2019 +0200 @@ -30,13 +30,14 @@ #include <boost/shared_ptr.hpp> #include <boost/weak_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> #include <vector> #include <cmath> namespace OrthancStone { - class AngleMeasureTool : public MeasureTool + class AngleMeasureTool : public MeasureTool, public boost::enable_shared_from_this<AngleMeasureTool> { public: AngleMeasureTool(MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW); @@ -47,18 +48,45 @@ void SetCenter(ScenePoint2D start); void SetSide2End(ScenePoint2D start); + virtual bool HitTest(ScenePoint2D p) const ORTHANC_OVERRIDE; + virtual void Highlight(ScenePoint2D p) ORTHANC_OVERRIDE; + virtual void ResetHighlightState() ORTHANC_OVERRIDE; + virtual boost::shared_ptr<IFlexiblePointerTracker> CreateEditionTracker(const PointerEvent& e) ORTHANC_OVERRIDE; + virtual boost::shared_ptr<MeasureToolMemento> GetMemento() const ORTHANC_OVERRIDE; + virtual void SetMemento(boost::shared_ptr<MeasureToolMemento>) ORTHANC_OVERRIDE; - virtual bool HitTest(ScenePoint2D p) const ORTHANC_OVERRIDE; + enum AngleHighlightArea + { + AngleHighlightArea_None, + AngleHighlightArea_Side1End, + AngleHighlightArea_Side1, + AngleHighlightArea_Side2End, + AngleHighlightArea_Side2, + AngleHighlightArea_Center + }; + + + AngleHighlightArea AngleHitTest(ScenePoint2D p) const; private: virtual void RefreshScene() ORTHANC_OVERRIDE; void RemoveFromScene(); + void SetAngleHighlightArea(AngleHighlightArea area); private: - ScenePoint2D side1End_; - ScenePoint2D side2End_; - ScenePoint2D center_; + ScenePoint2D side1End_; + ScenePoint2D side2End_; + ScenePoint2D center_; boost::shared_ptr<LayerHolder> layerHolder_; + AngleHighlightArea angleHighlightArea_; + }; + + class AngleMeasureToolMemento : public MeasureToolMemento + { + public: + ScenePoint2D side1End_; + ScenePoint2D side2End_; + ScenePoint2D center_; }; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Scene2DViewport/EditAngleMeasureTracker.cpp Fri Jul 05 15:33:02 2019 +0200 @@ -0,0 +1,112 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 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 + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#include "EditAngleMeasureTracker.h" + +namespace OrthancStone +{ + EditAngleMeasureTracker::EditAngleMeasureTracker( + boost::shared_ptr<AngleMeasureTool> measureTool, + MessageBroker& broker, + boost::weak_ptr<ViewportController> controllerW, + const PointerEvent& e) + : EditMeasureTracker(controllerW, e) + { + ScenePoint2D scenePos = e.GetMainPosition().Apply( + GetScene()->GetCanvasToSceneTransform()); + + modifiedZone_ = measureTool->AngleHitTest(scenePos); + + command_.reset(new EditAngleMeasureCommand(measureTool, broker, controllerW)); + } + + EditAngleMeasureTracker::~EditAngleMeasureTracker() + { + + } + + void EditAngleMeasureTracker::PointerMove(const PointerEvent& e) + { + ScenePoint2D scenePos = e.GetMainPosition().Apply( + GetScene()->GetCanvasToSceneTransform()); + + ScenePoint2D delta = scenePos - GetOriginalClickPosition(); + + boost::shared_ptr<AngleMeasureToolMemento> memento = + boost::dynamic_pointer_cast<AngleMeasureToolMemento>(command_->mementoOriginal_); + + ORTHANC_ASSERT(memento.get() != NULL); + + switch (modifiedZone_) + { + case AngleMeasureTool::AngleHighlightArea_Center: + { + ScenePoint2D newCenter = memento->center_ + delta; + GetCommand()->SetCenter(newCenter); + } + break; + case AngleMeasureTool::AngleHighlightArea_Side1: + case AngleMeasureTool::AngleHighlightArea_Side2: + { + ScenePoint2D newCenter = memento->center_ + delta; + ScenePoint2D newSide1End = memento->side1End_ + delta; + ScenePoint2D newSide2End = memento->side2End_ + delta; + GetCommand()->SetCenter(newCenter); + GetCommand()->SetSide1End(newSide1End); + GetCommand()->SetSide2End(newSide2End); + } + break; + case AngleMeasureTool::AngleHighlightArea_Side1End: + { + ScenePoint2D newSide1End = memento->side1End_ + delta; + GetCommand()->SetSide1End(newSide1End); + } + break; + case AngleMeasureTool::AngleHighlightArea_Side2End: + { + ScenePoint2D newSide2End = memento->side2End_ + delta; + GetCommand()->SetSide2End(newSide2End); + } + break; + default: + LOG(WARNING) << "Warning: please retry the measuring tool editing operation!"; + break; + } + } + + void EditAngleMeasureTracker::PointerUp(const PointerEvent& e) + { + alive_ = false; + } + + void EditAngleMeasureTracker::PointerDown(const PointerEvent& e) + { + LOG(WARNING) << "Additional touches (fingers, pen, mouse buttons...) " + "are ignored when the edit angle tracker is active"; + } + + boost::shared_ptr<EditAngleMeasureCommand> EditAngleMeasureTracker::GetCommand() + { + boost::shared_ptr<EditAngleMeasureCommand> ret = boost::dynamic_pointer_cast<EditAngleMeasureCommand>(command_); + ORTHANC_ASSERT(ret.get() != NULL, "Internal error in EditAngleMeasureTracker::GetCommand()"); + return ret; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Scene2DViewport/EditAngleMeasureTracker.h Fri Jul 05 15:33:02 2019 +0200 @@ -0,0 +1,54 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 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 + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#pragma once + +#include "MeasureTrackers.h" + +namespace OrthancStone +{ + class EditAngleMeasureTracker : public EditMeasureTracker + { + public: + /** + When you create this tracker, you need to supply it with the undo stack + where it will store the commands that perform the actual measure tool + creation and modification. + In turn, a container for these commands to store the actual measuring + must be supplied, too + */ + EditAngleMeasureTracker( + boost::shared_ptr<AngleMeasureTool> measureTool, + MessageBroker& broker, + boost::weak_ptr<ViewportController> controllerW, + const PointerEvent& e); + + ~EditAngleMeasureTracker(); + + virtual void PointerMove(const PointerEvent& e) ORTHANC_OVERRIDE; + virtual void PointerUp(const PointerEvent& e) ORTHANC_OVERRIDE; + virtual void PointerDown(const PointerEvent& e) ORTHANC_OVERRIDE; + + private: + AngleMeasureTool::AngleHighlightArea modifiedZone_; + + boost::shared_ptr<EditAngleMeasureCommand> GetCommand(); + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Scene2DViewport/EditLineMeasureTracker.cpp Fri Jul 05 15:33:02 2019 +0200 @@ -0,0 +1,107 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 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 + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#include "EditLineMeasureTracker.h" + +namespace OrthancStone +{ + EditLineMeasureTracker::EditLineMeasureTracker( + boost::shared_ptr<LineMeasureTool> measureTool, + MessageBroker& broker, + boost::weak_ptr<ViewportController> controllerW, + const PointerEvent& e) + : EditMeasureTracker(controllerW, e) + { + ScenePoint2D scenePos = e.GetMainPosition().Apply( + GetScene()->GetCanvasToSceneTransform()); + + modifiedZone_ = measureTool->LineHitTest(scenePos); + + command_.reset( + new EditLineMeasureCommand( + measureTool, + broker, + controllerW)); + } + + EditLineMeasureTracker::~EditLineMeasureTracker() + { + + } + + void EditLineMeasureTracker::PointerMove(const PointerEvent& e) + { + ScenePoint2D scenePos = e.GetMainPosition().Apply( + GetScene()->GetCanvasToSceneTransform()); + + ScenePoint2D delta = scenePos - GetOriginalClickPosition(); + + boost::shared_ptr<LineMeasureToolMemento> memento = + boost::dynamic_pointer_cast<LineMeasureToolMemento>(command_->mementoOriginal_); + + ORTHANC_ASSERT(memento.get() != NULL); + + switch (modifiedZone_) + { + case LineMeasureTool::LineHighlightArea_Start: + { + ScenePoint2D newStart = memento->start_ + delta; + GetCommand()->SetStart(newStart); + } + break; + case LineMeasureTool::LineHighlightArea_End: + { + ScenePoint2D newEnd = memento->end_ + delta; + GetCommand()->SetEnd(newEnd); + } + break; + case LineMeasureTool::LineHighlightArea_Segment: + { + ScenePoint2D newStart = memento->start_ + delta; + ScenePoint2D newEnd = memento->end_ + delta; + GetCommand()->SetStart(newStart); + GetCommand()->SetEnd(newEnd); + } + break; + default: + LOG(WARNING) << "Warning: please retry the measuring tool editing operation!"; + break; + } + } + + void EditLineMeasureTracker::PointerUp(const PointerEvent& e) + { + alive_ = false; + } + + void EditLineMeasureTracker::PointerDown(const PointerEvent& e) + { + LOG(WARNING) << "Additional touches (fingers, pen, mouse buttons...) " + "are ignored when the edit line tracker is active"; + } + + boost::shared_ptr<EditLineMeasureCommand> EditLineMeasureTracker::GetCommand() + { + boost::shared_ptr<EditLineMeasureCommand> ret = boost::dynamic_pointer_cast<EditLineMeasureCommand>(command_); + ORTHANC_ASSERT(ret.get() != NULL, "Internal error in EditLineMeasureTracker::GetCommand()"); + return ret; + } + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Scene2DViewport/EditLineMeasureTracker.h Fri Jul 05 15:33:02 2019 +0200 @@ -0,0 +1,54 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 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 + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#pragma once + +#include "MeasureTrackers.h" + +namespace OrthancStone +{ + class EditLineMeasureTracker : public EditMeasureTracker + { + public: + /** + When you create this tracker, you need to supply it with the undo stack + where it will store the commands that perform the actual measure tool + creation and modification. + In turn, a container for these commands to store the actual measuring + must be supplied, too + */ + EditLineMeasureTracker( + boost::shared_ptr<LineMeasureTool> measureTool, + MessageBroker& broker, + boost::weak_ptr<ViewportController> controllerW, + const PointerEvent& e); + + ~EditLineMeasureTracker(); + + virtual void PointerMove(const PointerEvent& e) ORTHANC_OVERRIDE; + virtual void PointerUp(const PointerEvent& e) ORTHANC_OVERRIDE; + virtual void PointerDown(const PointerEvent& e) ORTHANC_OVERRIDE; + + private: + LineMeasureTool::LineHighlightArea modifiedZone_; + + boost::shared_ptr<EditLineMeasureCommand> GetCommand(); + }; +}
--- a/Framework/Scene2DViewport/LineMeasureTool.cpp Fri Jul 05 14:52:43 2019 +0200 +++ b/Framework/Scene2DViewport/LineMeasureTool.cpp Fri Jul 05 15:33:02 2019 +0200 @@ -20,6 +20,7 @@ #include "LineMeasureTool.h" #include "MeasureToolsToolbox.h" +#include "EditLineMeasureTracker.h" #include "LayerHolder.h" #include <Core/Logging.h> @@ -33,6 +34,7 @@ MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW) : MeasureTool(broker, controllerW) , layerHolder_(boost::make_shared<LayerHolder>(controllerW, 1, 5)) + , lineHighlightArea_(LineHighlightArea_None) { } @@ -72,26 +74,88 @@ RefreshScene(); } - + void LineMeasureTool::SetLineHighlightArea(LineHighlightArea area) + { + if (lineHighlightArea_ != area) + { + lineHighlightArea_ = area; + RefreshScene(); + } + } - bool LineMeasureTool::HitTest(ScenePoint2D p) const + void LineMeasureTool::ResetHighlightState() + { + SetLineHighlightArea(LineHighlightArea_None); + } + + void LineMeasureTool::Highlight(ScenePoint2D p) + { + LineHighlightArea lineHighlightArea = LineHitTest(p); + SetLineHighlightArea(lineHighlightArea); + } + + LineMeasureTool::LineHighlightArea LineMeasureTool::LineHitTest(ScenePoint2D p) const { const double pixelToScene = GetScene()->GetCanvasToSceneTransform().ComputeZoom(); + const double SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD = pixelToScene * HIT_TEST_MAX_DISTANCE_CANVAS_COORD * pixelToScene * HIT_TEST_MAX_DISTANCE_CANVAS_COORD; - // the hit test will return true if the supplied point (in scene coords) - // is close to the handle or to the line. + const double sqDistanceFromStart = ScenePoint2D::SquaredDistancePtPt(p, start_); + if (sqDistanceFromStart <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD) + return LineHighlightArea_Start; + + const double sqDistanceFromEnd = ScenePoint2D::SquaredDistancePtPt(p, end_); + if (sqDistanceFromEnd <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD) + return LineHighlightArea_End; + + const double sqDistanceFromPtSegment = ScenePoint2D::SquaredDistancePtSegment(start_, end_, p); + if (sqDistanceFromPtSegment <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD) + return LineHighlightArea_Segment; + + return LineHighlightArea_None; + } - // since the handle is small, a nice approximation is to defined this - // as a threshold on the distance between the point and the handle center. + bool LineMeasureTool::HitTest(ScenePoint2D p) const + { + return LineHitTest(p) != LineHighlightArea_None; + } + + boost::shared_ptr<IFlexiblePointerTracker> LineMeasureTool::CreateEditionTracker(const PointerEvent& e) + { + ScenePoint2D scenePos = e.GetMainPosition().Apply( + GetScene()->GetCanvasToSceneTransform()); - // this threshold is defined as a constant value in CANVAS units. + if (!HitTest(scenePos)) + return boost::shared_ptr<IFlexiblePointerTracker>(); + + /** + new EditLineMeasureTracker( + boost::shared_ptr<LineMeasureTool> measureTool; + MessageBroker & broker, + boost::weak_ptr<ViewportController> controllerW, + const PointerEvent & e); + */ + boost::shared_ptr<EditLineMeasureTracker> editLineMeasureTracker( + new EditLineMeasureTracker(shared_from_this(), GetBroker(), GetController(), e)); + return editLineMeasureTracker; + } - // line equation from two points (non-normalized) - // (y0-y1)*x + (x1-x0)*xy + (x0*y1 - x1*y0) = 0 - // - return false; + boost::shared_ptr<MeasureToolMemento> LineMeasureTool::GetMemento() const + { + boost::shared_ptr<LineMeasureToolMemento> memento(new LineMeasureToolMemento()); + memento->start_ = start_; + memento->end_ = end_; + return memento; + } + + void LineMeasureTool::SetMemento(boost::shared_ptr<MeasureToolMemento> mementoBase) + { + boost::shared_ptr<LineMeasureToolMemento> memento = boost::dynamic_pointer_cast<LineMeasureToolMemento>(mementoBase); + ORTHANC_ASSERT(memento.get() != NULL, "Internal error: wrong (or bad) memento"); + start_ = memento->start_; + end_ = memento->end_; + RefreshScene(); } void LineMeasureTool::RefreshScene() @@ -112,11 +176,18 @@ TOOL_LINES_COLOR_GREEN, TOOL_LINES_COLOR_BLUE); + const Color highlightColor(TOOL_LINES_HL_COLOR_RED, + TOOL_LINES_HL_COLOR_GREEN, + TOOL_LINES_HL_COLOR_BLUE); + { PolylineSceneLayer::Chain chain; chain.push_back(start_); chain.push_back(end_); - polylineLayer->AddChain(chain, false, color); + if(lineHighlightArea_ == LineHighlightArea_Segment) + polylineLayer->AddChain(chain, false, highlightColor); + else + polylineLayer->AddChain(chain, false, color); } // handles @@ -128,7 +199,10 @@ AddSquare(chain, GetScene(), start_, GetController()->GetHandleSideLengthS()); - polylineLayer->AddChain(chain, true, color); + if (lineHighlightArea_ == LineHighlightArea_Start) + polylineLayer->AddChain(chain, true, highlightColor); + else + polylineLayer->AddChain(chain, true, color); } { @@ -138,7 +212,10 @@ AddSquare(chain, GetScene(), end_, GetController()->GetHandleSideLengthS()); - polylineLayer->AddChain(chain, true, color); + if (lineHighlightArea_ == LineHighlightArea_End) + polylineLayer->AddChain(chain, true, highlightColor); + else + polylineLayer->AddChain(chain, true, color); } } @@ -150,7 +227,7 @@ double squareDist = deltaX * deltaX + deltaY * deltaY; double dist = sqrt(squareDist); char buf[64]; - sprintf(buf, "%0.02f units", dist); + sprintf(buf, "%0.02f mm", dist); // TODO: for now we simply position the text overlay at the middle // of the measuring segment
--- a/Framework/Scene2DViewport/LineMeasureTool.h Fri Jul 05 14:52:43 2019 +0200 +++ b/Framework/Scene2DViewport/LineMeasureTool.h Fri Jul 05 15:33:02 2019 +0200 @@ -28,13 +28,14 @@ #include <boost/shared_ptr.hpp> #include <boost/weak_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> #include <vector> #include <cmath> namespace OrthancStone { - class LineMeasureTool : public MeasureTool + class LineMeasureTool : public MeasureTool, public boost::enable_shared_from_this<LineMeasureTool> { public: LineMeasureTool(MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW); @@ -47,16 +48,43 @@ virtual bool HitTest(ScenePoint2D p) const ORTHANC_OVERRIDE; + virtual void Highlight(ScenePoint2D p) ORTHANC_OVERRIDE; + virtual void ResetHighlightState() ORTHANC_OVERRIDE; + virtual boost::shared_ptr<IFlexiblePointerTracker> CreateEditionTracker(const PointerEvent& e) ORTHANC_OVERRIDE; + virtual boost::shared_ptr<MeasureToolMemento> GetMemento() const ORTHANC_OVERRIDE; + virtual void SetMemento(boost::shared_ptr<MeasureToolMemento>) ORTHANC_OVERRIDE; + + enum LineHighlightArea + { + LineHighlightArea_None, + LineHighlightArea_Start, + LineHighlightArea_End, + LineHighlightArea_Segment + }; + + + LineHighlightArea LineHitTest(ScenePoint2D p) const; private: virtual void RefreshScene() ORTHANC_OVERRIDE; void RemoveFromScene(); + void SetLineHighlightArea(LineHighlightArea area); + + private: private: - ScenePoint2D start_; - ScenePoint2D end_; - boost::shared_ptr<LayerHolder> layerHolder_; - int baseLayerIndex_; + ScenePoint2D start_; + ScenePoint2D end_; + boost::shared_ptr<LayerHolder> layerHolder_; + int baseLayerIndex_; + LineHighlightArea lineHighlightArea_; + }; + + class LineMeasureToolMemento : public MeasureToolMemento + { + public: + ScenePoint2D start_; + ScenePoint2D end_; }; }
--- a/Framework/Scene2DViewport/MeasureCommands.cpp Fri Jul 05 14:52:43 2019 +0200 +++ b/Framework/Scene2DViewport/MeasureCommands.cpp Fri Jul 05 15:33:02 2019 +0200 @@ -50,6 +50,30 @@ // we thus leave it as is } + EditMeasureCommand::EditMeasureCommand(boost::shared_ptr<MeasureTool> measureTool, boost::weak_ptr<ViewportController> controllerW) + : TrackerCommand(controllerW) + , mementoOriginal_(measureTool->GetMemento()) + , mementoModified_(measureTool->GetMemento()) + { + + } + + EditMeasureCommand::~EditMeasureCommand() + { + + } + + void EditMeasureCommand::Undo() + { + // simply disable the measure tool upon undo + GetMeasureTool()->SetMemento(mementoOriginal_); + } + + void EditMeasureCommand::Redo() + { + GetMeasureTool()->SetMemento(mementoModified_); + } + CreateLineMeasureCommand::CreateLineMeasureCommand( MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW, @@ -67,6 +91,29 @@ measureTool_->SetEnd(scenePos); } + EditLineMeasureCommand::EditLineMeasureCommand( + boost::shared_ptr<LineMeasureTool> measureTool, + MessageBroker& broker, + boost::weak_ptr<ViewportController> controllerW) + : EditMeasureCommand(measureTool,controllerW) + , measureTool_(measureTool) + { + } + + + void EditLineMeasureCommand::SetStart(ScenePoint2D scenePos) + { + measureTool_->SetStart(scenePos); + mementoModified_ = measureTool_->GetMemento(); + } + + + void EditLineMeasureCommand::SetEnd(ScenePoint2D scenePos) + { + measureTool_->SetEnd(scenePos); + mementoModified_ = measureTool_->GetMemento(); + } + CreateAngleMeasureCommand::CreateAngleMeasureCommand( MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW, @@ -99,4 +146,34 @@ assert(controller); // accessing dead object? return controller; } + + EditAngleMeasureCommand::EditAngleMeasureCommand( + boost::shared_ptr<AngleMeasureTool> measureTool, + MessageBroker& broker, + boost::weak_ptr<ViewportController> controllerW) + : EditMeasureCommand(measureTool, controllerW) + , measureTool_(measureTool) + { + } + + void EditAngleMeasureCommand::SetCenter(ScenePoint2D scenePos) + { + measureTool_->SetCenter(scenePos); + mementoModified_ = measureTool_->GetMemento(); + } + + + void EditAngleMeasureCommand::SetSide1End(ScenePoint2D scenePos) + { + measureTool_->SetSide1End(scenePos); + mementoModified_ = measureTool_->GetMemento(); + } + + + void EditAngleMeasureCommand::SetSide2End(ScenePoint2D scenePos) + { + measureTool_->SetSide2End(scenePos); + mementoModified_ = measureTool_->GetMemento(); + } + }
--- a/Framework/Scene2DViewport/MeasureCommands.h Fri Jul 05 14:52:43 2019 +0200 +++ b/Framework/Scene2DViewport/MeasureCommands.h Fri Jul 05 15:33:02 2019 +0200 @@ -42,6 +42,8 @@ } virtual void Undo() = 0; virtual void Redo() = 0; + + virtual ~TrackerCommand() {}; protected: boost::shared_ptr<ViewportController> GetController(); @@ -52,7 +54,7 @@ { public: CreateMeasureCommand(boost::weak_ptr<ViewportController> controllerW); - ~CreateMeasureCommand(); + virtual ~CreateMeasureCommand(); virtual void Undo() ORTHANC_OVERRIDE; virtual void Redo() ORTHANC_OVERRIDE; private: @@ -60,6 +62,27 @@ virtual boost::shared_ptr<MeasureTool> GetMeasureTool() = 0; }; + class EditMeasureCommand : public TrackerCommand + { + public: + EditMeasureCommand(boost::shared_ptr<MeasureTool> measureTool, boost::weak_ptr<ViewportController> controllerW); + virtual ~EditMeasureCommand(); + virtual void Undo() ORTHANC_OVERRIDE; + virtual void Redo() ORTHANC_OVERRIDE; + + /** This memento is the original object state */ + boost::shared_ptr<MeasureToolMemento> mementoOriginal_; + + private: + /** Must be implemented by the subclasses that edit the actual tool */ + virtual boost::shared_ptr<MeasureTool> GetMeasureTool() = 0; + + protected: + + /** This memento is updated by the subclasses upon modifications */ + boost::shared_ptr<MeasureToolMemento> mementoModified_; + }; + class CreateLineMeasureCommand : public CreateMeasureCommand { public: @@ -80,6 +103,26 @@ }; + class EditLineMeasureCommand : public EditMeasureCommand + { + public: + EditLineMeasureCommand( + boost::shared_ptr<LineMeasureTool> measureTool, + MessageBroker& broker, + boost::weak_ptr<ViewportController> controllerW); + + void SetStart(ScenePoint2D scenePos); + void SetEnd(ScenePoint2D scenePos); + + private: + virtual boost::shared_ptr<MeasureTool> GetMeasureTool() ORTHANC_OVERRIDE + { + return measureTool_; + } + boost::shared_ptr<LineMeasureTool> measureTool_; + }; + + class CreateAngleMeasureCommand : public CreateMeasureCommand { public: @@ -103,5 +146,31 @@ boost::shared_ptr<AngleMeasureTool> measureTool_; }; + class EditAngleMeasureCommand : public EditMeasureCommand + { + public: + /** Ctor sets end of side 1*/ + EditAngleMeasureCommand( + boost::shared_ptr<AngleMeasureTool> measureTool, + MessageBroker& broker, + boost::weak_ptr<ViewportController> controllerW); + + /** This method sets center*/ + void SetCenter(ScenePoint2D scenePos); + + /** This method sets end of side 1*/ + void SetSide1End(ScenePoint2D scenePos); + + /** This method sets end of side 2*/ + void SetSide2End(ScenePoint2D scenePos); + + private: + virtual boost::shared_ptr<MeasureTool> GetMeasureTool() ORTHANC_OVERRIDE + { + return measureTool_; + } + boost::shared_ptr<AngleMeasureTool> measureTool_; + }; + }
--- a/Framework/Scene2DViewport/MeasureTool.h Fri Jul 05 14:52:43 2019 +0200 +++ b/Framework/Scene2DViewport/MeasureTool.h Fri Jul 05 15:33:02 2019 +0200 @@ -35,6 +35,9 @@ namespace OrthancStone { + class IFlexiblePointerTracker; + class MeasureToolMemento; + class MeasureTool : public IObserver { public: @@ -71,6 +74,37 @@ measuring tool */ virtual bool HitTest(ScenePoint2D p) const = 0; + + /** + This method must return a memento the captures the tool state (not including + the highlighting state + */ + virtual boost::shared_ptr<MeasureToolMemento> GetMemento() const = 0; + + /** + This method must apply the supplied memento (this requires RTTI to check + the type) + */ + virtual void SetMemento(boost::shared_ptr<MeasureToolMemento>) = 0; + + /** + This must create an edition tracker suitable for the supplied click position, + or an empty pointer if no hit test (although this should have been checked + first) + */ + virtual boost::shared_ptr<IFlexiblePointerTracker> CreateEditionTracker(const PointerEvent& e) = 0; + + /** + Will change the measuring tool to provide visual feedback on the GUI + element that is in the pointer hit zone + */ + virtual void Highlight(ScenePoint2D p) = 0; + + /** + This function must reset the visual highlighted hot zone feedback + */ + virtual void ResetHighlightState() = 0; + protected: MeasureTool(MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW); @@ -104,6 +138,13 @@ boost::weak_ptr<ViewportController> controllerW_; bool enabled_; }; + + class MeasureToolMemento + { + public: + virtual ~MeasureToolMemento() {}; + }; + } extern void TrackerSample_SetInfoDisplayMessage(
--- a/Framework/Scene2DViewport/MeasureToolsToolbox.cpp Fri Jul 05 14:52:43 2019 +0200 +++ b/Framework/Scene2DViewport/MeasureToolsToolbox.cpp Fri Jul 05 15:33:02 2019 +0200 @@ -322,4 +322,11 @@ p.GetY() + yoffsets[i] * pixelToScene); } } + + std::ostream& operator<<(std::ostream& os, const ScenePoint2D& p) + { + os << "x = " << p.GetX() << " , y = " << p.GetY(); + return os; + } + }
--- a/Framework/Scene2DViewport/MeasureToolsToolbox.h Fri Jul 05 14:52:43 2019 +0200 +++ b/Framework/Scene2DViewport/MeasureToolsToolbox.h Fri Jul 05 15:33:02 2019 +0200 @@ -33,7 +33,7 @@ void AddSquare(PolylineSceneLayer::Chain& chain, boost::shared_ptr<const Scene2D> scene, const ScenePoint2D& centerS, - const double& sideLengthS); + const double& sideLengthS); /** Creates an arc centered on c that goes @@ -48,23 +48,23 @@ Warning: the existing chain content will be wiped out. */ void AddShortestArc( - PolylineSceneLayer::Chain& chain - , const ScenePoint2D& p1 - , const ScenePoint2D& c - , const ScenePoint2D& p2 - , const double& radiusS + PolylineSceneLayer::Chain& chain + , const ScenePoint2D& p1 + , const ScenePoint2D& c + , const ScenePoint2D& p2 + , const double& radiusS , const int subdivisionsCount = 63); /** - Creates an arc (open curve) with "numSubdivisions" (N + 1 points) from + Creates an arc (open curve) with "numSubdivisions" (N + 1 points) from start angle to end angle, by following the shortest arc. Warning: the existing chain content will be wiped out. */ void AddShortestArc( - PolylineSceneLayer::Chain& chain - , const ScenePoint2D& centerS - , const double& radiusS + PolylineSceneLayer::Chain& chain + , const ScenePoint2D& centerS + , const double& radiusS , const double startAngleRad , const double endAngleRad , const int subdivisionsCount = 63); @@ -79,24 +79,24 @@ - so that r2 belongs to the p2,c line - so that the distance from c to r2 equals radius - if clockwise is true, the arc is drawn from r1 to r2 with increasing + if clockwise is true, the arc is drawn from r1 to r2 with increasing angle values. Otherwise, the angle values decrease. Warning: the existing chain content will be wiped out. */ void AddArc( - PolylineSceneLayer::Chain& chain - , const Scene2D& scene - , const ScenePoint2D& p1 - , const ScenePoint2D& c - , const ScenePoint2D& p2 - , const double& radiusS + PolylineSceneLayer::Chain & chain + , const Scene2D & scene + , const ScenePoint2D & p1 + , const ScenePoint2D & c + , const ScenePoint2D & p2 + , const double& radiusS , const bool clockwise , const int subdivisionsCount = 63); - + /** - Creates an arc (open curve) with "numSubdivisions" (N + 1 points) from + Creates an arc (open curve) with "numSubdivisions" (N + 1 points) from start angle to end angle with the supplied radius. if clockwise is true, the arc is drawn from start to end by increasing the @@ -107,10 +107,10 @@ Warning: the existing chain content will be wiped out. */ void AddArc( - PolylineSceneLayer::Chain& chain - , const Scene2D& scene + PolylineSceneLayer::Chain& chain + , const Scene2D& scene , const ScenePoint2D& centerS - , const double& radiusS + , const double& radiusS , const double startAngleRad , const double endAngleRad , const bool clockwise @@ -123,9 +123,9 @@ Warning: the existing chain content will be wiped out. */ void AddCircle(PolylineSceneLayer::Chain& chain, - const Scene2D& scene, + const Scene2D& scene, const ScenePoint2D& centerS, - const double& radiusS, + const double& radiusS, const int numSubdivisions = 63); /** @@ -135,10 +135,10 @@ double NormalizeAngle(double angle); /** - Returns the angle magnitude between the p1,c and p2,c lines. + Returns the angle magnitude between the p1,c and p2,c lines. The returned angle is between 0 and 2*pi - If the angle is between 0 and pi, this means that the shortest arc + If the angle is between 0 and pi, this means that the shortest arc from p1 to p2 is clockwise. If the angle is between pi and 2*pi, this means that the shortest arc @@ -146,7 +146,7 @@ */ double MeasureAngle( - const ScenePoint2D& p1 + const ScenePoint2D& p1 , const ScenePoint2D& c , const ScenePoint2D& p2); @@ -163,7 +163,7 @@ to the *smallest* half-plane defined by the [c,p1[ and [c,p2[ half-lines. */ void GetPositionOnBisectingLine( - ScenePoint2D& result + ScenePoint2D& result , const ScenePoint2D& p1 , const ScenePoint2D& c , const ScenePoint2D& p2 @@ -172,14 +172,18 @@ /** This helper is used when drawing text with an outline. - It set the properties for several text layers at once : first the - four outline layers, with a position shift and then the actual main text + It set the properties for several text layers at once : first the + four outline layers, with a position shift and then the actual main text layer. The five text layers are supposed to already exist in the scene, starting - from layerIndex, up to (and not including) layerIndex+5. + from layerIndex, up to (and not including) layerIndex+5. */ void SetTextLayerOutlineProperties( boost::shared_ptr<Scene2D> scene, boost::shared_ptr<LayerHolder> layerHolder, const char* text, ScenePoint2D p); + + + std::ostream& operator<<(std::ostream& os, const ScenePoint2D& p); } +
--- a/Framework/Scene2DViewport/MeasureTrackers.cpp Fri Jul 05 14:52:43 2019 +0200 +++ b/Framework/Scene2DViewport/MeasureTrackers.cpp Fri Jul 05 15:33:02 2019 +0200 @@ -46,7 +46,6 @@ { // if the tracker completes successfully, we add the command // to the undo stack - // otherwise, we simply undo it if (commitResult_) controllerW_.lock()->PushCommand(command_); @@ -59,6 +58,41 @@ return controllerW_.lock()->GetScene(); } + EditMeasureTracker::EditMeasureTracker(boost::weak_ptr<ViewportController> controllerW, const PointerEvent& e) + : controllerW_(controllerW) + , alive_(true) + , commitResult_(true) + { + boost::shared_ptr<ViewportController> controller = controllerW.lock(); + originalClickPosition_ = e.GetMainPosition().Apply(controller->GetScene()->GetCanvasToSceneTransform()); + } + + boost::shared_ptr<Scene2D> EditMeasureTracker::GetScene() + { + return controllerW_.lock()->GetScene(); + } + + void EditMeasureTracker::Cancel() + { + commitResult_ = false; + alive_ = false; + } + + bool EditMeasureTracker::IsAlive() const + { + return alive_; + } + + EditMeasureTracker::~EditMeasureTracker() + { + // if the tracker completes successfully, we add the command + // to the undo stack + // otherwise, we simply undo it + if (commitResult_) + controllerW_.lock()->PushCommand(command_); + else + command_->Undo(); + } }
--- a/Framework/Scene2DViewport/MeasureTrackers.h Fri Jul 05 14:52:43 2019 +0200 +++ b/Framework/Scene2DViewport/MeasureTrackers.h Fri Jul 05 15:33:02 2019 +0200 @@ -50,5 +50,30 @@ private: bool commitResult_; }; + + class EditMeasureTracker : public IFlexiblePointerTracker + { + public: + virtual void Cancel() ORTHANC_OVERRIDE; + virtual bool IsAlive() const ORTHANC_OVERRIDE; + protected: + EditMeasureTracker(boost::weak_ptr<ViewportController> controllerW, const PointerEvent& e); + + ~EditMeasureTracker(); + + protected: + boost::shared_ptr<EditMeasureCommand> command_; + boost::weak_ptr<ViewportController> controllerW_; + bool alive_; + boost::shared_ptr<Scene2D> GetScene(); + + ScenePoint2D GetOriginalClickPosition() const + { + return originalClickPosition_; + } + private: + ScenePoint2D originalClickPosition_; + bool commitResult_; + }; }
--- a/Framework/Scene2DViewport/ViewportController.cpp Fri Jul 05 14:52:43 2019 +0200 +++ b/Framework/Scene2DViewport/ViewportController.cpp Fri Jul 05 15:33:02 2019 +0200 @@ -100,6 +100,15 @@ return ret; } + + void ViewportController::ResetMeasuringToolsHighlight() + { + for (size_t i = 0; i < measureTools_.size(); ++i) + { + measureTools_[i]->ResetHighlightState(); + } + } + const OrthancStone::AffineTransform2D& ViewportController::GetCanvasToSceneTransform() const { return scene_->GetCanvasToSceneTransform();
--- a/Framework/Scene2DViewport/ViewportController.h Fri Jul 05 14:52:43 2019 +0200 +++ b/Framework/Scene2DViewport/ViewportController.h Fri Jul 05 15:33:02 2019 +0200 @@ -42,10 +42,21 @@ const uint8_t TEXT_COLOR_GREEN = 223; const uint8_t TEXT_COLOR_BLUE = 81; + const uint8_t TOOL_ANGLE_LINES_COLOR_RED = 0; + const uint8_t TOOL_ANGLE_LINES_COLOR_GREEN = 183; + const uint8_t TOOL_ANGLE_LINES_COLOR_BLUE = 17; + + const uint8_t TOOL_ANGLE_LINES_HL_COLOR_RED = 0; + const uint8_t TOOL_ANGLE_LINES_HL_COLOR_GREEN = 17; + const uint8_t TOOL_ANGLE_LINES_HL_COLOR_BLUE = 183; + const uint8_t TOOL_LINES_COLOR_RED = 0; const uint8_t TOOL_LINES_COLOR_GREEN = 223; const uint8_t TOOL_LINES_COLOR_BLUE = 21; + const uint8_t TOOL_LINES_HL_COLOR_RED = 0; + const uint8_t TOOL_LINES_HL_COLOR_GREEN = 21; + const uint8_t TOOL_LINES_HL_COLOR_BLUE = 223; const uint8_t TEXT_OUTLINE_COLOR_RED = 0; const uint8_t TEXT_OUTLINE_COLOR_GREEN = 56; @@ -88,6 +99,12 @@ std::vector<boost::shared_ptr<MeasureTool> > HitTestMeasureTools(ScenePoint2D p); /** + This function will traverse the measuring tools and will clear their + highlighted state + */ + void ResetMeasuringToolsHighlight(); + + /** With this method, the object takes ownership of the supplied tracker and updates it according to user interaction */
--- a/Resources/CMake/OrthancStoneConfiguration.cmake Fri Jul 05 14:52:43 2019 +0200 +++ b/Resources/CMake/OrthancStoneConfiguration.cmake Fri Jul 05 15:33:02 2019 +0200 @@ -474,6 +474,14 @@ ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/CreateMeasureTracker.cpp ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/CreateMeasureTracker.h ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/CreateSimpleTrackerAdapter.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/EditAngleMeasureCommand.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/EditAngleMeasureCommand.h + ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/EditAngleMeasureTracker.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/EditAngleMeasureTracker.h + ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/EditLineMeasureCommand.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/EditLineMeasureCommand.h + ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/EditLineMeasureTracker.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/EditLineMeasureTracker.h ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/IFlexiblePointerTracker.h ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/LayerHolder.cpp ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/LayerHolder.h
--- a/Samples/Sdl/TrackerSampleApp.cpp Fri Jul 05 14:52:43 2019 +0200 +++ b/Samples/Sdl/TrackerSampleApp.cpp Fri Jul 05 15:33:02 2019 +0200 @@ -247,7 +247,7 @@ DisplayFloatingCtrlInfoText(e); } - else + else if (activeTracker_.get() != NULL) { HideInfoText(); //LOG(TRACE) << "(event.type == SDL_MOUSEMOTION)"; @@ -268,6 +268,32 @@ activeTracker_.reset(); } } + else + { + HideInfoText(); + + PointerEvent e; + e.AddPosition(compositor_->GetPixelCenterCoordinates(event.button.x, event.button.y)); + + ScenePoint2D scenePos = e.GetMainPosition().Apply( + controller_->GetScene()->GetCanvasToSceneTransform()); + //auto measureTools = GetController()->HitTestMeasureTools(scenePos); + //LOG(TRACE) << "# of hit tests: " << measureTools.size(); + + // this returns the collection of measuring tools where hit test is true + std::vector<boost::shared_ptr<MeasureTool> > measureTools = controller_->HitTestMeasureTools(scenePos); + + // let's refresh the measuring tools highlighted state + // first let's tag them as "unhighlighted" + controller_->ResetMeasuringToolsHighlight(); + + // then immediately take the first one and ask it to highlight the + // measuring tool UI part that is hot + if (measureTools.size() > 0) + { + measureTools[0]->Highlight(scenePos); + } + } } else if (event.type == SDL_MOUSEBUTTONUP) { @@ -596,6 +622,15 @@ boost::shared_ptr<IFlexiblePointerTracker> TrackerSampleApp::TrackerHitTest(const PointerEvent & e) { // std::vector<boost::shared_ptr<MeasureTool>> measureTools_; + ScenePoint2D scenePos = e.GetMainPosition().Apply( + controller_->GetScene()->GetCanvasToSceneTransform()); + + std::vector<boost::shared_ptr<MeasureTool> > measureTools = controller_->HitTestMeasureTools(scenePos); + + if (measureTools.size() > 0) + { + return measureTools[0]->CreateEditionTracker(e); + } return boost::shared_ptr<IFlexiblePointerTracker>(); }