1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci* Copyright 2017 Google Inc.
3cb93a386Sopenharmony_ci*
4cb93a386Sopenharmony_ci* Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci* found in the LICENSE file.
6cb93a386Sopenharmony_ci*/
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#ifndef ImGuiLayer_DEFINED
9cb93a386Sopenharmony_ci#define ImGuiLayer_DEFINED
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
12cb93a386Sopenharmony_ci#include "include/private/SkTArray.h"
13cb93a386Sopenharmony_ci#include "include/private/SkTPin.h"
14cb93a386Sopenharmony_ci#include "tools/sk_app/Window.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ci#include "imgui.h"
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_cinamespace ImGui {
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_ci// Helper object for drawing in a widget region, with draggable points
21cb93a386Sopenharmony_cistruct DragCanvas {
22cb93a386Sopenharmony_ci    DragCanvas(const void* id, SkPoint tl = { 0.0f, 0.0f }, SkPoint br = { 1.0f, 1.0f },
23cb93a386Sopenharmony_ci               float aspect = -1.0f)
24cb93a386Sopenharmony_ci            : fID(0), fDragging(false) {
25cb93a386Sopenharmony_ci        ImGui::PushID(id);
26cb93a386Sopenharmony_ci        fDrawList = ImGui::GetWindowDrawList();
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_ci        // Logical size
29cb93a386Sopenharmony_ci        SkScalar w = SkTAbs(br.fX - tl.fX),
30cb93a386Sopenharmony_ci                 h = SkTAbs(br.fY - tl.fY);
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_ci        // Determine aspect ratio automatically by default
33cb93a386Sopenharmony_ci        if (aspect < 0) {
34cb93a386Sopenharmony_ci            aspect = h / w;
35cb93a386Sopenharmony_ci        }
36cb93a386Sopenharmony_ci
37cb93a386Sopenharmony_ci        float availWidth = std::max(ImGui::GetContentRegionAvailWidth(), 1.0f);
38cb93a386Sopenharmony_ci        fPos = ImGui::GetCursorScreenPos();
39cb93a386Sopenharmony_ci        fSize = ImVec2(availWidth, availWidth * aspect);
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_ci        SkPoint local[4] = {
42cb93a386Sopenharmony_ci            { tl.fX, tl.fY },
43cb93a386Sopenharmony_ci            { br.fX, tl.fY },
44cb93a386Sopenharmony_ci            { tl.fX, br.fY },
45cb93a386Sopenharmony_ci            { br.fX, br.fY },
46cb93a386Sopenharmony_ci        };
47cb93a386Sopenharmony_ci        SkPoint screen[4] = {
48cb93a386Sopenharmony_ci            { fPos.x          , fPos.y           },
49cb93a386Sopenharmony_ci            { fPos.x + fSize.x, fPos.y           },
50cb93a386Sopenharmony_ci            { fPos.x          , fPos.y + fSize.y },
51cb93a386Sopenharmony_ci            { fPos.x + fSize.x, fPos.y + fSize.y },
52cb93a386Sopenharmony_ci        };
53cb93a386Sopenharmony_ci        fLocalToScreen.setPolyToPoly(local, screen, 4);
54cb93a386Sopenharmony_ci        fScreenToLocal.setPolyToPoly(screen, local, 4);
55cb93a386Sopenharmony_ci    }
56cb93a386Sopenharmony_ci
57cb93a386Sopenharmony_ci    ~DragCanvas() {
58cb93a386Sopenharmony_ci        ImGui::SetCursorScreenPos(ImVec2(fPos.x, fPos.y + fSize.y));
59cb93a386Sopenharmony_ci        ImGui::Spacing();
60cb93a386Sopenharmony_ci        ImGui::PopID();
61cb93a386Sopenharmony_ci    }
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ci    void fillColor(ImU32 color) {
64cb93a386Sopenharmony_ci        fDrawList->AddRectFilled(fPos, ImVec2(fPos.x + fSize.x, fPos.y + fSize.y), color);
65cb93a386Sopenharmony_ci    }
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_ci    void dragPoint(SkPoint* p, bool tooltip = false, ImU32 color = 0xFFFFFFFF) {
68cb93a386Sopenharmony_ci        // Transform points from logical coordinates to screen coordinates
69cb93a386Sopenharmony_ci        SkPoint center = fLocalToScreen.mapXY(p->fX, p->fY);
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_ci        // Invisible 10x10 button
72cb93a386Sopenharmony_ci        ImGui::PushID(fID++);
73cb93a386Sopenharmony_ci        ImGui::SetCursorScreenPos(ImVec2(center.fX - 5, center.fY - 5));
74cb93a386Sopenharmony_ci        ImGui::InvisibleButton("", ImVec2(10, 10));
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci        if (ImGui::IsItemActive() && ImGui::IsMouseDragging(0)) {
77cb93a386Sopenharmony_ci            // Update screen position to track mouse, clamped to our area
78cb93a386Sopenharmony_ci            ImGuiIO& io = ImGui::GetIO();
79cb93a386Sopenharmony_ci            center.set(SkTPin(io.MousePos.x, fPos.x, fPos.x + fSize.x),
80cb93a386Sopenharmony_ci                       SkTPin(io.MousePos.y, fPos.y, fPos.y + fSize.y));
81cb93a386Sopenharmony_ci
82cb93a386Sopenharmony_ci            // Update local coordinates for the caller
83cb93a386Sopenharmony_ci            *p = fScreenToLocal.mapXY(center.fX, center.fY);
84cb93a386Sopenharmony_ci            fDragging = true;
85cb93a386Sopenharmony_ci        }
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_ci        if (tooltip && ImGui::IsItemHovered()) {
88cb93a386Sopenharmony_ci            ImGui::SetTooltip("x: %.3f\ny: %.3f", p->fX, p->fY);
89cb93a386Sopenharmony_ci        }
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_ci        ImGui::PopID();
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_ci        fScreenPoints.push_back(ImVec2(center.fX, center.fY));
94cb93a386Sopenharmony_ci        fDrawList->AddCircle(fScreenPoints.back(), 5.0f, color);
95cb93a386Sopenharmony_ci    }
96cb93a386Sopenharmony_ci
97cb93a386Sopenharmony_ci    ImDrawList* fDrawList;
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci    // Location and dimensions (in screen coordinates)
100cb93a386Sopenharmony_ci    ImVec2 fPos;
101cb93a386Sopenharmony_ci    ImVec2 fSize;
102cb93a386Sopenharmony_ci
103cb93a386Sopenharmony_ci    // Screen coordinates of points (for additional user drawing)
104cb93a386Sopenharmony_ci    SkSTArray<4, ImVec2, true> fScreenPoints;
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci    // To simplify dragPoint
107cb93a386Sopenharmony_ci    SkMatrix fLocalToScreen;
108cb93a386Sopenharmony_ci    SkMatrix fScreenToLocal;
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ci    int fID;
111cb93a386Sopenharmony_ci    bool fDragging;
112cb93a386Sopenharmony_ci};
113cb93a386Sopenharmony_ci
114cb93a386Sopenharmony_ci}  // namespace ImGui
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_ciclass ImGuiLayer : public sk_app::Window::Layer {
117cb93a386Sopenharmony_cipublic:
118cb93a386Sopenharmony_ci    ImGuiLayer();
119cb93a386Sopenharmony_ci    ~ImGuiLayer() override;
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_ci    void setScaleFactor(float scaleFactor);
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_ci    typedef std::function<void(SkCanvas*)> SkiaWidgetFunc;
124cb93a386Sopenharmony_ci    void skiaWidget(const ImVec2& size, SkiaWidgetFunc func);
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci    void onAttach(sk_app::Window* window) override;
127cb93a386Sopenharmony_ci    void onPrePaint() override;
128cb93a386Sopenharmony_ci    void onPaint(SkSurface*) override;
129cb93a386Sopenharmony_ci    bool onMouse(int x, int y, skui::InputState state, skui::ModifierKey modifiers) override;
130cb93a386Sopenharmony_ci    bool onMouseWheel(float delta, skui::ModifierKey modifiers) override;
131cb93a386Sopenharmony_ci    bool onKey(skui::Key key, skui::InputState state, skui::ModifierKey modifiers) override;
132cb93a386Sopenharmony_ci    bool onChar(SkUnichar c, skui::ModifierKey modifiers) override;
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ciprivate:
135cb93a386Sopenharmony_ci    sk_app::Window* fWindow;
136cb93a386Sopenharmony_ci    SkPaint fFontPaint;
137cb93a386Sopenharmony_ci    SkTArray<SkiaWidgetFunc> fSkiaWidgetFuncs;
138cb93a386Sopenharmony_ci};
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_ci#endif
141