blob: b386f049539293da329bf62cfcd845169b71c892 [file] [log] [blame]
/*
* Copyright 2017 Google Inc.
*
* 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/base/SkTArray.h"
#include "include/private/base/SkTPin.h"
#include "include/private/base/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, 4);
fScreenToLocal.setPolyToPoly(screen, local, 4);
}
~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.mapXY(p->fX, p->fY);
// 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.mapXY(center.fX, center.fY);
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