feat(udpscope): BSP pane tree with split, close and hit-testing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
c1029a25df
commit
0e5d103e73
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* @file PaneTree.h
|
||||
* @brief Binary-space-partition layout of the plot area.
|
||||
*
|
||||
* Framework-free: no ImGui, no UDPS. The geometry and the hit-testing are the
|
||||
* fiddly part of the pane UI and are unit-tested without a window.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace udpscope {
|
||||
|
||||
/** Direction a node splits its rectangle in. */
|
||||
enum class Orient { Columns, Rows };
|
||||
|
||||
/** Vertical scaling strategy for one trace. */
|
||||
enum class VMode { Auto, Range, Manual };
|
||||
|
||||
struct VScale {
|
||||
VMode mode = VMode::Auto;
|
||||
double div = 1.0; /**< Units per division, Manual only. */
|
||||
double offset = 0.0; /**< Centre value, Manual only. */
|
||||
};
|
||||
|
||||
/** One signal drawn in one pane. Signals are named, never indexed. */
|
||||
struct Assignment {
|
||||
std::string signalName;
|
||||
Color color;
|
||||
float lineWidth = 1.5f;
|
||||
VScale vs;
|
||||
};
|
||||
|
||||
/** Smallest a pane may be squeezed to, in pixels. */
|
||||
constexpr double kMinPaneSize = 80.0;
|
||||
|
||||
/** Thickness of the splitter drag zone and of the inset handles, in pixels. */
|
||||
constexpr double kSplitterGrab = 6.0;
|
||||
constexpr double kHandleSize = 18.0;
|
||||
|
||||
/** What the pointer is over inside a pane. */
|
||||
enum class Handle { None, Left, Right, Top, Bottom, Close };
|
||||
|
||||
struct PaneNode {
|
||||
bool leaf = true;
|
||||
|
||||
/* leaf only */
|
||||
std::vector<Assignment> signals;
|
||||
bool profilePane = false; /**< Holds vector signals, not time series. */
|
||||
|
||||
/* split only */
|
||||
Orient orient = Orient::Columns;
|
||||
double ratio = 0.5; /**< First child's share of the parent. */
|
||||
std::unique_ptr<PaneNode> a, b;
|
||||
};
|
||||
|
||||
class PaneTree {
|
||||
public:
|
||||
struct Placed { PaneNode* leaf; Rect rect; };
|
||||
struct Splitter { PaneNode* node; Rect rect; Orient orient; };
|
||||
|
||||
PaneTree();
|
||||
|
||||
PaneNode* root() { return root_.get(); }
|
||||
const PaneNode* root() const { return root_.get(); }
|
||||
|
||||
/** Replaces the whole tree, e.g. when loading a session. */
|
||||
void setRoot(std::unique_ptr<PaneNode> node);
|
||||
|
||||
/**
|
||||
* @brief Walk the tree, producing every leaf's rectangle and every split's
|
||||
* drag zone.
|
||||
*/
|
||||
void layout(const Rect& area,
|
||||
std::vector<Placed>& leaves,
|
||||
std::vector<Splitter>& splitters) const;
|
||||
|
||||
/** Turn a leaf into a split; the original content stays in the first child. */
|
||||
void splitLeaf(PaneNode* leaf, Orient orient);
|
||||
|
||||
/** Replace the leaf's parent with its sibling. No-op on the last leaf. */
|
||||
void closeLeaf(PaneNode* leaf);
|
||||
|
||||
void setRatio(PaneNode* split, double ratio);
|
||||
|
||||
size_t leafCount() const;
|
||||
|
||||
/** @return the splitter under the point, or nullptr. */
|
||||
const Splitter* hitTestSplitter(const std::vector<Splitter>& splitters,
|
||||
double px, double py) const;
|
||||
|
||||
/**
|
||||
* @brief Which inset handle of @p pane the point is over.
|
||||
*
|
||||
* Handles sit inside the pane so they never overlap the splitter drag zone,
|
||||
* and every pane has all four regardless of whether it touches a window
|
||||
* edge — a pane in the middle of a 3x3 touches none.
|
||||
*/
|
||||
static Handle hitTestHandle(const Rect& pane, double px, double py);
|
||||
|
||||
private:
|
||||
static void layoutNode(PaneNode* node, const Rect& r,
|
||||
std::vector<Placed>& leaves,
|
||||
std::vector<Splitter>& splitters);
|
||||
static size_t countLeaves(const PaneNode* node);
|
||||
static PaneNode* findParent(PaneNode* node, const PaneNode* child);
|
||||
static double clampRatio(double ratio, double extent);
|
||||
|
||||
std::unique_ptr<PaneNode> root_;
|
||||
};
|
||||
|
||||
} /* namespace udpscope */
|
||||
Reference in New Issue
Block a user