| /* | |
| * Copyright 2017 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #ifndef ImGuiLayer_DEFINED | |
| #define ImGuiLayer_DEFINED | |
| #include "include/core/SkMatrix.h" | |
| #include "include/core/SkPaint.h" | |
| #include "include/core/SkPoint.h" | |
| #include "include/core/SkScalar.h" | |
| #include "include/core/SkTypes.h" | |
| #include "include/private/SkTArray.h" | |
| #include "include/private/SkTPin.h" | |
| #include "include/private/SkTemplates.h" | |
| #include "tools/sk_app/Window.h" | |
| #include <algorithm> | |
| #include <functional> | |
| #include "imgui.h" | |
| class SkCanvas; | |
| class SkSurface; | |
| namespace skui { | |
| enum class InputState; | |
| enum class Key; | |
| enum class ModifierKey; | |
| } // namespace skui | |
| namespace ImGui { | |
| // Helper object for drawing in a widget region, with draggable points | |
| struct DragCanvas { | |
| DragCanvas(const void* id, SkPoint tl = { 0.0f, 0.0f }, SkPoint br = { 1.0f, 1.0f }, | |
| float aspect = -1.0f) | |
| : fID(0), fDragging(false) { | |
| ImGui::PushID(id); | |
| fDrawList = ImGui::GetWindowDrawList(); | |
| // Logical size | |
| SkScalar w = SkTAbs(br.fX - tl.fX), | |
| h = SkTAbs(br.fY - tl.fY); | |
| // Determine aspect ratio automatically by default | |
| if (aspect < 0) { | |
| aspect = h / w; | |
| } | |
| float availWidth = std::max(ImGui::GetContentRegionAvailWidth(), 1.0f); | |
| fPos = ImGui::GetCursorScreenPos(); | |
| fSize = ImVec2(availWidth, availWidth * aspect); | |
| SkPoint local[4] = { | |
| { tl.fX, tl.fY }, | |
| { br.fX, tl.fY }, | |
| { tl.fX, br.fY }, | |
| { br.fX, br.fY }, | |
| }; | |
| SkPoint screen[4] = { | |
| { fPos.x , fPos.y }, | |
| { fPos.x + fSize.x, fPos.y }, | |
| { fPos.x , fPos.y + fSize.y }, | |
| { fPos.x + fSize.x, fPos.y + fSize.y }, | |
| }; | |
| fLocalToScreen.setPolyToPoly(local, screen); | |
| fScreenToLocal.setPolyToPoly(screen, local); | |
| } | |
| ~DragCanvas() { | |
| ImGui::SetCursorScreenPos(ImVec2(fPos.x, fPos.y + fSize.y)); | |
| ImGui::Spacing(); | |
| ImGui::PopID(); | |
| } | |
| void fillColor(ImU32 color) { | |
| fDrawList->AddRectFilled(fPos, ImVec2(fPos.x + fSize.x, fPos.y + fSize.y), color); | |
| } | |
| void dragPoint(SkPoint* p, bool tooltip = false, ImU32 color = 0xFFFFFFFF) { | |
| // Transform points from logical coordinates to screen coordinates | |
| SkPoint center = fLocalToScreen.mapPoint(*p); | |
| // Invisible 10x10 button | |
| ImGui::PushID(fID++); | |
| ImGui::SetCursorScreenPos(ImVec2(center.fX - 5, center.fY - 5)); | |
| ImGui::InvisibleButton("", ImVec2(10, 10)); | |
| if (ImGui::IsItemActive() && ImGui::IsMouseDragging(0)) { | |
| // Update screen position to track mouse, clamped to our area | |
| ImGuiIO& io = ImGui::GetIO(); | |
| center.set(SkTPin(io.MousePos.x, fPos.x, fPos.x + fSize.x), | |
| SkTPin(io.MousePos.y, fPos.y, fPos.y + fSize.y)); | |
| // Update local coordinates for the caller | |
| *p = fScreenToLocal.mapPoint(center); | |
| fDragging = true; | |
| } | |
| if (tooltip && ImGui::IsItemHovered()) { | |
| ImGui::SetTooltip("x: %.3f\ny: %.3f", p->fX, p->fY); | |
| } | |
| ImGui::PopID(); | |
| fScreenPoints.push_back(ImVec2(center.fX, center.fY)); | |
| fDrawList->AddCircle(fScreenPoints.back(), 5.0f, color); | |
| } | |
| ImDrawList* fDrawList; | |
| // Location and dimensions (in screen coordinates) | |
| ImVec2 fPos; | |
| ImVec2 fSize; | |
| // Screen coordinates of points (for additional user drawing) | |
| skia_private::STArray<4, ImVec2, true> fScreenPoints; | |
| // To simplify dragPoint | |
| SkMatrix fLocalToScreen; | |
| SkMatrix fScreenToLocal; | |
| int fID; | |
| bool fDragging; | |
| }; | |
| } // namespace ImGui | |
| class ImGuiLayer : public sk_app::Window::Layer { | |
| public: | |
| ImGuiLayer(); | |
| ~ImGuiLayer() override; | |
| void setScaleFactor(float scaleFactor); | |
| typedef std::function<void(SkCanvas*)> SkiaWidgetFunc; | |
| void skiaWidget(const ImVec2& size, SkiaWidgetFunc func); | |
| void onAttach(sk_app::Window* window) override; | |
| void onPrePaint() override; | |
| void onPaint(SkSurface*) override; | |
| bool onMouse(int x, int y, skui::InputState state, skui::ModifierKey modifiers) override; | |
| bool onMouseWheel(float delta, int x, int y, skui::ModifierKey modifiers) override; | |
| bool onKey(skui::Key key, skui::InputState state, skui::ModifierKey modifiers) override; | |
| bool onChar(SkUnichar c, skui::ModifierKey modifiers) override; | |
| private: | |
| sk_app::Window* fWindow; | |
| SkPaint fFontPaint; | |
| skia_private::TArray<SkiaWidgetFunc> fSkiaWidgetFuncs; | |
| }; | |
| #endif |