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