diff options
-rw-r--r-- | BUILD.gn | 1 | ||||
-rw-r--r-- | DEPS | 3 | ||||
-rw-r--r-- | third_party/imgui/BUILD.gn | 19 | ||||
-rw-r--r-- | tools/viewer/Viewer.cpp | 212 | ||||
-rw-r--r-- | tools/viewer/Viewer.h | 7 | ||||
-rw-r--r-- | tools/viewer/sk_app/CommandSet.cpp | 13 | ||||
-rw-r--r-- | tools/viewer/sk_app/CommandSet.h | 8 | ||||
-rw-r--r-- | tools/viewer/sk_app/Window.cpp | 9 | ||||
-rw-r--r-- | tools/viewer/sk_app/Window.h | 25 | ||||
-rw-r--r-- | tools/viewer/sk_app/mac/Window_mac.cpp | 52 | ||||
-rw-r--r-- | tools/viewer/sk_app/mac/main_mac.cpp | 2 | ||||
-rw-r--r-- | tools/viewer/sk_app/unix/Window_unix.cpp | 64 | ||||
-rw-r--r-- | tools/viewer/sk_app/win/Window_win.cpp | 55 |
13 files changed, 400 insertions, 70 deletions
@@ -1429,6 +1429,7 @@ if (skia_enable_tools) { ":skia", ":tool_utils", ":views", + "//third_party/imgui", "//third_party/jsoncpp", ] if (is_android) { @@ -41,6 +41,9 @@ deps = { # microhttpd for skiaserve "third_party/externals/microhttpd" : "https://android.googlesource.com/platform/external/libmicrohttpd@748945ec6f1c67b7efc934ab0808e1d32f2fb98d", + + # imgui for Viewer/SampleApp widgets + "third_party/externals/imgui" : "https://github.com/ocornut/imgui.git@6384eee34f08cb7eab8d835043e1738e4adcdf75", } recursedeps = [ "common" ] diff --git a/third_party/imgui/BUILD.gn b/third_party/imgui/BUILD.gn new file mode 100644 index 0000000000..5e3769ccbd --- /dev/null +++ b/third_party/imgui/BUILD.gn @@ -0,0 +1,19 @@ +# Copyright 2016 Google Inc. +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +declare_args() { +} + +import("../third_party.gni") + +third_party("imgui") { + public_include_dirs = [ "../externals/imgui" ] + + sources = [ + "../externals/imgui/imgui.cpp", + "../externals/imgui/imgui_demo.cpp", + "../externals/imgui/imgui_draw.cpp", + ] +} diff --git a/tools/viewer/Viewer.cpp b/tools/viewer/Viewer.cpp index 384e9c6a5b..85b6e7da9c 100644 --- a/tools/viewer/Viewer.cpp +++ b/tools/viewer/Viewer.cpp @@ -25,8 +25,11 @@ #include "SkRandom.h" #include "SkStream.h" #include "SkSurface.h" +#include "SkSwizzle.h" #include "SkTime.h" +#include "imgui.h" + using namespace sk_app; Application* Application::Create(int argc, char** argv, void* platformData) { @@ -52,6 +55,51 @@ static void on_ui_state_changed_handler(const SkString& stateName, const SkStrin return viewer->onUIStateChanged(stateName, stateValue); } +static bool on_mouse_handler(int x, int y, Window::InputState state, uint32_t modifiers, + void* userData) { + ImGuiIO& io = ImGui::GetIO(); + io.MousePos.x = static_cast<float>(x); + io.MousePos.y = static_cast<float>(y); + if (Window::kDown_InputState == state) { + io.MouseDown[0] = true; + } else if (Window::kUp_InputState == state) { + io.MouseDown[0] = false; + } + return true; +} + +static bool on_mouse_wheel_handler(float delta, uint32_t modifiers, void* userData) { + ImGuiIO& io = ImGui::GetIO(); + io.MouseWheel += delta; + return true; +} + +static bool on_key_handler(Window::Key key, Window::InputState state, uint32_t modifiers, + void* userData) { + ImGuiIO& io = ImGui::GetIO(); + io.KeysDown[static_cast<int>(key)] = (Window::kDown_InputState == state); + + if (io.WantCaptureKeyboard) { + return true; + } else { + Viewer* viewer = reinterpret_cast<Viewer*>(userData); + return viewer->onKey(key, state, modifiers); + } +} + +static bool on_char_handler(SkUnichar c, uint32_t modifiers, void* userData) { + ImGuiIO& io = ImGui::GetIO(); + if (io.WantTextInput) { + if (c > 0 && c < 0x10000) { + io.AddInputCharacter(c); + } + return true; + } else { + Viewer* viewer = reinterpret_cast<Viewer*>(userData); + return viewer->onChar(c, modifiers); + } +} + static DEFINE_bool2(fullscreen, f, true, "Run fullscreen."); static DEFINE_string2(match, m, nullptr, @@ -122,6 +170,8 @@ Viewer::Viewer(int argc, char** argv, void* platformData) : fCurrentMeasurement(0) , fDisplayStats(false) , fRefresh(false) + , fShowImGuiDebugWindow(false) + , fShowImGuiTestWindow(false) , fBackendType(sk_app::Window::kNativeGL_BackendType) , fColorType(kN32_SkColorType) , fColorSpace(nullptr) @@ -159,8 +209,20 @@ Viewer::Viewer(int argc, char** argv, void* platformData) fWindow->registerPaintFunc(on_paint_handler, this); fWindow->registerTouchFunc(on_touch_handler, this); fWindow->registerUIStateChangedFunc(on_ui_state_changed_handler, this); + fWindow->registerMouseFunc(on_mouse_handler, this); + fWindow->registerMouseWheelFunc(on_mouse_wheel_handler, this); + fWindow->registerKeyFunc(on_key_handler, this); + fWindow->registerCharFunc(on_char_handler, this); // add key-bindings + fCommands.addCommand(' ', "GUI", "Toggle Debug GUI", [this]() { + this->fShowImGuiDebugWindow = !this->fShowImGuiDebugWindow; + fWindow->inval(); + }); + fCommands.addCommand('g', "GUI", "Toggle GUI Demo", [this]() { + this->fShowImGuiTestWindow = !this->fShowImGuiTestWindow; + fWindow->inval(); + }); fCommands.addCommand('s', "Overlays", "Toggle stats display", [this]() { this->fDisplayStats = !this->fDisplayStats; fWindow->inval(); @@ -234,6 +296,10 @@ Viewer::Viewer(int argc, char** argv, void* platformData) fWindow->registerPaintFunc(on_paint_handler, this); fWindow->registerTouchFunc(on_touch_handler, this); fWindow->registerUIStateChangedFunc(on_ui_state_changed_handler, this); + fWindow->registerMouseFunc(on_mouse_handler, this); + fWindow->registerMouseWheelFunc(on_mouse_wheel_handler, this); + fWindow->registerKeyFunc(on_key_handler, this); + fWindow->registerCharFunc(on_char_handler, this); } #endif fWindow->attach(fBackendType, DisplayParams()); @@ -252,6 +318,39 @@ Viewer::Viewer(int argc, char** argv, void* platformData) fCurrentSlide = 0; setupCurrentSlide(-1); + // ImGui initialization: + ImGuiIO& io = ImGui::GetIO(); + io.DisplaySize.x = static_cast<float>(fWindow->width()); + io.DisplaySize.y = static_cast<float>(fWindow->height()); + + // Keymap... + io.KeyMap[ImGuiKey_Tab] = (int)Window::Key::kTab; + io.KeyMap[ImGuiKey_LeftArrow] = (int)Window::Key::kLeft; + io.KeyMap[ImGuiKey_RightArrow] = (int)Window::Key::kRight; + io.KeyMap[ImGuiKey_UpArrow] = (int)Window::Key::kUp; + io.KeyMap[ImGuiKey_DownArrow] = (int)Window::Key::kDown; + io.KeyMap[ImGuiKey_PageUp] = (int)Window::Key::kPageUp; + io.KeyMap[ImGuiKey_PageDown] = (int)Window::Key::kPageDown; + io.KeyMap[ImGuiKey_Home] = (int)Window::Key::kHome; + io.KeyMap[ImGuiKey_End] = (int)Window::Key::kEnd; + io.KeyMap[ImGuiKey_Delete] = (int)Window::Key::kDelete; + io.KeyMap[ImGuiKey_Backspace] = (int)Window::Key::kBack; + io.KeyMap[ImGuiKey_Enter] = (int)Window::Key::kOK; + io.KeyMap[ImGuiKey_Escape] = (int)Window::Key::kEscape; + io.KeyMap[ImGuiKey_A] = (int)Window::Key::kA; + io.KeyMap[ImGuiKey_C] = (int)Window::Key::kC; + io.KeyMap[ImGuiKey_V] = (int)Window::Key::kV; + io.KeyMap[ImGuiKey_X] = (int)Window::Key::kX; + io.KeyMap[ImGuiKey_Y] = (int)Window::Key::kY; + io.KeyMap[ImGuiKey_Z] = (int)Window::Key::kZ; + + int w, h; + unsigned char* pixels; + io.Fonts->GetTexDataAsAlpha8(&pixels, &w, &h); + SkImageInfo info = SkImageInfo::MakeA8(w, h); + SkPixmap pmap(info, pixels, info.minRowBytes()); + fImGuiFontImage = SkImage::MakeFromRaster(pmap, nullptr, nullptr); + fWindow->show(); } @@ -498,6 +597,18 @@ void Viewer::drawSlide(SkCanvas* canvas) { } void Viewer::onPaint(SkCanvas* canvas) { + // Update ImGui input + ImGuiIO& io = ImGui::GetIO(); + io.DeltaTime = 1.0f / 60.0f; + io.DisplaySize.x = static_cast<float>(fWindow->width()); + io.DisplaySize.y = static_cast<float>(fWindow->height()); + + io.KeyAlt = io.KeysDown[static_cast<int>(Window::Key::kOption)]; + io.KeyCtrl = io.KeysDown[static_cast<int>(Window::Key::kCtrl)]; + io.KeyShift = io.KeysDown[static_cast<int>(Window::Key::kShift)]; + + ImGui::NewFrame(); + drawSlide(canvas); // Advance our timing bookkeeping @@ -510,6 +621,8 @@ void Viewer::onPaint(SkCanvas* canvas) { } fCommands.drawHelp(canvas); + drawImGui(canvas); + // Update the FPS updateUIState(); } @@ -598,13 +711,102 @@ void Viewer::drawStats(SkCanvas* canvas) { canvas->restore(); } +void Viewer::drawImGui(SkCanvas* canvas) { + // Support drawing the ImGui demo window. Superfluous, but gives a good idea of what's possible + if (fShowImGuiTestWindow) { + ImGui::ShowTestWindow(&fShowImGuiTestWindow); + } + + if (fShowImGuiDebugWindow) { + if (ImGui::Begin("Debug", &fShowImGuiDebugWindow)) { + if (ImGui::CollapsingHeader("Slide")) { + static ImGuiTextFilter filter; + filter.Draw(); + int previousSlide = fCurrentSlide; + fCurrentSlide = 0; + for (auto slide : fSlides) { + if (filter.PassFilter(slide->getName().c_str())) { + ImGui::BulletText("%s", slide->getName().c_str()); + if (ImGui::IsItemClicked()) { + setupCurrentSlide(previousSlide); + break; + } + } + ++fCurrentSlide; + } + if (fCurrentSlide >= fSlides.count()) { + fCurrentSlide = previousSlide; + } + } + } + + ImGui::End(); + } + + // This causes ImGui to rebuild vertex/index data based on all immediate-mode commands + // (widgets, etc...) that have been issued + ImGui::Render(); + + // Then we fetch the most recent data, and convert it so we can render with Skia + const ImDrawData* drawData = ImGui::GetDrawData(); + SkTDArray<SkPoint> pos; + SkTDArray<SkPoint> uv; + SkTDArray<SkColor> color; + SkPaint imguiPaint; + imguiPaint.setColor(SK_ColorWHITE); + SkMatrix localMatrix = SkMatrix::MakeScale(1.0f / fImGuiFontImage->width(), + 1.0f / fImGuiFontImage->height()); + imguiPaint.setShader(fImGuiFontImage->makeShader(SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode, + &localMatrix)); + imguiPaint.setFilterQuality(kLow_SkFilterQuality); + + for (int i = 0; i < drawData->CmdListsCount; ++i) { + const ImDrawList* drawList = drawData->CmdLists[i]; + + // De-interleave all vertex data (sigh), convert to Skia types + pos.rewind(); uv.rewind(); color.rewind(); + for (int i = 0; i < drawList->VtxBuffer.size(); ++i) { + const ImDrawVert& vert = drawList->VtxBuffer[i]; + pos.push(SkPoint::Make(vert.pos.x, vert.pos.y)); + uv.push(SkPoint::Make(vert.uv.x, vert.uv.y)); + color.push(vert.col); + } + // ImGui colors are RGBA + SkSwapRB(color.begin(), color.begin(), color.count()); + + int indexOffset = 0; + + // Draw everything with canvas.drawVertices... + for (int j = 0; j < drawList->CmdBuffer.size(); ++j) { + const ImDrawCmd* drawCmd = &drawList->CmdBuffer[j]; + + // TODO: Find min/max index for each draw, so we know how many vertices (sigh) + if (drawCmd->UserCallback) { + drawCmd->UserCallback(drawList, drawCmd); + } else { + canvas->save(); + canvas->clipRect(SkRect::MakeLTRB(drawCmd->ClipRect.x, drawCmd->ClipRect.y, + drawCmd->ClipRect.z, drawCmd->ClipRect.w)); + canvas->drawVertices(SkCanvas::kTriangles_VertexMode, drawList->VtxBuffer.size(), + pos.begin(), uv.begin(), color.begin(), + drawList->IdxBuffer.begin() + indexOffset, drawCmd->ElemCount, + imguiPaint); + indexOffset += drawCmd->ElemCount; + canvas->restore(); + } + } + } +} + void Viewer::onIdle() { double startTime = SkTime::GetMSecs(); fAnimTimer.updateTime(); bool animateWantsInval = fSlides[fCurrentSlide]->animate(fAnimTimer); fAnimateTimes[fCurrentMeasurement] = SkTime::GetMSecs() - startTime; - if (animateWantsInval || fDisplayStats || fRefresh) { + ImGuiIO& io = ImGui::GetIO(); + if (animateWantsInval || fDisplayStats || fRefresh || io.MetricsActiveWindows) { fWindow->inval(); } } @@ -706,3 +908,11 @@ void Viewer::onUIStateChanged(const SkString& stateName, const SkString& stateVa SkDebugf("Unknown stateName: %s", stateName.c_str()); } } + +bool Viewer::onKey(sk_app::Window::Key key, sk_app::Window::InputState state, uint32_t modifiers) { + return fCommands.onKey(key, state, modifiers); +} + +bool Viewer::onChar(SkUnichar c, uint32_t modifiers) { + return fCommands.onChar(c, modifiers); +} diff --git a/tools/viewer/Viewer.h b/tools/viewer/Viewer.h index 7b08df5437..9499c6c979 100644 --- a/tools/viewer/Viewer.h +++ b/tools/viewer/Viewer.h @@ -27,6 +27,8 @@ public: void onIdle() override; bool onTouch(intptr_t owner, sk_app::Window::InputState state, float x, float y); void onUIStateChanged(const SkString& stateName, const SkString& stateValue); + bool onKey(sk_app::Window::Key key, sk_app::Window::InputState state, uint32_t modifiers); + bool onChar(SkUnichar c, uint32_t modifiers); private: void initSlides(); @@ -38,6 +40,7 @@ private: void drawSlide(SkCanvas* canvs); void drawStats(SkCanvas* canvas); + void drawImGui(SkCanvas* canvas); void changeZoomLevel(float delta); SkMatrix computeMatrix(); @@ -57,6 +60,10 @@ private: bool fDisplayStats; bool fRefresh; // whether to continuously refresh for measuring render time + sk_sp<SkImage> fImGuiFontImage; + bool fShowImGuiDebugWindow; + bool fShowImGuiTestWindow; + sk_app::Window::BackendType fBackendType; // Color properties for slide rendering diff --git a/tools/viewer/sk_app/CommandSet.cpp b/tools/viewer/sk_app/CommandSet.cpp index 4805e6aafe..f6568ec342 100644 --- a/tools/viewer/sk_app/CommandSet.cpp +++ b/tools/viewer/sk_app/CommandSet.cpp @@ -12,17 +12,6 @@ namespace sk_app { -static bool on_key_handler(Window::Key key, Window::InputState state, uint32_t modifiers, - void* userData) { - CommandSet* cs = reinterpret_cast<CommandSet*>(userData); - return cs->onKey(key, state, modifiers); -} - -static bool on_char_handler(SkUnichar c, uint32_t modifiers, void* userData) { - CommandSet* cs = reinterpret_cast<CommandSet*>(userData); - return cs->onChar(c, modifiers); -} - CommandSet::CommandSet() : fHelpMode(kNone_HelpMode) { this->addCommand('h', "Overlays", "Show help screen", [this]() { @@ -43,8 +32,6 @@ CommandSet::CommandSet() void CommandSet::attach(Window* window) { fWindow = window; - window->registerKeyFunc(on_key_handler, this); - window->registerCharFunc(on_char_handler, this); } bool CommandSet::onKey(Window::Key key, Window::InputState state, uint32_t modifiers) { diff --git a/tools/viewer/sk_app/CommandSet.h b/tools/viewer/sk_app/CommandSet.h index 4cbb367e01..0784a3875e 100644 --- a/tools/viewer/sk_app/CommandSet.h +++ b/tools/viewer/sk_app/CommandSet.h @@ -22,13 +22,15 @@ namespace sk_app { * Helper class used by applications that want to hook keypresses to trigger events. * * An app can simply store an instance of CommandSet and then use it as follows: - * 1) Attach to the Window at initialization time. This registers key handlers on the window. + * 1) Attach to the Window at initialization time. * 2) Register commands to be executed for characters or keys. Each command needs a Group and a * description (both just strings). Commands attached to Keys (rather than characters) also need * a displayable name for the Key. Finally, a function to execute when the key or character is * pressed must be supplied. The easiest option to is pass in a lambda that captures [this] * (your application object), and performs whatever action is desired. - * 3) At the end of your onPaint, call drawHelp, and pass in the application's canvas. + * 3) Register key and char handlers with the Window, and - depending on your state - forward those + * events to the CommandSet's onKey, onChar, and onSoftKey. + * 4) At the end of your onPaint, call drawHelp, and pass in the application's canvas. * The CommandSet always binds 'h' to cycle through two different help screens. The first shows * all commands, organized by Group (with headings for each Group). The second shows all commands @@ -63,7 +65,7 @@ private: std::function<void(void)> function) : fType(kChar_CommandType) , fChar(c) - , fKeyName(SkStringPrintf("%c", c)) + , fKeyName(' ' == c ? SkString("Space") : SkStringPrintf("%c", c)) , fGroup(group) , fDescription(description) , fFunction(function) {} diff --git a/tools/viewer/sk_app/Window.cpp b/tools/viewer/sk_app/Window.cpp index dec15840a1..9d14a174ff 100644 --- a/tools/viewer/sk_app/Window.cpp +++ b/tools/viewer/sk_app/Window.cpp @@ -27,6 +27,10 @@ static bool default_mouse_func(int x, int y, Window::InputState state, uint32_t return false; } +static bool default_mouse_wheel_func(float delta, uint32_t modifiers, void* userData) { + return false; +} + static bool default_touch_func(intptr_t owner, Window::InputState state, float x, float y, void* userData) { return false; @@ -40,6 +44,7 @@ static void default_paint_func(SkCanvas*, void* userData) {} Window::Window() : fCharFunc(default_char_func) , fKeyFunc(default_key_func) , fMouseFunc(default_mouse_func) + , fMouseWheelFunc(default_mouse_wheel_func) , fTouchFunc(default_touch_func) , fUIStateChangedFunc(default_ui_state_changed_func) , fPaintFunc(default_paint_func) { @@ -62,6 +67,10 @@ bool Window::onMouse(int x, int y, InputState state, uint32_t modifiers) { return fMouseFunc(x, y, state, modifiers, fMouseUserData); } +bool Window::onMouseWheel(float delta, uint32_t modifiers) { + return fMouseWheelFunc(delta, modifiers, fMouseWheelUserData); +} + bool Window::onTouch(intptr_t owner, InputState state, float x, float y) { return fTouchFunc(owner, state, x, y, fTouchUserData); } diff --git a/tools/viewer/sk_app/Window.h b/tools/viewer/sk_app/Window.h index ea6f6c14ea..b20eec8860 100644 --- a/tools/viewer/sk_app/Window.h +++ b/tools/viewer/sk_app/Window.h @@ -86,6 +86,22 @@ public: kLeft, kRight, + // Keys needed by ImGui + kTab, + kPageUp, + kPageDown, + kDelete, + kEscape, + kShift, + kCtrl, + kOption, // AKA Alt + kA, + kC, + kV, + kX, + kY, + kZ, + kOK, //!< the center key kVolUp, //!< volume up - match android @@ -115,6 +131,7 @@ public: typedef bool(*OnCharFunc)(SkUnichar c, uint32_t modifiers, void* userData); typedef bool(*OnKeyFunc)(Key key, InputState state, uint32_t modifiers, void* userData); typedef bool(*OnMouseFunc)(int x, int y, InputState state, uint32_t modifiers, void* userData); + typedef bool(*OnMouseWheelFunc)(float delta, uint32_t modifiers, void* userData); typedef bool(*OnTouchFunc)(intptr_t owner, InputState state, float x, float y, void* userData); typedef void(*OnUIStateChangedFunc)( const SkString& stateName, const SkString& stateValue, void* userData); @@ -135,6 +152,11 @@ public: fMouseUserData = userData; } + void registerMouseWheelFunc(OnMouseWheelFunc func, void* userData) { + fMouseWheelFunc = func; + fMouseWheelUserData = userData; + } + void registerPaintFunc(OnPaintFunc func, void* userData) { fPaintFunc = func; fPaintUserData = userData; @@ -153,6 +175,7 @@ public: bool onChar(SkUnichar c, uint32_t modifiers); bool onKey(Key key, InputState state, uint32_t modifiers); bool onMouse(int x, int y, InputState state, uint32_t modifiers); + bool onMouseWheel(float delta, uint32_t modifiers); bool onTouch(intptr_t owner, InputState state, float x, float y); // multi-owner = multi-touch void onUIStateChanged(const SkString& stateName, const SkString& stateValue); void onPaint(); @@ -176,6 +199,8 @@ protected: void* fKeyUserData; OnMouseFunc fMouseFunc; void* fMouseUserData; + OnMouseWheelFunc fMouseWheelFunc; + void* fMouseWheelUserData; OnTouchFunc fTouchFunc; void* fTouchUserData; OnUIStateChangedFunc diff --git a/tools/viewer/sk_app/mac/Window_mac.cpp b/tools/viewer/sk_app/mac/Window_mac.cpp index 8e707a49c3..a23316dc80 100644 --- a/tools/viewer/sk_app/mac/Window_mac.cpp +++ b/tools/viewer/sk_app/mac/Window_mac.cpp @@ -92,7 +92,26 @@ static Window::Key get_key(const SDL_Keysym& keysym) { { SDLK_UP, Window::Key::kUp }, { SDLK_DOWN, Window::Key::kDown }, { SDLK_LEFT, Window::Key::kLeft }, - { SDLK_RIGHT, Window::Key::kRight } + { SDLK_RIGHT, Window::Key::kRight }, + { SDLK_TAB, Window::Key::kTab }, + { SDLK_PAGEUP, Window::Key::kPageUp }, + { SDLK_PAGEDOWN, Window::Key::kPageDown }, + { SDLK_HOME, Window::Key::kHome }, + { SDLK_END, Window::Key::kEnd }, + { SDLK_DELETE, Window::Key::kDelete }, + { SDLK_ESCAPE, Window::Key::kEscape }, + { SDLK_LSHIFT, Window::Key::kShift }, + { SDLK_RSHIFT, Window::Key::kShift }, + { SDLK_LCTRL, Window::Key::kCtrl }, + { SDLK_RCTRL, Window::Key::kCtrl }, + { SDLK_LALT, Window::Key::kOption }, + { SDLK_LALT, Window::Key::kOption }, + { 'A', Window::Key::kA }, + { 'C', Window::Key::kC }, + { 'V', Window::Key::kV }, + { 'X', Window::Key::kX }, + { 'Y', Window::Key::kY }, + { 'Z', Window::Key::kZ }, }; for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) { if (gPair[i].fSDLK == keysym.sym) { @@ -176,24 +195,22 @@ bool Window_mac::handleEvent(const SDL_Event& event) { break; case SDL_MOUSEMOTION: - // only track if left button is down - if (event.motion.state & SDL_BUTTON_LMASK) { - this->onMouse(event.motion.x, event.motion.y, - Window::kMove_InputState, get_modifiers(event)); - } + this->onMouse(event.motion.x, event.motion.y, + Window::kMove_InputState, get_modifiers(event)); + break; + + case SDL_MOUSEWHEEL: + this->onMouseWheel(event.wheel.y, get_modifiers(event)); break; case SDL_KEYDOWN: { - if (event.key.keysym.sym == SDLK_ESCAPE) { - return true; - } Window::Key key = get_key(event.key.keysym); if (key != Window::Key::kNONE) { - (void) this->onKey(key, Window::kDown_InputState, - get_modifiers(event)); - } else { - (void) this->onChar((SkUnichar) event.key.keysym.sym, - get_modifiers(event)); + if (!this->onKey(key, Window::kDown_InputState, get_modifiers(event))) { + if (event.key.keysym.sym == SDLK_ESCAPE) { + return true; + } + } } } break; @@ -205,6 +222,13 @@ bool Window_mac::handleEvent(const SDL_Event& event) { } } break; + case SDL_TEXTINPUT: { + const char* textIter = &event.text.text[0]; + while (SkUnichar c = SkUTF8_NextUnichar(&textIter)) { + (void) this->onChar(c, get_modifiers(event)); + } + } break; + default: break; } diff --git a/tools/viewer/sk_app/mac/main_mac.cpp b/tools/viewer/sk_app/mac/main_mac.cpp index c7040b5adb..b30a7ea781 100644 --- a/tools/viewer/sk_app/mac/main_mac.cpp +++ b/tools/viewer/sk_app/mac/main_mac.cpp @@ -32,8 +32,10 @@ int main(int argc, char* argv[]) { case SDL_MOUSEMOTION: case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: + case SDL_MOUSEWHEEL: case SDL_KEYDOWN: case SDL_KEYUP: + case SDL_TEXTINPUT: done = sk_app::Window_mac::HandleWindowEvent(event); break; diff --git a/tools/viewer/sk_app/unix/Window_unix.cpp b/tools/viewer/sk_app/unix/Window_unix.cpp index d22502bc91..2481bdbca6 100644 --- a/tools/viewer/sk_app/unix/Window_unix.cpp +++ b/tools/viewer/sk_app/unix/Window_unix.cpp @@ -155,7 +155,26 @@ static Window::Key get_key(KeySym keysym) { { XK_Up, Window::Key::kUp }, { XK_Down, Window::Key::kDown }, { XK_Left, Window::Key::kLeft }, - { XK_Right, Window::Key::kRight } + { XK_Right, Window::Key::kRight }, + { XK_Tab, Window::Key::kTab }, + { XK_Page_Up, Window::Key::kPageUp }, + { XK_Page_Down, Window::Key::kPageDown }, + { XK_Home, Window::Key::kHome }, + { XK_End, Window::Key::kEnd }, + { XK_Delete, Window::Key::kDelete }, + { XK_Escape, Window::Key::kEscape }, + { XK_Shift_L, Window::Key::kShift }, + { XK_Shift_R, Window::Key::kShift }, + { XK_Control_L, Window::Key::kCtrl }, + { XK_Control_R, Window::Key::kCtrl }, + { XK_Alt_L, Window::Key::kOption }, + { XK_Alt_R, Window::Key::kOption }, + { 'A', Window::Key::kA }, + { 'C', Window::Key::kC }, + { 'V', Window::Key::kV }, + { 'X', Window::Key::kX }, + { 'Y', Window::Key::kY }, + { 'Z', Window::Key::kZ }, }; for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) { if (gPair[i].fXK == keysym) { @@ -200,9 +219,17 @@ bool Window_unix::handleEvent(const XEvent& event) { break; case ButtonPress: - if (event.xbutton.button == Button1) { - this->onMouse(event.xbutton.x, event.xbutton.y, - Window::kDown_InputState, get_modifiers(event)); + switch (event.xbutton.button) { + case Button1: + this->onMouse(event.xbutton.x, event.xbutton.y, + Window::kDown_InputState, get_modifiers(event)); + break; + case Button4: + this->onMouseWheel(1.0f, get_modifiers(event)); + break; + case Button5: + this->onMouseWheel(-1.0f, get_modifiers(event)); + break; } break; @@ -214,31 +241,26 @@ bool Window_unix::handleEvent(const XEvent& event) { break; case MotionNotify: - // only track if left button is down - if (event.xmotion.state & Button1Mask) { - this->onMouse(event.xmotion.x, event.xmotion.y, - Window::kMove_InputState, get_modifiers(event)); - } + this->onMouse(event.xmotion.x, event.xmotion.y, + Window::kMove_InputState, get_modifiers(event)); break; case KeyPress: { int shiftLevel = (event.xkey.state & ShiftMask) ? 1 : 0; - KeySym keysym = XkbKeycodeToKeysym(fDisplay, event.xkey.keycode, - 0, shiftLevel); - if (keysym == XK_Escape) { - return true; - } + KeySym keysym = XkbKeycodeToKeysym(fDisplay, event.xkey.keycode, 0, shiftLevel); Window::Key key = get_key(keysym); if (key != Window::Key::kNONE) { - (void) this->onKey(key, Window::kDown_InputState, - get_modifiers(event)); - } else { - long uni = keysym2ucs(keysym); - if (uni != -1) { - (void) this->onChar((SkUnichar) uni, - get_modifiers(event)); + if (!this->onKey(key, Window::kDown_InputState, get_modifiers(event))) { + if (keysym == XK_Escape) { + return true; + } } } + + long uni = keysym2ucs(keysym); + if (uni != -1) { + (void) this->onChar((SkUnichar) uni, get_modifiers(event)); + } } break; case KeyRelease: { diff --git a/tools/viewer/sk_app/win/Window_win.cpp b/tools/viewer/sk_app/win/Window_win.cpp index f7cb547f2a..6f6e72d590 100644 --- a/tools/viewer/sk_app/win/Window_win.cpp +++ b/tools/viewer/sk_app/win/Window_win.cpp @@ -107,7 +107,23 @@ static Window::Key get_key(WPARAM vk) { { VK_UP, Window::Key::kUp }, { VK_DOWN, Window::Key::kDown }, { VK_LEFT, Window::Key::kLeft }, - { VK_RIGHT, Window::Key::kRight } + { VK_RIGHT, Window::Key::kRight }, + { VK_TAB, Window::Key::kTab }, + { VK_PRIOR, Window::Key::kPageUp }, + { VK_NEXT, Window::Key::kPageDown }, + { VK_HOME, Window::Key::kHome }, + { VK_END, Window::Key::kEnd }, + { VK_DELETE, Window::Key::kDelete }, + { VK_ESCAPE, Window::Key::kEscape }, + { VK_SHIFT, Window::Key::kShift }, + { VK_CONTROL, Window::Key::kCtrl }, + { VK_MENU, Window::Key::kOption }, + { 'A', Window::Key::kA }, + { 'C', Window::Key::kC }, + { 'V', Window::Key::kV }, + { 'X', Window::Key::kX }, + { 'Y', Window::Key::kY }, + { 'Z', Window::Key::kZ }, }; for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) { if (gPair[i].fVK == vk) { @@ -151,6 +167,7 @@ static uint32_t get_modifiers(UINT message, WPARAM wParam, LPARAM lParam) { case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_MOUSEMOVE: + case WM_MOUSEWHEEL: if (wParam & MK_CONTROL) { modifiers |= Window::kControl_ModifierKey; } @@ -236,23 +253,25 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) get_modifiers(message, wParam, lParam)); } break; - case WM_MOUSEMOVE: - // only track if left button is down - if ((wParam & MK_LBUTTON) != 0) { - int xPos = GET_X_LPARAM(lParam); - int yPos = GET_Y_LPARAM(lParam); - - //if (!gIsFullscreen) - //{ - // RECT rc = { 0, 0, 640, 480 }; - // AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); - // xPos -= rc.left; - // yPos -= rc.top; - //} - - eventHandled = window->onMouse(xPos, yPos, Window::kMove_InputState, - get_modifiers(message, wParam, lParam)); - } + case WM_MOUSEMOVE: { + int xPos = GET_X_LPARAM(lParam); + int yPos = GET_Y_LPARAM(lParam); + + //if (!gIsFullscreen) + //{ + // RECT rc = { 0, 0, 640, 480 }; + // AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); + // xPos -= rc.left; + // yPos -= rc.top; + //} + + eventHandled = window->onMouse(xPos, yPos, Window::kMove_InputState, + get_modifiers(message, wParam, lParam)); + } break; + + case WM_MOUSEWHEEL: + eventHandled = window->onMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f, + get_modifiers(message, wParam, lParam)); break; default: |