kate-deft/src/radial/radialmenu.h

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