//////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2018 Leo Tenenbaum // This file is part of GraphColoring. // // GraphColoring is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GraphColoring is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with GraphColoring. If not, see . //////////////////////////////////////////////////////////////////////////////// #include "edge.hpp" #define _USE_MATH_DEFINES #include #include #include "utils/geometry.hpp" #include "utils/errors.hpp" namespace graphcoloring { int Edge::id_counter = 0; void Edge::ResetID() { id_counter = 0; } Edge::Edge(gui::Window* window_, Vertex& from_, Vertex& to_, gui::Color color_, const gui::Position& viewport_position_, bool directed_) : id(id_counter++), from(from_), to(to_), window(window_), viewport_position(viewport_position_) { color = color_; directed = directed_; color_menu = nullptr; mousedown_callback_id = window->SetMousedownCallback([this] (gui::Window*, int x, int y) { MouseCallback(x, y); }); x_keyup_callback_id = window->SetKeyupCallback([this] (gui::Window*) { if (hovering && !is_delete_protected && delete_callback && !is_locked) delete_callback(); }, GDK_KEY_x); } Edge::~Edge() { window->RemoveMousedownCallback(mousedown_callback_id); window->RemoveKeyupCallback(x_keyup_callback_id, GDK_KEY_x); } int Edge::OtherEndpoint(int vertex_id) const { if (from.id == vertex_id) return to.id; if (to.id == vertex_id) return from.id; utils::errors::Die("No other endpoint."); return -1; } void Edge::Lock() { is_locked = true; } void Edge::Unlock() { is_locked = false; } bool Edge::IsHovering() const { return hovering; } bool Edge::IsAdjacentTo(const Edge& edge) const { return edge.HasEndpoint(from.id) || edge.HasEndpoint(to.id); } void Edge::SetDeleteCallback(std::function delete_callback_) { delete_callback = delete_callback_; } gui::Color Edge::Color() const { return color; } bool Edge::ChangeColor(gui::Color new_color) { if (is_color_protected) return false; color = new_color; return true; } bool Edge::HasEndpoints(int id1, int id2) const { if (from.id == id1 && to.id == id2) return true; return !directed && from.id == id2 && to.id == id1; } bool Edge::HasEndpoint(int v_id) const { return from.id == v_id || to.id == v_id; } void Edge::Render(bool is_in_path) { int dist = utils::geometry::PointToLineSegmentDistance( window->GetMouseX(), window->GetMouseY(), from.RenderX(), from.RenderY(), to.RenderX(), to.RenderY(), EDGE_CLICK_TOLERANCE); hovering = dist < EDGE_CLICK_TOLERANCE && dist != -1; int from_x = from.RenderX(); int from_y = from.RenderY(); int to_x = to.RenderX(); int to_y = to.RenderY(); double theta1 = utils::geometry::LineAngle(from_x, from_y, to_x, to_y); double theta2 = utils::geometry::LineAngle(to_x, to_y, from_x, from_y); int x1 = from_x + Vertex::VERTEX_RADIUS * std::cos(theta1); int y1 = from_y + Vertex::VERTEX_RADIUS * std::sin(theta1); int x2 = to_x + Vertex::VERTEX_RADIUS * std::cos(theta2); int y2 = to_y + Vertex::VERTEX_RADIUS * std::sin(theta2); window->SetDrawColor(is_in_path ? gui::colors::WHITE : color); window->DrawLine(x1, y1, x2, y2); if (directed) { double theta3 = theta2 - M_PI / 4; double theta4 = theta2 + M_PI / 4; int x3 = x2 + ARROW_SIZE * std::cos(theta3); int y3 = y2 + ARROW_SIZE * std::sin(theta3); int x4 = x2 + ARROW_SIZE * std::cos(theta4); int y4 = y2 + ARROW_SIZE * std::sin(theta4); window->DrawLine(x2, y2, x3, y3); window->DrawLine(x2, y2, x4, y4); } } void Edge::RenderColorMenu() { if (color_menu != nullptr) color_menu->Render(); } void Edge::MouseCallback(int mouse_x, int mouse_y) { if (!hovering || color_menu != nullptr || is_color_protected || is_locked) return; std::function callback = [this] (gui::Color color) { assert(ChangeColor(color)); color_menu = nullptr; }; color_menu = std::make_unique(window, mouse_x+viewport_position.X(), mouse_y+viewport_position.Y(), viewport_position, callback); std::function close_callback = [this] () { color_menu = nullptr; }; color_menu->SetCloseCallback(close_callback); } } // namespace graphcoloring