Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[glass] Canvas2D Support #5941

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
9 changes: 6 additions & 3 deletions glass/src/app/native/cpp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,17 +223,20 @@ int main(int argc, char** argv) {

gPlotProvider = std::make_unique<glass::PlotProvider>(
glass::GetStorageRoot().GetChild("Plots"));
gNtProvider = std::make_unique<glass::NetworkTablesProvider>(
glass::GetStorageRoot().GetChild("NetworkTables"));

glass::SetStorageName("glass");
glass::SetStorageDir(saveDir.empty() ? gui::GetPlatformSaveFileDir()
: saveDir);
gPlotProvider->GlobalInit();
gui::AddInit([] { glass::ResetTime(); });
gNtProvider->GlobalInit();
NtInitialize();

// TODO: Hack; moved this below so the model is initialized
gNtProvider = std::make_unique<glass::NetworkTablesProvider>(
glass::GetStorageRoot().GetChild("NetworkTables"),
gNetworkTablesModel->GetStructDatabase());
gNtProvider->GlobalInit();

glass::AddStandardNetworkTablesViews(*gNtProvider);

gui::AddLateExecute([] { gMainMenu.Display(); });
Expand Down
106 changes: 106 additions & 0 deletions glass/src/lib/native/cpp/other/Canvas2D.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.

#include "glass/other/Canvas2D.h"

#include <span>
#include <vector>

#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui.h>
#include <wpigui.h>

using namespace glass;
namespace gui = wpi::gui;

void Canvas2DLine::Draw(float scale, const ImVec2& cursorPos,
ImDrawList* drawList) const {
drawList->AddLine(cursorPos + (m_point1 * scale),
cursorPos + (m_point2 * scale), m_color, m_weight * scale);
}

void Canvas2DQuad::Draw(float scale, const ImVec2& cursorPos,
ImDrawList* drawList) const {
if (m_fill) {
drawList->AddQuadFilled(cursorPos + (m_point1 * scale),
cursorPos + (m_point2 * scale),
cursorPos + (m_point3 * scale),
cursorPos + (m_point4 * scale), m_color);
} else {
drawList->AddQuad(
cursorPos + (m_point1 * scale), cursorPos + (m_point2 * scale),
cursorPos + (m_point3 * scale), cursorPos + (m_point4 * scale), m_color,
m_weight * scale);
}
}

void Canvas2DCircle::Draw(float scale, const ImVec2& cursorPos,
ImDrawList* drawList) const {
if (m_fill) {
drawList->AddCircleFilled(cursorPos + (m_center * scale), m_radius * scale,
m_color);
} else {
drawList->AddCircle(cursorPos + (m_center * scale), m_radius * scale,
m_color, 0, m_weight * scale);
}
}

void Canvas2DNgon::Draw(float scale, const ImVec2& cursorPos,
ImDrawList* drawList) const {
if (m_fill) {
drawList->AddNgonFilled(cursorPos + (m_center * scale), m_radius * scale,
m_color, m_numSides);
} else {
drawList->AddNgon(cursorPos + (m_center * scale), m_radius * scale, m_color,
m_numSides, m_weight * scale);
}
}

void Canvas2DText::Draw(float scale, const ImVec2& cursorPos,
ImDrawList* drawList) const {
drawList->AddText(nullptr, m_fontSize * scale,
cursorPos + (m_position * scale), m_color, m_text.c_str(),
nullptr, m_wrapWidth * scale);
}

void glass::DisplayCanvas2D(Canvas2DModel* model, const ImVec2& contentSize) {
if (contentSize.x <= 0 || contentSize.y <= 0) {
return;
}

ImVec2 dimensions = model->GetDimensions();
ImDrawList* drawList = ImGui::GetWindowDrawList();

float scale;
ImVec2 cursorPos = ImGui::GetWindowPos() + ImGui::GetCursorPos();
if (contentSize.x / dimensions.x > contentSize.y / dimensions.y) {
scale = contentSize.y / dimensions.y;
cursorPos.x += (contentSize.x - dimensions.x * scale) / 2;
} else {
scale = contentSize.x / dimensions.x;
cursorPos.y += (contentSize.y - dimensions.y * scale) / 2;
}

for (auto&& element : model->GetElements()) {
element->Draw(scale, cursorPos, drawList);
}
}

void glass::DisplayCanvas2DSettings(Canvas2DModel* model) {
// TODO
}

void Canvas2DView::Display() {
DisplayCanvas2D(m_model, ImGui::GetWindowContentRegionMax() -
ImGui::GetWindowContentRegionMin());
}

void Canvas2DView::Settings() {
DisplayCanvas2DSettings(m_model);
}

bool Canvas2DView::HasSettings() {
// TODO
return false;
}
212 changes: 212 additions & 0 deletions glass/src/lib/native/include/glass/other/Canvas2D.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.

#pragma once

#include <set>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui.h>

#include "glass/Model.h"
#include "glass/View.h"

namespace glass {

class Canvas2DElement {
public:
virtual ~Canvas2DElement() = default;
virtual void Draw(float scale, const ImVec2& cursorPos,
ImDrawList* drawList) const = 0;
virtual int GetZOrder() const = 0;
};

struct Canvas2DElementSort {
bool operator()(const Canvas2DElement* a, const Canvas2DElement* b) const {
return a->GetZOrder() < b->GetZOrder();
}
};

class Canvas2DLine : public Canvas2DElement {
public:
Canvas2DLine(ImVec2 point1, ImVec2 point2, float weight, ImU32 color,
int zOrder)
: m_point1{point1},
m_point2{point2},
m_weight{weight},
m_color{color},
m_zOrder{zOrder} {}

ImVec2 GetPoint1() const { return m_point1; }
ImVec2 GetPoint2() const { return m_point2; }
float GetWeight() const { return m_weight; }
ImU32 GetColor() const { return m_color; }
int GetZOrder() const override { return m_zOrder; }

void Draw(float scale, const ImVec2& cursorPos,
ImDrawList* drawList) const override;

private:
ImVec2 m_point1;
ImVec2 m_point2;
float m_weight;
ImU32 m_color;
int m_zOrder;
};

class Canvas2DQuad : public Canvas2DElement {
public:
Canvas2DQuad(ImVec2 point1, ImVec2 point2, ImVec2 point3, ImVec2 point4,
float weight, bool fill, ImU32 color, int zOrder)
: m_point1{point1},
m_point2{point2},
m_point3{point3},
m_point4{point4},
m_weight(weight),
m_fill{fill},
m_color{color},
m_zOrder{zOrder} {}

ImVec2 GetPoint1() const { return m_point1; }
ImVec2 GetPoint2() const { return m_point2; }
ImVec2 GetPoint3() const { return m_point3; }
ImVec2 GetPoint4() const { return m_point4; }
float GetWeight() const { return m_weight; }
ImU32 GetColor() const { return m_color; }
bool IsFill() const { return m_fill; }
int GetZOrder() const override { return m_zOrder; }

void Draw(float scale, const ImVec2& cursorPos,
ImDrawList* drawList) const override;

private:
ImVec2 m_point1;
ImVec2 m_point2;
ImVec2 m_point3;
ImVec2 m_point4;
float m_weight;
bool m_fill;
ImU32 m_color;
int m_zOrder;
};

class Canvas2DCircle : public Canvas2DElement {
public:
Canvas2DCircle(ImVec2 center, float radius, float weight, bool fill,
ImU32 color, int zOrder)
: m_center{center},
m_radius{radius},
m_weight(weight),
m_fill{fill},
m_color{color},
m_zOrder{zOrder} {}

ImVec2 GetCenter() const { return m_center; }
float GetRadius() const { return m_radius; }
float GetWeight() const { return m_weight; }
bool IsFill() const { return m_fill; }
ImU32 GetColor() const { return m_color; }
int GetZOrder() const override { return m_zOrder; }

void Draw(float scale, const ImVec2& cursorPos,
ImDrawList* drawList) const override;

private:
ImVec2 m_center;
float m_radius;
float m_weight;
bool m_fill;
ImU32 m_color;
int m_zOrder;
};

class Canvas2DNgon : public Canvas2DElement {
public:
Canvas2DNgon(ImVec2 center, float radius, int numSides, float weight,
bool fill, ImU32 color, int zOrder)
: m_center{center},
m_radius{radius},
m_numSides{numSides},
m_weight{weight},
m_fill{fill},
m_color{color},
m_zOrder{zOrder} {}

ImVec2 GetCenter() const { return m_center; }
float GetRadius() const { return m_radius; }
int GetNumSides() const { return m_numSides; }
float GetWeight() const { return m_weight; }
bool IsFill() const { return m_fill; }
ImU32 GetColor() const { return m_color; }
int GetZOrder() const override { return m_zOrder; }

void Draw(float scale, const ImVec2& cursorPos,
ImDrawList* drawList) const override;

private:
ImVec2 m_center;
float m_radius;
int m_numSides;
float m_weight;
bool m_fill;
ImU32 m_color;
int m_zOrder;
};

class Canvas2DText : public Canvas2DElement {
public:
Canvas2DText(ImVec2 position, float fontSize, std::string text, ImU32 color,
float wrapWidth, int zOrder)
: m_position{position},
m_fontSize{fontSize},
m_text(std::move(text)),
m_color{color},
m_wrapWidth{wrapWidth},
m_zOrder{zOrder} {}

ImVec2 GetPosition() const { return m_position; }
float GetFontSize() const { return m_fontSize; }
std::string_view GetText() const { return m_text; }
ImU32 GetColor() const { return m_color; }
float GetWrapWidth() const { return m_wrapWidth; }
int GetZOrder() const override { return m_zOrder; }

void Draw(float scale, const ImVec2& cursorPos,
ImDrawList* drawList) const override;

private:
ImVec2 m_position;
float m_fontSize;
std::string m_text;
ImU32 m_color;
float m_wrapWidth;
int m_zOrder;
};

class Canvas2DModel : public Model {
public:
virtual std::set<const Canvas2DElement*, Canvas2DElementSort> GetElements()
const = 0;
virtual ImVec2 GetDimensions() const = 0;
};

void DisplayCanvas2D(Canvas2DModel* model, const ImVec2& contentSize);
void DisplayCanvas2DSettings(Canvas2DModel* model);

class Canvas2DView : public View {
public:
explicit Canvas2DView(Canvas2DModel* model) : m_model{model} {}

void Display() override;
void Settings() override;
bool HasSettings() override;

private:
Canvas2DModel* m_model;
};
} // namespace glass
Loading
Loading