1
0
Fork 0
forked from hanez/xtc
xtc/src/gui/graph_widget.hpp

201 lines
7.1 KiB
C++
Raw Normal View History

#ifndef XTC_GRAPH_WIDGET_HPP
#define XTC_GRAPH_WIDGET_HPP
#include <FL/Fl_Widget.H>
#include <array>
#include "xtc/xtc_engine.h"
2026-10-27 01:37:21 +01:00
class Fl_Box;
/* GUI positions/selection only. Domain snapshots and edits stay in the C API. */
class GraphWidget : public Fl_Widget {
2026-10-27 01:37:21 +01:00
public:
/**
* @brief Applies a graph edit using an opaque context and optional added-node output.
*
* The handler receives the context, edit command, and output identifier in that order.
* @return XTC_OK on success, or an edit error.
*/
using EditHandler = xtc_result (*)(void *, const xtc_graph_edit &, size_t *);
/**
* @brief Constructs a graph widget bound to a graph and an edit callback.
*
* The widget stores the graph, handler, context, and feedback box without
* taking ownership of any of them.
*
* @param x Left coordinate in FLTK screen space.
* @param y Top coordinate in FLTK screen space.
* @param width Widget width in pixels.
* @param height Widget height in pixels.
* @param graph Borrowed graph snapshot; must outlive the widget's use of it.
* @param handler Edit callback invoked for every graph mutation.
* @param context Opaque pointer passed back to @p handler; may be NULL.
* @param feedback Borrowed label used to report edit results; must outlive the widget.
*/
2026-10-27 01:37:21 +01:00
GraphWidget(int x, int y, int width, int height, const xtc_graph *graph, EditHandler handler, void *context,
Fl_Box *feedback);
/**
* @brief Clears cached node positions, selection, and interaction state.
*
* Does not change the borrowed graph pointer or the graph's own layout.
*/
2026-10-27 01:37:21 +01:00
void reset_layout()
{
count_ = 0;
selected_node_ = SIZE_MAX;
edge_selected_ = dragging_ = wiring_ = false;
}
/**
* @brief Replaces the graph snapshot and rebuilds cached node positions.
*
* Existing positions are preserved by node ID; new nodes are placed on a grid
* that avoids overlapping previously known nodes. Selections that no longer
* exist are cleared. The widget does not take ownership of @p graph.
*
* @param graph Borrowed graph that must outlive the widget's use of it.
*/
void set_graph(const xtc_graph *graph);
2026-10-27 01:37:21 +01:00
/**
* @brief Returns the graph snapshot currently displayed.
*
* The returned pointer is borrowed and valid for GUI thread use only.
*
* @return Borrowed graph pointer; may be NULL when none was supplied.
*/
2026-10-27 01:37:21 +01:00
const xtc_graph *graph() const
{
return graph_;
} // Borrowed, GUI thread only.
/**
* @brief Requests creation of a node through the edit handler.
*
* Selects the new node when the edit succeeds.
*
* @param type Kind of node to add.
* @return Result reported by the edit handler.
*/
xtc_result add_node(xtc_node_type type);
/**
* @brief Requests a connection between two ports through the edit handler.
*
* @param connection Connection describing the source and destination node/port pairs.
* @return Result reported by the edit handler.
*/
xtc_result connect_ports(const xtc_connection_info &connection);
/**
* @brief Requests removal of the selected wire or node through the edit handler.
*
* @return Result reported by the edit handler, or XTC_ERR_INVALID_STATE when
* nothing is selected.
*/
xtc_result delete_selected();
/**
* @brief Selects a node by ID and clears any wire selection.
*
* @param id Stable node identifier.
* @return True when the node has a cached position, false otherwise.
*/
bool select_node(size_t id);
/**
* @brief Selects a wire between two nodes and clears the node selection.
*
* @param source Source node identifier.
* @param destination Destination node identifier.
* @return True when a matching connection exists, false otherwise.
*/
bool select_connection(size_t source, size_t destination);
/**
* @brief Moves a node within the widget, clamped to the visible bounds.
*
* @param id Stable node identifier.
* @param left Requested left position in widget-local coordinates.
* @param top Requested top position in widget-local coordinates.
* @return True when the node has a cached position, false otherwise.
*/
bool move_node(size_t id, int left, int top);
/**
* @brief Looks up the cached position of a node.
*
* @param id Stable node identifier.
* @param left Receives the left position in widget-local coordinates.
* @param top Receives the top position in widget-local coordinates.
* @return True when the node has a cached position, false otherwise.
*/
bool node_position(size_t id, int &left, int &top) const;
/**
* @brief Handles mouse and keyboard events for selection, dragging, and wiring.
*
* @param event FLTK event code.
* @return 1 when the event was consumed, 0 for unsupported left-button input,
* or the result of Fl_Widget::handle() for unhandled events.
*/
int handle(int event) override;
2026-10-27 01:37:21 +01:00
protected:
/**
* @brief Draws the background, wires, nodes, ports, and any pending wire.
*/
void draw() override;
2026-10-27 01:37:21 +01:00
private:
struct Position {
size_t id = SIZE_MAX;
int left = 0, top = 0;
};
std::array<Position, 256> positions_{};
size_t count_ = 0U;
const xtc_graph *graph_;
EditHandler handler_;
void *context_;
Fl_Box *feedback_;
size_t selected_node_ = SIZE_MAX;
xtc_connection_info selected_edge_{};
bool edge_selected_ = false;
bool dragging_ = false, wiring_ = false;
size_t wire_node_ = SIZE_MAX, wire_port_ = 0U;
int drag_x_ = 0, drag_y_ = 0, mouse_x_ = 0, mouse_y_ = 0;
/**
* @brief Shows the outcome of an edit in the feedback label.
*
* @param result Result returned by the edit handler.
* @param success Text shown when @p result is XTC_OK; must be valid then and is ignored otherwise.
*/
void feedback(xtc_result result, const char *success);
/**
* @brief Finds the port nearest to a widget-local point.
*
* Searches nodes in reverse draw order and accepts points within 9 pixels of a
* port center.
*
* @param left Widget-local x coordinate to test.
* @param top Widget-local y coordinate to test.
* @param node Receives the matching node ID when true is returned.
* @param port Receives the matching port index (0 input, 1 output) when true is returned.
* @return True when a port is within range, false otherwise.
*/
bool hit_port(int left, int top, size_t &node, size_t &port) const;
/**
* @brief Computes the widget-local center of a node port.
*
* @param id Stable node identifier.
* @param port Port index; 0 selects the input and 1 the output.
* @param left Receives the port center x coordinate.
* @param top Receives the port center y coordinate.
* @return True when the node and port exist, false otherwise.
*/
bool port_position(size_t id, size_t port, int &left, int &top) const;
};
#endif