Skip to content
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

feat(Controller): add support for settings #11300

Merged
merged 18 commits into from Mar 28, 2024

Conversation

acolombier
Copy link
Contributor

@acolombier acolombier commented Feb 23, 2023

This PR addresses the feature request #8135

A few capabilities have been added from the original plan:

  • Ability to use group with a label attribute
  • Ability to use row which will organize settings horizontally if the settings group box is wider than 960px, with support for horizontal (default) and and vertical label/widget disposition

Outstanding work:

  • Add more setting type (real numbers, boolean, enum)
  • Add state persistence
  • Add HID support
  • Add MIDI support This will require refactoring the load function and IMHO it is wiser to do so in a dedicated PR
  • Add test for setting spec
  • Add test for setting edition (from Pref dialog and cfg)
  • Add test for the parser

An update of the Wiki is currently in progress.

Current status

Simple

image

XML Config
<?xml version='1.0' encoding='utf-8'?>
<MixxxControllerPreset mixxxVersion="2.4.0" schemaVersion="1">
    <info>
        <name>Dummy Device Test Mapping 1</name>
        <author>acolombier</author>
        <description>HID Mapping virtual test device</description>
        <manual>test_dumy_hid</manual>
        <devices>
            <product protocol="hid" vendor_id="0x1234" product_id="0x5678" />
        </devices>
    </info>
    <settings>
        <option
            variable="myFactor"
            type="integer"
            min="1"
            max="1000"
            step="10"
            default="100"
            label="My dummy factor"
            label_de="Mein Dummy-Faktor"
            label_fr="Mon facteur factice" />
        <option
            variable="foo"
            type="string"
            default="Bar"
            label="My unsupport setting" />
        <column></column>
        <option
            variable="myOtherFactor"
            type="real"
            precision="2"
            min="0"
            max="1"
            step="0.05"
            default="0.15"
            label="My other factor">
            <description>
                This factor is useful for one thing that you definitely need.
            </description>
            <description lang="de">
                Dieser Faktor ist nützlich für eine Sache, die Sie unbedingt brauchen.
            </description>
        </option>
        <option
            variable="myToggle"
            type="boolean"
            default="false"
            label="My beta feature">
            <description lang="de">
                It include many things, you should try it.
            </description>
        </option>
        <option
            variable="myOptionList"
            type="enum"
            label="My list of option">
            <value label="A" default="true">a</value>
            <value label="B">b</value>
            <value label="C">c</value>
            <description>
                This list define how A will interact with the rest of the letters.
            </description>
        </option>
        <group label="Test group">
            <option
                variable="myFactor2"
                type="integer"
                min="1"
                max="1000"
                step="10"
                default="100"
                label="My dummy factor" />
        </group>
        <group label="Default row">
            <row>
                <option
                    variable="myFactorInNormalRow"
                    type="integer"
                    min="1"
                    max="1000"
                    step="10"
                    default="100"
                    label="My dummy factor" />
                <option
                    variable="myOtherFactorInNormalRow"
                    type="real"
                    precision="2"
                    min="0"
                    max="1"
                    step="0.05"
                    default="0.15"
                    label="My other factor">
                    <description>
                        This factor is useful for one thing that you definitely need.
                    </description>
                </option>
                <option
                    variable="myToggleInNormalRow"
                    type="boolean"
                    default="false"
                    label="My beta feature">
                    <description>
                        It include many things, you should try it.
                    </description>
                </option>
                <option
                    variable="myOptionListInNormalRow"
                    type="enum"
                    label="My list of option">
                    <value label="A" default="true">a</value>
                    <value label="B">b</value>
                    <value label="C">c</value>
                    <description>
                        This list define how A will interact with the rest of the letters.
                    </description>
                </option>
            </row>
        </group>
        <group label="Row with preferred widget orientation">
            <row orientation="vertical">
                <option
                    variable="myFactorInRowWithVerticalWidgetOrientation"
                    type="integer"
                    min="1"
                    max="1000"
                    step="10"
                    default="100"
                    label="My dummy factor" />
                <option
                    variable="myOtherFactorInRowWithVerticalWidgetOrientation"
                    type="real"
                    precision="2"
                    min="0"
                    max="1"
                    step="0.05"
                    default="0.15"
                    label="My other factor">
                    <description>
                        This factor is useful for one thing that you definitely need.
                    </description>
                </option>
                <option
                    variable="myToggleInRowWithVerticalWidgetOrientation"
                    type="boolean"
                    default="false"
                    label="My beta feature">
                    <description>
                        It include many things, you should try it.
                    </description>
                </option>
                <option
                    variable="myOptionListInRowWithVerticalWidgetOrientation"
                    type="enum"
                    label="My list of option">
                    <value label="A" default="true">a</value>
                    <value label="B">b</value>
                    <value label="C">c</value>
                    <description>
                        This list define how A will interact with the rest of the letters.
                    </description>
                </option>
            </row>
        </group>
    </settings>
    <controller id="Dummy">
        <scriptfiles>
            <file filename="Test-HID-Dummy.js" functionprefix="Dummy" />
        </scriptfiles>
    </controller>
</MixxxControllerPreset>

Kontrol S4 MK3

This is an example of how this feature would be used for the support of the S4 Mk3, currently in progress in PR #11284

image

XML Config
<?xml version='1.0' encoding='utf-8'?>
<MixxxControllerPreset mixxxVersion="2.4.0" schemaVersion="1">
    <info>
        <name>Dummy Device Test Mapping 3</name>
        <author>acolombier</author>
        <description>HID Mapping virtual test device</description>
        <manual>test_dumy_hid</manual>
        <devices>
            <product protocol="hid" vendor_id="0x1234" product_id="0x5678" />
        </devices>
    </info>
    <settings>
        <group label="Deck lighting">
            <row orientation="vertical">
                <option
                    variable="deckA"
                    type="enum"
                    label="Deck A">
                    <value label="Aqua">aqua</value>
                    <value label="Azalea">azalea</value>
                    <value label="Blue">blue</value>
                    <value label="Celeste">celeste</value>
                    <value label="Fuscia">fuscia</value>
                    <value label="Green">green</value>
                    <value label="Lime">lime</value>
                    <value label="Orange">orange</value>
                    <value label="Purple">purple</value>
                    <value label="Red" default="true">red</value>
                    <value label="Salmon">salmon</value>
                    <value label="Sky">sky</value>
                    <value label="White">white</value>
                    <value label="Yellow">yellow</value>
                </option>
                <option
                    variable="deckB"
                    type="enum"
                    label="Deck B">
                    <value label="Aqua">aqua</value>
                    <value label="Azalea">azalea</value>
                    <value label="Blue" default="true">blue</value>
                    <value label="Celeste">celeste</value>
                    <value label="Fuscia">fuscia</value>
                    <value label="Green">green</value>
                    <value label="Lime">lime</value>
                    <value label="Orange">orange</value>
                    <value label="Purple">purple</value>
                    <value label="Red">red</value>
                    <value label="Salmon">salmon</value>
                    <value label="Sky">sky</value>
                    <value label="White">white</value>
                    <value label="Yellow">yellow</value>
                </option>
                <option
                    variable="deckC"
                    type="enum"
                    label="Deck C">
                    <value label="Aqua">aqua</value>
                    <value label="Azalea">azalea</value>
                    <value label="Blue" default="true">blue</value>
                    <value label="Celeste">celeste</value>
                    <value label="Fuscia">fuscia</value>
                    <value label="Green">green</value>
                    <value label="Lime">lime</value>
                    <value label="Orange">orange</value>
                    <value label="Purple">purple</value>
                    <value label="Red">red</value>
                    <value label="Salmon">salmon</value>
                    <value label="Sky">sky</value>
                    <value label="White">white</value>
                    <value label="Yellow" default="true">yellow</value>
                </option>
                <option
                    variable="deckD"
                    type="enum"
                    label="Deck D">
                    <value label="Aqua">aqua</value>
                    <value label="Azalea">azalea</value>
                    <value label="Blue">blue</value>
                    <value label="Celeste">celeste</value>
                    <value label="Fuscia">fuscia</value>
                    <value label="Green">green</value>
                    <value label="Lime">lime</value>
                    <value label="Orange">orange</value>
                    <value label="Purple" default="true">purple</value>
                    <value label="Red">red</value>
                    <value label="Salmon">salmon</value>
                    <value label="Sky">sky</value>
                    <value label="White">white</value>
                    <value label="Yellow">yellow</value>
                </option>
            </row>
            <option
                variable="keepLEDWithOneColorDimedWhenInactive"
                type="boolean"
                default="true"
                label="Keep one-color LED dimmed insted of off when inactive">
                <description>
                    This will always ensure every button has some lighting which may help in dark environment, but may put off the lead color of the deck.
                </description>
            </option>
            <option
                variable="gridButtonBlinkOverBeat"
                type="boolean"
                default="true"
                label="Make the GRID button blink over beat">
                <description>
                    This will Make the GRID button blink when the track is going over a detected beat. This can help adjusting the beat grid or BPM.
                </description>
            </option>
            <option
                variable="tempoFaderSoftTakeoverColorLow"
                type="enum"
                label="Tempo fader low soft takeover color">
                <value label="Aqua">aqua</value>
                <value label="Azalea">azalea</value>
                <value label="Blue" default="true">blue</value>
                <value label="Celeste">celeste</value>
                <value label="Fuscia">fuscia</value>
                <value label="Green">green</value>
                <value label="Lime">lime</value>
                <value label="Orange">orange</value>
                <value label="Purple">purple</value>
                <value label="Red">red</value>
                <value label="Salmon">salmon</value>
                <value label="Sky">sky</value>
                <value label="White" default="true">white</value>
                <value label="Yellow">yellow</value>
                <description>This color defines how the LED next to tempo fader will be backlit when the real BPM is lower than the fader value</description>
            </option>
            <option
                variable="tempoFaderSoftTakeoverColorHigh"
                type="enum"
                label="Tempo fader low soft takeover color">
                <value label="Aqua">aqua</value>
                <value label="Azalea">azalea</value>
                <value label="Blue">blue</value>
                <value label="Celeste">celeste</value>
                <value label="Fuscia">fuscia</value>
                <value label="Green" default="true">green</value>
                <value label="Lime">lime</value>
                <value label="Orange">orange</value>
                <value label="Purple">purple</value>
                <value label="Red">red</value>
                <value label="Salmon">salmon</value>
                <value label="Sky">sky</value>
                <value label="White">white</value>
                <value label="Yellow">yellow</value>
                <description>This color defines how the LED next to tempo fader will be backlit when the real BPM is higher than the fader value</description>
            </option>
        </group>
        <group label="Alternative mapping">
            <option
                variable="useKeylockOnMaster"
                type="boolean"
                default="false"
                label="Keylock on shift+Master instead of shift+sync">
                <description>
                    This will make it so the keylock can be toggled on push instead as of release as there is a long press action on shift+sync (copy key).
                </description>
            </option>
            <option
                variable="useBeatloopRoolInsteadOfSampler"
                type="boolean"
                default="true"
                label="Use the Sampler tab as a beatloop roll tab instead">
                <description>
                    This is useful if you don't use samplers and would like to have access to a set of predefined beatloop rolls. Defined beats are 0.0625, 0.125, 0.25, 0.5, 1, 2, 4 and 8.
                </description>
            </option>
        </group>
        <group label="Library">
            <row orientation="vertical">
                <option
                    variable="librarySortableColumns1Value"
                    type="enum"
                    label="First column">
                    <value label="Artist" default="true">1</value>
                    <value label="Title">2</value>
                    <value label="Album">3</value>
                    <value label="Albumartist">4</value>
                    <value label="Year">5</value>
                    <value label="Genre">6</value>
                    <value label="Composer">7</value>
                    <value label="Grouping">8</value>
                    <value label="Tracknumber">9</value>
                    <value label="Filetype">10</value>
                    <value label="Native Location">11</value>
                    <value label="Comment">12</value>
                    <value label="Duration">13</value>
                    <value label="Bitrate">14</value>
                    <value label="BPM">15</value>
                    <value label="ReplayGain">16</value>
                    <value label="Datetime Added">17</value>
                    <value label="Times Played">18</value>
                    <value label="Rating">19</value>
                    <value label="Key">20</value>
                    <description>First column when iterating over sortable library columns using VIEW+Library Encoder press</description>
                </option>
                <option
                    variable="librarySortableColumns2Value"
                    type="enum"
                    label="Second column">
                    <value label="---">0</value>
                    <value label="Artist">1</value>
                    <value label="Title" default="true">2</value>
                    <value label="Album">3</value>
                    <value label="Albumartist">4</value>
                    <value label="Year">5</value>
                    <value label="Genre">6</value>
                    <value label="Composer">7</value>
                    <value label="Grouping">8</value>
                    <value label="Tracknumber">9</value>
                    <value label="Filetype">10</value>
                    <value label="Native Location">11</value>
                    <value label="Comment">12</value>
                    <value label="Duration">13</value>
                    <value label="Bitrate">14</value>
                    <value label="BPM">15</value>
                    <value label="ReplayGain">16</value>
                    <value label="Datetime Added">17</value>
                    <value label="Times Played">18</value>
                    <value label="Rating">19</value>
                    <value label="Key">20</value>
                    <description>Second column when iterating over sortable library columns using VIEW+Library Encoder press</description>
                </option>
                <option
                    variable="librarySortableColumns3Value"
                    type="enum"
                    label="Third column">
                    <value label="---">0</value>
                    <value label="Artist">1</value>
                    <value label="Title">2</value>
                    <value label="Album">3</value>
                    <value label="Albumartist">4</value>
                    <value label="Year">5</value>
                    <value label="Genre">6</value>
                    <value label="Composer">7</value>
                    <value label="Grouping">8</value>
                    <value label="Tracknumber">9</value>
                    <value label="Filetype">10</value>
                    <value label="Native Location">11</value>
                    <value label="Comment">12</value>
                    <value label="Duration">13</value>
                    <value label="Bitrate">14</value>
                    <value label="BPM" default="true">15</value>
                    <value label="ReplayGain">16</value>
                    <value label="Datetime Added">17</value>
                    <value label="Times Played">18</value>
                    <value label="Rating">19</value>
                    <value label="Key">20</value>
                    <description>Third column when iterating over sortable library columns using VIEW+Library Encoder press</description>
                </option>
                <option
                    variable="librarySortableColumns4Value"
                    type="enum"
                    label="Fourth column">
                    <value label="---" default="true">0</value>
                    <value label="Artist">1</value>
                    <value label="Title">2</value>
                    <value label="Album">3</value>
                    <value label="Albumartist">4</value>
                    <value label="Year">5</value>
                    <value label="Genre">6</value>
                    <value label="Composer">7</value>
                    <value label="Grouping">8</value>
                    <value label="Tracknumber">9</value>
                    <value label="Filetype">10</value>
                    <value label="Native Location">11</value>
                    <value label="Comment">12</value>
                    <value label="Duration">13</value>
                    <value label="Bitrate">14</value>
                    <value label="BPM">15</value>
                    <value label="ReplayGain">16</value>
                    <value label="Datetime Added">17</value>
                    <value label="Times Played">18</value>
                    <value label="Rating">19</value>
                    <value label="Key" default="true">20</value>
                    <description>Fourth column when iterating over sortable library columns using VIEW+Library Encoder press</description>
                </option>
                <option
                    variable="librarySortableColumns5Value"
                    type="enum"
                    label="Fifth column">
                    <value label="---" default="true">0</value>
                    <value label="Artist">1</value>
                    <value label="Title">2</value>
                    <value label="Album">3</value>
                    <value label="Albumartist">4</value>
                    <value label="Year">5</value>
                    <value label="Genre">6</value>
                    <value label="Composer">7</value>
                    <value label="Grouping">8</value>
                    <value label="Tracknumber">9</value>
                    <value label="Filetype">10</value>
                    <value label="Native Location">11</value>
                    <value label="Comment">12</value>
                    <value label="Duration">13</value>
                    <value label="Bitrate">14</value>
                    <value label="BPM">15</value>
                    <value label="ReplayGain">16</value>
                    <value label="Datetime Added">17</value>
                    <value label="Times Played">18</value>
                    <value label="Rating">19</value>
                    <value label="Key">20</value>
                    <description>Fifth column when iterating over sortable library columns using VIEW+Library Encoder press</description>
                </option>
                <option
                    variable="librarySortableColumns6Value"
                    type="enum"
                    label="Sixth column">
                    <value label="---" default="true">0</value>
                    <value label="Artist">1</value>
                    <value label="Title">2</value>
                    <value label="Album">3</value>
                    <value label="Albumartist">4</value>
                    <value label="Year">5</value>
                    <value label="Genre">6</value>
                    <value label="Composer">7</value>
                    <value label="Grouping">8</value>
                    <value label="Tracknumber">9</value>
                    <value label="Filetype">10</value>
                    <value label="Native Location">11</value>
                    <value label="Comment">12</value>
                    <value label="Duration">13</value>
                    <value label="Bitrate">14</value>
                    <value label="BPM">15</value>
                    <value label="ReplayGain">16</value>
                    <value label="Datetime Added">17</value>
                    <value label="Times Played">18</value>
                    <value label="Rating">19</value>
                    <value label="Key">20</value>
                    <description>Sixth column when iterating over sortable library columns using VIEW+Library Encoder press</description>
                </option>
            </row>
        </group>
        <group label="Jog wheel">
            <option
                variable="loopWheelMoveFactor"
                type="integer"
                min="20"
                max="250"
                step="2"
                default="50"
                label="Jogwheel sensitivity in loop mode" />
            <description>
                Define the sensitivity factor when the jogwheel is used to move the in and out point of a loop using the Loop Mode.
            </description>
            <row>
                <option
                    variable="loopEncoderMoveFactor"
                    type="integer"
                    min="100"
                    max="2500"
                    step="20"
                    default="500"
                    label="Loop encoder sensitivity in loop mode">
                    <description>
                        Define the sensitivity of the loop encoder when moving loop position in the Loop Mode.
                    </description>
                </option>
                <option
                    variable="loopEncoderShiftMoveFactor"
                    type="integer"
                    min="500"
                    max="12500"
                    step="20"
                    default="2500"
                    label="Loop encoder sensitivity in loop mode (shift)">
                    <description>
                        Define the sensitivity of shift+the loop encoder when moving loop position in the Loop Mode.
                    </description>
                </option>

            </row>

            <option
                variable="wheelSpeedSample"
                type="integer"
                min="2"
                max="80"
                step="2"
                default="5"
                label="Speed sample">
                <description>
                    Define how many wheel moves are sampled to compute the speed. The more you have, the more the speed is accurate, but the less responsive it gets in Mixxx.
                </description>
            </option>
            <option
                variable="baseRevolutionsPerMinute"
                type="enum"
                label="Turntable spped">
                <value label="33.3 RPM" default="true">33.33</value>
                <value label="45 RPM">45</value>
                <description>Define how fast the jogwheel would rotate with the default play rate. This whill impact scratch sensitivity, motor speed and ring LED pace.</description>
            </option>
        </group>
        <group label="Haptic drive feature (BETA)">
            <option
                variable="useMotors"
                type="boolean"
                default="false"
                label="Use beta Haptic Drive features &lt;b&gt;(BETA)&lt;/b&gt;">
                <description>
                    This will defines whether or not Mixxx is allowed to interact with the motors. &lt;br /&gt;&lt;b&gt;WARNING&lt;/b&gt;: while interacting with motors should be harmless for your device, it isn't possible to give a full guaranty that this will not accelerate wearing off.
                </description>
            </option>
            <option
                variable="turnTableSpeedSample"
                type="integer"
                min="2"
                max="80"
                step="2"
                default="40"
                label="Turntable speed sample">
                <description>
                    Define how many wheel moves are sampled to compute the speed when using the motor. This is helpful to mitigate delay that occurs in communication as well as Mixxx limitation to 20ms latency. The more you have, the more the speed is accurate, but the less responsive it gets in Mixxx
                </description>
            </option>

            <row>
                <option
                    variable="tightnessFactor"
                    type="real"
                    precision="2"
                    min="0"
                    max="1"
                    step="0.05"
                    default="0.5"
                    label="Jogwheel tension">
                    <description>
                        Define how much the jogwheel will resist. It is a similar setting that the Grid+Wheel in Tracktor. 0 is very tight, 1 is very loose.
                    </description>
                </option>

                <option
                    variable="maxWheelForce"
                    type="integer"
                    min="8000"
                    max="32000"
                    step="500"
                    default="25000"
                    label="Jogwheel torque">
                    <description>
                        This setting defines how much torque can Mixxx use on the motor.
                    </description>
                </option>
            </row>
        </group>
    </settings>
    <controller id="Dummy">
        <scriptfiles>
            <file filename="Test-HID-Dummy.js" functionprefix="Dummy" />
        </scriptfiles>
    </controller>
</MixxxControllerPreset>

Regarding the previous list, let me know if you would like to split the work in multiple PR to ease reviewing.

@Be-ing
Copy link
Contributor

Be-ing commented Feb 24, 2023

My biggest question is what will the interface be between the GUI and JavaScript? AFAICT this only builds the GUI so far, but it doesn't expose it the device-specific settings to the script?

@acolombier
Copy link
Contributor Author

acolombier commented Feb 24, 2023

Yes, that's correct, I haven't done this part yet, hopefully will get some part of it done today.
The interface for HID and MIDi is detailed in the issue #8135

Update: with this commit , I have made the settings injection into the script. The logic is similar to how scriptfiles are propagated to the engine.

Copy link
Member

@daschuer daschuer left a comment

Choose a reason for hiding this comment

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

Thank you this PR looks very promising. I have added dome comments from my first read.

src/controllers/controller.cpp Outdated Show resolved Hide resolved
src/controllers/dlgprefcontroller.cpp Outdated Show resolved Hide resolved
src/controllers/dlgprefcontroller.cpp Outdated Show resolved Hide resolved
src/controllers/legacycontrollermapping.h Outdated Show resolved Hide resolved
src/controllers/legacycontrollersettings.cpp Outdated Show resolved Hide resolved
src/controllers/legacycontrollersettings.cpp Outdated Show resolved Hide resolved
src/controllers/legacycontrollersettings.h Outdated Show resolved Hide resolved
src/controllers/legacycontrollersettingsfactory.h Outdated Show resolved Hide resolved
@acolombier acolombier force-pushed the feat/controller-custom-settings branch 2 times, most recently from 5fe6d41 to 1a8681c Compare February 25, 2023 20:18
@acolombier acolombier force-pushed the feat/controller-custom-settings branch from 1a8681c to d5e281b Compare February 25, 2023 21:42
@acolombier acolombier force-pushed the feat/controller-custom-settings branch 2 times, most recently from 3ed3cad to e7fe278 Compare February 25, 2023 22:54
@ronso0
Copy link
Member

ronso0 commented Feb 25, 2023

Regarding the layout in the mapping GUI:
I vote for keeping it simple, i.e. one option per row. The preferences should be as compact as possible because IMHO horizontal scrollbars are a PITA.
While desktop users with common 1200px screens may enlarge the preferences window, we should keep in mind that Mixxx has a growing user base on SOCs like the R'Pi with (very) small screens. If required the skins can be adapted to these, but preferences can't :|

@JoergAtGithub
Copy link
Member

I don't think multiple options per row are the issue here. The issue are the long description texts. Have a look on the narrow layout of the Traktor preferences, with up to 4 options per row.
What I would change, is to use bubble-help for the long description texts - as we do in the main window already.

@acolombier
Copy link
Contributor Author

acolombier commented Feb 25, 2023

I agree, horizontal scrollbars are PITA.
But in the meantime, while I was all in favour of the "1 options per row", looking at the demo I did for the S4 Mk3 (visible in the PR description), it actually does feel like a great middle ground to allow it for certain cases.
Perhaps one additional easy features I could do is, do a main screen query, if it smaller than 1600(or some limit we define), rows get disabled, forcing the one option per row. What do you think?

@acolombier acolombier force-pushed the feat/controller-custom-settings branch from e7fe278 to 52ae9c4 Compare February 26, 2023 09:51
@acolombier
Copy link
Contributor Author

I followed @JoergAtGithub 's advice and tried with tool-tip instead of sub-line descriptions. I believe this looks great.
I also added some logic, where rows will be disabled and the "one item per line" will be adopted of the screen on which the preferences are being displayed is narrow than 1280px

image

@JoergAtGithub
Copy link
Member

This looks much cleaner now! 🤩

But for the multi option per row, the allignment could be improved. There is much space between the label and the control belonging to the label.
IMHO a good example of alignment of multiple options in a row, is the Visual Gain on the Waveforms page of the preferences. I think the deck colors of your example could look similar.
Another good example is Decks page of our preferences.

@acolombier
Copy link
Contributor Author

Like this?

image

I just want to mention here that it is likely there will be very different options depending devices and mappings. Those settings are meant to cover the greater and be dynamically rendered; IMHO, there is no way we can have as great results as in the statically defined preferences as references :)

@JoergAtGithub
Copy link
Member

IMHO this looks really good now!

You might want to tune the vertical whitespaces to improve the look further (more height for the checkbox options, move the Deck-Labels a few pixels down). But such visual optimizations are beyond what is necessary.

@acolombier acolombier force-pushed the feat/controller-custom-settings branch 2 times, most recently from f1b9766 to 507d0bc Compare February 26, 2023 12:51
@ronso0
Copy link
Member

ronso0 commented Feb 26, 2023

I also added some logic, where rows will be disabled and the "one item per line" will be adopted of the screen on which the preferences are being displayed is narrow than 1280px

Great, if that works reliably! Though I suggest to make it depend on the width of groupBoxSettings so it just fits into the dialog. Please also keep in mind that English often has the shortest strings and most (european) translations that come to mind are usually much longer. That's why I think that we should always use one control per line, but allow exceptions for groups like the deck color settings that definitely have short labels and much more sense in a horizontal layout.

In regards to the label/control arrangement: the are usually (always?) layed out horizontally => Label: [control]
Let's stick to that rule and not mix it with vertical layouts.

@JoergAtGithub
Copy link
Member

In regards to the label/control arrangement: the are usually (always?) layed out horizontally => Label: [control]
Let's stick to that rule and not mix it with vertical layouts.

IMHO it looks much cleaner now with the vertical label arrangement and it's consistent with the layout of other preference pages (Waveform, Decks).

@acolombier
Copy link
Contributor Author

I guess I could add an orientation attribute in the <row> element. We can then mention in the doc that vertical must be used in certain cases only?

@ronso0
Copy link
Member

ronso0 commented Feb 26, 2023

Would yo mind including the dummy mapping for testing here?

In regards to the label/control arrangement: the are usually (always?) layed out horizontally => Label: [control]
Let's stick to that rule and not mix it with vertical layouts.

IMHO it looks much cleaner now with the vertical label arrangement and it's consistent with the layout of other preference pages (Waveform, Decks).

Hmm?
In Decks everything is layed out horizontally: Label [spinbox/radiobuttons/combobox].
In waveforms, too, with the High/Mid/Low/Gain controls being an exception like the deck colors in the example above.

@acolombier
Copy link
Contributor Author

Would yo mind including the dummy mapping for testing here?

It's in the PR description. I haven't updated the visual, but the XML mapping remains the same

@ronso0
Copy link
Member

ronso0 commented Feb 26, 2023

I guess I could add an orientation attribute in the <row> element. We can then mention in the doc that vertical must be used in certain cases only?

Yup, sounds good. Should default to horizontal (if absent) so the vertical layout is used only when required. We should keep an eye on it when reviewing mappings.

@acolombier
Copy link
Contributor Author

acolombier commented Feb 26, 2023

I have added the orientation option for row. Here is the result. Also, as @ronso0 suggested, I have added dynamic sizing, so if the group setting is less than 960px wide, it will force one item per row.

On the 960px choice, I tried a few values, and that one seemed to be a great trade off, but can always be changed if you have a value you think we should stick to.

Hopefully, everything looks good now from your perspectives. I will continue unit tests/docstring/guideline and will get started with the wiki update.

FYI, the three mappings visible on the video are attached here (had to zip it because Github is sometime stupid), so hopefully it will help for review, or if you guys want to give it a spin locally.

video.mp4

@acolombier acolombier force-pushed the feat/controller-custom-settings branch from efa9242 to 2c3a6b8 Compare March 25, 2024 23:40
@acolombier acolombier force-pushed the feat/controller-custom-settings branch from 2c3a6b8 to a57332a Compare March 26, 2024 09:30
Copy link
Member

@JoergAtGithub JoergAtGithub left a comment

Choose a reason for hiding this comment

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

Now finally everything works as expected! I approve this PR hereby!

@daschuer If your points are addressed too, please merge this PR!

@ywwg
Copy link
Member

ywwg commented Mar 26, 2024

can't wait to make the traktor S3 config use this feature!

Copy link
Member

@daschuer daschuer left a comment

Choose a reason for hiding this comment

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

I was not able to create settings for a midi device. Does it also work for midi?
Do you have a working sample?

src/controllers/dlgprefcontroller.cpp Outdated Show resolved Hide resolved
@JoergAtGithub
Copy link
Member

JoergAtGithub commented Mar 27, 2024

I was not able to create settings for a midi device. Does it also work for midi?

No, this is written in the PR description. This PR is HID only. MIDI is planned for an follow-up PR.

Working sample is in #12995

@acolombier
Copy link
Contributor Author

acolombier commented Mar 27, 2024

Yes, the original plan was to address this in a future PR. I will look at the leak asap.

@acolombier
Copy link
Contributor Author

acolombier commented Mar 27, 2024

@daschuer I fixed that leak with the suggested patch.

For transparency sake, I am not sure I will carry on with the MIDI work right away as this first part wasn't an easy ride and kinda shut my motivation down for the original plan suggested in the issue. I also don't own any MIDI device so it would be hard for me to work and test usability of the feature.
Of course, I'm more than happy to help with the feature as much as possible but not sure I can drive it like I did for HID anymore. Alternatively, I'd be happy to implement it as long as we have a clear delimitation and spec requirement of what MIDI needs to look like, which should allow me to remediate to not having any MIDI devices.

Edit: I actually have a Terminal Mix 4 buried in a cupboard which might still work. Perhaps that can help me for testing, but I'd still like a well define direction for the final result.

@acolombier acolombier force-pushed the feat/controller-custom-settings branch 2 times, most recently from 716c110 to 3e98e4e Compare March 27, 2024 23:45
@daschuer
Copy link
Member

Oh, you have debased everything :-( This is not permitted under review, because we now have technically 17 commit to review again. What was the reason for it? Can we find a shortcut for merging?

I can confirm that the last commit fixes my last comment.

@acolombier
Copy link
Contributor Author

When I rebased my branch, there was conflict with pretty much every commits (due to my recently merge PR touching on the same files), could it be the reason?

Open to suggestions on shortcuts for merging?

@daschuer
Copy link
Member

Next time, please just merge upstream/main in a single commit and resolve the conflict in a single merge commit.

Did you do a brief test with you example mapping after the rebase?

@acolombier acolombier force-pushed the feat/controller-custom-settings branch from 3e98e4e to d72e012 Compare March 28, 2024 09:01
@acolombier
Copy link
Contributor Author

Apologies for the git mess - @daschuer I restored the previous commit with reflog and did an upstream merge instead just for peace of mind.
FYI, I did a diff before and it looks like there was no difference.

Copy link
Member

@daschuer daschuer left a comment

Choose a reason for hiding this comment

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

LGTM, Thank you for this often requested feature.

@daschuer daschuer merged commit 99406cb into mixxxdj:main Mar 28, 2024
13 checks passed
@fwcd
Copy link
Member

fwcd commented Mar 28, 2024

Wow, thanks to everyone involved, super excited to play with this soon!

(If I find time, I'll see if I can update the MC7000 mapping 😄)

@JoergAtGithub
Copy link
Member

(If I find time, I'll see if I can update the MC7000 mapping 😄)

Currently only HID is supported, not yet MIDI.

@fwcd
Copy link
Member

fwcd commented Mar 29, 2024

Ah, that's a shame. But if I read the initial comment correctly, MIDI support is on the radar.

@acolombier
Copy link
Contributor Author

It was, but unfortunately the plan for MIDI didn't get a consensus (see the original issue and Zulip
As I mentioned above, I'd be happy to do the MIDI part as long as there is a clear agreement on what it got to look like, and I don't have to go back and forth with the work.

@JoergAtGithub
Copy link
Member

I think we've the consensus, that we all want the same JavaScript setting API, that we've now for HID, for MIDI (and BULK) too.
What is open, is if and how we want to handle semantic (currently XML in future maybe QML) mappings and the MIDI Learning Wizard.

@fwcd
Copy link
Member

fwcd commented Apr 20, 2024

Linking

for completeness, I assume MIDI mappings are now supported?

@JoergAtGithub
Copy link
Member

for completeness, I assume MIDI mappings are now supported?

Yes!

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.

allow users to change mapping options from GUI without having to edit XML or JS
9 participants