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