Skip to content

Commit

Permalink
add PlayButton: drop previewing HotcueButton onto it to latch play
Browse files Browse the repository at this point in the history
  • Loading branch information
ronso0 committed Jan 30, 2025
1 parent 1823775 commit af3dafa
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 10 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1554,6 +1554,7 @@ add_library(
src/widget/wnumberrate.cpp
src/widget/woverview.cpp
src/widget/wpixmapstore.cpp
src/widget/wplaybutton.cpp
src/widget/wpushbutton.cpp
src/widget/wraterange.cpp
src/widget/wstarratingaction.cpp
Expand Down
59 changes: 59 additions & 0 deletions res/skins/LateNight/controls/button_play_2state_right_display.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<!--
Description:
A button that has click or display controls.
Left-click control is one of the play controls.
HotcueButtons of the same player (engine, not necessarily same player in skin)
can be dropped onto it in order to latch play when previewing from hotcue.
Make sure to use one of the 'play' ToolTipIDs so the dnd behavior is discoverable.
Variables:
ObjectName : object name
ToolTipID : standard Tooltip from mixxx db
see: https://github.com/mixxxdj/mixxx/blob/main/src/skin/legacy/tooltips.cpp
Group : BasePlayer group
Size : button size
state_X_text : label text for state X
state_X_pressed : background graphic for pressed state X
state_X_unpressed : background graphic for unpressed state X
Align : alignment of text
ConfigKey : left-click control
ConfigKeyRight : right-click control
ConfigKeyDisp : display control
-->
<Template>
<PlayButton>
<TooltipId><Variable name="TooltipId"/></TooltipId>
<ObjectName><Variable name="ObjectName"/></ObjectName>
<Size><Variable name="Size"/></Size>
<NumberStates>2</NumberStates>
<RightClickIsPushButton>true</RightClickIsPushButton>
<Group><Variable name="Group"/></Group>
<State>
<Number>0</Number>
<Text><Variable name="state_0_text"/></Text>
<Alignment><Variable name="Align"/></Alignment>
<Unpressed scalemode="STRETCH">skins:LateNight/<Variable name="BtnScheme"/>/buttons/btn_<Variable name="BtnType"/>_<Variable name="BtnSize"/>.svg</Unpressed>
<Pressed scalemode="STRETCH">skins:LateNight/<Variable name="BtnScheme"/>/buttons/btn_<Variable name="BtnType"/>_<Variable name="BtnSize"/>_active.svg</Pressed>
</State>
<State>
<Number>1</Number>
<Text><Variable name="state_1_text"/></Text>
<Alignment><Variable name="Align"/></Alignment>
<Unpressed scalemode="STRETCH">skins:LateNight/<Variable name="BtnScheme"/>/buttons/btn_<Variable name="BtnType"/>_<Variable name="BtnSize"/>_active.svg</Unpressed>
<Pressed scalemode="STRETCH">skins:LateNight/<Variable name="BtnScheme"/>/buttons/btn_<Variable name="BtnType"/>_<Variable name="BtnSize"/>_active.svg</Pressed>
</State>
<Connection>
<ConfigKey><Variable name="ConfigKey"/></ConfigKey>
<ButtonState>LeftButton</ButtonState>
</Connection>
<Connection>
<ConfigKey><Variable name="ConfigKeyRight"/></ConfigKey>
<ButtonState>RightButton</ButtonState>
</Connection>
<Connection>
<ConfigKey><Variable name="ConfigKeyDisp"/></ConfigKey>
<ConnectValueFromWidget>false</ConnectValueFromWidget>
</Connection>
</PlayButton>
</Template>
2 changes: 1 addition & 1 deletion res/skins/LateNight/decks/row_5_transportLoopJump.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
<Layout>stacked</Layout>
<Size>68f,26f</Size>
<Children>
<Template src="skins:LateNight/controls/button_2state_right_display.xml">
<Template src="skins:LateNight/controls/button_play_2state_right_display.xml">
<SetVariable name="TooltipId">play_cue_set</SetVariable>
<SetVariable name="ObjectName">PlayDeck</SetVariable>
<SetVariable name="Size">68f,26f</SetVariable>
Expand Down
2 changes: 1 addition & 1 deletion res/skins/LateNight/samplers/sampler.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
<Layout>stacked</Layout>
<SizePolicy>max,max</SizePolicy>
<Children>
<Template src="skins:LateNight/controls/button_2state_right_display.xml">
<Template src="skins:LateNight/controls/button_play_2state_right_display.xml">
<SetVariable name="TooltipId">cue_gotoandplay_cue_default</SetVariable>
<SetVariable name="ObjectName">PlaySampler</SetVariable>
<SetVariable name="Size">34f,34f</SetVariable>
Expand Down
15 changes: 15 additions & 0 deletions src/skin/legacy/legacyskinparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
#include "widget/wnumberrate.h"
#include "widget/woverview.h"
#include "widget/wpixmapstore.h"
#include "widget/wplaybutton.h"
#include "widget/wpushbutton.h"
#include "widget/wraterange.h"
#include "widget/wrecordingduration.h"
Expand Down Expand Up @@ -536,6 +537,8 @@ QList<QWidget*> LegacySkinParser::parseNode(const QDomElement& node) {
result = wrapWidget(parseStandardWidget<WSliderComposed>(node));
} else if (nodeName == "PushButton") {
result = wrapWidget(parseStandardWidget<WPushButton>(node));
} else if (nodeName == "PlayButton") {
result = wrapWidget(parsePlayButton(node));
} else if (nodeName == "EffectPushButton") {
result = wrapWidget(parseEffectPushButton(node));
} else if (nodeName == "HotcueButton") {
Expand Down Expand Up @@ -1942,6 +1945,18 @@ QWidget* LegacySkinParser::parseHotcueButton(const QDomElement& element) {
return pWidget;
}

QWidget* LegacySkinParser::parsePlayButton(const QDomElement& element) {
QString group = lookupNodeGroup(element);
WPlayButton* pWidget = new WPlayButton(m_pParent, group);
commonWidgetSetup(element, pWidget);
pWidget->setup(element, *m_pContext);
pWidget->installEventFilter(m_pKeyboard);
pWidget->installEventFilter(
m_pControllerManager->getControllerLearningEventFilter());
pWidget->Init();
return pWidget;
}

QWidget* LegacySkinParser::parseEffectChainName(const QDomElement& node) {
WEffectChain* pEffectChain = new WEffectChain(m_pParent, m_pEffectsManager);
setupLabelWidget(node, pEffectChain);
Expand Down
1 change: 1 addition & 0 deletions src/skin/legacy/legacyskinparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class LegacySkinParser : public QObject, public SkinParser {
QWidget* parseEffectPushButton(const QDomElement& node);
QWidget* parseEffectSelector(const QDomElement& node);
QWidget* parseHotcueButton(const QDomElement& node);
QWidget* parsePlayButton(const QDomElement& node);

// Legacy pre-1.12.0 skin support.
QWidget* parseBackground(const QDomElement& node, QWidget* pOuterWidget, QWidget* pInnerWidget);
Expand Down
23 changes: 18 additions & 5 deletions src/skin/legacy/tooltips.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,8 +534,13 @@ void Tooltips::addStandardTooltips() {
// Currently used for samplers
add("play_start")
<< tr("Play/Pause")
<< QString("%1: %2").arg(leftClick, tr("Starts playing from the beginning of the track."))
<< QString("%1: %2").arg(rightClick, tr("Jumps to the beginning of the track and stops."));
<< QString("%1: %2").arg(leftClick,
tr("Starts playing from the beginning of the track."))
<< QString("%1: %2").arg(rightClick,
tr("Jumps to the beginning of the track and stops."))
<< " " // add linebreak, '\n' would result in two linebreaks
<< tr("Drag a Hotcue button here to continue playing after "
"releasing the Hotcue.");

QString whilePlaying = tr("(while playing)");
QString whileStopped = tr("(while stopped)");
Expand All @@ -552,7 +557,10 @@ void Tooltips::addStandardTooltips() {
<< tr("Play/Pause")
<< QString("%1: %2").arg(leftClick, tr("Plays or pauses the track."))
<< QString("%1 %2: %3").arg(leftClick, whilePreviewing, latchingPlay)
<< QString("%1: %2").arg(rightClick, cueSet);
<< QString("%1: %2").arg(rightClick, cueSet)
<< " " // add linebreak, '\n' would result in two linebreaks
<< tr("Drag a Hotcue button here to continue playing after "
"releasing the Hotcue.");

// Currently used for minimal decks
add("play_cue_default")
Expand All @@ -561,7 +569,10 @@ void Tooltips::addStandardTooltips() {
<< QString("%1 %2: %3").arg(rightClick, whilePlaying, cueWhilePlaying)
<< QString("%1 %2: %3").arg(rightClick, whileStopped, cueWhileStopped)
<< cueHint
<< quantizeSnap;
<< quantizeSnap
<< " " // add linebreak, '\n' would result in two linebreaks
<< tr("Drag a Hotcue button here to continue playing after "
"releasing the Hotcue.");
add("cue_default_cue_gotoandstop")
<< tr("Cue")
<< QString("%1 %2: %3").arg(leftClick, whilePlaying, cueWhilePlaying)
Expand Down Expand Up @@ -703,8 +714,10 @@ void Tooltips::addStandardTooltips() {
<< tr("Drag this button onto another Hotcue button to move it "
"there (change its index). If the other hotcue is set, "
"the two are swapped.")
<< tr("Drag this button onto a Play button while previewing "
"to continue playback after release.")
<< tr("Dragging with Shift key pressed will not start previewing "
"the hotcue");
"the hotcue.");

// Status displays and toggle buttons
add("toggle_recording")
Expand Down
2 changes: 0 additions & 2 deletions src/widget/hotcuedrag.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
#include <widget/hotcuedrag.h>

#include <QDragEnterEvent>
#include <QMimeData>
#include <QMouseEvent>
#include <QString>

#include "mixer/playerinfo.h"
#include "track/track.h"
Expand Down
2 changes: 1 addition & 1 deletion src/widget/hotcuedrag.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ template<typename T>
bool isValidHotcueDragOrDropEvent(T* pEvent,
QObject* pTarget,
const QString& group,
int ignoreHotcueIndex,
int ignoreHotcueIndex = Cue::kNoHotCue,
HotcueDragInfo* pDragData = nullptr);

} // namespace hotcuedrag
Expand Down
46 changes: 46 additions & 0 deletions src/widget/wplaybutton.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "widget/wplaybutton.h"

#include <QMouseEvent>

#include "control/controlobject.h"
#include "moc_wplaybutton.cpp"
#include "widget/hotcuedrag.h"

using namespace mixxx::hotcuedrag;

WPlayButton::WPlayButton(QWidget* pParent, const QString& group)
: WPushButton(pParent),
m_group(group) {
setAcceptDrops(true);
}

void WPlayButton::dragEnterEvent(QDragEnterEvent* pEvent) {
if (isValidHotcueDragOrDropEvent<QDragEnterEvent>(
pEvent,
this,
m_group)) {
pEvent->acceptProposedAction();
} else {
pEvent->ignore();
}
}

void WPlayButton::dropEvent(QDropEvent* pEvent) {
// Enable 'play' if we drop a hotcue here while we're
// previewing it but NOT playing.
// If not previewing this is no-op.
if (ControlObject::get(ConfigKey(m_group, QStringLiteral("play_latched"))) <= 0 &&
isValidHotcueDragOrDropEvent<QDropEvent>(
pEvent,
this,
m_group)) {
// This seems counterintuitive but it's the same action that
// allows to latch `play` with keyboard or controllers while
// previewing a hotcue.
// See EngineBuffer::slotControlPlayRequest()
ControlObject::set(ConfigKey(m_group, QStringLiteral("play")), 0.0);
pEvent->accept();
} else {
pEvent->ignore();
}
}
17 changes: 17 additions & 0 deletions src/widget/wplaybutton.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include "widget/wpushbutton.h"

struct HotcueDragInfo;

class WPlayButton : public WPushButton {
Q_OBJECT
public:
WPlayButton(QWidget* pParent, const QString& group);

private:
void dragEnterEvent(QDragEnterEvent* pEvent) override;
void dropEvent(QDropEvent* pEvent) override;

QString m_group;
};

0 comments on commit af3dafa

Please sign in to comment.