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