diff --git a/officecfg/registry/schema/org/openoffice/Office/Impress.xcs b/officecfg/registry/schema/org/openoffice/Office/Impress.xcs
index c4de6da82393..93dbfc342428 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Impress.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Impress.xcs
@@ -639,6 +639,44 @@
false
+
+
+ Specifies the timing display mode for rehearsal: 0=Current slide/Total time, 1=Current slide only, 2=Total time only.
+
+
+
+
+
+ Minimum value is 0 (Current slide/Total time).
+
+
+
+
+ Maximum value is 2 (Total time only).
+
+
+
+ 0
+
+
+
+ Specifies the position where the rehearsal timer will be displayed: 0=Top left, 1=Bottom left, 2=Top center, 3=Bottom center, 4=Top right, 5=Bottom right.
+
+
+
+
+
+ Minimum value is 0 (Top left).
+
+
+
+
+ Maximum value is 5 (Bottom right).
+
+
+
+ 0
+
diff --git a/sd/inc/drawdoc.hxx b/sd/inc/drawdoc.hxx
index d4dad173b7fb..62d9d32849ac 100644
--- a/sd/inc/drawdoc.hxx
+++ b/sd/inc/drawdoc.hxx
@@ -113,6 +113,9 @@ namespace sd
bool mbShowPauseLogo;
bool mbStartCustomShow;
bool mbInteractive;
+ bool mnRehearseTimerGlobalSetting; // 是否使用全局计时器设置
+ sal_Int32 mnTimerMode; // 计时器显示模式: 0=当前/总时间, 1=当前幻灯片, 2=总时间
+ sal_Int32 mnTimerPosition; // 计时器位置: 0=左上, 1=左下, 2=中上, 3=中下, 4=右上, 5=右下
PresentationSettings();
};
diff --git a/sd/inc/sdattr.hrc b/sd/inc/sdattr.hrc
index 3bc08b04de81..141790367da5 100644
--- a/sd/inc/sdattr.hrc
+++ b/sd/inc/sdattr.hrc
@@ -56,8 +56,11 @@ class XColorItem;
#define ATTR_PRESENT_SHOW_PAUSELOGO ATTR_PRESENT_START + 14
#define ATTR_PRESENT_DISPLAY TypedWhichId(ATTR_PRESENT_START + 15)
#define ATTR_PRESENT_INTERACTIVE ATTR_PRESENT_START + 16
+#define ATTR_PRESENT_TIMER_GLOBAL_SETTING TypedWhichId(ATTR_PRESENT_START + 17)
+#define ATTR_PRESENT_TIMING_MODE TypedWhichId(ATTR_PRESENT_START + 18)
+#define ATTR_PRESENT_TIMER_POSITION TypedWhichId(ATTR_PRESENT_START + 19)
-#define ATTR_PRESENT_END ATTR_PRESENT_INTERACTIVE
+#define ATTR_PRESENT_END ATTR_PRESENT_TIMER_POSITION
// animation attributes
#define ATTR_ANIMATION_START ATTR_PRESENT_END + 1
diff --git a/sd/source/core/drawdoc.cxx b/sd/source/core/drawdoc.cxx
index a07d24e4ffcb..8e7d1e05e679 100644
--- a/sd/source/core/drawdoc.cxx
+++ b/sd/source/core/drawdoc.cxx
@@ -112,8 +112,35 @@ PresentationSettings::PresentationSettings()
mnPauseTimeout( 0 ),
mbShowPauseLogo( false ),
mbStartCustomShow( false ),
- mbInteractive( true )
+ mbInteractive( true ),
+ mnRehearseTimerGlobalSetting(true), // 默认排练计时器全局设置为True
+ mnTimerMode( 0 ), // 默认显示当前/总时间
+ mnTimerPosition( 0 ) // 默认位置左上
{
+ // 从全局配置文件读取排练计时器设置
+ if (mnRehearseTimerGlobalSetting)
+ {
+ try
+ {
+ mnTimerMode = officecfg::Office::Impress::Misc::Start::RehearseTimingsMode::get();
+ mnTimerPosition = officecfg::Office::Impress::Misc::Start::RehearseTimingsPosition::get();
+
+ // 校验范围,防止配置文件被手动修改为非法值
+ if (mnTimerMode < 0 || mnTimerMode > 2)
+ {
+ mnTimerMode = 0;
+ }
+
+ if (mnTimerPosition < 0 || mnTimerPosition > 5)
+ {
+ mnTimerPosition = 0;
+ }
+ }
+ catch (const css::uno::Exception& e)
+ {
+ // 保持默认值 0, 0
+ }
+ }
}
SdDrawDocument::SdDrawDocument(DocumentType eType, SfxObjectShell* pDrDocSh)
diff --git a/sd/source/ui/dlg/present.cxx b/sd/source/ui/dlg/present.cxx
index d3d79fba41f4..de2bd898c8df 100644
--- a/sd/source/ui/dlg/present.cxx
+++ b/sd/source/ui/dlg/present.cxx
@@ -79,6 +79,9 @@ SdStartPresentationDlg::SdStartPresentationDlg(weld::Window* pWindow, const SfxI
, m_xAllMonitors(m_xBuilder->weld_label(u"allmonitors_str"_ustr))
, m_xMonitorExternal(m_xBuilder->weld_label(u"externalmonitor_str"_ustr))
, m_xExternal(m_xBuilder->weld_label(u"external_str"_ustr))
+ , m_xCbxTimerGlobalSettings(m_xBuilder->weld_check_button(u"globalrehearsetimings"_ustr) )
+ , m_xLbTimerMode(m_xBuilder->weld_combo_box(u"timingmode_cb"_ustr))
+ , m_xLbTimerPosition(m_xBuilder->weld_combo_box(u"timerposition_cb"_ustr))
{
m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
m_xFormatter->EnableEmptyField(false);
@@ -180,6 +183,45 @@ SdStartPresentationDlg::SdStartPresentationDlg(weld::Window* pWindow, const SfxI
m_xCbxInteractiveMode->set_active( static_cast( rOutAttrs.Get( ATTR_PRESENT_INTERACTIVE ) ).GetValue() );
+ // 初始化全局设置复选框状态
+ bool bGlobalSettings = static_cast( rOutAttrs.Get( ATTR_PRESENT_TIMER_GLOBAL_SETTING ) ).GetValue();
+ m_xCbxTimerGlobalSettings->set_active(bGlobalSettings);
+
+ // 初始化计时器设置
+ sal_Int32 nTimerMode = 0; // Default to "Current slide / Total time" (matches drawdoc.cxx)
+ sal_Int32 nTimerPosition = 0; // Default to "Top left" (matches drawdoc.cxx)
+
+ // 如果启用全局设置,则从配置中读取,否则使用文档中的值
+ if (bGlobalSettings) {
+ nTimerMode = officecfg::Office::Impress::Misc::Start::RehearseTimingsMode::get();
+ nTimerPosition = officecfg::Office::Impress::Misc::Start::RehearseTimingsPosition::get();
+ } else {
+ // 从配置文件读取计时器设置
+ const SfxPoolItem* pItem;
+ if (rOutAttrs.GetItemState(ATTR_PRESENT_TIMING_MODE, true, &pItem) == SfxItemState::SET) {
+ nTimerMode = static_cast(pItem)->GetValue();
+ }
+
+ if (rOutAttrs.GetItemState(ATTR_PRESENT_TIMER_POSITION, true, &pItem) == SfxItemState::SET) {
+ nTimerPosition = static_cast(pItem)->GetValue();
+ }
+ }
+
+ // 校验计时器设置范围,如果超出范围,则重置为默认值
+ if (nTimerMode < 0 || nTimerMode > 2)
+ nTimerMode = 0; // Reset to default if invalid
+ if (nTimerPosition < 0 || nTimerPosition > 5)
+ nTimerPosition = 0; // Reset to default if invalid
+
+ // 计时器设置赋值
+ if (m_xLbTimerMode) {
+ m_xLbTimerMode->set_active(nTimerMode);
+ }
+
+ if (m_xLbTimerPosition) {
+ m_xLbTimerPosition->set_active(nTimerPosition);
+ }
+
InitMonitorSettings();
ChangeRangeHdl(*m_xRbtCustomshow);
@@ -211,6 +253,13 @@ short SdStartPresentationDlg::run()
m_xCbxShowNavigationButton->get_active(), batch);
officecfg::Office::Impress::Layout::Display::NavigationBtnScale::set(
m_xLbNavigationButtonsSize->get_active(), batch);
+ bool bGlobalSettings = m_xCbxTimerGlobalSettings->get_active();
+ if (bGlobalSettings){
+ officecfg::Office::Impress::Misc::Start::RehearseTimingsMode::set(
+ m_xLbTimerMode->get_active(), batch);
+ officecfg::Office::Impress::Misc::Start::RehearseTimingsPosition::set(
+ m_xLbTimerPosition->get_active(), batch);
+ }
#ifdef ENABLE_SDREMOTE
officecfg::Office::Impress::Misc::Start::EnableSdremote::set(m_xCbxEnableRemote->get_active(), batch);
@@ -340,6 +389,26 @@ void SdStartPresentationDlg::GetAttr( SfxItemSet& rAttr )
rAttr.Put( SfxUInt32Item ( ATTR_PRESENT_PAUSE_TIMEOUT, m_xFormatter->GetTime().GetMSFromTime() / 1000 ) );
rAttr.Put( SfxBoolItem ( ATTR_PRESENT_SHOW_PAUSELOGO, m_xCbxAutoLogo->get_active() ) );
rAttr.Put( SfxBoolItem ( ATTR_PRESENT_INTERACTIVE, m_xCbxInteractiveMode->get_active() ) );
+ rAttr.Put( SfxBoolItem ( ATTR_PRESENT_TIMER_GLOBAL_SETTING, m_xCbxTimerGlobalSettings->get_active() ) );
+
+ // 保存计时器的属性值
+ sal_Int32 nTimingMode = 0;
+ sal_Int32 nTimerPosition = 0;
+
+ // 从下拉列表中获取计时器的属性值
+ if (m_xLbTimerMode)
+ nTimingMode = m_xLbTimerMode->get_active();
+ if (m_xLbTimerPosition)
+ nTimerPosition = m_xLbTimerPosition->get_active();
+
+ // 校验计时器属性值的合法性
+ if (nTimingMode < 0 || nTimingMode > 2)
+ nTimingMode = 0; // Reset to default if invalid
+ if (nTimerPosition < 0 || nTimerPosition > 5)
+ nTimerPosition = 0; // Reset to default if invalid
+
+ rAttr.Put( SfxInt32Item ( ATTR_PRESENT_TIMING_MODE, nTimingMode ) );
+ rAttr.Put( SfxInt32Item ( ATTR_PRESENT_TIMER_POSITION, nTimerPosition ) );
int nPos = m_xLBMonitor->get_active();
if (nPos != -1)
diff --git a/sd/source/ui/func/fusldlg.cxx b/sd/source/ui/func/fusldlg.cxx
index 9198fa351194..09a2936e4fd8 100644
--- a/sd/source/ui/func/fusldlg.cxx
+++ b/sd/source/ui/func/fusldlg.cxx
@@ -108,6 +108,9 @@ void FuSlideShowDlg::DoExecute( SfxRequest& )
aDlgSet.Put( SfxUInt32Item( ATTR_PRESENT_PAUSE_TIMEOUT, rPresentationSettings.mnPauseTimeout ) );
aDlgSet.Put( SfxBoolItem( ATTR_PRESENT_SHOW_PAUSELOGO, rPresentationSettings.mbShowPauseLogo ) );
aDlgSet.Put( SfxBoolItem( ATTR_PRESENT_INTERACTIVE, rPresentationSettings.mbInteractive ) );
+ aDlgSet.Put( SfxBoolItem( ATTR_PRESENT_TIMER_GLOBAL_SETTING, rPresentationSettings.mnRehearseTimerGlobalSetting ) );
+ aDlgSet.Put( SfxInt32Item( ATTR_PRESENT_TIMING_MODE, rPresentationSettings.mnTimerMode ) );
+ aDlgSet.Put( SfxInt32Item( ATTR_PRESENT_TIMER_POSITION, rPresentationSettings.mnTimerPosition ) );
SdOptions* pOptions = SdModule::get()->GetSdOptions(DocumentType::Impress);
aDlgSet.Put( SfxInt32Item( ATTR_PRESENT_DISPLAY, pOptions->GetDisplay() ) );
@@ -220,6 +223,27 @@ void FuSlideShowDlg::DoExecute( SfxRequest& )
rPresentationSettings.mbInteractive = bValue;
}
+ bValue = ITEMVALUE( aDlgSet, ATTR_PRESENT_TIMER_GLOBAL_SETTING, SfxBoolItem );
+ if ( bValue != rPresentationSettings.mnRehearseTimerGlobalSetting ) {
+ bValuesChanged = true;
+ rPresentationSettings.mnRehearseTimerGlobalSetting = bValue;
+ }
+
+ // Handle timing mode setting
+ nValue32 = ITEMVALUE( aDlgSet, ATTR_PRESENT_TIMING_MODE, SfxInt32Item );
+ if ( nValue32 != rPresentationSettings.mnTimerMode )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.mnTimerMode = nValue32;
+ }
+
+ nValue32 = ITEMVALUE( aDlgSet, ATTR_PRESENT_TIMER_POSITION, SfxInt32Item );
+ if ( nValue32 != rPresentationSettings.mnTimerPosition )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.mnTimerPosition = nValue32;
+ }
+
bValue = ITEMVALUE( aDlgSet, ATTR_PRESENT_PEN, SfxBoolItem );
if ( bValue != rPresentationSettings.mbMouseAsPen )
{
diff --git a/sd/source/ui/inc/present.hxx b/sd/source/ui/inc/present.hxx
index 36d746958263..8920fbb50db8 100644
--- a/sd/source/ui/inc/present.hxx
+++ b/sd/source/ui/inc/present.hxx
@@ -72,6 +72,11 @@ private:
std::unique_ptr m_xMonitorExternal;
std::unique_ptr m_xExternal;
+ // Rehearse timings controls
+ std::unique_ptr m_xCbxTimerGlobalSettings;
+ std::unique_ptr m_xLbTimerMode;
+ std::unique_ptr m_xLbTimerPosition;
+
DECL_LINK(ChangeRemoteHdl, weld::Toggleable&, void);
DECL_LINK(ChangeRangeHdl, weld::Toggleable&, void);
DECL_LINK(ClickWindowPresentationHdl, weld::Toggleable&, void);
diff --git a/sd/source/ui/slideshow/slideshow.cxx b/sd/source/ui/slideshow/slideshow.cxx
index 49cb4f489bf5..62f3a01d1e26 100644
--- a/sd/source/ui/slideshow/slideshow.cxx
+++ b/sd/source/ui/slideshow/slideshow.cxx
@@ -123,6 +123,8 @@ static std::span ImplGetPresentationPropertyMap()
{ u"Pause"_ustr, ATTR_PRESENT_PAUSE_TIMEOUT, ::cppu::UnoType::get(), 0, 0 },
{ u"StartWithNavigator"_ustr, ATTR_PRESENT_NAVIGATOR, cppu::UnoType::get(), 0, 0 },
{ u"UsePen"_ustr, ATTR_PRESENT_PEN, cppu::UnoType::get(), 0, 0 },
+ { u"TimingMode"_ustr, ATTR_PRESENT_TIMING_MODE, ::cppu::UnoType::get(), 0, 0 },
+ { u"TimerPosition"_ustr, ATTR_PRESENT_TIMER_POSITION, ::cppu::UnoType::get(), 0, 0 },
};
return aPresentationPropertyMap_Impl;
@@ -529,6 +531,37 @@ void SAL_CALL SlideShow::setPropertyValue( const OUString& aPropertyName, const
}
break;
}
+ // 添加计时模式设置
+ case ATTR_PRESENT_TIMING_MODE:
+ {
+ sal_Int32 nValue = 0;
+ if( (aValue >>= nValue) && (nValue >= 0 && nValue <= 2) )
+ {
+ bIllegalArgument = false;
+ if( rPresSettings.mnTimerMode != nValue )
+ {
+ bValuesChanged = true;
+ rPresSettings.mnTimerMode = nValue;
+ }
+ }
+ break;
+ }
+
+ // 添加计时器位置设置
+ case ATTR_PRESENT_TIMER_POSITION:
+ {
+ sal_Int32 nValue = 0;
+ if( (aValue >>= nValue) && (nValue >= 0 && nValue <= 5) )
+ {
+ bIllegalArgument = false;
+ if( rPresSettings.mnTimerPosition != nValue )
+ {
+ bValuesChanged = true;
+ rPresSettings.mnTimerPosition = nValue;
+ }
+ }
+ break;
+ }
default:
throw UnknownPropertyException( OUString::number(pEntry ? pEntry->nWID : -1), static_cast(this));
@@ -601,6 +634,10 @@ Any SAL_CALL SlideShow::getPropertyValue( const OUString& PropertyName )
SdOptions* pOptions = SdModule::get()->GetSdOptions(DocumentType::Impress);
return Any(pOptions->GetDisplay());
}
+ case ATTR_PRESENT_TIMING_MODE:
+ return Any( rPresSettings.mnTimerMode );
+ case ATTR_PRESENT_TIMER_POSITION:
+ return Any( rPresSettings.mnTimerPosition );
default:
throw UnknownPropertyException( OUString::number(pEntry ? pEntry->nWID : -1), static_cast(this));
@@ -835,7 +872,16 @@ void SAL_CALL SlideShow::end()
void SAL_CALL SlideShow::rehearseTimings()
{
- Sequence< PropertyValue > aArguments{ comphelper::makePropertyValue(u"RehearseTimings"_ustr, true) };
+ // Get the presentation settings to retrieve timing mode and timer position
+ const PresentationSettings& rSettings = mpDoc->getPresentationSettings();
+
+ // Create arguments array with RehearseTimings, TimingMode, and TimerPosition
+ Sequence< PropertyValue > aArguments{
+ comphelper::makePropertyValue(u"RehearseTimings"_ustr, true),
+ comphelper::makePropertyValue(u"TimingMode"_ustr, rSettings.mnTimerMode),
+ comphelper::makePropertyValue(u"TimerPosition"_ustr, rSettings.mnTimerPosition)
+ };
+
startWithArguments( aArguments );
}
diff --git a/sd/source/ui/slideshow/slideshowimpl.cxx b/sd/source/ui/slideshow/slideshowimpl.cxx
index fd7384f379bb..d04a39c25afe 100644
--- a/sd/source/ui/slideshow/slideshowimpl.cxx
+++ b/sd/source/ui/slideshow/slideshowimpl.cxx
@@ -554,6 +554,8 @@ SlideshowImpl::SlideshowImpl( const Reference< XPresentation2 >& xPresentation,
, mbWasPaused(false)
, mbInputFreeze(false)
, mbActive(false)
+, mnTimerMode(0) // 默认显示当前/总时间
+, mnTimerPosition(0) // 默认位置左上
, maPresSettings( pDoc->getPresentationSettings() )
, mnUserPaintColor( 0x80ff0000L )
, mbUsePen(false)
@@ -1061,6 +1063,8 @@ bool SlideshowImpl::startShow( PresentationSettingsEx const * pPresSettings )
{
maPresSettings = *pPresSettings;
mbRehearseTimings = pPresSettings->mbRehearseTimings;
+ mnTimerMode = pPresSettings->mnTimerMode;
+ mnTimerPosition = pPresSettings->mnTimerPosition;
}
OUString aPresSlide( maPresSettings.maPresPage );
@@ -1220,6 +1224,10 @@ bool SlideshowImpl::startShow( PresentationSettingsEx const * pPresSettings )
if (mbRehearseTimings) {
aProperties.emplace_back( "RehearseTimings" ,
-1, Any(true), beans::PropertyState_DIRECT_VALUE );
+ aProperties.emplace_back( "TimingMode" ,
+ -1, Any(mnTimerMode), beans::PropertyState_DIRECT_VALUE );
+ aProperties.emplace_back( "TimerPosition" ,
+ -1, Any(mnTimerPosition), beans::PropertyState_DIRECT_VALUE );
}
bRet = startShowImpl( Sequence(
@@ -3557,6 +3565,8 @@ PresentationSettingsEx::PresentationSettingsEx( const PresentationSettingsEx& r
, mbRehearseTimings(r.mbRehearseTimings)
, mbPreview(r.mbPreview)
, mpParentWindow( nullptr )
+, mnTimerMode(r.mnTimerMode)
+, mnTimerPosition(r.mnTimerPosition)
{
}
@@ -3565,14 +3575,22 @@ PresentationSettingsEx::PresentationSettingsEx( PresentationSettings const & r )
, mbRehearseTimings(false)
, mbPreview(false)
, mpParentWindow(nullptr)
+, mnTimerMode(r.mnTimerMode) // 从基础设置获取计时器显示模式
+, mnTimerPosition(r.mnTimerPosition) // 从基础设置获取计时器位置
{
}
void PresentationSettingsEx::SetArguments( const Sequence< PropertyValue >& rArguments )
{
- for( const PropertyValue& rValue : rArguments )
+ // for( const PropertyValue& rValue : rArguments )
+ // {
+ // SetPropertyValue( rValue.Name, rValue.Value );
+ // }
+ for (const PropertyValue& rValue : rArguments)
{
- SetPropertyValue( rValue.Name, rValue.Value );
+ OUString aName = rValue.Name;
+
+ SetPropertyValue(aName, rValue.Value);
}
}
@@ -3663,6 +3681,16 @@ void PresentationSettingsEx::SetPropertyValue( std::u16string_view rProperty, co
if( rValue >>= mbMouseAsPen )
return;
}
+ else if ( rProperty == u"TimingMode" )
+ {
+ if( rValue >>= mnTimerMode )
+ return;
+ }
+ else if ( rProperty == u"TimerPosition" )
+ {
+ if( rValue >>= mnTimerPosition )
+ return;
+ }
throw IllegalArgumentException();
}
diff --git a/sd/source/ui/slideshow/slideshowimpl.hxx b/sd/source/ui/slideshow/slideshowimpl.hxx
index 00f9c80003b7..01fb5cd24c8e 100644
--- a/sd/source/ui/slideshow/slideshowimpl.hxx
+++ b/sd/source/ui/slideshow/slideshowimpl.hxx
@@ -58,6 +58,8 @@ struct PresentationSettingsEx : public PresentationSettings
VclPtr mpParentWindow;
css::uno::Reference< css::drawing::XDrawPage > mxStartPage;
css::uno::Reference< css::animations::XAnimationNode > mxAnimationNode;
+ sal_Int32 mnTimerMode;
+ sal_Int32 mnTimerPosition;
PresentationSettingsEx( const PresentationSettingsEx& );
explicit PresentationSettingsEx( PresentationSettings const & );
@@ -340,6 +342,8 @@ private:
bool mbWasPaused; // used to cache pause state during context menu
bool mbInputFreeze;
bool mbActive;
+ sal_Int32 mnTimerMode; // 计时器显示模式
+ sal_Int32 mnTimerPosition; // 计时器位置
PresentationSettings maPresSettings;
sal_Int32 mnUserPaintColor;
diff --git a/sd/uiconfig/simpress/ui/presentationdialog.ui b/sd/uiconfig/simpress/ui/presentationdialog.ui
index 33bfc4f9d64a..d4e5b58171ed 100644
--- a/sd/uiconfig/simpress/ui/presentationdialog.ui
+++ b/sd/uiconfig/simpress/ui/presentationdialog.ui
@@ -80,7 +80,7 @@
-
+
+
+
+
+ 0
+ 3
+
+
True
@@ -864,7 +1000,7 @@
0
- 3
+ 4
diff --git a/slideshow/source/engine/rehearsetimingsactivity.cxx b/slideshow/source/engine/rehearsetimingsactivity.cxx
index 0d8295716092..7dd88d29186a 100644
--- a/slideshow/source/engine/rehearsetimingsactivity.cxx
+++ b/slideshow/source/engine/rehearsetimingsactivity.cxx
@@ -17,7 +17,6 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
-
#include
#include
#include
@@ -134,12 +133,17 @@ private:
const sal_Int32 LEFT_BORDER_SPACE = 10;
const sal_Int32 LOWER_BORDER_SPACE = 30;
-RehearseTimingsActivity::RehearseTimingsActivity( const SlideShowContext& rContext ) :
+RehearseTimingsActivity::RehearseTimingsActivity( const SlideShowContext& rContext,
+ sal_Int32 nTimingMode,
+ sal_Int32 nTimerPosition ) :
mrEventQueue(rContext.mrEventQueue),
mrScreenUpdater(rContext.mrScreenUpdater),
mrEventMultiplexer(rContext.mrEventMultiplexer),
mrActivitiesQueue(rContext.mrActivitiesQueue),
maElapsedTime( rContext.mrEventQueue.getTimer() ),
+ maTotalElapsedTime( rContext.mrEventQueue.getTimer() ), // 添加一个总的计时器
+ mnTimerMode( nTimingMode ), // 计时器显示模式
+ mnTimerPosition( nTimerPosition ), // 计时器位置
maViews(),
maSpriteRectangle(),
maFont( Application::GetSettings().GetStyleSettings().GetLabelFont() ),
@@ -155,15 +159,38 @@ RehearseTimingsActivity::RehearseTimingsActivity( const SlideShowContext& rConte
maFont.SetAlignment( ALIGN_BASELINE );
maFont.SetColor( COL_BLACK );
- // determine sprite size (in pixel):
+ // determine sprite size (in pixel) for dual timing display:
ScopedVclPtrInstance< VirtualDevice > blackHole;
blackHole->EnableOutput(false);
blackHole->SetFont( maFont );
blackHole->SetMapMode(MapMode(MapUnit::MapPixel));
tools::Rectangle rect;
const FontMetric metric( blackHole->GetFontMetric() );
- blackHole->GetTextBoundRect( rect, u"XX:XX:XX"_ustr );
- maSpriteSizePixel.setX( rect.getOpenWidth() * 12 / 10 );
+ // 根据计时器显示模式选择不同的样本字符串来计算宽度
+ OUString aSampleText;
+ sal_Int32 nWidthFactor; // 宽度系数(分子,分母固定为10)
+
+ switch (mnTimerMode)
+ {
+ case 1: // 只显示当前幻灯片计时
+ case 2: // 只显示总时间计时
+ // 单计时显示:"XX:XX:XX"
+ aSampleText = u"XX:XX:XX"_ustr;
+ nWidthFactor = 12; // 1.2倍
+ break;
+ case 0: // 显示当前幻灯片/总时间(双计时显示)
+ default:
+ // 双计时显示:"XX:XX:XX / XX:XX:XX"
+ aSampleText = u"XX:XX:XX / XX:XX:XX"_ustr;
+ nWidthFactor = 11; // 1.1倍
+ break;
+ }
+
+ // 先计算文本边界
+ blackHole->GetTextBoundRect( rect, aSampleText );
+
+ // 再根据计算结果和对应的系数设置宽度
+ maSpriteSizePixel.setX( rect.getOpenWidth() * nWidthFactor / 10 );
maSpriteSizePixel.setY( metric.GetLineHeight() * 11 / 10 );
mnYOffset = (metric.GetAscent() + (metric.GetLineHeight() / 20));
@@ -184,10 +211,12 @@ RehearseTimingsActivity::~RehearseTimingsActivity()
}
std::shared_ptr RehearseTimingsActivity::create(
- const SlideShowContext& rContext )
+ const SlideShowContext& rContext,
+ sal_Int32 nTimingMode,
+ sal_Int32 nTimerPosition )
{
std::shared_ptr pActivity(
- new RehearseTimingsActivity( rContext ));
+ new RehearseTimingsActivity( rContext, nTimingMode, nTimerPosition ));
pActivity->mpMouseHandler =
std::make_shared(*pActivity);
@@ -204,6 +233,11 @@ std::shared_ptr RehearseTimingsActivity::create(
void RehearseTimingsActivity::start()
{
maElapsedTime.reset();
+ // 当总时间为0时,重置总时间计时器
+ if (maTotalElapsedTime.getElapsedTime() == 0.0)
+ {
+ maTotalElapsedTime.reset();
+ }
mbDrawPressed = false;
mbActive = true;
@@ -306,11 +340,50 @@ basegfx::B2DRange RehearseTimingsActivity::calcSpriteRectangle( UnoViewSharedPtr
return basegfx::B2DRange();
const geometry::IntegerSize2D realSize( xBitmap->getSize() );
- // pixel:
- basegfx::B2DPoint spritePos(
- std::min( realSize.Width, LEFT_BORDER_SPACE ),
- std::max( 0, realSize.Height - maSpriteSizePixel.getY()
- - LOWER_BORDER_SPACE ) );
+
+ // 根据计时器位置设置计算显示位置
+ basegfx::B2DPoint spritePos;
+
+ switch (mnTimerPosition)
+ {
+ case 0: // 左上
+ spritePos = basegfx::B2DPoint(
+ std::min( realSize.Width, LEFT_BORDER_SPACE ),
+ std::min( realSize.Height, LOWER_BORDER_SPACE ) );
+ break;
+ case 1: // 左下
+ spritePos = basegfx::B2DPoint(
+ std::min( realSize.Width, LEFT_BORDER_SPACE ),
+ std::max( 0, realSize.Height - maSpriteSizePixel.getY()
+ - LOWER_BORDER_SPACE ) );
+ break;
+ case 2: // 中上
+ spritePos = basegfx::B2DPoint(
+ std::max( 0, (realSize.Width - maSpriteSizePixel.getX()) / 2 ),
+ std::min( realSize.Height, LOWER_BORDER_SPACE ) );
+ break;
+ case 3: // 中下
+ spritePos = basegfx::B2DPoint(
+ std::max( 0, (realSize.Width - maSpriteSizePixel.getX()) / 2 ),
+ std::max( 0, realSize.Height - maSpriteSizePixel.getY()
+ - LOWER_BORDER_SPACE ) );
+ break;
+ case 4: // 右上
+ spritePos = basegfx::B2DPoint(
+ std::max( 0, realSize.Width - maSpriteSizePixel.getX()
+ - LEFT_BORDER_SPACE ),
+ std::min( realSize.Height, LOWER_BORDER_SPACE ) );
+ break;
+ case 5: // 右下
+ default:
+ spritePos = basegfx::B2DPoint(
+ std::max( 0, realSize.Width - maSpriteSizePixel.getX()
+ - LEFT_BORDER_SPACE ),
+ std::max( 0, realSize.Height - maSpriteSizePixel.getY()
+ - LOWER_BORDER_SPACE ) );
+ break;
+ }
+
basegfx::B2DHomMatrix transformation( rView->getTransformation() );
transformation.invert();
spritePos *= transformation;
@@ -408,23 +481,98 @@ void RehearseTimingsActivity::paintAllSprites() const
void RehearseTimingsActivity::paint( cppcanvas::CanvasSharedPtr const & canvas ) const
{
- // build timer string:
- const sal_Int32 nTimeSecs =
+ // 只在第一次绘制时打印
+ static bool bFirstPaint = true;
+ if (bFirstPaint) {
+ bFirstPaint = false;
+ }
+ // build timer strings based on timing mode setting
+ const sal_Int32 nCurrentSlideTimeSecs =
static_cast(maElapsedTime.getElapsedTime());
- OUStringBuffer buf;
- sal_Int32 n = nTimeSecs / 3600;
- if (n < 10)
- buf.append( '0' );
- buf.append( OUString::number(n) + ":" );
- n = ((nTimeSecs % 3600) / 60);
- if (n < 10)
- buf.append( '0' );
- buf.append( OUString::number(n) + ":" );
- n = (nTimeSecs % 60);
- if (n < 10)
- buf.append( '0' );
- buf.append( n );
- const OUString time = buf.makeStringAndClear();
+ const sal_Int32 nTotalTimeSecs =
+ static_cast(maTotalElapsedTime.getElapsedTime());
+
+ OUString time;
+
+ // 根据计时器显示模式设置显示不同的计时信息
+ switch (mnTimerMode)
+ {
+ case 1: // 只显示当前幻灯片计时
+ {
+ OUStringBuffer buf;
+ sal_Int32 n = nCurrentSlideTimeSecs / 3600;
+ if (n < 10)
+ buf.append( '0' );
+ buf.append( OUString::number(n) + ":" );
+ n = ((nCurrentSlideTimeSecs % 3600) / 60);
+ if (n < 10)
+ buf.append( '0' );
+ buf.append( OUString::number(n) + ":" );
+ n = (nCurrentSlideTimeSecs % 60);
+ if (n < 10)
+ buf.append( '0' );
+ buf.append( n );
+ time = buf.makeStringAndClear();
+ break;
+ }
+ case 2: // 只显示总时间计时
+ {
+ OUStringBuffer buf;
+ sal_Int32 n = nTotalTimeSecs / 3600;
+ if (n < 10)
+ buf.append( '0' );
+ buf.append( OUString::number(n) + ":" );
+ n = ((nTotalTimeSecs % 3600) / 60);
+ if (n < 10)
+ buf.append( '0' );
+ buf.append( OUString::number(n) + ":" );
+ n = (nTotalTimeSecs % 60);
+ if (n < 10)
+ buf.append( '0' );
+ buf.append( n );
+ time = buf.makeStringAndClear();
+ break;
+ }
+ case 0: // 显示当前幻灯片/总时间(双计时显示)
+ default:
+ {
+ // 格式化当前幻灯片的排练计时
+ OUStringBuffer currentBuf;
+ sal_Int32 n = nCurrentSlideTimeSecs / 3600;
+ if (n < 10)
+ currentBuf.append( '0' );
+ currentBuf.append( OUString::number(n) + ":" );
+ n = ((nCurrentSlideTimeSecs % 3600) / 60);
+ if (n < 10)
+ currentBuf.append( '0' );
+ currentBuf.append( OUString::number(n) + ":" );
+ n = (nCurrentSlideTimeSecs % 60);
+ if (n < 10)
+ currentBuf.append( '0' );
+ currentBuf.append( n );
+ const OUString currentTime = currentBuf.makeStringAndClear();
+
+ // 格式化当前总的排练计时
+ OUStringBuffer totalBuf;
+ n = nTotalTimeSecs / 3600;
+ if (n < 10)
+ totalBuf.append( '0' );
+ totalBuf.append( OUString::number(n) + ":" );
+ n = ((nTotalTimeSecs % 3600) / 60);
+ if (n < 10)
+ totalBuf.append( '0' );
+ totalBuf.append( OUString::number(n) + ":" );
+ n = (nTotalTimeSecs % 60);
+ if (n < 10)
+ totalBuf.append( '0' );
+ totalBuf.append( n );
+ const OUString totalTime = totalBuf.makeStringAndClear();
+
+ // 组装当前幻灯片计时和总计时
+ time = currentTime + " / " + totalTime;
+ break;
+ }
+ }
// create the MetaFile:
GDIMetaFile metaFile;
diff --git a/slideshow/source/engine/rehearsetimingsactivity.hxx b/slideshow/source/engine/rehearsetimingsactivity.hxx
index 784ebfb2f584..3f5276976753 100644
--- a/slideshow/source/engine/rehearsetimingsactivity.hxx
+++ b/slideshow/source/engine/rehearsetimingsactivity.hxx
@@ -53,7 +53,9 @@ public:
/** Creates the activity.
*/
static std::shared_ptr create(
- const SlideShowContext& rContext );
+ const SlideShowContext& rContext,
+ sal_Int32 nTimingMode = 0, // 计时器显示模式
+ sal_Int32 nTimerPosition = 0 ); // 计时器位置
virtual ~RehearseTimingsActivity() override;
RehearseTimingsActivity(const RehearseTimingsActivity&) = delete;
@@ -90,7 +92,9 @@ public:
private:
class WakeupEvent;
- explicit RehearseTimingsActivity( const SlideShowContext& rContext );
+ explicit RehearseTimingsActivity( const SlideShowContext& rContext,
+ sal_Int32 nTimingMode = 0, // 计时器显示模式
+ sal_Int32 nTimerPosition = 0 ); // 计时器位置
void paint( ::cppcanvas::CanvasSharedPtr const & canvas ) const;
void paintAllSprites() const;
@@ -119,6 +123,9 @@ private:
EventMultiplexer& mrEventMultiplexer;
ActivitiesQueue& mrActivitiesQueue;
canvas::tools::ElapsedTime maElapsedTime;
+ canvas::tools::ElapsedTime maTotalElapsedTime; // 添加总的计时器
+ sal_Int32 mnTimerMode; // 计时器显示模式
+ sal_Int32 mnTimerPosition; // 计时器位置
ViewsVecT maViews;
diff --git a/slideshow/source/engine/slideshowimpl.cxx b/slideshow/source/engine/slideshowimpl.cxx
index f0e91d0bec15..046bf747f39f 100644
--- a/slideshow/source/engine/slideshowimpl.cxx
+++ b/slideshow/source/engine/slideshowimpl.cxx
@@ -17,7 +17,6 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
-
#include
#include
@@ -378,6 +377,9 @@ private:
/// stops the current slide transition sound
void stopSlideTransitionSound();
+ // 创建RehearseTimingsActivity
+ void maybeCreateOrUpdateRehearseTimingsActivity();
+
/** Prepare a slide transition
This method registers all necessary events and
@@ -494,6 +496,11 @@ private:
bool mbSlideShowIdle;
bool mbDisableAnimationZOrder;
bool mbMovingForward;
+ bool mbRehearseTimings; // 排练计时功能开关
+ sal_Int32 mnTimerMode; // 计时器显示模式
+ sal_Int32 mnTimerPosition; // 计时器位置
+ bool mbTimerPositionSet; // 计时器显示模式标识
+ bool mbTimerModeSet; // 计时器位置标识
EffectRewinder maEffectRewinder;
FrameSynchronization maFrameSynchronization;
@@ -606,6 +613,11 @@ SlideShowImpl::SlideShowImpl(
mbSlideShowIdle( true ),
mbDisableAnimationZOrder( false ),
mbMovingForward( true ),
+ mbRehearseTimings( false ), // 默认关闭排练计时
+ mnTimerMode( 0 ), // 默认显示当前/总时间
+ mnTimerPosition( 0 ), // 默认位置左上
+ mbTimerPositionSet(false), // 默认计时器位置未发生改变
+ mbTimerModeSet(false), // 默认计时器显示模式未发生改变
maEffectRewinder(maEventMultiplexer, maEventQueue, maUserEventQueue),
maFrameSynchronization(1.0 / FrameRate::PreferredFramesPerSecond)
@@ -1852,28 +1864,49 @@ sal_Bool SlideShowImpl::setProperty( beans::PropertyValue const& rProperty )
return (rProperty.Value >>= mbForceManualAdvance);
}
+ if ( rProperty.Name == "TimingMode" )
+ {
+ sal_Int32 nTimingMode = 0;
+ if (! (rProperty.Value >>= nTimingMode))
+ return false;
+
+ mnTimerMode = nTimingMode;
+ mbTimerModeSet = true;
+
+ // 统一调用一个 helper
+ maybeCreateOrUpdateRehearseTimingsActivity();
+
+ return true;
+ }
+
+ if ( rProperty.Name == "TimerPosition" )
+ {
+ sal_Int32 nTimerPosition = 0;
+ if (! (rProperty.Value >>= nTimerPosition))
+ return false;
+
+ mnTimerPosition = nTimerPosition;
+ mbTimerPositionSet = true;
+
+ // 统一调用一个 helper
+ maybeCreateOrUpdateRehearseTimingsActivity();
+
+ return true;
+ }
+
if ( rProperty.Name == "RehearseTimings" )
{
bool bRehearseTimings = false;
if (! (rProperty.Value >>= bRehearseTimings))
return false;
+ mbRehearseTimings = bRehearseTimings;
+
if (bRehearseTimings)
{
- // TODO(Q3): Move to slide
- mpRehearseTimingsActivity = RehearseTimingsActivity::create(
- SlideShowContext(
- mpDummyPtr,
- maEventQueue,
- maEventMultiplexer,
- maScreenUpdater,
- maActivitiesQueue,
- maUserEventQueue,
- *this,
- *this,
- maViewContainer,
- mxComponentContext,
- mpBox2DDummyPtr ) );
+ // 启用排练计时,但不直接创建,让 helper 根据当前参数决定
+ maybeCreateOrUpdateRehearseTimingsActivity();
+
}
else if (mpRehearseTimingsActivity)
{
@@ -2017,6 +2050,37 @@ sal_Bool SlideShowImpl::setProperty( beans::PropertyValue const& rProperty )
return false;
}
+void SlideShowImpl::maybeCreateOrUpdateRehearseTimingsActivity()
+{
+ // 1) 没启用排练计时就不用创建
+ if (!mbRehearseTimings)
+ return;
+
+ // 2) 两个参数都至少要被设置过一次
+ if (!mbTimerModeSet || !mbTimerPositionSet)
+ return;
+
+ // 3) 如果还没创建过,就创建一次
+ if (!mpRehearseTimingsActivity)
+ {
+ mpRehearseTimingsActivity = RehearseTimingsActivity::create(
+ SlideShowContext(
+ mpDummyPtr,
+ maEventQueue,
+ maEventMultiplexer,
+ maScreenUpdater,
+ maActivitiesQueue,
+ maUserEventQueue,
+ *this,
+ *this,
+ maViewContainer,
+ mxComponentContext,
+ mpBox2DDummyPtr ),
+ mnTimerMode,
+ mnTimerPosition );
+ }
+}
+
void SlideShowImpl::addSlideShowListener(
uno::Reference const& xListener )
{