diff --git a/src/lib/core/view/Window.cpp b/src/lib/core/view/Window.cpp index 5bcc1fd66a..845f5aed7a 100644 --- a/src/lib/core/view/Window.cpp +++ b/src/lib/core/view/Window.cpp @@ -468,6 +468,7 @@ void View::resizeEvent(QResizeEvent* e) QMainWindow::resizeEvent(e); sizeChanged(e->size()); } + bool score::View::event(QEvent* event) { if (event->type() == QEvent::StatusTip) @@ -484,7 +485,7 @@ bool score::View::event(QEvent* event) tip.push_front(""); tip.push_back(""); } - tip.replace(QChar('\n'), "
"); + tip.replace(QChar('\n'), "
"); m_status->setText(tip); } else if (event->type() == QEvent::ToolTip) diff --git a/src/lib/score/graphics/GraphicsItem.hpp b/src/lib/score/graphics/GraphicsItem.hpp index 0c30a0b9c7..aa0371bfec 100644 --- a/src/lib/score/graphics/GraphicsItem.hpp +++ b/src/lib/score/graphics/GraphicsItem.hpp @@ -31,15 +31,16 @@ QGraphicsView* getView(const QPainter& painter); SCORE_LIB_BASE_EXPORT QImage newImage(double logical_w, double logical_h); + template struct graphics_item_ptr { T* impl{}; graphics_item_ptr() = default; graphics_item_ptr(const graphics_item_ptr&) = default; - graphics_item_ptr(graphics_item_ptr&&) = default; + graphics_item_ptr(graphics_item_ptr&&) noexcept = default; graphics_item_ptr& operator=(const graphics_item_ptr&) = default; - graphics_item_ptr& operator=(graphics_item_ptr&&) = default; + graphics_item_ptr& operator=(graphics_item_ptr&&) noexcept = default; graphics_item_ptr(T* p) : impl{p} diff --git a/src/plugins/score-lib-process/Effect/EffectLayout.hpp b/src/plugins/score-lib-process/Effect/EffectLayout.hpp index 8ab76bd1c0..7ab659364d 100644 --- a/src/plugins/score-lib-process/Effect/EffectLayout.hpp +++ b/src/plugins/score-lib-process/Effect/EffectLayout.hpp @@ -142,6 +142,7 @@ auto createControl( QPointF pos = Process::currentWigetPos(i, setup.getControlSize); item->setPos(pos); item->setRect(itemRect); + item->setToolTip(QString("%1\n%2").arg(port.name(), port.description())); return Controls{item, portItem, widg, lab, itemRect}; } @@ -153,6 +154,7 @@ auto createControl( lab->setPos(20., 2); item->setPos(pos); item->setRect(itemRect); + item->setToolTip(QString("%1\n%2").arg(port.name(), port.description())); return Controls{item, portItem, nullptr, lab, itemRect}; } diff --git a/src/plugins/score-lib-process/Process/Dataflow/CableItem.cpp b/src/plugins/score-lib-process/Process/Dataflow/CableItem.cpp index 5bb6dae7d6..60afb6bcba 100644 --- a/src/plugins/score-lib-process/Process/Dataflow/CableItem.cpp +++ b/src/plugins/score-lib-process/Process/Dataflow/CableItem.cpp @@ -41,6 +41,7 @@ CableItem::CableItem( auto& plug = ctx.dataflow; this->setCursor(Qt::CrossCursor); this->setFlag(QGraphicsItem::ItemClipsToShape); + this->setToolTip(tr("Cable\n")); SCORE_ASSERT(canCreateCable(c, plug)); diff --git a/src/plugins/score-lib-process/Process/Dataflow/NodeItem.cpp b/src/plugins/score-lib-process/Process/Dataflow/NodeItem.cpp index 70d03a540c..3467c50269 100644 --- a/src/plugins/score-lib-process/Process/Dataflow/NodeItem.cpp +++ b/src/plugins/score-lib-process/Process/Dataflow/NodeItem.cpp @@ -319,6 +319,17 @@ void NodeItem::createContentItem() m_contentSize = m_fx->boundingRect().size(); } + if(m_fx->toolTip().isEmpty()) + { + auto& p = this->m_context.app.interfaces(); + const auto& desc = p.get(m_model.concreteKey())->descriptor({}); + this->setToolTip(QString("%1\n%2").arg(desc.prettyName, desc.description)); + } + else + { + this->setToolTip(m_fx->toolTip()); + } + // Positions / size m_fx->setPos({0, 0}); diff --git a/src/plugins/score-plugin-curve/Curve/Segment/CurveSegmentView.cpp b/src/plugins/score-plugin-curve/Curve/Segment/CurveSegmentView.cpp index 4a4259c8bd..830a2cce08 100644 --- a/src/plugins/score-plugin-curve/Curve/Segment/CurveSegmentView.cpp +++ b/src/plugins/score-plugin-curve/Curve/Segment/CurveSegmentView.cpp @@ -32,6 +32,8 @@ SegmentView::SegmentView( : QGraphicsItem{parent} , m_style{style} { + this->setToolTip(QObject::tr("Curve segment\nRight-click to change options. If the type is power, shift can be used to change its curvature.")); + this->setCacheMode(QGraphicsItem::NoCache); this->setZValue(1); this->setFlag(ItemIsFocusable, false); diff --git a/src/plugins/score-plugin-midi/Midi/MidiNoteView.cpp b/src/plugins/score-plugin-midi/Midi/MidiNoteView.cpp index 73ddb3949a..34396cce7e 100644 --- a/src/plugins/score-plugin-midi/Midi/MidiNoteView.cpp +++ b/src/plugins/score-plugin-midi/Midi/MidiNoteView.cpp @@ -19,6 +19,7 @@ NoteView::NoteView(const Note& n, Presenter& p, View* parent) , m_presenter{p} , m_action{None} { + this->setToolTip(QObject::tr("A MIDI note.")); this->setFlag(QGraphicsItem::ItemIsSelectable, true); this->setFlag(QGraphicsItem::ItemIsMovable, true); this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/CommentBlock/CommentBlockView.cpp b/src/plugins/score-plugin-scenario/Scenario/Document/CommentBlock/CommentBlockView.cpp index 47cd763f7e..04a6dbd860 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/CommentBlock/CommentBlockView.cpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/CommentBlock/CommentBlockView.cpp @@ -25,6 +25,7 @@ CommentBlockView::CommentBlockView( this->setParentItem(parent); this->setZValue(ZPos::Comment); this->setAcceptHoverEvents(true); + this->setToolTip(tr("Comment box\nPut the text you want in here by double-clicking !")); m_textItem = new score::TextItem{"", this}; diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/Event/ConditionView.cpp b/src/plugins/score-plugin-scenario/Scenario/Document/Event/ConditionView.cpp index 751ef50c80..9fced64fdf 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/Event/ConditionView.cpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/Event/ConditionView.cpp @@ -37,6 +37,7 @@ ConditionView::ConditionView(const EventModel& model, QGraphicsItem* parent) , m_model{model} { this->setCacheMode(QGraphicsItem::NoCache); + this->setToolTip(tr("Condition\nSet whether the following intervals will execute.")); setFlag(ItemStacksBehindParent, true); setCursor(Qt::CursorShape::CrossCursor); setHeight(0.); diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/Interval/FullView/AddressBarItem.cpp b/src/plugins/score-plugin-scenario/Scenario/Document/Interval/FullView/AddressBarItem.cpp index d953f351dd..7fc88c80df 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/Interval/FullView/AddressBarItem.cpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/Interval/FullView/AddressBarItem.cpp @@ -26,6 +26,7 @@ AddressBarItem::AddressBarItem( : QGraphicsItem{parent} , m_ctx{ctx} { + this->setToolTip(tr("Address bar\nClick here to travel to the specific hierarchy level")); this->setFlag(QGraphicsItem::ItemHasNoContents, true); } diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/Interval/FullView/TimeSignatureItem.hpp b/src/plugins/score-plugin-scenario/Scenario/Document/Interval/FullView/TimeSignatureItem.hpp index 80f9a6cd47..42fcaf705b 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/Interval/FullView/TimeSignatureItem.hpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/Interval/FullView/TimeSignatureItem.hpp @@ -110,6 +110,7 @@ class TimeSignatureHandle TimeSignatureHandle(const IntervalModel& itv, QGraphicsItem* parent) : QGraphicsItem{parent} { + this->setToolTip(QObject::tr("Time signature handle\nDrag to displace, double-click to change the signature.")); setFlag(ItemIsSelectable, true); } diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/Interval/IntervalView.cpp b/src/plugins/score-plugin-scenario/Scenario/Document/Interval/IntervalView.cpp index 31c190853a..53a7ece06f 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/Interval/IntervalView.cpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/Interval/IntervalView.cpp @@ -37,6 +37,7 @@ IntervalView::IntervalView(IntervalPresenter& presenter, QGraphicsItem* parent) , m_dropTarget{false} , m_state{} { + this->setToolTip(QObject::tr("Interval\nA span of time which can contain processes.")); setAcceptHoverEvents(true); setAcceptDrops(true); diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/Interval/LayerData.cpp b/src/plugins/score-plugin-scenario/Scenario/Document/Interval/LayerData.cpp index 6dddc314d2..a87068fc0c 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/Interval/LayerData.cpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/Interval/LayerData.cpp @@ -44,6 +44,12 @@ void LayerData::addView( container->setFlag(QGraphicsItem::ItemClipsChildrenToShape); container->setY(m_slotY); auto view = factory.makeLayerView(*m_model, context, container); + if(view->toolTip().isEmpty()) + { + auto& p = context.app.interfaces(); + const auto& desc = p.get(m_model->concreteKey())->descriptor({}); + view->setToolTip(QString("%1\n%2").arg(desc.prettyName, desc.description)); + } double startX = m_model->flags() & Process::ProcessFlags::HandlesLooping ? 0. diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/Interval/SlotHeader.cpp b/src/plugins/score-plugin-scenario/Scenario/Document/Interval/SlotHeader.cpp index 5469377507..c579ab6be9 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/Interval/SlotHeader.cpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/Interval/SlotHeader.cpp @@ -34,6 +34,7 @@ SlotHeader::SlotHeader( , m_width{slotView.view()->boundingRect().width()} , m_slotIndex{slotIndex} { + this->setToolTip(QObject::tr("Slot header\nDrag the \u2630 symbol to move the slot elsewhere.")); this->setCacheMode(QGraphicsItem::NoCache); this->setAcceptHoverEvents(true); this->setFlag(ItemClipsToShape); @@ -312,6 +313,7 @@ AmovibleSlotFooter::AmovibleSlotFooter( , m_fullView{ bool(qobject_cast(&m_presenter))} { + this->setToolTip(QObject::tr("Drag me to resize this slot.")); auto& skin = score::Skin::instance(); this->setCursor(skin.CursorScaleV); } diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/Interval/Temporal/Braces/LeftBrace.hpp b/src/plugins/score-plugin-scenario/Scenario/Document/Interval/Temporal/Braces/LeftBrace.hpp index e0b1d6b03e..790cd11a94 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/Interval/Temporal/Braces/LeftBrace.hpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/Interval/Temporal/Braces/LeftBrace.hpp @@ -14,6 +14,7 @@ class SCORE_PLUGIN_SCENARIO_EXPORT LeftBraceView final : public IntervalBrace LeftBraceView(const IntervalView& parentCstr, QGraphicsItem* parent) : IntervalBrace{parentCstr, parent} { + this->setToolTip(QObject::tr("Interval left brace\nDrag to change the minimal duration of an interval.")); } ~LeftBraceView() override; @@ -28,6 +29,7 @@ class SCORE_PLUGIN_SCENARIO_EXPORT RightBraceView final : public IntervalBrace : IntervalBrace{parentCstr, parent} { this->setRotation(180); + this->setToolTip(QObject::tr("Interval right brace\nDrag to change the maximal duration of an interval.")); } ~RightBraceView() override; diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioDocumentView.cpp b/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioDocumentView.cpp index 26fad1dd20..c6cf7e24b4 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioDocumentView.cpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioDocumentView.cpp @@ -424,6 +424,55 @@ void ProcessGraphicsView::dropEvent(QDropEvent* event) } } +bool ProcessGraphicsView::event(QEvent* event) +{ + switch (event->type()) + { + case QEvent::HoverEnter: + hoverEnterEvent(static_cast(event)); + return true; + case QEvent::HoverLeave: + hoverLeaveEvent(static_cast(event)); + return true; + case QEvent::HoverMove: + hoverMoveEvent(static_cast(event)); + return true; + default: + return QGraphicsView::event(event); + } +} + +void ProcessGraphicsView::hoverEnterEvent(QHoverEvent* event) +{ + +} + +void ProcessGraphicsView::hoverMoveEvent(QHoverEvent* event) +{ + const auto scenePos = this->mapToScene(event->pos()); + auto items = this->scene()->items(scenePos); + auto set_tip = [&] (const QString& t) { + QStatusTipEvent ev{t}; + auto obj = reinterpret_cast(this->m_app.mainWindow); + obj->event(&ev); + }; + for (int i = 0; i < items.size(); ++i) + { + if(const auto& tooltip = items.at(i)->toolTip(); !tooltip.isEmpty()) + { + set_tip(tooltip); + return; + } + } + + set_tip(QString{}); +} + +void ProcessGraphicsView::hoverLeaveEvent(QHoverEvent* event) +{ + +} + ScenarioDocumentView::ScenarioDocumentView( const score::DocumentContext& ctx, QObject* parent) diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioDocumentView.hpp b/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioDocumentView.hpp index 1cd92a4353..aea5c40620 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioDocumentView.hpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioDocumentView.hpp @@ -98,6 +98,12 @@ class SCORE_PLUGIN_SCENARIO_EXPORT ProcessGraphicsView final void dragMoveEvent(QDragMoveEvent* event) override; void dragLeaveEvent(QDragLeaveEvent* event) override; void dropEvent(QDropEvent* event) override; + bool event(QEvent*) override; + + void hoverEnterEvent(QHoverEvent* event); + void hoverMoveEvent(QHoverEvent* event); + void hoverLeaveEvent(QHoverEvent* event); + void checkAndRemoveCurrentDialog(QPoint pos); // void drawBackground(QPainter* painter, const QRectF& rect) override; diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioScene.cpp b/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioScene.cpp index 9c9f350759..1c0072586a 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioScene.cpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioScene.cpp @@ -11,4 +11,8 @@ ScenarioScene::ScenarioScene(QObject* parent) { setItemIndexMethod(QGraphicsScene::NoIndex); } + +void ScenarioScene::helpEvent(QGraphicsSceneHelpEvent* event) +{ +} } diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioScene.hpp b/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioScene.hpp index 4bcf37cf4b..98a94ef347 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioScene.hpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/ScenarioDocument/ScenarioScene.hpp @@ -10,5 +10,7 @@ class ScenarioScene final : public QGraphicsScene W_OBJECT(ScenarioScene) public: ScenarioScene(QObject* parent); + + void helpEvent(QGraphicsSceneHelpEvent* event) override; }; } diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/State/StateMenuOverlay.hpp b/src/plugins/score-plugin-scenario/Scenario/Document/State/StateMenuOverlay.hpp index cbfcd88409..554105df1d 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/State/StateMenuOverlay.hpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/State/StateMenuOverlay.hpp @@ -15,7 +15,7 @@ namespace Scenario class CrossOverlay : public QGraphicsItem { public: - CrossOverlay(StateView* parent) + explicit CrossOverlay(StateView* parent) : QGraphicsItem{parent} { this->setFlag(ItemStacksBehindParent, true); @@ -111,7 +111,11 @@ class CrossOverlay : public QGraphicsItem class StatePlusOverlay final : public CrossOverlay { public: - using CrossOverlay::CrossOverlay; + explicit StatePlusOverlay(StateView* parent) + : CrossOverlay{parent} + { + this->setToolTip(QObject::tr("Create an interval.\nDrag the plus to create an interval")); + } private: const score::Brush& brush() const noexcept override @@ -140,7 +144,11 @@ class StatePlusOverlay final : public CrossOverlay class StateGraphPlusOverlay final : public CrossOverlay { public: - using CrossOverlay::CrossOverlay; + explicit StateGraphPlusOverlay(StateView* parent) + : CrossOverlay{parent} + { + this->setToolTip(QObject::tr("Create a graph link.\nDrag the plus to create a graph link")); + } private: const score::Brush& brush() const noexcept override @@ -169,7 +177,11 @@ class StateGraphPlusOverlay final : public CrossOverlay class StateSequencePlusOverlay final : public CrossOverlay { public: - using CrossOverlay::CrossOverlay; + explicit StateSequencePlusOverlay(StateView* parent) + : CrossOverlay{parent} + { + this->setToolTip(QObject::tr("Create a sequence.\nDrag the plus to create a sequence.")); + } private: const score::Brush& brush() const noexcept override diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/State/StateView.cpp b/src/plugins/score-plugin-scenario/Scenario/Document/State/StateView.cpp index 6c3325ef38..235d8f27c0 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/State/StateView.cpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/State/StateView.cpp @@ -70,6 +70,7 @@ StateView::StateView(StatePresenter& pres, QGraphicsItem* parent) if (!is_hidpi()) this->setCacheMode(QGraphicsItem::CacheMode::ItemCoordinateCache); this->setParentItem(parent); + this->setToolTip(QStringLiteral("State view")); auto& skin = score::Skin::instance(); this->setCursor(skin.CursorMove); diff --git a/src/plugins/score-plugin-scenario/Scenario/Document/TimeSync/TriggerView.cpp b/src/plugins/score-plugin-scenario/Scenario/Document/TimeSync/TriggerView.cpp index 8affdf9f93..5571c23b77 100644 --- a/src/plugins/score-plugin-scenario/Scenario/Document/TimeSync/TriggerView.cpp +++ b/src/plugins/score-plugin-scenario/Scenario/Document/TimeSync/TriggerView.cpp @@ -57,6 +57,7 @@ TriggerView::TriggerView(QGraphicsItem* parent) , m_waiting{false} { auto& skin = score::Skin::instance(); + this->setToolTip(QObject::tr("Trigger\nUsed to introduce temporal interactions.")); this->setCursor(skin.CursorPointingHand); this->setCacheMode(QGraphicsItem::NoCache); this->setAcceptHoverEvents(true);