Skip to content

[GSoC] LateNightQML: Deck (part 2) - #16691

Open
xARSENICx wants to merge 11 commits into
mixxxdj:mainfrom
xARSENICx:LateNightQML/Deck-week6
Open

[GSoC] LateNightQML: Deck (part 2)#16691
xARSENICx wants to merge 11 commits into
mixxxdj:mainfrom
xARSENICx:LateNightQML/Deck-week6

Conversation

@xARSENICx

@xARSENICx xARSENICx commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

This PR continues the LateNightQML deck work after Deck (part 1), focusing on the remaining deck waveform, overview, track metadata actions, vinyl/pass visuals, and rate-control polish for both the Classic and PaleMoon color schemes.

Testing the Experimental Skin

Since this is an early experimental milestone, you must first run Mixxx with the developer flag:

./build/mixxx --developer

Once Mixxx is open, switch to the experimental skin:
Preferences -> Interface -> LateNight QML (Experimental)

You can dynamically toggle between the Classic and PaleMoon color schemes under preferences.

Previews

Classic

Screenshot 2026-07-06 at 1 25 54 AM

PaleMoon

Screenshot 2026-07-06 at 1 25 17 AM

Scope of Changes

Implemented in this PR:

  • Deck Track Actions: Track title/artist fields now support deck track context menu and properties actions through QML.
  • Waveforms & Overview: Adds LateNightQML waveform display styling, beatgrid controls, waveform marker rendering, and overview marker/range overlays.
  • Vinyl & Rate Polish: Restores LateNight-style vinyl/pass button fills and text states, keeps vinyl/pass requests routed through engine controls, and fixes clipped rate-range labels.

Note:

  • Hotcue and loop deck control functionality has been removed from this branch for now and will be restored in a later commit or follow-up PR.

Tracking

GSoC: LateNightQML PR-6

@xARSENICx
xARSENICx force-pushed the LateNightQML/Deck-week6 branch from f99a567 to 5855cca Compare July 5, 2026 19:53
@ronso0

ronso0 commented Jul 6, 2026

Copy link
Copy Markdown
Member

Just a note - not sure when it started nor whether this is related to running Mixxx QML in VirtualBox:
My log is spammed with these lines

debug [Main] Processing QEvent::Timer for object 0x6371a673c060 took 18 ms
debug [Main] Processing QEvent::UpdateRequest for object ApplicationWindow_QMLTYPE_131_QML_146(0x6371a673c060) running in thread: "Main" took 25 ms

Log spam frequency increases otably as soon as I load a track into a deck.

And the EDIT mode (dnd to rearrange UI elements) doesn't work anymore.

@xARSENICx

Copy link
Copy Markdown
Contributor Author

The log spam comes from MixxxApplication::notify() slow-event logging in developer mode, not from a specific LateNightQML qDebug IIRC.

the EDIT mode (dnd to rearrange UI elements) doesn't work anymore.

Yeah, it is not being introduced as of now.

@JoergAtGithub

Copy link
Copy Markdown
Member

the EDIT mode (dnd to rearrange UI elements) doesn't work anymore.

Yeah, it is not being introduced as of now.

It's definetally a nice feature, but somehow we need to restrict the scope, so that we can deliver a complete product at the end of the project that doesn't have any significant functionality gaps.

@xARSENICx
xARSENICx force-pushed the LateNightQML/Deck-week6 branch from f4dd9e1 to 6355228 Compare July 18, 2026 09:46
Comment thread res/skins/LateNightQML/Deck/LateNightBpmTapEditor.qml
}

function handleTapClick(mouse) {
if (Date.now() - root.tapModeEnteredAt < root.tapModeClickGuardTimeout) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tapModeEnteredAt should be an required property

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tapModeEnteredAt is internal state set when the component enters tap mode, so making it required would add an invalid caller contract. I’ll keep it local.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant "readonly property" with initialization. Without initialization the outcome of
if (Date.now() - root.tapModeEnteredAt < root.tapModeClickGuardTimeout)
is random.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood. Since the guard is restarted whenever tap mode opens, the timestamp cannot be readonly. I replaced it with a Timer so the guard state is initialized and deterministic.


function applyEditValueAndQuit() {
const parsedValue = Number(editInput.text);
if (!isFinite(parsedValue)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Number("") returns 0, not NaN, so isFinite guard does't catch empty input which result in 0.0 BPM display. Please fix and test this!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NaN, doesn't legacy display it as 0.0 too? I didn't get you

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Legacy LateNight restores the original BPM value in case of an empty string. With 0.0 BPM the music would stop.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Empty input now closes the editor without writing the control, so the original BPM or rate is preserved.

Comment thread res/skins/LateNightQML/Deck/LateNightTrackPropertyText.qml
id: root

required property string group
required property var track

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
required property var track
required property Mixxx.Track track

Always use typed vars

Layout.preferredWidth: 180
Layout.fillHeight: true
group: root.group
track: currentTrack

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
track: currentTrack
track: root.currentTrack

Comment thread res/skins/LateNightQML/Deck/TitleTimeRows.qml
Comment thread res/skins/LateNightQML/Deck/VinylControlsPlaceholder.qml
Comment thread res/skins/LateNightQML/Deck/OverviewRow.qml
width: 12
height: 10
text: hotcueMarker.hotcueNumber
color: "#FFFFFF"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded color values should only be used in LateNightTheme.qml
Please change this everywehere!
Despite that, the text color of hotcues depend on the hotcue color. please check the logic in existing Latenight. There is a light and dark decision logic.

Comment thread src/qml/qmllibraryproxy.h Outdated
@@ -1,5 +1,6 @@
#pragma once
#include <QObject>
#include <QPoint>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this added? in the header file?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a leftover from a pointer position implementation I was checking locally. Will clean up.

pixmap,
endPixmap,
icon,
endPixmap,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is wrong. See

struct DefaultMarkerStyle {

The previous order was correct. Did you find an issue somewhere else?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You’re right. I did not find an issue elsewhere; I mixed up the WaveformMark::create() argument order with DefaultMarkerStyle. The struct’s original order is correct, so will restore it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still present

@github-actions github-actions Bot added the build label Aug 4, 2026
@xARSENICx
xARSENICx force-pushed the LateNightQML/Deck-week6 branch from e61a59d to 815cfb2 Compare August 8, 2026 15:38

@JoergAtGithub JoergAtGithub left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The numeric entry field for the BPM rate is not useable for me. It close automatically before I can enter all digits of the new value.
The expected behavior is that this remains open until I confirm the value by Enter keyboard button or cancel, e.g by. ESC,

@JoergAtGithub

Copy link
Copy Markdown
Member

This fix does not work for me:

Aufzeichnung.2026-08-09.130634.mp4

@xARSENICx
xARSENICx force-pushed the LateNightQML/Deck-week6 branch from 506361a to 238ab3f Compare August 10, 2026 18:56
@JoergAtGithub

JoergAtGithub commented Aug 10, 2026

Copy link
Copy Markdown
Member

Rate value editing works now, but while the BPM entry field is open, there appear wrong placed + and - rate buttons and the borders of the area llok wrong too:

Aufzeichnung.2026-08-10.212853.mp4

For comparistion, the original LateNight:

Aufzeichnung.2026-08-10.213733.mp4

Somehow the borders in the video look different than on my screen

pixmap,
endPixmap,
icon,
endPixmap,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still present

readonly property var deckPlayer: Mixxx.PlayerManager.getPlayer(root.group)
readonly property var currentTrack: deckPlayer?.currentTrack
readonly property Mixxx.Player deckPlayer: Mixxx.PlayerManager.getPlayer(root.group)
readonly property Mixxx.Track currentTrack: root.deckPlayer?.currentTrack

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this will work because currentTrack may be null. Does this not raise any warning when this is the case?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. It now explicitly falls back to null when no player or track is available, in latest commit.

width: parent.width
height: 24
text: visualBpmProxy.value.toFixed(2)
text: bpmProxy.value.toFixed(2)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this defined?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -26,41 +26,12 @@ Skin.EmbeddedText {
property double remaining: durationControl.value * (1 - playPositionControl.value)

function toTime(value) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the rational for moving this from JS to C++? Making this C++ makes customisation harder, as it requires our user to recompile Mixxx entirely.
Editing C++ also requires non trivial experience (e.g memory management, exception handling), while QML/JS is much more beginner friendly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was explicitly requested in Joerg’s earlier review. cc @JoergAtGithub

@acolombier
acolombier dismissed their stale review August 10, 2026 20:46

Lifting my change request as I will be away for a while and don't want to block merge. Please do address my comment nevertheless!

@xARSENICx

Copy link
Copy Markdown
Contributor Author

#16691 (comment)

The review thread opens the old BASE..6355228 comparison, which still shows the incorrect reorder. It was restored in 815cfb2, and qmlwaveformrenderer.cpp is absent from the current all-commits Files changed view. Could you recheck the current PR diff?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants