83 lines
2.8 KiB
C++
83 lines
2.8 KiB
C++
/*
|
|
* SPDX-License-Identifier: LGPL-2.0-or-later
|
|
*
|
|
* RadialMenu — a frameless, multi-level radial (pie) menu widget.
|
|
*
|
|
* Shows the current ring of a RadialModel centred on a screen point. Two
|
|
* interaction modes are supported from a single widget:
|
|
* - Drag gesture: opened with a mouse button held (the RMB gesture), the user
|
|
* drags toward a slice and releases to select; a release that never left the
|
|
* central dead zone instead switches to click mode (the menu stays open).
|
|
* - Click mode: discrete hover + click. A click on a slice selects, a click
|
|
* outside the ring cancels, the central hub goes back one level or cancels.
|
|
* Esc ascends one level, or cancels at the root.
|
|
*/
|
|
#ifndef DEFT_RADIALMENU_H
|
|
#define DEFT_RADIALMENU_H
|
|
|
|
#include "radialmodel.h"
|
|
|
|
#include <QWidget>
|
|
|
|
#include <memory>
|
|
|
|
namespace deft
|
|
{
|
|
|
|
class RadialMenu : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
explicit RadialMenu(QWidget *parent = nullptr);
|
|
~RadialMenu() override;
|
|
|
|
/*!
|
|
* Show the menu for \a root, centred on the global point \a globalCenter.
|
|
* Any previously shown tree is replaced and navigation resets to the root.
|
|
*/
|
|
void popup(const RadialNode &root, const QPoint &globalCenter);
|
|
|
|
/*!
|
|
* Drive the menu from an external gesture (the plugin's event filter), using
|
|
* global coordinates. Needed because the mouse-button press that opens the
|
|
* menu leaves an implicit grab on the editor view, so live move/release
|
|
* events are delivered there, not to this popup.
|
|
*/
|
|
void driveHoverGlobal(const QPoint &global);
|
|
void driveReleaseGlobal(const QPoint &global);
|
|
|
|
Q_SIGNALS:
|
|
void activatedId(const QString &id);
|
|
void cancelled();
|
|
|
|
protected:
|
|
void paintEvent(QPaintEvent *event) override;
|
|
void mousePressEvent(QMouseEvent *event) override;
|
|
void mouseMoveEvent(QMouseEvent *event) override;
|
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
|
void keyPressEvent(QKeyEvent *event) override;
|
|
|
|
private:
|
|
RadialLayout currentLayout() const;
|
|
// allowFarFlick: when true, a point beyond the outer radius still selects
|
|
// the slice in that direction (confident drag-flick). When false, such a
|
|
// point is treated as "outside" and cancels/ascends (discrete click mode).
|
|
void handleActivationAt(const QPointF &localPos, bool allowFarFlick);
|
|
void finishActivated(const QString &id);
|
|
void finishCancelled();
|
|
|
|
std::unique_ptr<RadialModel> m_model;
|
|
QPointF m_center; // local widget coordinates of the ring centre
|
|
int m_hoverSlice = RadialModel::InvalidSlice;
|
|
bool m_armed = false; // opened with a button held => drag candidate
|
|
bool m_externalDrive = false; // gesture driven by the plugin event filter
|
|
|
|
double m_innerRadius = 36.0;
|
|
double m_outerRadius = 130.0;
|
|
};
|
|
|
|
} // namespace deft
|
|
|
|
#endif
|