diff --git a/src/library/basesqltablemodel.cpp b/src/library/basesqltablemodel.cpp index bae2b19ee0a2..f2a90e889d86 100644 --- a/src/library/basesqltablemodel.cpp +++ b/src/library/basesqltablemodel.cpp @@ -655,7 +655,7 @@ QVariant BaseSqlTableModel::data(const QModelIndex& index, int role) const { if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_DURATION)) { int duration = value.toInt(); if (duration > 0) { - value = mixxx::Duration::formatSeconds(duration); + value = mixxx::Duration::formatTime(duration); } else { value = QString(); } diff --git a/src/library/crate/cratesummary.h b/src/library/crate/cratesummary.h index 4318a9ee40b7..88407a5c566a 100644 --- a/src/library/crate/cratesummary.h +++ b/src/library/crate/cratesummary.h @@ -34,7 +34,7 @@ class CrateSummary: public Crate { } // Returns the duration formatted as a string H:MM:SS QString getTrackDurationText() const { - return mixxx::Duration::formatSeconds(getTrackDuration(), mixxx::Duration::Precision::SECONDS); + return mixxx::Duration::formatTime(getTrackDuration(), mixxx::Duration::Precision::SECONDS); } private: diff --git a/src/preferences/dialog/dlgprefdeck.cpp b/src/preferences/dialog/dlgprefdeck.cpp index 937d3104e02c..f7ad5ed612fd 100644 --- a/src/preferences/dialog/dlgprefdeck.cpp +++ b/src/preferences/dialog/dlgprefdeck.cpp @@ -19,6 +19,7 @@ #include "control/controlobject.h" #include "mixxx.h" #include "defs_urls.h" +#include "util/duration.h" namespace { constexpr int kDefaultRateRangePercent = 8; @@ -82,30 +83,74 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, // If not present in the config, set the default value if (!m_pConfig->exists(ConfigKey("[Controls]","PositionDisplay"))) { m_pConfig->set(ConfigKey("[Controls]","PositionDisplay"), - QString::number(static_cast(TrackTime::DisplayMode::Remaining))); + QString::number(static_cast(TrackTime::DisplayMode::REMAINING))); } double positionDisplayType = m_pConfig->getValue( ConfigKey("[Controls]", "PositionDisplay"), - static_cast(TrackTime::DisplayMode::Elapsed)); + static_cast(TrackTime::DisplayMode::ELAPSED)); if (positionDisplayType == - static_cast(TrackTime::DisplayMode::Remaining)) { + static_cast(TrackTime::DisplayMode::REMAINING)) { radioButtonRemaining->setChecked(true); m_pControlTrackTimeDisplay->set( - static_cast(TrackTime::DisplayMode::Remaining)); + static_cast(TrackTime::DisplayMode::REMAINING)); } else if (positionDisplayType == - static_cast(TrackTime::DisplayMode::ElapsedAndRemaining)) { + static_cast(TrackTime::DisplayMode::ELAPSED_AND_REMAINING)) { radioButtonElapsedAndRemaining->setChecked(true); m_pControlTrackTimeDisplay->set( - static_cast(TrackTime::DisplayMode::ElapsedAndRemaining)); + static_cast(TrackTime::DisplayMode::ELAPSED_AND_REMAINING)); } else { radioButtonElapsed->setChecked(true); m_pControlTrackTimeDisplay->set( - static_cast(TrackTime::DisplayMode::Elapsed)); + static_cast(TrackTime::DisplayMode::ELAPSED)); } connect(buttonGroupTrackTime, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(slotSetTrackTimeDisplay(QAbstractButton *))); + // display time format + + m_pControlTrackTimeFormat = new ControlObject( + ConfigKey("[Controls]", "TimeFormat")); + connect(m_pControlTrackTimeDisplay, SIGNAL(valueChanged(double)), + this, SLOT(slotTimeFormatChanged(double))); + + QLocale locale; + // Track Display model + comboBoxTimeFormat->clear(); + + comboBoxTimeFormat->addItem(tr("mm:ss%1zz - Traditional") + .arg(mixxx::DurationBase::kDecimalSeparator), + static_cast + (TrackTime::DisplayFormat::TRADITIONAL)); + + comboBoxTimeFormat->addItem(tr("mm:ss - Traditional (Coarse)"), + static_cast + (TrackTime::DisplayFormat::TRADITIONAL_COARSE)); + + comboBoxTimeFormat->addItem(tr("s%1zz - Seconds") + .arg(mixxx::DurationBase::kDecimalSeparator), + static_cast + (TrackTime::DisplayFormat::SECONDS)); + + comboBoxTimeFormat->addItem(tr("sss%1zz - Seconds (Long)") + .arg(mixxx::DurationBase::kDecimalSeparator), + static_cast + (TrackTime::DisplayFormat::SECONDS_LONG)); + + comboBoxTimeFormat->addItem(tr("s%1sss%2zz - Kiloseconds") + .arg(QString(mixxx::DurationBase::kDecimalSeparator), + QString(mixxx::DurationBase::kKiloGroupSeparator)), + static_cast + (TrackTime::DisplayFormat::KILO_SECONDS)); + + double time_format = static_cast( + m_pConfig->getValue( + ConfigKey("[Controls]", "TimeFormat"), + static_cast(TrackTime::DisplayFormat::TRADITIONAL))); + m_pControlTrackTimeFormat->set(time_format); + comboBoxTimeFormat->setCurrentIndex( + comboBoxTimeFormat->findData(time_format)); + // Override Playing Track on Track Load // The check box reflects the opposite of the config value m_bDisallowTrackLoadToPlayingDeck = !m_pConfig->getValue( @@ -447,20 +492,20 @@ void DlgPrefDeck::slotJumpToCueOnTrackLoadCheckbox(bool checked) { void DlgPrefDeck::slotSetTrackTimeDisplay(QAbstractButton* b) { if (b == radioButtonRemaining) { - m_timeDisplayMode = TrackTime::DisplayMode::Remaining; + m_timeDisplayMode = TrackTime::DisplayMode::REMAINING; } else if (b == radioButtonElapsedAndRemaining) { - m_timeDisplayMode = TrackTime::DisplayMode::ElapsedAndRemaining; + m_timeDisplayMode = TrackTime::DisplayMode::ELAPSED_AND_REMAINING; } else { - m_timeDisplayMode = TrackTime::DisplayMode::Elapsed; + m_timeDisplayMode = TrackTime::DisplayMode::ELAPSED; } } void DlgPrefDeck::slotSetTrackTimeDisplay(double v) { m_timeDisplayMode = static_cast(static_cast(v)); m_pConfig->set(ConfigKey("[Controls]","PositionDisplay"), ConfigValue(v)); - if (m_timeDisplayMode == TrackTime::DisplayMode::Remaining) { + if (m_timeDisplayMode == TrackTime::DisplayMode::REMAINING) { radioButtonRemaining->setChecked(true); - } else if (m_timeDisplayMode == TrackTime::DisplayMode::ElapsedAndRemaining) { + } else if (m_timeDisplayMode == TrackTime::DisplayMode::ELAPSED_AND_REMAINING) { radioButtonElapsedAndRemaining->setChecked(true); } else { // Elapsed radioButtonElapsed->setChecked(true); @@ -495,11 +540,23 @@ void DlgPrefDeck::slotRateRampingModeLinearButton(bool checked) { } } +void DlgPrefDeck::slotTimeFormatChanged(double v) { + int i = static_cast(v); + m_pConfig->set(ConfigKey("[Controls]","TimeFormat"), ConfigValue(v)); + comboBoxTimeFormat->setCurrentIndex( + comboBoxTimeFormat->findData(i)); +} + void DlgPrefDeck::slotApply() { double timeDisplay = static_cast(m_timeDisplayMode); m_pConfig->set(ConfigKey("[Controls]","PositionDisplay"), ConfigValue(timeDisplay)); m_pControlTrackTimeDisplay->set(timeDisplay); + // time format + double timeFormat = comboBoxTimeFormat->itemData(comboBoxTimeFormat->currentIndex()).toDouble(); + m_pControlTrackTimeFormat->set(timeFormat); + m_pConfig->setValue(ConfigKey("[Controls]", "TimeFormat"), timeFormat); + // Set cue mode for every deck for (ControlProxy* pControl : m_cueControls) { pControl->set(m_iCueMode); diff --git a/src/preferences/dialog/dlgprefdeck.h b/src/preferences/dialog/dlgprefdeck.h index 10788e02d2cf..ebc77ce2a7db 100644 --- a/src/preferences/dialog/dlgprefdeck.h +++ b/src/preferences/dialog/dlgprefdeck.h @@ -18,9 +18,18 @@ class ControlObject; namespace TrackTime { enum class DisplayMode { - Elapsed, - Remaining, - ElapsedAndRemaining, + ELAPSED, + REMAINING, + ELAPSED_AND_REMAINING, + }; + + enum class DisplayFormat { + TRADITIONAL, + TRADITIONAL_COARSE, + SECONDS, + SECONDS_LONG, + KILO_SECONDS, + HECTO_SECONDS, }; } @@ -67,6 +76,8 @@ class DlgPrefDeck : public DlgPreferencePage, public Ui::DlgPrefDeckDlg { void slotRateRampingModeLinearButton(bool); void slotRateRampSensitivitySlider(int); + void slotTimeFormatChanged(double); + void slotNumDecksChanged(double, bool initializing=false); void slotNumSamplersChanged(double, bool initializing=false); @@ -85,6 +96,7 @@ class DlgPrefDeck : public DlgPreferencePage, public Ui::DlgPrefDeckDlg { UserSettingsPointer m_pConfig; ControlObject* m_pControlTrackTimeDisplay; + ControlObject* m_pControlTrackTimeFormat; ControlProxy* m_pNumDecks; ControlProxy* m_pNumSamplers; QList m_cueControls; diff --git a/src/preferences/dialog/dlgprefdeckdlg.ui b/src/preferences/dialog/dlgprefdeckdlg.ui index 35712d80e95d..4fa7b1b9f2f7 100644 --- a/src/preferences/dialog/dlgprefdeckdlg.ui +++ b/src/preferences/dialog/dlgprefdeckdlg.ui @@ -20,41 +20,16 @@ Deck options - - + + 10 + + + - Cue mode - - - true + Auto cue - ComboBoxCueMode - - - - - - - Mixxx mode: -- Cue button while pause at cue point = preview -- Cue button while pause not at cue point = set cue point -- Cue button while playing = pause at cue point -Mixxx mode (no blinking): -- Same as Mixxx mode but with no blinking indicators -Pioneer mode: -- Same as Mixxx mode with a flashing play button -Denon mode: -- Cue button at cue point = preview -- Cue button not at cue point = pause at cue point -- Play = set cue point -Numark mode: -- Same as Denon mode, but without a flashing play button -CUP mode: -- Cue button while pause at cue point = play after release -- Cue button while pause not at cue point = set cue point and play after release -- Cue button while playing = go to cue point and play after release - + checkBoxSeekToCue @@ -77,6 +52,24 @@ CUP mode: + + + + Do not load tracks into playing decks + + + + + + + Automatically seeks to the first saved cue point on track load. + If none exists, seeks to the beginning of the track. + + + Jump to main cue point on track load + + + @@ -111,44 +104,64 @@ CUP mode: - - + + - Auto cue + Cue mode + + + true - checkBoxSeekToCue + ComboBoxCueMode - - + + - Automatically seeks to the first saved cue point on track load. - If none exists, seeks to the beginning of the track. - - - Jump to main cue point on track load + Mixxx mode: +- Cue button while pause at cue point = preview +- Cue button while pause not at cue point = set cue point +- Cue button while playing = pause at cue point +Mixxx mode (no blinking): +- Same as Mixxx mode but with no blinking indicators +Pioneer mode: +- Same as Mixxx mode with a flashing play button +Denon mode: +- Cue button at cue point = preview +- Cue button not at cue point = pause at cue point +- Play = set cue point +Numark mode: +- Same as Denon mode, but without a flashing play button +CUP mode: +- Cue button while pause at cue point = play after release +- Cue button while pause not at cue point = set cue point and play after release +- Cue button while playing = go to cue point and play after release + - + - Playing track protection + Pla&ying track protection checkBoxDisallowLoadToPlayingDeck - - + + - Do not load tracks into playing decks + Time Format + + + @@ -755,13 +768,13 @@ CUP mode: - - false + + diff --git a/src/test/durationutiltest.cpp b/src/test/durationutiltest.cpp index 7fec8b61f145..149b4b31ff54 100644 --- a/src/test/durationutiltest.cpp +++ b/src/test/durationutiltest.cpp @@ -25,6 +25,23 @@ class DurationUtilTest : public testing::Test { } } + void formatTime(QString expectedMilliseconds, double dSeconds) { + ASSERT_LE(4, expectedMilliseconds.length()); // 3 digits + 1 decimal point + const QString actualSeconds = + mixxx::Duration::formatTime(dSeconds, mixxx::Duration::Precision::SECONDS); + const QString expectedSeconds = + adjustPrecision(expectedMilliseconds, mixxx::Duration::Precision::SECONDS); + EXPECT_EQ(expectedSeconds, actualSeconds); + const QString expectedCentiseconds = + adjustPrecision(expectedMilliseconds, mixxx::Duration::Precision::CENTISECONDS); + const QString actualCentiseconds = + mixxx::Duration::formatTime(dSeconds, mixxx::Duration::Precision::CENTISECONDS); + EXPECT_EQ(expectedCentiseconds, actualCentiseconds); + const QString actualMilliseconds = + mixxx::Duration::formatTime(dSeconds, mixxx::Duration::Precision::MILLISECONDS); + EXPECT_EQ(actualMilliseconds, actualMilliseconds); + } + void formatSeconds(QString expectedMilliseconds, double dSeconds) { ASSERT_LE(4, expectedMilliseconds.length()); // 3 digits + 1 decimal point const QString actualSeconds = @@ -41,24 +58,91 @@ class DurationUtilTest : public testing::Test { mixxx::Duration::formatSeconds(dSeconds, mixxx::Duration::Precision::MILLISECONDS); EXPECT_EQ(actualMilliseconds, actualMilliseconds); } + + void formatSecondsLong(QString expectedMilliseconds, double dSeconds) { + ASSERT_LE(4, expectedMilliseconds.length()); // 3 digits + 1 decimal point + const QString actualSeconds = + mixxx::Duration::formatSecondsLong(dSeconds, mixxx::Duration::Precision::SECONDS); + const QString expectedSeconds = + adjustPrecision(expectedMilliseconds, mixxx::Duration::Precision::SECONDS); + EXPECT_EQ(expectedSeconds, actualSeconds); + const QString expectedCentiseconds = + adjustPrecision(expectedMilliseconds, mixxx::Duration::Precision::CENTISECONDS); + const QString actualCentiseconds = + mixxx::Duration::formatSecondsLong(dSeconds, mixxx::Duration::Precision::CENTISECONDS); + EXPECT_EQ(expectedCentiseconds, actualCentiseconds); + const QString actualMilliseconds = + mixxx::Duration::formatSecondsLong(dSeconds, mixxx::Duration::Precision::MILLISECONDS); + EXPECT_EQ(actualMilliseconds, actualMilliseconds); + } + + void formatKiloSeconds(QString expectedMilliseconds, double dSeconds) { + ASSERT_LE(4, expectedMilliseconds.length()); // 3 digits + 1 decimal point + const QString actualSeconds = + mixxx::Duration::formatKiloSeconds(dSeconds, mixxx::Duration::Precision::SECONDS); + const QString expectedSeconds = + adjustPrecision(expectedMilliseconds, mixxx::Duration::Precision::SECONDS); + EXPECT_EQ(expectedSeconds, actualSeconds); + const QString expectedCentiseconds = + adjustPrecision(expectedMilliseconds, mixxx::Duration::Precision::CENTISECONDS); + const QString actualCentiseconds = + mixxx::Duration::formatKiloSeconds(dSeconds, mixxx::Duration::Precision::CENTISECONDS); + EXPECT_EQ(expectedCentiseconds, actualCentiseconds); + const QString actualMilliseconds = + mixxx::Duration::formatKiloSeconds(dSeconds, mixxx::Duration::Precision::MILLISECONDS); + EXPECT_EQ(actualMilliseconds, actualMilliseconds); + } }; TEST_F(DurationUtilTest, FormatSecondsNegative) { - EXPECT_EQ("?", mixxx::Duration::formatSeconds(-1, mixxx::Duration::Precision::SECONDS)); - EXPECT_EQ("?", mixxx::Duration::formatSeconds(-1, mixxx::Duration::Precision::CENTISECONDS)); - EXPECT_EQ("?", mixxx::Duration::formatSeconds(-1, mixxx::Duration::Precision::MILLISECONDS)); + EXPECT_EQ("?", mixxx::Duration::formatTime(-1, mixxx::Duration::Precision::SECONDS)); + EXPECT_EQ("?", mixxx::Duration::formatTime(-1, mixxx::Duration::Precision::CENTISECONDS)); + EXPECT_EQ("?", mixxx::Duration::formatTime(-1, mixxx::Duration::Precision::MILLISECONDS)); +} + +TEST_F(DurationUtilTest, formatTime) { + formatTime("00:00.000", 0); + formatTime("00:01.000", 1); + formatTime("00:59.000", 59); + formatTime("01:00.000", 60); + formatTime("01:01.123", 61.1234); + formatTime("59:59.999", 3599.999); + formatTime("01:00:00.000", 3600); + formatTime("23:59:59.000", 24 * 3600 - 1); + formatTime("24:00:00.000", 24 * 3600); + formatTime("24:00:01.000", 24 * 3600 + 1); + formatTime("25:00:01.000", 25 * 3600 + 1); +} + +TEST_F(DurationUtilTest, formatSeconds) { + formatSeconds("0.000", 0); + formatSeconds("1.000", 1); + formatSeconds("59.000", 59); + formatSeconds("60.000", 60); + formatSeconds("321.123", 321.1234); +} + +TEST_F(DurationUtilTest, formatSecondsLong) { + formatSecondsLong("000.000", 0); + formatSecondsLong("001.000", 1); + formatSecondsLong("059.000", 59); + formatSecondsLong("321.123", 321.1234); + formatSecondsLong("321.124", 321.1235); + formatSecondsLong("4321.123", 4321.1234); } -TEST_F(DurationUtilTest, FormatSeconds) { - formatSeconds("00:00.000", 0); - formatSeconds("00:01.000", 1); - formatSeconds("00:59.000", 59); - formatSeconds("01:00.000", 60); - formatSeconds("01:01.123", 61.1234); - formatSeconds("59:59.999", 3599.999); - formatSeconds("01:00:00.000", 3600); - formatSeconds("23:59:59.000", 24 * 3600 - 1); - formatSeconds("1d, 00:00:00.000", 24 * 3600); + +TEST_F(DurationUtilTest, FormatKiloSeconds) { + formatKiloSeconds(QString::fromUtf8("0.000\u2009000"), 0); + formatKiloSeconds(QString::fromUtf8("0.001\u2009000"), 1); + formatKiloSeconds(QString::fromUtf8("0.001\u2009490"), 1.49); + formatKiloSeconds(QString::fromUtf8("0.059\u2009000"), 59); + formatKiloSeconds(QString::fromUtf8("0.061\u2009123"), 61.1234); + formatKiloSeconds(QString::fromUtf8("0.999\u2009990"), 999.99); + formatKiloSeconds(QString::fromUtf8("1.000\u2009000"), 1000.00); + formatKiloSeconds(QString::fromUtf8("86.400\u2009000"), 24 * 3600); } + + } // anonymous namespace diff --git a/src/track/track.cpp b/src/track/track.cpp index b86d8c0dc00d..4581718469b9 100644 --- a/src/track/track.cpp +++ b/src/track/track.cpp @@ -459,7 +459,7 @@ QString Track::getDurationText(mixxx::Duration::Precision precision) const { } else { duration = getDuration(DurationRounding::NONE); } - return mixxx::Duration::formatSeconds(duration, precision); + return mixxx::Duration::formatTime(duration, precision); } QString Track::getTitle() const { diff --git a/src/util/duration.cpp b/src/util/duration.cpp index d050b55b22ae..198e124ba6e0 100644 --- a/src/util/duration.cpp +++ b/src/util/duration.cpp @@ -18,10 +18,17 @@ static const qint64 kSecondsPerDay = 24 * kSecondsPerHour; } // namespace // static -QString DurationBase::formatSeconds(double dSeconds, Precision precision) { +const QString DurationBase::kInvalidDurationString = "?"; +// Unicode for thin space +QChar DurationBase::kKiloGroupSeparator = QChar(0x2009); +// Unicode for decimal point +QChar DurationBase::kDecimalSeparator = QChar(0x002E); + +// static +QString DurationBase::formatTime(double dSeconds, Precision precision) { if (dSeconds < 0.0) { // negative durations are not supported - return "?"; + return kInvalidDurationString; } const qint64 days = static_cast(std::floor(dSeconds)) / kSecondsPerDay; @@ -32,12 +39,86 @@ QString DurationBase::formatSeconds(double dSeconds, Precision precision) { QTime t = QTime(0, 0).addMSecs(dSeconds * kMillisPerSecond); QString formatString = - (days > 0 ? (QString::number(days) % - QLatin1String("'d', ")) : QString()) % - QLatin1String(days > 0 || t.hour() > 0 ? "hh:mm:ss" : "mm:ss") % + QLatin1String(t.hour() > 0 && days < 1 ? "hh:mm:ss" : "mm:ss") % QLatin1String(Precision::SECONDS == precision ? "" : ".zzz"); QString durationString = t.toString(formatString); + if (days > 0) { + durationString = QString("%1:").arg(days * 24 + t.hour()) % durationString; + } + + // The format string gives us milliseconds but we want + // centiseconds. Slice one character off. + if (Precision::CENTISECONDS == precision) { + DEBUG_ASSERT(1 <= durationString.length()); + durationString = durationString.left(durationString.length() - 1); + } + + return durationString; +} + +// static +QString DurationBase::formatSeconds(double dSeconds, Precision precision) { + if (dSeconds < 0.0) { + // negative durations are not supported + return kInvalidDurationString; + } + + QString durationString; + + if (Precision::CENTISECONDS == precision) { + durationString = QString::number(dSeconds, 'f', 2); + } else if (Precision::MILLISECONDS == precision) { + durationString = QString::number(dSeconds, 'f', 3); + } else { + durationString = QString::number(dSeconds, 'f', 0); + } + + return durationString; +} + +// static +QString DurationBase::formatSecondsLong(double dSeconds, Precision precision) { + if (dSeconds < 0.0) { + // negative durations are not supported + return kInvalidDurationString; + } + + QString durationString; + + if (Precision::CENTISECONDS == precision) { + durationString = QString::number(dSeconds, 'f', 2) + .rightJustified(6, QLatin1Char('0')); + } else if (Precision::MILLISECONDS == precision) { + durationString = QString::number(dSeconds, 'f', 3) + .rightJustified(7, QLatin1Char('0')); + } else { + durationString = QString::number(dSeconds, 'f', 0) + .rightJustified(3, QLatin1Char('0')); + } + + return durationString; +} + +// static +QString DurationBase::formatKiloSeconds(double dSeconds, Precision precision) { + if (dSeconds < 0.0) { + // negative durations are not supported + return kInvalidDurationString; + } + + int kilos = (int)dSeconds / 1000; + double seconds = floor(fmod(dSeconds, 1000)); + double subs = fmod(dSeconds, 1); + + QString durationString = + QString("%1%2%3").arg( + QString::number(kilos), + QString(kDecimalSeparator), + QString::number(seconds).rightJustified(3, QLatin1Char('0'))); + if (Precision::SECONDS != precision) { + durationString += kKiloGroupSeparator % QString::number(subs, 'f', 3).right(3); + } // The format string gives us milliseconds but we want // centiseconds. Slice one character off. diff --git a/src/util/duration.h b/src/util/duration.h index 075a30607bee..0d933f9032b2 100644 --- a/src/util/duration.h +++ b/src/util/duration.h @@ -14,6 +14,7 @@ namespace mixxx { class DurationBase { public: + enum Units { SECONDS, MILLIS, @@ -70,15 +71,29 @@ class DurationBase { // The standard way of formatting a floating-point duration in seconds. // Used for display of track duration, etc. + static QString formatTime( + double dSeconds, + Precision precision = Precision::SECONDS); + // Alternative format for duration based on seconds static QString formatSeconds( double dSeconds, Precision precision = Precision::SECONDS); + static QString formatSecondsLong( + double dSeconds, + Precision precision = Precision::SECONDS); + static QString formatKiloSeconds( + double dSeconds, + Precision precision = Precision::SECONDS); static constexpr qint64 kMillisPerSecond = 1000; static constexpr qint64 kMicrosPerSecond = kMillisPerSecond * 1000; static constexpr qint64 kNanosPerSecond = kMicrosPerSecond * 1000; static constexpr qint64 kNanosPerMilli = kNanosPerSecond / 1000; static constexpr qint64 kNanosPerMicro = kNanosPerMilli / 1000; + static const QString kInvalidDurationString; + static QChar kKiloGroupSeparator; + static QChar kHectoGroupSeparator; + static QChar kDecimalSeparator; protected: explicit DurationBase(qint64 durationNanos) diff --git a/src/widget/wnumberpos.cpp b/src/widget/wnumberpos.cpp index f7f833bcdf48..109d58f458f5 100644 --- a/src/widget/wnumberpos.cpp +++ b/src/widget/wnumberpos.cpp @@ -14,12 +14,20 @@ WNumberPos::WNumberPos(const char* group, QWidget* parent) m_pTimeElapsed = new ControlProxy(group, "time_elapsed", this); m_pTimeElapsed->connectValueChanged(this, &WNumberPos::slotSetTimeElapsed); m_pTimeRemaining = new ControlProxy(group, "time_remaining", this); - m_pTimeRemaining->connectValueChanged(this, &WNumberPos::slotTimeRemainingUpdated); + m_pTimeRemaining->connectValueChanged( + this, &WNumberPos::slotTimeRemainingUpdated); m_pShowTrackTimeRemaining = new ControlProxy( "[Controls]", "ShowDurationRemaining", this); - m_pShowTrackTimeRemaining->connectValueChanged(this, &WNumberPos::slotSetDisplayMode); + m_pShowTrackTimeRemaining->connectValueChanged( + this, &WNumberPos::slotSetDisplayMode); slotSetDisplayMode(m_pShowTrackTimeRemaining->get()); + + m_pTimeFormat = new ControlProxy( + "[Controls]", "TimeFormat", this); + m_pTimeFormat->connectValueChanged( + this, &WNumberPos::slotSetTimeFormat); + slotSetTimeFormat(m_pTimeFormat->get()); } void WNumberPos::mousePressEvent(QMouseEvent* pEvent) { @@ -27,12 +35,12 @@ void WNumberPos::mousePressEvent(QMouseEvent* pEvent) { if (leftClick) { // Cycle through display modes - if (m_displayMode == TrackTime::DisplayMode::Elapsed) { - m_displayMode = TrackTime::DisplayMode::Remaining; - } else if (m_displayMode == TrackTime::DisplayMode::Remaining) { - m_displayMode = TrackTime::DisplayMode::ElapsedAndRemaining; - } else if (m_displayMode == TrackTime::DisplayMode::ElapsedAndRemaining) { - m_displayMode = TrackTime::DisplayMode::Elapsed; + if (m_displayMode == TrackTime::DisplayMode::ELAPSED) { + m_displayMode = TrackTime::DisplayMode::REMAINING; + } else if (m_displayMode == TrackTime::DisplayMode::REMAINING) { + m_displayMode = TrackTime::DisplayMode::ELAPSED_AND_REMAINING; + } else if (m_displayMode == TrackTime::DisplayMode::ELAPSED_AND_REMAINING) { + m_displayMode = TrackTime::DisplayMode::ELAPSED; } m_pShowTrackTimeRemaining->set(static_cast(m_displayMode)); @@ -50,31 +58,40 @@ void WNumberPos::setValue(double dValue) { void WNumberPos::slotSetTimeElapsed(double dTimeElapsed) { double dTimeRemaining = m_pTimeRemaining->get(); + QString (*timeFormat)(double dSeconds, mixxx::Duration::Precision precision); + + if (m_displayFormat == TrackTime::DisplayFormat::KILO_SECONDS) { + timeFormat = &mixxx::Duration::formatKiloSeconds; + } else if (m_displayFormat == TrackTime::DisplayFormat::SECONDS_LONG) { + timeFormat = &mixxx::Duration::formatSecondsLong; + } else if (m_displayFormat == TrackTime::DisplayFormat::SECONDS) { + timeFormat = &mixxx::Duration::formatSeconds; + } else { + timeFormat = &mixxx::Duration::formatTime; + } + + mixxx::Duration::Precision precision; + if (m_displayFormat != TrackTime::DisplayFormat::TRADITIONAL_COARSE) { + precision = mixxx::Duration::Precision::CENTISECONDS; + } else { + precision = mixxx::Duration::Precision::SECONDS; + } - if (m_displayMode == TrackTime::DisplayMode::Elapsed) { + if (m_displayMode == TrackTime::DisplayMode::ELAPSED) { if (dTimeElapsed >= 0.0) { - setText(mixxx::Duration::formatSeconds( - dTimeElapsed, mixxx::Duration::Precision::CENTISECONDS)); + setText(timeFormat(dTimeElapsed, precision)); } else { - setText(QLatin1String("-") % mixxx::Duration::formatSeconds( - -dTimeElapsed, mixxx::Duration::Precision::CENTISECONDS)); + setText(QLatin1String("-") % timeFormat(-dTimeElapsed, precision)); } - } else if (m_displayMode == TrackTime::DisplayMode::Remaining) { - setText(QLatin1String("-") % mixxx::Duration::formatSeconds( - dTimeRemaining, mixxx::Duration::Precision::CENTISECONDS)); - } else if (m_displayMode == TrackTime::DisplayMode::ElapsedAndRemaining) { + } else if (m_displayMode == TrackTime::DisplayMode::REMAINING) { + setText(QLatin1String("-") % timeFormat(dTimeRemaining, precision)); + } else if (m_displayMode == TrackTime::DisplayMode::ELAPSED_AND_REMAINING) { if (dTimeElapsed >= 0.0) { - setText(mixxx::Duration::formatSeconds( - dTimeElapsed, mixxx::Duration::Precision::CENTISECONDS) - % QLatin1String(" -") % - mixxx::Duration::formatSeconds( - dTimeRemaining, mixxx::Duration::Precision::CENTISECONDS)); + setText(timeFormat(dTimeElapsed, precision) + % QLatin1String(" -") % timeFormat(dTimeRemaining, precision)); } else { - setText(QLatin1String("-") % mixxx::Duration::formatSeconds( - -dTimeElapsed, mixxx::Duration::Precision::CENTISECONDS) - % QLatin1String(" -") % - mixxx::Duration::formatSeconds( - dTimeRemaining, mixxx::Duration::Precision::CENTISECONDS)); + setText(QLatin1String("-") % timeFormat(-dTimeElapsed, precision) + % QLatin1String(" -") % timeFormat(dTimeRemaining, precision)); } } m_dOldTimeElapsed = dTimeElapsed; @@ -93,12 +110,17 @@ void WNumberPos::slotTimeRemainingUpdated(double dTimeRemaining) { void WNumberPos::slotSetDisplayMode(double remain) { if (remain == 1.0) { - m_displayMode = TrackTime::DisplayMode::Remaining; + m_displayMode = TrackTime::DisplayMode::REMAINING; } else if (remain == 2.0) { - m_displayMode = TrackTime::DisplayMode::ElapsedAndRemaining; + m_displayMode = TrackTime::DisplayMode::ELAPSED_AND_REMAINING; } else { - m_displayMode = TrackTime::DisplayMode::Elapsed; + m_displayMode = TrackTime::DisplayMode::ELAPSED; } slotSetTimeElapsed(m_dOldTimeElapsed); } +void WNumberPos::slotSetTimeFormat(double v) { + m_displayFormat = static_cast(static_cast(v)); + + slotSetTimeElapsed(m_dOldTimeElapsed); +} diff --git a/src/widget/wnumberpos.h b/src/widget/wnumberpos.h index c4023100ae22..03aac328df49 100644 --- a/src/widget/wnumberpos.h +++ b/src/widget/wnumberpos.h @@ -12,6 +12,7 @@ class ControlProxy; class WNumberPos : public WNumber { Q_OBJECT + public: explicit WNumberPos(const char *group, QWidget *parent=nullptr); @@ -23,15 +24,18 @@ class WNumberPos : public WNumber { void slotSetTimeElapsed(double); void slotTimeRemainingUpdated(double); void slotSetDisplayMode(double); + void slotSetTimeFormat(double); private: TrackTime::DisplayMode m_displayMode; + TrackTime::DisplayFormat m_displayFormat; double m_dOldTimeElapsed; ControlProxy* m_pTimeElapsed; ControlProxy* m_pTimeRemaining; ControlProxy* m_pShowTrackTimeRemaining; + ControlProxy* m_pTimeFormat; }; #endif