aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2021-05-14 20:52:00 -0700
committerrtk0c <[email protected]>2021-05-14 20:52:00 -0700
commitfa13cad2bf12d8f7f63f7ff6aab07dd2eaf6ec6d (patch)
tree994198f3636030b3974f73170fc59b04a794681d /core
parent765df313e065f8401319c68ba70cd41b0bc34c9d (diff)
Node graph editor basic functionality
Diffstat (limited to 'core')
-rw-r--r--core/locale/zh_CN.json1
-rw-r--r--core/src/Model/Workflow/Nodes/DocumentNodes.cpp2
-rw-r--r--core/src/Model/Workflow/Nodes/NumericNodes.cpp4
-rw-r--r--core/src/Model/Workflow/Nodes/TextNodes.cpp2
-rw-r--r--core/src/Model/Workflow/Nodes/UserInputNodes.cpp4
-rw-r--r--core/src/Model/Workflow/Workflow.hpp29
-rw-r--r--core/src/Model/Workflow/Workflow_Main.cpp57
-rw-r--r--core/src/UI/Localization.hpp1
-rw-r--r--core/src/UI/UI_Workflows.cpp100
-rw-r--r--core/src/Utils/Color.hpp4
10 files changed, 159 insertions, 45 deletions
diff --git a/core/locale/zh_CN.json b/core/locale/zh_CN.json
index 4c3db9a..31f8827 100644
--- a/core/locale/zh_CN.json
+++ b/core/locale/zh_CN.json
@@ -4,6 +4,7 @@
"Generic.Add": "\uf067 新建",
"Generic.Edit": "\uf044 编辑",
"Generic.Delete": "\uf1f8 删除",
+ "Generic.Disconnect": "\uf127 断开连接",
"Generic.Close": "\uf00d 关闭",
"Generic.Dialog.Confirm": "确定",
"Generic.Dialog.Cancel": "取消",
diff --git a/core/src/Model/Workflow/Nodes/DocumentNodes.cpp b/core/src/Model/Workflow/Nodes/DocumentNodes.cpp
index b858b49..3925dec 100644
--- a/core/src/Model/Workflow/Nodes/DocumentNodes.cpp
+++ b/core/src/Model/Workflow/Nodes/DocumentNodes.cpp
@@ -9,7 +9,7 @@ bool DocumentTemplateExpansionNode::IsInstance(const WorkflowNode* node)
}
DocumentTemplateExpansionNode::DocumentTemplateExpansionNode()
- : WorkflowNode(KD_DocumentTemplateExpansion)
+ : WorkflowNode(KD_DocumentTemplateExpansion, false)
{
}
diff --git a/core/src/Model/Workflow/Nodes/NumericNodes.cpp b/core/src/Model/Workflow/Nodes/NumericNodes.cpp
index 083172e..ad51fb4 100644
--- a/core/src/Model/Workflow/Nodes/NumericNodes.cpp
+++ b/core/src/Model/Workflow/Nodes/NumericNodes.cpp
@@ -36,7 +36,7 @@ bool NumericOperationNode::IsInstance(const WorkflowNode* node)
}
NumericOperationNode::NumericOperationNode(OperationType type)
- : WorkflowNode(OperationTypeToNodeKind(type))
+ : WorkflowNode(OperationTypeToNodeKind(type), false)
, mType{ type }
{
mInputs.resize(2);
@@ -85,7 +85,7 @@ bool NumericExpressionNode::IsInstance(const WorkflowNode* node)
}
NumericExpressionNode::NumericExpressionNode()
- : WorkflowNode(KD_NumericExpression)
+ : WorkflowNode(KD_NumericExpression, false)
{
}
diff --git a/core/src/Model/Workflow/Nodes/TextNodes.cpp b/core/src/Model/Workflow/Nodes/TextNodes.cpp
index b70290d..6c71309 100644
--- a/core/src/Model/Workflow/Nodes/TextNodes.cpp
+++ b/core/src/Model/Workflow/Nodes/TextNodes.cpp
@@ -53,7 +53,7 @@ bool TextFormatterNode::IsInstance(const WorkflowNode* node)
}
TextFormatterNode::TextFormatterNode()
- : WorkflowNode(KD_TextFormatting)
+ : WorkflowNode(KD_TextFormatting, false)
{
}
diff --git a/core/src/Model/Workflow/Nodes/UserInputNodes.cpp b/core/src/Model/Workflow/Nodes/UserInputNodes.cpp
index 3a30631..f8d3e01 100644
--- a/core/src/Model/Workflow/Nodes/UserInputNodes.cpp
+++ b/core/src/Model/Workflow/Nodes/UserInputNodes.cpp
@@ -9,7 +9,7 @@ bool FormInputNode::IsInstance(const WorkflowNode* node)
}
FormInputNode::FormInputNode()
- : WorkflowNode(KD_FormInput)
+ : WorkflowNode(KD_FormInput, false)
{
}
@@ -23,7 +23,7 @@ bool DatabaseRowsInputNode::IsInstance(const WorkflowNode* node)
}
DatabaseRowsInputNode::DatabaseRowsInputNode()
- : WorkflowNode(KD_DatabaseRowsInput)
+ : WorkflowNode(KD_DatabaseRowsInput, false)
{
}
diff --git a/core/src/Model/Workflow/Workflow.hpp b/core/src/Model/Workflow/Workflow.hpp
index 79c2b2f..847aa72 100644
--- a/core/src/Model/Workflow/Workflow.hpp
+++ b/core/src/Model/Workflow/Workflow.hpp
@@ -4,6 +4,7 @@
#include "Utils/Vector.hpp"
#include "cplt_fwd.hpp"
+#include <imgui_node_editor.h>
#include <cstddef>
#include <cstdint>
#include <iosfwd>
@@ -14,6 +15,8 @@
#include <variant>
#include <vector>
+namespace ImNodes = ax::NodeEditor;
+
class WorkflowConnection
{
public:
@@ -31,7 +34,7 @@ public:
bool IsValid() const;
/// Used for `LinkId` when interfacing with imgui node editor. Runtime only (not saved to disk and generated when loading).
- size_t GetLinkId() const;
+ ImNodes::LinkId GetLinkId() const;
void DrawDebugInfo() const;
void ReadFrom(std::istream& stream);
@@ -99,13 +102,14 @@ protected:
uint32_t mId;
Kind mKind;
int mDepth;
+ bool mLocked;
public:
static const char* FormatKind(Kind kind);
static const char* FormatType(Type type);
static std::unique_ptr<WorkflowNode> CreateByKind(Kind kind);
- WorkflowNode(Kind kind);
+ WorkflowNode(Kind kind, bool locked);
virtual ~WorkflowNode() = default;
WorkflowNode(const WorkflowNode&) = delete;
@@ -118,23 +122,28 @@ public:
uint32_t GetId() const;
/// Used for `NodeId` when interfacing with imgui node editor. Runtime only (not saved to disk and generated when loading).
- size_t GetNodeId() const;
+ ImNodes::NodeId GetNodeId() const;
Kind GetKind() const;
int GetDepth() const;
+ bool IsLocked() const;
Type GetType() const;
bool IsInputNode() const;
bool IsOutputNode() const;
- void ConnectInput(uint32_t pinId, WorkflowNode& output, uint32_t outputNodeId);
+ void ConnectInput(uint32_t pinId, WorkflowNode& srcNode, uint32_t srcPinId);
void DisconnectInput(uint32_t pinId);
+
+ void DrawInputPinDebugInfo(uint32_t pinId) const;
const InputPin& GetInputPin(uint32_t pinId)const ;
- size_t GetInputPinUniqueId(uint32_t pinId) const;
+ ImNodes::PinId GetInputPinUniqueId(uint32_t pinId) const;
- void ConnectOutput(uint32_t pinId, WorkflowNode& input, uint32_t inputNodeId);
+ void ConnectOutput(uint32_t pinId, WorkflowNode& dstNode, uint32_t dstPinId);
void DisconnectOutput(uint32_t pinId);
+
+ void DrawOutputPinDebugInfo(uint32_t pinId)const;
const OutputPin& GetOutputPin(uint32_t pinId)const ;
- size_t GetOutputPinUniqueId(uint32_t pinId) const;
+ ImNodes::PinId GetOutputPinUniqueId(uint32_t pinId) const;
virtual void Evaluate(WorkflowEvaluationContext& ctx) = 0;
@@ -187,7 +196,9 @@ public:
std::vector<std::unique_ptr<BaseValue>>& GetConstants();
WorkflowConnection* GetConnectionById(uint32_t id);
+ WorkflowConnection* GetConnectionByLinkId(ImNodes::LinkId linkId);
WorkflowNode* GetNodeById(uint32_t id);
+ WorkflowNode* GetNodeByNodeId(ImNodes::NodeId nodeId);
BaseValue* GetConstantById(uint32_t id);
struct GlobalPinId
@@ -200,8 +211,8 @@ public:
};
/// `pinId` should be the `UniqueId` of a pin from a node that's within this workflow.
- GlobalPinId DisassembleGlobalPinId(size_t id);
- size_t FabricateGlobalPinId(const WorkflowNode& node, uint32_t pinId, bool isOutput) const;
+ GlobalPinId DisassembleGlobalPinId(ImNodes::PinId id);
+ ImNodes::PinId FabricateGlobalPinId(const WorkflowNode& node, uint32_t pinId, bool isOutput) const;
const std::vector<std::vector<uint32_t>>& GetDepthGroups() const;
bool DoesDepthNeedsUpdate() const;
diff --git a/core/src/Model/Workflow/Workflow_Main.cpp b/core/src/Model/Workflow/Workflow_Main.cpp
index 678b4b8..1b50064 100644
--- a/core/src/Model/Workflow/Workflow_Main.cpp
+++ b/core/src/Model/Workflow/Workflow_Main.cpp
@@ -24,7 +24,7 @@ bool WorkflowConnection::IsValid() const
return Id != 0;
}
-size_t WorkflowConnection::GetLinkId() const
+ImNodes::LinkId WorkflowConnection::GetLinkId() const
{
// Our id is 0-based (represents an index directly)
// but imgui-node-editor uses the value 0 to represent a null id, so we need to offset by 1
@@ -33,12 +33,10 @@ size_t WorkflowConnection::GetLinkId() const
void WorkflowConnection::DrawDebugInfo() const
{
- ImGui::BeginTooltip();
ImGui::Text("Source (node with output pin):");
ImGui::Text("{ Node = %u, Pin = %u }", SourceNode, SourcePin);
ImGui::Text("Destination (node with input pin):");
ImGui::Text("{ Node = %u, Pin = %u }", DestinationNode, DestinationPin);
- ImGui::EndTooltip();
}
void WorkflowConnection::ReadFrom(std::istream& stream)
@@ -78,9 +76,10 @@ BaseValue::Kind WorkflowNode::OutputPin::GetMatchingType() const
return MatchingType;
}
-WorkflowNode::WorkflowNode(Kind kind)
+WorkflowNode::WorkflowNode(Kind kind, bool locked)
: mKind{ kind }
, mDepth{ -1 }
+ , mLocked(locked)
{
}
@@ -99,7 +98,7 @@ uint32_t WorkflowNode::GetId() const
return mId;
}
-size_t WorkflowNode::GetNodeId() const
+ImNodes::NodeId WorkflowNode::GetNodeId() const
{
// See WorkflowConnection::GetLinkId for the rationale
return mId + 1;
@@ -115,6 +114,11 @@ int WorkflowNode::GetDepth() const
return mDepth;
}
+bool WorkflowNode::IsLocked() const
+{
+ return mLocked;
+}
+
WorkflowNode::Type WorkflowNode::GetType() const
{
if (IsInputNode()) {
@@ -136,9 +140,9 @@ bool WorkflowNode::IsOutputNode() const
return mOutputs.size() == 0;
}
-void WorkflowNode::ConnectInput(uint32_t pinId, WorkflowNode& output, uint32_t outputNodeId)
+void WorkflowNode::ConnectInput(uint32_t pinId, WorkflowNode& srcNode, uint32_t srcPinId)
{
- mWorkflow->Connect(*this, pinId, output, outputNodeId);
+ mWorkflow->Connect(*this, pinId, srcNode, srcPinId);
}
void WorkflowNode::DisconnectInput(uint32_t pinId)
@@ -146,19 +150,25 @@ void WorkflowNode::DisconnectInput(uint32_t pinId)
mWorkflow->DisconnectByDestination(*this, pinId);
}
+void WorkflowNode::DrawInputPinDebugInfo(uint32_t pinId) const
+{
+ ImGui::Text("Node ID: %d", mId);
+ ImGui::Text("Pin ID: (input) %d", pinId);
+}
+
const WorkflowNode::InputPin& WorkflowNode::GetInputPin(uint32_t pinId) const
{
return mInputs[pinId];
}
-size_t WorkflowNode::GetInputPinUniqueId(uint32_t pinId) const
+ImNodes::PinId WorkflowNode::GetInputPinUniqueId(uint32_t pinId) const
{
return mWorkflow->FabricateGlobalPinId(*this, pinId, false);
}
-void WorkflowNode::ConnectOutput(uint32_t pinId, WorkflowNode& input, uint32_t inputNodeId)
+void WorkflowNode::ConnectOutput(uint32_t pinId, WorkflowNode& dstNode, uint32_t dstPinId)
{
- mWorkflow->Connect(input, inputNodeId, *this, pinId);
+ mWorkflow->Connect(dstNode, dstPinId, *this, pinId);
}
void WorkflowNode::DisconnectOutput(uint32_t pinId)
@@ -166,12 +176,18 @@ void WorkflowNode::DisconnectOutput(uint32_t pinId)
mWorkflow->DisconnectBySource(*this, pinId);
}
+void WorkflowNode::DrawOutputPinDebugInfo(uint32_t pinId) const
+{
+ ImGui::Text("Node ID: %d", mId);
+ ImGui::Text("Pin ID: (output) %d", pinId);
+}
+
const WorkflowNode::OutputPin& WorkflowNode::GetOutputPin(uint32_t pinId) const
{
return mOutputs[pinId];
}
-size_t WorkflowNode::GetOutputPinUniqueId(uint32_t pinId) const
+ImNodes::PinId WorkflowNode::GetOutputPinUniqueId(uint32_t pinId) const
{
return mWorkflow->FabricateGlobalPinId(*this, pinId, true);
}
@@ -180,12 +196,14 @@ void WorkflowNode::Draw()
{
for (uint32_t i = 0; i < mInputs.size(); ++i) {
auto& pin = mInputs[i];
+ auto& typeInfo = BaseValue::QueryInfo(pin.MatchingType);
ImNodes::BeginPin(GetInputPinUniqueId(i), ImNodes::PinKind::Input);
// TODO
ImNodes::EndPin();
}
for (uint32_t i = 0; i < mOutputs.size(); ++i) {
auto& pin = mOutputs[i];
+ auto& typeInfo = BaseValue::QueryInfo(pin.MatchingType);
ImNodes::BeginPin(GetOutputPinUniqueId(i), ImNodes::PinKind::Output);
// TODO
ImNodes::EndPin();
@@ -194,13 +212,11 @@ void WorkflowNode::Draw()
void WorkflowNode::DrawDebugInfo() const
{
- ImGui::BeginTooltip();
ImGui::Text("Node kind: %s", FormatKind(mKind));
ImGui::Text("Node type: %s", FormatType(GetType()));
ImGui::Text("Node ID: %u", mId);
ImGui::Text("Depth: %d", mDepth);
DrawExtraDebugInfo();
- ImGui::EndTooltip();
}
void WorkflowNode::ReadFrom(std::istream& stream)
@@ -338,17 +354,27 @@ WorkflowConnection* Workflow::GetConnectionById(uint32_t id)
return &mConnections[id];
}
+WorkflowConnection* Workflow::GetConnectionByLinkId(ImNodes::LinkId id)
+{
+ return &mConnections[(uint32_t)(size_t)id - 1];
+}
+
WorkflowNode* Workflow::GetNodeById(uint32_t id)
{
return mNodes[id].get();
}
+WorkflowNode* Workflow::GetNodeByNodeId(ImNodes::NodeId id)
+{
+ return mNodes[(uint32_t)(size_t)id - 1].get();
+}
+
BaseValue* Workflow::GetConstantById(uint32_t id)
{
return mConstants[id].get();
}
-Workflow::GlobalPinId Workflow::DisassembleGlobalPinId(size_t id)
+Workflow::GlobalPinId Workflow::DisassembleGlobalPinId(ImNodes::PinId pinId)
{
// imgui-node-editor requires all pins to have a global, unique id
// but in our model the pin are typed (input vs output) and associated with a node: there is no built-in global id
@@ -362,6 +388,7 @@ Workflow::GlobalPinId Workflow::DisassembleGlobalPinId(size_t id)
// 1 is added to pin id to prevent the 0th node's 0th input pin resulting in a 0 global pin id
// (this is problematic because imgui-node-editor use 0 to represent null)
+ auto id = static_cast<uint64_t>(pinId);
GlobalPinId result;
result.Node = mNodes[id >> 32].get();
@@ -371,7 +398,7 @@ Workflow::GlobalPinId Workflow::DisassembleGlobalPinId(size_t id)
return result;
}
-size_t Workflow::FabricateGlobalPinId(const WorkflowNode& node, uint32_t pinId, bool isOutput) const
+ImNodes::PinId Workflow::FabricateGlobalPinId(const WorkflowNode& node, uint32_t pinId, bool isOutput) const
{
// See this->DisassembleGlobalPinId for format details and rationale
diff --git a/core/src/UI/Localization.hpp b/core/src/UI/Localization.hpp
index 65fcdfd..b421d24 100644
--- a/core/src/UI/Localization.hpp
+++ b/core/src/UI/Localization.hpp
@@ -19,6 +19,7 @@ public:
BasicTranslation Add{ "Generic.Add"sv };
BasicTranslation Edit{ "Generic.Edit"sv };
BasicTranslation Delete{ "Generic.Delete"sv };
+ BasicTranslation Disconnect{ "Generic.Disconnect"sv };
BasicTranslation Close{ "Generic.Close"sv };
BasicTranslation DialogConfirm{ "Generic.Dialog.Confirm"sv };
BasicTranslation DialogCancel{ "Generic.Dialog.Cancel"sv };
diff --git a/core/src/UI/UI_Workflows.cpp b/core/src/UI/UI_Workflows.cpp
index 7aefeab..1a4294f 100644
--- a/core/src/UI/UI_Workflows.cpp
+++ b/core/src/UI/UI_Workflows.cpp
@@ -138,6 +138,10 @@ private:
ImNodes::EditorContext* mContext;
WorkflowDatabase mWorkflowDatabase;
+ ImNodes::NodeId mContextMenuNodeId = 0;
+ ImNodes::PinId mContextMenuPinId = 0;
+ ImNodes::LinkId mContextMenuLinkId = 0;
+
public:
WorkflowUI()
{
@@ -152,9 +156,12 @@ public:
void Draw()
{
+ auto ls = LocaleStrings::Instance.get();
+
ImNodes::SetCurrentEditor(mContext);
ImNodes::Begin("");
+ // Defer creation of tooltip because within the node editor, cursor positioning is going to be off
const char* tooltipMessage = nullptr;
for (auto& node : mWorkflow->GetNodes()) {
@@ -180,8 +187,8 @@ public:
goto createError;
}
- auto [srcNode, srcPinId, srcIsOutput] = mWorkflow->DisassembleGlobalPinId((size_t)src);
- auto [dstNode, dstPinId, dstIsOutput] = mWorkflow->DisassembleGlobalPinId((size_t)dst);
+ auto [srcNode, srcPinId, srcIsOutput] = mWorkflow->DisassembleGlobalPinId(src);
+ auto [dstNode, dstPinId, dstIsOutput] = mWorkflow->DisassembleGlobalPinId(dst);
if (srcNode == dstNode) {
ImNodes::RejectNewItem();
@@ -208,7 +215,7 @@ public:
ImNodes::PinId newNodePin = 0;
if (ImNodes::QueryNewNode(&newNodePin)) {
- auto [node, pinId, isOutput] = mWorkflow->DisassembleGlobalPinId((size_t)newNodePin);
+ auto [node, pinId, isOutput] = mWorkflow->DisassembleGlobalPinId(newNodePin);
if ((isOutput && node->GetOutputPin(pinId).IsConnected()) ||
(!isOutput && node->GetInputPin(pinId).IsConnected()))
@@ -230,10 +237,22 @@ public:
if (ImNodes::BeginDelete()) {
ImNodes::LinkId deletedLinkId;
if (ImNodes::QueryDeletedLink(&deletedLinkId)) {
- // Link id is the same as our connection id
- auto& conn = *mWorkflow->GetConnectionById((size_t)deletedLinkId);
+ auto& conn = *mWorkflow->GetConnectionByLinkId(deletedLinkId);
+ mWorkflow->RemoveConnection(conn.Id);
+ }
+
+ ImNodes::NodeId deletedNodeId;
+ if (ImNodes::QueryDeletedNode(&deletedNodeId)) {
+ auto node = mWorkflow->GetNodeByNodeId(deletedNodeId);
+ if (!node) {
+ ImNodes::RejectDeletedItem();
+ goto deleteError;
+ }
- // TODO
+ if (node->IsLocked()) {
+ ImNodes::RejectDeletedItem();
+ goto deleteError;
+ }
}
}
deleteError:
@@ -241,23 +260,77 @@ public:
// Popups
ImNodes::Suspend();
+ if (ImNodes::ShowNodeContextMenu(&mContextMenuNodeId)) {
+ ImGui::OpenPopup("Node Context Menu");
+ } else if (ImNodes::ShowPinContextMenu(&mContextMenuPinId)) {
+ ImGui::OpenPopup("Pin Context Menu");
+ } else if (ImNodes::ShowLinkContextMenu(&mContextMenuLinkId)) {
+ ImGui::OpenPopup("Link Context Menu");
+ }
+
if (ImGui::BeginPopup("Node Context Menu")) {
- // TODO
+ auto& node = *mWorkflow->GetNodeByNodeId(mContextMenuNodeId);
+ node.DrawDebugInfo();
+
+ if (ImGui::MenuItem(ls->Delete.Get())) {
+ ImNodes::DeleteNode(mContextMenuNodeId);
+ }
+
ImGui::EndPopup();
}
+
+ if (ImGui::BeginPopup("Pin Context Menu")) {
+ auto [node, pinId, isOutput] = mWorkflow->DisassembleGlobalPinId(mContextMenuPinId);
+ if (isOutput) {
+ node->DrawOutputPinDebugInfo(pinId);
+ } else {
+ node->DrawInputPinDebugInfo(pinId);
+ }
+
+ if (ImGui::MenuItem(ls->Disconnect.Get())) {
+ if (isOutput) {
+ auto& pin = node->GetOutputPin(pinId);
+ if (pin.IsConnected()) {
+ auto linkId = mWorkflow->GetConnectionById(pin.Connection)->GetLinkId();
+ ImNodes::DeleteLink(linkId);
+ }
+ } else {
+ auto& pin = node->GetInputPin(pinId);
+ if (pin.IsConstantConnection()) {
+ // TODO
+ } else if (pin.IsConnected()) {
+ auto linkId = mWorkflow->GetConnectionById(pin.Connection)->GetLinkId();
+ ImNodes::DeleteLink(linkId);
+ }
+ }
+ }
+
+ ImGui::EndPopup();
+ }
+
if (ImGui::BeginPopup("Link Context Menu")) {
- // TODO
+ auto& conn = *mWorkflow->GetConnectionByLinkId(mContextMenuLinkId);
+ conn.DrawDebugInfo();
+
+ if (ImGui::MenuItem(ls->Delete.Get())) {
+ ImNodes::DeleteLink(mContextMenuLinkId);
+ }
+
ImGui::EndPopup();
}
+
if (ImGui::BeginPopup("Create Node")) {
auto DisplayCandidatesCategory = [&](const char* name, std::span<const WorkflowDatabase::Candidate> candidates) {
- ImGui::TreeNode(name);
- for (auto& candidate : candidates) {
- if (ImGui::MenuItem(candidate.Name.c_str())) {
- // TODO
+ if (ImGui::BeginMenu(name)) {
+ for (auto& candidate : candidates) {
+ if (ImGui::MenuItem(candidate.Name.c_str())) {
+ // Create node
+ auto uptr = candidate.Constructor();
+ mWorkflow->AddNode(std::move(uptr));
+ }
}
+ ImGui::EndMenu();
}
- ImGui::TreePop();
};
DisplayCandidatesCategory("Numeric nodes", mWorkflowDatabase.GetNumericNodes());
@@ -268,6 +341,7 @@ public:
DisplayCandidatesCategory("Output nodes", mWorkflowDatabase.GetOutputNodes());
ImGui::EndPopup();
}
+
if (tooltipMessage) {
ImGui::BeginTooltip();
ImGui::TextUnformatted(tooltipMessage);
diff --git a/core/src/Utils/Color.hpp b/core/src/Utils/Color.hpp
index 26cfdd4..5f4691f 100644
--- a/core/src/Utils/Color.hpp
+++ b/core/src/Utils/Color.hpp
@@ -164,8 +164,8 @@ constexpr HsvColor RgbaColor::ToHsv() const noexcept
float fb = GetNormalizedGreen();
float fa = GetNormalizedAlpha();
- auto p = fg < fb ? ImVec4(fb, fg, -1, 2.0f / 3.0f) : ImVec4(fg, fb, 0, -1.0f / 3.0f);
- auto q = fr < p.x ? ImVec4(p.x, p.y, p.w, fr) : ImVec4(fr, p.y, p.z, p.x);
+ auto p = fg < fb ? Vec4f{ fb, fg, -1, 2.0f / 3.0f } : Vec4f{ fg, fb, 0, -1.0f / 3.0f };
+ auto q = fr < p.x ? Vec4f{ p.x, p.y, p.w, fr } : Vec4f{ fr, p.y, p.z, p.x };
float c = q.x - std::min(q.w, q.y);
float h = std::abs((q.w - q.y) / (6 * c + std::numeric_limits<float>::epsilon()) + q.z);