From 6f347d993909572cd0b616f6ae99d4030d81ac5c Mon Sep 17 00:00:00 2001 From: Jun Zhu Date: Fri, 30 Aug 2024 11:26:12 +0200 Subject: [PATCH] Implement mouse dragging in alphamap --- docs/docs/gui.md | 1 + .../graphics/widgets/material_widget.hpp | 8 +++ gui/src/graphics/widgets/material_widget.cpp | 65 +++++++++++-------- 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/docs/docs/gui.md b/docs/docs/gui.md index 67e6a36e..316e0429 100644 --- a/docs/docs/gui.md +++ b/docs/docs/gui.md @@ -90,6 +90,7 @@ - *Alphamap*: - Ctrl + Left mouse button: Add a new point. - d: Delete a point while hovering it (the point will be highlighted). + - Left mouse button: Press to drag a point vertically. It is not allowed to drag the first point. - *ISO Surface*: Check to render the volume as meshes. It is still an experimental feature. diff --git a/gui/include/graphics/widgets/material_widget.hpp b/gui/include/graphics/widgets/material_widget.hpp index 4402c9a6..63bbe44a 100644 --- a/gui/include/graphics/widgets/material_widget.hpp +++ b/gui/include/graphics/widgets/material_widget.hpp @@ -47,8 +47,16 @@ class TransferFuncWidget : public Widget { std::shared_ptr material_; std::map alpha_; + bool dragging_ {false}; + std::map::iterator dragged_point_; const size_t max_num_points_; + const ImColor frame_color_ {180, 180, 180, 255}; + const ImColor point_color_ {180, 180, 90, 255}; + const ImColor line_color_ {180, 180, 120, 255}; + const float line_width_ = 2.f; + const ImColor highlight_color_ {255, 0, 0, 255}; + void renderSelector(); void renderColorbar(); diff --git a/gui/src/graphics/widgets/material_widget.cpp b/gui/src/graphics/widgets/material_widget.cpp index 8e467514..333fb638 100644 --- a/gui/src/graphics/widgets/material_widget.cpp +++ b/gui/src/graphics/widgets/material_widget.cpp @@ -54,6 +54,7 @@ TransferFuncWidget::TransferFuncWidget(std::shared_ptr material) : Widget("Material " + std::to_string(material->id())), material_(std::move(material)), alpha_{{0.f, 0.f}, {1.f, 1.f}}, + dragged_point_(alpha_.end()), max_num_points_(10) { material_->am_.set(alpha_); id_ = "##MAT" + std::to_string(material_->id()); @@ -125,12 +126,6 @@ void TransferFuncWidget::renderLevelsControl() { } void TransferFuncWidget::renderAlphaEditor() { - const ImColor frame_color_ {180, 180, 180, 255}; - const ImColor point_color_ {180, 180, 90, 255}; - const ImColor line_color_ {180, 180, 120, 255}; - const float line_width_ = 2.f; - const ImColor highlight_color_ {255, 0, 0, 255}; - if (ImGui::GetCurrentWindow()->SkipItems) return; ImGui::Text("Alphamap"); @@ -144,36 +139,51 @@ void TransferFuncWidget::renderAlphaEditor() { ImDrawList *draw_list = ImGui::GetWindowDrawList(); draw_list->AddRect(canvas_pos, {canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y}, frame_color_); + float radius_p = std::max(4.f / canvas_size.x, 0.008f); + float radius_s = 2 * radius_p; + bool alpha_changed = false; + + auto hovered = alpha_.end(); + auto m_pos = G.IO.MousePos; float m_pos_x = static_cast(m_pos.x - canvas_pos.x) / canvas_size.x; float m_pos_y = 1.f - static_cast(m_pos.y - canvas_pos.y) / canvas_size.y; - bool is_hovered = m_pos_x >= 0.f && m_pos_x <= 1.f && m_pos_y >= 0.f && m_pos_y <= 1.f; - - float point_r = std::max(4.f / canvas_size.x, 0.008f); - float select_r = 2 * point_r; - auto selected = alpha_.end(); - bool alpha_changed = false; - if (is_hovered) { + if (m_pos_x >= 0.f && m_pos_x <= 1.f && m_pos_y >= 0.f && m_pos_y <= 1.f) { auto it = alpha_.upper_bound(m_pos_x); auto prev_it = std::prev(it); - if (it->first - m_pos_x < select_r && std::abs(it->second - m_pos_x) < select_r) { - selected = it; - } else if (m_pos_x - prev_it->first < select_r && std::abs(prev_it->second - m_pos_y) < select_r) { - selected = prev_it; + if (it->first - m_pos_x < radius_s && std::abs(it->second - m_pos_x) < radius_s) { + hovered = it; + } else if (m_pos_x - prev_it->first < radius_s && std::abs(prev_it->second - m_pos_y) < radius_s) { + hovered = prev_it; + } + + bool mouse_down = ImGui::IsMouseDown(0); + // The first point is not allowed to be dragged since alpha must be 0 if the density is 0. + if (mouse_down && !dragging_ && hovered != alpha_.end() && hovered != alpha_.begin()) { + dragging_ = true; + dragged_point_ = hovered; + } else if (dragging_ && !mouse_down) { + dragging_ = false; + dragged_point_ = alpha_.end(); + } + + if (dragging_ && ImGui::IsMouseDragging(0)) { + dragged_point_->second = m_pos_y; + alpha_changed = true; } - // select and press D to delete a point + // select and press x to delete a point // cannot delete the first and last points ImGui::SetNextFrameWantCaptureKeyboard(true); - if (selected != alpha_.end() && selected != alpha_.begin() && selected != std::prev(alpha_.end()) - && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_D))) { - alpha_.erase(selected); - selected = alpha_.end(); + if (hovered != alpha_.end() && hovered != alpha_.begin() && hovered != std::prev(alpha_.end()) + && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_X))) { + alpha_.erase(hovered); + hovered = alpha_.end(); alpha_changed = true; } // ctrl + left mouse click to add a new point - if (selected == alpha_.end() && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { + if (hovered == alpha_.end() && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { if (G.IO.KeyCtrl) { if (alpha_.size() > max_num_points_) { log::warn("Maximum number of points reached!"); @@ -198,12 +208,13 @@ void TransferFuncWidget::renderAlphaEditor() { draw_list->AddPolyline(points.data(), (int)points.size(), line_color_, false, line_width_); for (auto& point : points) { - draw_list->AddCircleFilled(point, point_r * scale.x, point_color_); + draw_list->AddCircleFilled(point, radius_p * scale.x, point_color_); } - if (selected != alpha_.end()) { - const ImVec2 pos = { selected->first * scale.x + offset.x, selected->second * scale.y + offset.y }; - draw_list->AddCircle(pos, select_r * scale.x, highlight_color_); + auto highlighted = dragging_? dragged_point_ : hovered; + if (highlighted != alpha_.end()) { + const ImVec2 pos = { highlighted->first * scale.x + offset.x, highlighted->second * scale.y + offset.y }; + draw_list->AddCircle(pos, radius_s * scale.x, highlight_color_); } if (alpha_changed) material_->am_.set(alpha_);