Skip to content

WBeatspinbox: added jump feature with L/R button in beatjump and loopmove #14476

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

icezuk
Copy link

@icezuk icezuk commented Mar 13, 2025

Adding the functionality to jump using the L/R buttons while in Beatjump/Loopmove or Loopsize spinbox.
Related to 14363.
Additions:

  1. Ctrl + L/R moves the loop by one beat
  2. Alt + L/R moves the loop by 1/8 beat
    Not ready to be merged, because of known issue: After using the L/R buttons the BeatjumpBackward/Forward arrows get marked if the value of BeatjumpSize is 1 and unmarked if it is anything else.

Also would love to know any other mechanism of detecting which spinbox is currently selected other than the hardcoded QSize.

Copy link
Member

@ronso0 ronso0 left a comment

Choose a reason for hiding this comment

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

Thanks for this PR!
I left some notes.

Comment on lines 35 to 45
ControlProxy beatJumpForward;
ControlProxy beatJumpBackward;
ControlProxy beatJumpSize;
ControlProxy beatJumpOneForward;
ControlProxy beatJumpOneBackward;
ControlProxy beatJumpEightForward;
ControlProxy beatJumpEightBackward;
ControlProxy beatLoopEnabled;
ControlProxy beatLoopSize;
QSize sizeSpinBox;
QSize sizeLoopBox;
Copy link
Member

Choose a reason for hiding this comment

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

For class members we use m_ prefix.
I suggest you take a look at https://github.com/mixxxdj/mixxx/wiki/Coding-Guidelines

@ronso0
Copy link
Member

ronso0 commented Mar 17, 2025

Not ready to be merged, because of known issue: After using the L/R buttons the BeatjumpBackward/Forward arrows get marked if the value of BeatjumpSize is 1 and unmarked if it is anything else.

That is to be expected.
In skins there are WPushButton widgets, connected to corresponding ControlPushButtons.
They are styled with qss (Qt stylesheets), and stylesheets usually only contain selectors for the expected states.
beatjump_forward is a trigger button so it has only 2 states styled: 0 and 1.
(you can start Mixxx with --developer arg to get more info in the widget tooltips, eg. state of connected controls, size etc.)

To trigger the beatjump via BeatJump::slotJumpForward you only need value > 0. So if you set it to beatJumpSize.get() (which can be anything between 1/32 and 512) there is simply no stylesheet selector for this ControlObject state.
If you use value 1, the GUI buttons are lit (which is fine since it provides feedback for what is happeing).
So to reset the GUI button (and the ControlPushButton) you'd do this:

beatJumpOneForward.set(1); CO is 1, button is lit (style), beatjump slot is called, beatjump is performed by engine
beatJumpOneForward.set(0); CO is 0, button unlit (style), nothing else happens

@icezuk
Copy link
Author

icezuk commented Mar 17, 2025

Hi @ronso0 ,

I've fixed all the things you mentioned in the notes in the PR except the one with detecting which spinbox the signal comes from. You mentioned I could use configKey, which I am using to configure all the controlProxies, but I still can't figure out how to use this for differentiating between which spinbox sent the signal and so I decided to ask for help. You said that only beatjump_size and beatloop_size are keys, which I am a bit confused by as I thought these are items that belong to a configKey that belongs to configObject. And the difference between beatjump/loop_size and the other controlProxies is that the first two are controlObjects while the others are controlPushButtons.

I've searched around in the codebase( for example loopingcontrol, looping_test_control) and also some documentation explaining the controls( for example this and this) and tried a bunch of things out(using connect() to fake a signal, trying all of the proxies's get or similar methods to find some information, using the configKey given to this, other methods of this, etc.) but still couldn't figure it out.

Thanks in advance!

Edit:
This question was asked in private conversation between me and Ronso in Zulip and he advised me it'd be better to ask here for anyone who might have a similar question so I decided to leave it here for the record

@ronso0
Copy link
Member

ronso0 commented Mar 17, 2025

I think I already answered your questions above.

@icezuk
Copy link
Author

icezuk commented Mar 17, 2025

Hi @ronso0 ,

Changes done. Appreciate if you could take a look.

Thanks

@icezuk icezuk marked this pull request as ready for review March 24, 2025 18:47
@ronso0
Copy link
Member

ronso0 commented Mar 26, 2025

I'm sorry I pushed this back on my list.
There are a few more adjustements necessary, will review soonish.

Comment on lines +305 to +324
if (m_valueControl.getKey().item == "beatjump_size") {
if (pEvent->key() == Qt::Key_Right && pEvent->modifiers() == Qt::ControlModifier) {
m_beatJumpOneForward.set(1);
m_beatJumpOneForward.set(0);
} else if (pEvent->key() == Qt::Key_Left && pEvent->modifiers() == Qt::ControlModifier) {
m_beatJumpOneBackward.set(1);
m_beatJumpOneBackward.set(0);
} else if (pEvent->key() == Qt::Key_Right && pEvent->modifiers() == Qt::AltModifier) {
m_beatJumpEightForward.set(1);
m_beatJumpEightForward.set(0);
} else if (pEvent->key() == Qt::Key_Left && pEvent->modifiers() == Qt::AltModifier) {
m_beatJumpEightBackward.set(1);
m_beatJumpEightBackward.set(0);
} else if (pEvent->key() == Qt::Key_Right) {
m_beatJumpForward.set(1);
m_beatJumpForward.set(0);
} else if (pEvent->key() == Qt::Key_Left) {
m_beatJumpBackward.set(1);
m_beatJumpBackward.set(0);
}
Copy link
Member

Choose a reason for hiding this comment

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

I think Alt and Alt+Shift are the only combinations we can safely use without breaking default QLineEdit behavior:

  • Ctrl+Left/Right normally jumps to prev/next word (boundary)
  • Ctrl+Shift+Left/Right normally extends/shrinks selection up to prev/next word boundary
  • pure Left/Right jumps back/forth by character

So we actually have only two jump sizes available. One should be the current beatjump_size.
The other one I don't know.

Let's try evaluate which jump sizes would be useful useful.
The default keyboard mapping already provides shortcuts for 1 beat back/forth for deck 1 & 2.
One scenario I can imagine is that you just activated a loop and go to the beatjump size box to shift it.

In case the loop is positioned a bit too early or too late, 1/8 beat would be handy (without having to adjust the jump size).
And even though we have GUI buttons for +- current beatjump_size, doing these jumps from within the size box seems reasonable (ie. without having to use the touchpad/mouse for the GUI buttons).

What do you think?
What's youruse case?

Copy link
Author

Choose a reason for hiding this comment

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

I think that the use cases that you described are what I've been using these for. I am using this for quickly jumping when I'm inside the the beatjump size box. That's also what's the description of the issue is. I personally don't use the 1/8 that much but you've said in the issue to this PR that you like it, so I don't see why leave it.

About the buttons we can use safely without breaking QLineEdit, do you think that just switching the modifiers from alt and ctrl to alt and alt+shift is reasonable and applicable here? The more natural (to me at least) distribution is alt for 1 beat and alt+shift for 1/8. What do you think about that?

The changes here are simple but we need to come to some consensus on how to do it exactly.

Copy link
Member

Choose a reason for hiding this comment

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

do you think that just switching the modifiers from alt and ctrl to alt and alt+shift is reasonable and applicable here?

That's what I was trying to say.

Copy link
Member

Choose a reason for hiding this comment

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

The default keyboard mapping already provides shortcuts for 1 beat back/forth for deck 1 & 2.

I just noticed that, unfortunately, the regular shortcuts (a-z + modifiers) don't work in the boxes (when they have focus). But solving this is not necessary to implement the jump shortcuts at least partially.

For the loop box I suggest the quick fix shortcuts:

  • Alt: jump +-1 beat
  • Alt+Shift: jump 1/8 beat

For the jumpsize box we may use

  • Alt for the selected jump size
  • Alt+Shift for 1/8 beat

What do you think?
What do others think? @mixxxdj/developers

Copy link
Author

Choose a reason for hiding this comment

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

Hi @ronso0

I implemented the changes and will push them here soon but I have a question. In your suggestion you say that the Alt modifier should be used in jumpsize box for selected jump size, but that is already done via no modifiers(just left/right). Did you mean Alt for +- 1 beat, same as loop box?

Copy link
Member

Choose a reason for hiding this comment

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

that is already done via no modifiers

pure Left/Right are used to move the cursor, so performing any special actions for these would be surprising.
Let's stick to the modofier combos.

Copy link
Author

Choose a reason for hiding this comment

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

Ok so Shift + Alt is not it, haha

I changed the modifiers to be Shift + Alt. I used both the code in this PR(with pEvent->modifiers() == Qt::$some_modifier) and pEvent->modifiers().testFlag(Qt::$some_modifier). Both result in broken behavior, which is I believe what you refer to when talking about broken QLineEdit.

Here is a video showcasing the aforementioned broken behavior. The first part is only using Alt for selected beatjump and then it's Alt + Shift for 1/8 first only forward and then both forward and backward(the first break happens with backward).

Mixxx.2025-04-16.21-32-06.mp4

If this is not a mistake on my front, I suggest using Ctrl + Alt or even Shift + Ctrl as this does not happen with these combinations. Shift + Alt seems to break behavior even when it is not being detected for any beatjump.

Copy link
Member

@ronso0 ronso0 Apr 17, 2025

Choose a reason for hiding this comment

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

Uuuh, I totally overlooked that Alt+L/R are the default shortcuts for loading a track to deck 1/2, and Alt+Shift+L/R does eject deck 1/2. https://manual.mixxx.org/2.5/en/chapters/controlling_mixxx#using-a-keyboard
These default global shortcuts should always work, regardless which widget has focus, they are caught in the main window before they are passed down the widget tree until they are maybe processed by individual widgets.
So all that's left that would work without (Mixxx internal) conflicts would be Ctrl+Alt, but that may be used for (system) global shortcuts (I have it mapped to move left/right between virtual desktops).

I'm sorry, I think this is a dead end.

Copy link
Author

Choose a reason for hiding this comment

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

What about substituting Left/Right with A/D? The pairing with Alt and Alt+Shift could be the same as your previous comment. I tested it and it works properly. But do you think I got ahead of myself and maybe this solution is not practical for users? I personally feel as if it is comfortable, but I have to factor in my own bias, haha. Anyway do share what you think!

ControlProxy m_beatJumpOneBackward;
ControlProxy m_beatJumpEightForward;
ControlProxy m_beatJumpEightBackward;
ControlProxy m_beatLoopEnabled;
Copy link
Member

Choose a reason for hiding this comment

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

We usually use pointers, specifically parented_ptr (src/util/parented_ptr.h). You'll find many examples in the codebase for how to use ad create those.

Copy link

This PR is marked as stale because it has been open 90 days with no activity.

@github-actions github-actions bot added the stale Stale issues that haven't been updated for a long time. label Jul 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale Stale issues that haven't been updated for a long time. ui
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants