diff options
author | Caolán McNamara <caolanm@redhat.com> | 2018-05-06 15:21:33 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2018-05-10 14:37:06 +0200 |
commit | 476ed0aed1c09055fa05209485919a026e5f014e (patch) | |
tree | 68c2cc8ca587dd7b47f97d800d32560339f546fc /vcl | |
parent | 7cee480efe22d48af9e9d96b49ad4358a4010690 (diff) |
weld SdStartPresentationDlg
to get duration spinbutton working need to know where the cursor
is in the spinbutton and to change the adjustment factor depending
on that, and need to additionally disable the vcl round to nearest base unit on
up/down
Change-Id: I6dd09e1639454cb4820d3aeb0c0c698fcebd417e
Reviewed-on: https://gerrit.libreoffice.org/54065
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/source/app/salvtables.cxx | 43 | ||||
-rw-r--r-- | vcl/source/control/field.cxx | 60 | ||||
-rw-r--r-- | vcl/source/control/field2.cxx | 242 | ||||
-rw-r--r-- | vcl/source/window/builder.cxx | 78 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkinst.cxx | 35 |
5 files changed, 327 insertions, 131 deletions
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 713e5acada9c..d5d613b892f1 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -1146,6 +1146,7 @@ private: VclPtr<Edit> m_xEntry; DECL_LINK(ChangeHdl, Edit&, void); + DECL_LINK(CursorListener, VclWindowEvent&, void); class WeldTextFilter : public TextFilter { @@ -1237,8 +1238,17 @@ public: m_xEntry->SetFont(rFont); } + virtual void connect_cursor_position(const Link<Entry&, void>& rLink) override + { + assert(!m_aCursorPositionHdl.IsSet()); + m_xEntry->AddEventListener(LINK(this, SalInstanceEntry, CursorListener)); + weld::Entry::connect_cursor_position(rLink); + } + virtual ~SalInstanceEntry() override { + if (m_aCursorPositionHdl.IsSet()) + m_xEntry->RemoveEventListener(LINK(this, SalInstanceEntry, CursorListener)); m_xEntry->SetTextFilter(nullptr); m_xEntry->SetModifyHdl(Link<Edit&, void>()); } @@ -1249,6 +1259,12 @@ IMPL_LINK_NOARG(SalInstanceEntry, ChangeHdl, Edit&, void) signal_changed(); } +IMPL_LINK(SalInstanceEntry, CursorListener, VclWindowEvent&, rEvent, void) +{ + if (rEvent.GetId() == VclEventId::EditSelectionChanged || rEvent.GetId() == VclEventId::EditCaretChanged) + signal_cursor_position(); +} + class SalInstanceTreeView : public SalInstanceContainer, public virtual weld::TreeView { private: @@ -1442,6 +1458,7 @@ private: DECL_LINK(UpDownHdl, SpinField&, void); DECL_LINK(LoseFocusHdl, Control&, void); DECL_LINK(OutputHdl, Edit&, bool); + DECL_LINK(InputHdl, sal_Int64*, TriState); public: SalInstanceSpinButton(NumericField* pButton, bool bTakeOwnership) @@ -1452,6 +1469,7 @@ public: m_xButton->SetDownHdl(LINK(this, SalInstanceSpinButton, UpDownHdl)); m_xButton->SetLoseFocusHdl(LINK(this, SalInstanceSpinButton, LoseFocusHdl)); m_xButton->SetOutputHdl(LINK(this, SalInstanceSpinButton, OutputHdl)); + m_xButton->SetInputHdl(LINK(this, SalInstanceSpinButton, InputHdl)); } virtual int get_value() const override @@ -1494,6 +1512,11 @@ public: m_xButton->SetDecimalDigits(digits); } + void DisableRemainderFactor() + { + m_xButton->DisableRemainderFactor(); + } + virtual unsigned int get_digits() const override { return m_xButton->GetDecimalDigits(); @@ -1501,6 +1524,7 @@ public: virtual ~SalInstanceSpinButton() override { + m_xButton->SetInputHdl(Link<sal_Int64*, TriState>()); m_xButton->SetOutputHdl(Link<Edit&, bool>()); m_xButton->SetLoseFocusHdl(Link<Control&, void>()); m_xButton->SetDownHdl(Link<SpinField&, void>()); @@ -1523,6 +1547,15 @@ IMPL_LINK_NOARG(SalInstanceSpinButton, OutputHdl, Edit&, bool) return signal_output(); } +IMPL_LINK(SalInstanceSpinButton, InputHdl, sal_Int64*, pResult, TriState) +{ + int nResult; + TriState eRet = signal_input(&nResult); + if (eRet == TRISTATE_TRUE) + *pResult = nResult; + return eRet; +} + class SalInstanceLabel : public SalInstanceWidget, public virtual weld::Label { private: @@ -2154,6 +2187,16 @@ public: return pSpinButton ? new SalInstanceSpinButton(pSpinButton, bTakeOwnership) : nullptr; } + virtual weld::TimeSpinButton* weld_time_spin_button(const OString& id, TimeFieldFormat eFormat, + bool bTakeOwnership) override + { + weld::TimeSpinButton* pRet = new weld::TimeSpinButton(weld_spin_button(id, bTakeOwnership), eFormat); + SalInstanceSpinButton* pButton = dynamic_cast<SalInstanceSpinButton*>(pRet->get_widget()); + assert(pButton); + pButton->DisableRemainderFactor(); //so with hh::mm::ss, incrementing mm will not reset ss + return pRet; + } + virtual weld::ComboBoxText* weld_combo_box_text(const OString &id, bool bTakeOwnership) override { vcl::Window* pComboBoxText = m_xBuilder->get<vcl::Window>(id); diff --git a/vcl/source/control/field.cxx b/vcl/source/control/field.cxx index 6221a6f688fa..1ebcfe95e9ad 100644 --- a/vcl/source/control/field.cxx +++ b/vcl/source/control/field.cxx @@ -452,12 +452,6 @@ void FormatterBase::ImplSetText( const OUString& rText, Selection const * pNewSe aSel.Min() = aSel.Max(); mpField->SetText(rText, aSel); } - if (maOutputHdl.IsSet()) - { - OUString sText(mpField->GetText()); - if (!maOutputHdl.Call(*mpField)) - mpField->SetText(sText); - } MarkToBeReformatted( false ); } } @@ -474,13 +468,18 @@ bool FormatterBase::IsEmptyFieldValue() const return (!mpField || mpField->GetText().isEmpty()); } -void NumericFormatter::ImplNumericReformat(sal_Int64& rValue, OUString& rOutStr) +void NumericFormatter::FormatValue(Selection const * pNewSelection) { - if (ImplNumericGetValue(GetField()->GetText(), rValue, GetDecimalDigits(), ImplGetLocaleDataWrapper())) - { - sal_Int64 nTempVal = ClipAgainstMinMax(rValue); - rOutStr = CreateFieldText( nTempVal ); - } + mbFormatting = true; + if (!m_aOutputHdl.IsSet() || !m_aOutputHdl.Call(*GetField())) + ImplSetText(CreateFieldText(mnLastValue), pNewSelection); + mbFormatting = false; +} + +void NumericFormatter::ImplNumericReformat() +{ + mnLastValue = GetValue(); + FormatValue(); } void NumericFormatter::ImplInit() @@ -495,6 +494,8 @@ void NumericFormatter::ImplInit() mbThousandSep = true; mbShowTrailingZeros = true; mbWrapOnLimits = false; + mbFormatting = false; + mbDisableRemainderFactor = false; // for fields mnSpinSize = 1; @@ -567,7 +568,7 @@ void NumericFormatter::ImplSetUserValue( sal_Int64 nNewValue, Selection const * mnLastValue = nNewValue; if ( GetField() ) - ImplSetText( CreateFieldText( nNewValue ), pNewSelection ); + FormatValue(pNewSelection); } void NumericFormatter::SetUserValue( sal_Int64 nNewValue ) @@ -590,6 +591,22 @@ sal_Int64 NumericFormatter::GetValueFromString(const OUString& rStr) const sal_Int64 NumericFormatter::GetValue() const { + if (mbFormatting) //don't parse the entry if we're currently formatting what to put in it + return mnLastValue; + + if (m_aInputHdl.IsSet()) + { + sal_Int64 nResult; + TriState eState = m_aInputHdl.Call(&nResult); + if (eState != TRISTATE_INDET) + { + if (eState == TRISTATE_TRUE) + return ClipAgainstMinMax(nResult); + else + return mnLastValue; + } + } + return GetField() ? GetValueFromString(GetField()->GetText()) : 0; } @@ -643,21 +660,18 @@ void NumericFormatter::Reformat() if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() ) return; - OUString aStr; - sal_Int64 nTemp = mnLastValue; - ImplNumericReformat(nTemp, aStr); - mnLastValue = nTemp; + ImplNumericReformat(); +} - if ( !aStr.isEmpty() ) - ImplSetText( aStr ); - else - SetValue( mnLastValue ); +void NumericFormatter::DisableRemainderFactor() +{ + mbDisableRemainderFactor = true; } void NumericFormatter::FieldUp() { sal_Int64 nValue = GetValue(); - sal_Int64 nRemainder = nValue % mnSpinSize; + sal_Int64 nRemainder = mbDisableRemainderFactor ? 0 : (nValue % mnSpinSize); if (nValue >= 0) nValue = (nRemainder == 0) ? nValue + mnSpinSize : nValue + mnSpinSize - nRemainder; else @@ -671,7 +685,7 @@ void NumericFormatter::FieldUp() void NumericFormatter::FieldDown() { sal_Int64 nValue = GetValue(); - sal_Int64 nRemainder = nValue % mnSpinSize; + sal_Int64 nRemainder = mbDisableRemainderFactor ? 0 : (nValue % mnSpinSize); if (nValue >= 0) nValue = (nRemainder == 0) ? nValue - mnSpinSize : nValue - nRemainder; else diff --git a/vcl/source/control/field2.cxx b/vcl/source/control/field2.cxx index dff8cee200b5..12a4e7dc4ff9 100644 --- a/vcl/source/control/field2.cxx +++ b/vcl/source/control/field2.cxx @@ -1964,9 +1964,8 @@ static bool ImplCutTimePortion( OUStringBuffer& _rStr, sal_Int32 _nSepPos, bool return true; } -static bool ImplTimeGetValue( const OUString& rStr, tools::Time& rTime, - TimeFieldFormat eFormat, bool bDuration, - const LocaleDataWrapper& rLocaleDataWrapper, bool _bSkipInvalidCharacters = true ) +bool TimeFormatter::TextToTime(const OUString& rStr, tools::Time& rTime, TimeFieldFormat eFormat, + bool bDuration, const LocaleDataWrapper& rLocaleDataWrapper, bool _bSkipInvalidCharacters) { OUStringBuffer aStr = rStr; short nHour = 0; @@ -2161,7 +2160,7 @@ static bool ImplTimeGetValue( const OUString& rStr, tools::Time& rTime, bool TimeFormatter::ImplTimeReformat( const OUString& rStr, OUString& rOutStr ) { tools::Time aTime( 0, 0, 0 ); - if ( !ImplTimeGetValue( rStr, aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() ) ) + if ( !TextToTime( rStr, aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() ) ) return true; tools::Time aTempTime = aTime; @@ -2211,81 +2210,102 @@ bool TimeFormatter::ImplTimeReformat( const OUString& rStr, OUString& rOutStr ) return true; } + bool TimeFormatter::ImplAllowMalformedInput() const { return !IsEnforceValidValue(); } -void TimeField::ImplTimeSpinArea( bool bUp ) +int TimeFormatter::GetTimeArea(TimeFieldFormat eFormat, const OUString& rText, int nCursor, + const LocaleDataWrapper& rLocaleDataWrapper) { - if ( GetField() ) - { - sal_Int32 nTimeArea = 0; - tools::Time aTime( GetTime() ); - OUString aText( GetText() ); - Selection aSelection( GetField()->GetSelection() ); + int nTimeArea = 0; - // Area search - if ( GetFormat() != TimeFieldFormat::F_SEC_CS ) + // Area search + if (eFormat != TimeFieldFormat::F_SEC_CS) + { + //Which area is the cursor in of HH:MM:SS.TT + for ( sal_Int32 i = 1, nPos = 0; i <= 4; i++ ) { - //Which area is the cursor in of HH:MM:SS.TT - for ( sal_Int32 i = 1, nPos = 0; i <= 4; i++ ) + sal_Int32 nPos1 = rText.indexOf(rLocaleDataWrapper.getTimeSep(), nPos); + sal_Int32 nPos2 = rText.indexOf(rLocaleDataWrapper.getTime100SecSep(), nPos); + //which ever comes first, bearing in mind that one might not be there + if (nPos1 >= 0 && nPos2 >= 0) + nPos = std::min(nPos1, nPos2); + else if (nPos1 >= 0) + nPos = nPos1; + else + nPos = nPos2; + if (nPos < 0 || nPos >= nCursor) { - sal_Int32 nPos1 = aText.indexOf( ImplGetLocaleDataWrapper().getTimeSep(), nPos ); - sal_Int32 nPos2 = aText.indexOf( ImplGetLocaleDataWrapper().getTime100SecSep(), nPos ); - //which ever comes first, bearing in mind that one might not be there - if (nPos1 >= 0 && nPos2 >= 0) - nPos = std::min(nPos1, nPos2); - else if (nPos1 >= 0) - nPos = nPos1; - else - nPos = nPos2; - if ( nPos < 0 || nPos >= aSelection.Max() ) - { - nTimeArea = i; - break; - } - else - nPos++; + nTimeArea = i; + break; } + else + nPos++; } + } + else + { + sal_Int32 nPos = rText.indexOf(rLocaleDataWrapper.getTime100SecSep()); + if (nPos < 0 || nPos >= nCursor) + nTimeArea = 3; else + nTimeArea = 4; + } + + return nTimeArea; +} + +tools::Time TimeFormatter::SpinTime(bool bUp, const tools::Time& rTime, TimeFieldFormat eFormat, + bool bDuration, const OUString& rText, int nCursor, + const LocaleDataWrapper& rLocaleDataWrapper) +{ + tools::Time aTime(rTime); + + int nTimeArea = GetTimeArea(eFormat, rText, nCursor, rLocaleDataWrapper); + + if ( nTimeArea ) + { + tools::Time aAddTime( 0, 0, 0 ); + if ( nTimeArea == 1 ) + aAddTime = tools::Time( 1, 0 ); + else if ( nTimeArea == 2 ) + aAddTime = tools::Time( 0, 1 ); + else if ( nTimeArea == 3 ) + aAddTime = tools::Time( 0, 0, 1 ); + else if ( nTimeArea == 4 ) + aAddTime = tools::Time( 0, 0, 0, 1 ); + + if ( !bUp ) + aAddTime = -aAddTime; + + aTime += aAddTime; + if (!bDuration) { - sal_Int32 nPos = aText.indexOf( ImplGetLocaleDataWrapper().getTime100SecSep() ); - if ( nPos < 0 || nPos >= aSelection.Max() ) - nTimeArea = 3; - else - nTimeArea = 4; + tools::Time aAbsMaxTime( 23, 59, 59, 999999999 ); + if ( aTime > aAbsMaxTime ) + aTime = aAbsMaxTime; + tools::Time aAbsMinTime( 0, 0 ); + if ( aTime < aAbsMinTime ) + aTime = aAbsMinTime; } + } - if ( nTimeArea ) - { - tools::Time aAddTime( 0, 0, 0 ); - if ( nTimeArea == 1 ) - aAddTime = tools::Time( 1, 0 ); - else if ( nTimeArea == 2 ) - aAddTime = tools::Time( 0, 1 ); - else if ( nTimeArea == 3 ) - aAddTime = tools::Time( 0, 0, 1 ); - else if ( nTimeArea == 4 ) - aAddTime = tools::Time( 0, 0, 0, 1 ); + return aTime; +} - if ( !bUp ) - aAddTime = -aAddTime; +void TimeField::ImplTimeSpinArea( bool bUp ) +{ + if ( GetField() ) + { + tools::Time aTime( GetTime() ); + OUString aText( GetText() ); + Selection aSelection( GetField()->GetSelection() ); - aTime += aAddTime; - if ( !IsDuration() ) - { - tools::Time aAbsMaxTime( 23, 59, 59, 999999999 ); - if ( aTime > aAbsMaxTime ) - aTime = aAbsMaxTime; - tools::Time aAbsMinTime( 0, 0 ); - if ( aTime < aAbsMinTime ) - aTime = aAbsMinTime; - } - ImplNewFieldValue( aTime ); - } + aTime = TimeFormatter::SpinTime(bUp, aTime, GetFormat(), IsDuration(), aText, aSelection.Max(), ImplGetLocaleDataWrapper()); + ImplNewFieldValue( aTime ); } } @@ -2329,7 +2349,7 @@ void TimeFormatter::SetMax( const tools::Time& rNewMax ) ReformatAll(); } -void TimeFormatter::SetTimeFormat( TimeFormatter::TimeFormat eNewFormat ) +void TimeFormatter::SetTimeFormat( TimeFormat eNewFormat ) { mnTimeFormat = eNewFormat; } @@ -2383,6 +2403,54 @@ void TimeFormatter::ImplNewFieldValue( const tools::Time& rTime ) } } +OUString TimeFormatter::FormatTime(const tools::Time& rNewTime, TimeFieldFormat eFormat, TimeFormat eHourFormat, bool bDuration, const LocaleDataWrapper& rLocaleData) +{ + OUString aStr; + bool bSec = false; + bool b100Sec = false; + if ( eFormat != TimeFieldFormat::F_NONE ) + bSec = true; + if ( eFormat == TimeFieldFormat::F_SEC_CS ) + b100Sec = true; + if ( eFormat == TimeFieldFormat::F_SEC_CS ) + { + sal_uLong n = rNewTime.GetHour() * 3600L; + n += rNewTime.GetMin() * 60L; + n += rNewTime.GetSec(); + aStr = OUString::number( n ); + aStr += rLocaleData.getTime100SecSep(); + std::ostringstream ostr; + ostr.fill('0'); + ostr.width(9); + ostr << rNewTime.GetNanoSec(); + aStr += OUString::createFromAscii(ostr.str().c_str()); + } + else if ( bDuration ) + { + aStr = rLocaleData.getDuration( rNewTime, bSec, b100Sec ); + } + else + { + aStr = rLocaleData.getTime( rNewTime, bSec, b100Sec ); + if ( eHourFormat == TimeFormat::Hour12 ) + { + if ( rNewTime.GetHour() > 12 ) + { + tools::Time aT( rNewTime ); + aT.SetHour( aT.GetHour() % 12 ); + aStr = rLocaleData.getTime( aT, bSec, b100Sec ); + } + // Don't use LocaleDataWrapper, we want AM/PM + if ( rNewTime.GetHour() < 12 ) + aStr += "AM"; // rLocaleData.getTimeAM(); + else + aStr += "PM"; // rLocaleData.getTimePM(); + } + } + + return aStr; +} + void TimeFormatter::ImplSetUserTime( const tools::Time& rNewTime, Selection const * pNewSelection ) { tools::Time aNewTime = rNewTime; @@ -2394,49 +2462,7 @@ void TimeFormatter::ImplSetUserTime( const tools::Time& rNewTime, Selection cons if ( GetField() ) { - OUString aStr; - bool bSec = false; - bool b100Sec = false; - if ( meFormat != TimeFieldFormat::F_NONE ) - bSec = true; - if ( meFormat == TimeFieldFormat::F_SEC_CS ) - b100Sec = true; - if ( meFormat == TimeFieldFormat::F_SEC_CS ) - { - sal_uLong n = aNewTime.GetHour() * 3600L; - n += aNewTime.GetMin() * 60L; - n += aNewTime.GetSec(); - aStr = OUString::number( n ); - aStr += ImplGetLocaleDataWrapper().getTime100SecSep(); - std::ostringstream ostr; - ostr.fill('0'); - ostr.width(9); - ostr << aNewTime.GetNanoSec(); - aStr += OUString::createFromAscii(ostr.str().c_str()); - } - else if ( mbDuration ) - { - aStr = ImplGetLocaleDataWrapper().getDuration( aNewTime, bSec, b100Sec ); - } - else - { - aStr = ImplGetLocaleDataWrapper().getTime( aNewTime, bSec, b100Sec ); - if ( GetTimeFormat() == TimeFormat::Hour12 ) - { - if ( aNewTime.GetHour() > 12 ) - { - tools::Time aT( aNewTime ); - aT.SetHour( aT.GetHour() % 12 ); - aStr = ImplGetLocaleDataWrapper().getTime( aT, bSec, b100Sec ); - } - // Don't use LocaleDataWrapper, we want AM/PM - if ( aNewTime.GetHour() < 12 ) - aStr += "AM"; // ImplGetLocaleDataWrapper().getTimeAM(); - else - aStr += "PM"; // ImplGetLocaleDataWrapper().getTimePM(); - } - } - + OUString aStr = TimeFormatter::FormatTime(aNewTime, meFormat, GetTimeFormat(), mbDuration, ImplGetLocaleDataWrapper()); ImplSetText( aStr, pNewSelection ); } } @@ -2453,7 +2479,7 @@ tools::Time TimeFormatter::GetTime() const if ( GetField() ) { bool bAllowMailformed = ImplAllowMalformedInput(); - if ( ImplTimeGetValue( GetField()->GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), !bAllowMailformed ) ) + if ( TextToTime( GetField()->GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), !bAllowMailformed ) ) { if ( aTime > GetMax() ) aTime = GetMax(); @@ -2488,7 +2514,7 @@ void TimeFormatter::Reformat() if ( !aStr.isEmpty() ) { ImplSetText( aStr ); - ImplTimeGetValue( aStr, maLastTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() ); + TextToTime( aStr, maLastTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() ); } else SetTime( maLastTime ); @@ -2534,7 +2560,7 @@ bool TimeField::EventNotify( NotifyEvent& rNEvt ) else { tools::Time aTime( 0, 0, 0 ); - if ( ImplTimeGetValue( GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), false ) ) + if ( TextToTime( GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), false ) ) // even with strict text analysis, our text is a valid time -> do a complete // reformat Reformat(); diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx index 1b6b7726cf38..72f41efad638 100644 --- a/vcl/source/window/builder.cxx +++ b/vcl/source/window/builder.cxx @@ -242,6 +242,84 @@ namespace weld { return MetricField::ConvertValue(nValue, 0, m_xSpinButton->get_digits(), eInUnit, eOutUnit); } + + IMPL_LINK_NOARG(TimeSpinButton, spin_button_cursor_position, Entry&, void) + { + int nStartPos, nEndPos; + m_xSpinButton->get_selection_bounds(nStartPos, nEndPos); + + const SvtSysLocale aSysLocale; + const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData(); + const int nTimeArea = TimeFormatter::GetTimeArea(m_eFormat, m_xSpinButton->get_text(), nEndPos, + rLocaleData); + + int nIncrements = 1; + + if (nTimeArea == 1) + nIncrements = 1000 * 60 * 60; + else if (nTimeArea == 2) + nIncrements = 1000 * 60; + else if (nTimeArea == 3) + nIncrements = 1000; + + m_xSpinButton->set_increments(nIncrements, nIncrements * 10); + } + + IMPL_LINK_NOARG(TimeSpinButton, spin_button_value_changed, SpinButton&, void) + { + signal_value_changed(); + } + + IMPL_LINK(TimeSpinButton, spin_button_output, SpinButton&, rSpinButton, void) + { + int nStartPos, nEndPos; + rSpinButton.get_selection_bounds(nStartPos, nEndPos); + rSpinButton.set_text(format_number(rSpinButton.get_value())); + rSpinButton.set_position(nEndPos); + } + + IMPL_LINK(TimeSpinButton, spin_button_input, int*, result, bool) + { + int nStartPos, nEndPos; + m_xSpinButton->get_selection_bounds(nStartPos, nEndPos); + + const SvtSysLocale aSysLocale; + const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData(); + tools::Time aResult(0); + bool bRet = TimeFormatter::TextToTime(m_xSpinButton->get_text(), aResult, m_eFormat, true, rLocaleData); + if (bRet) + *result = ConvertValue(aResult); + return bRet; + } + + void TimeSpinButton::update_width_chars() + { + int min, max; + m_xSpinButton->get_range(min, max); + auto width = std::max(m_xSpinButton->get_pixel_size(format_number(min)).Width(), + m_xSpinButton->get_pixel_size(format_number(max)).Width()); + int chars = ceil(width / m_xSpinButton->get_approximate_digit_width()); + m_xSpinButton->set_width_chars(chars); + } + + tools::Time TimeSpinButton::ConvertValue(int nValue) const + { + tools::Time aTime(0); + aTime.MakeTimeFromMS(nValue); + return aTime; + } + + int TimeSpinButton::ConvertValue(const tools::Time& rTime) const + { + return rTime.GetMSFromTime(); + } + + OUString TimeSpinButton::format_number(int nValue) const + { + const SvtSysLocale aSysLocale; + const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData(); + return TimeFormatter::FormatTime(ConvertValue(nValue), m_eFormat, TimeFormat::Hour24, true, rLocaleData); + } } VclBuilder::VclBuilder(vcl::Window *pParent, const OUString& sUIDir, const OUString& sUIFile, const OString& sID, diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index d881155c7d40..f0cbf0ed97e4 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -2753,6 +2753,7 @@ private: GtkEntry* m_pEntry; gulong m_nChangedSignalId; gulong m_nInsertTextSignalId; + gulong m_nCursorPosSignalId; static void signalChanged(GtkEntry*, gpointer widget) { @@ -2784,12 +2785,20 @@ private: } g_signal_stop_emission_by_name(pEntry, "insert-text"); } + + static void signalCursorPosition(GtkEntry*, GParamSpec*, gpointer widget) + { + GtkInstanceEntry* pThis = static_cast<GtkInstanceEntry*>(widget); + pThis->signal_cursor_position(); + } + public: GtkInstanceEntry(GtkEntry* pEntry, bool bTakeOwnership) : GtkInstanceWidget(GTK_WIDGET(pEntry), bTakeOwnership) , m_pEntry(pEntry) , m_nChangedSignalId(g_signal_connect(pEntry, "changed", G_CALLBACK(signalChanged), this)) , m_nInsertTextSignalId(g_signal_connect(pEntry, "insert-text", G_CALLBACK(signalInsertText), this)) + , m_nCursorPosSignalId(g_signal_connect(pEntry, "notify::cursor-position", G_CALLBACK(signalCursorPosition), this)) { } @@ -2941,6 +2950,7 @@ public: virtual ~GtkInstanceEntry() override { + g_signal_handler_disconnect(m_pEntry, m_nCursorPosSignalId); g_signal_handler_disconnect(m_pEntry, m_nInsertTextSignalId); g_signal_handler_disconnect(m_pEntry, m_nChangedSignalId); } @@ -3279,6 +3289,7 @@ private: GtkSpinButton* m_pButton; gulong m_nValueChangedSignalId; gulong m_nOutputSignalId; + gulong m_nInputSignalId; static void signalValueChanged(GtkSpinButton*, gpointer widget) { @@ -3294,6 +3305,22 @@ private: return pThis->signal_output(); } + static gboolean signalInput(GtkSpinButton*, gdouble* new_value, gpointer widget) + { + GtkInstanceSpinButton* pThis = static_cast<GtkInstanceSpinButton*>(widget); + SolarMutexGuard aGuard; + int result; + TriState eHandled = pThis->signal_input(&result); + if (eHandled == TRISTATE_INDET) + return false; + if (eHandled == TRISTATE_TRUE) + { + *new_value = result; + return true; + } + return GTK_INPUT_ERROR; + } + double toGtk(int nValue) const { return static_cast<double>(nValue) / Power10(get_digits()); @@ -3310,6 +3337,7 @@ public: , m_pButton(pButton) , m_nValueChangedSignalId(g_signal_connect(pButton, "value-changed", G_CALLBACK(signalValueChanged), this)) , m_nOutputSignalId(g_signal_connect(pButton, "output", G_CALLBACK(signalOutput), this)) + , m_nInputSignalId(g_signal_connect(pButton, "input", G_CALLBACK(signalInput), this)) { } @@ -3381,6 +3409,7 @@ public: virtual ~GtkInstanceSpinButton() override { + g_signal_handler_disconnect(m_pButton, m_nInputSignalId); g_signal_handler_disconnect(m_pButton, m_nOutputSignalId); g_signal_handler_disconnect(m_pButton, m_nValueChangedSignalId); } @@ -4587,6 +4616,12 @@ public: return new GtkInstanceSpinButton(pSpinButton, bTakeOwnership); } + virtual weld::TimeSpinButton* weld_time_spin_button(const OString& id, TimeFieldFormat eFormat, + bool bTakeOwnership) override + { + return new weld::TimeSpinButton(weld_spin_button(id, bTakeOwnership), eFormat); + } + virtual weld::ComboBoxText* weld_combo_box_text(const OString &id, bool bTakeOwnership) override { GtkComboBoxText* pComboBoxText = GTK_COMBO_BOX_TEXT(gtk_builder_get_object(m_pBuilder, id.getStr())); |