vcl: allow for overriding the default PDF rendering resolution
[LibreOffice.git] / sdext / source / presenter / PresenterHelpView.cxx
blob70e3f57291c6c22636514f8b072a5f6b7abfc788
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/settings.hxx>
21 #include "PresenterHelpView.hxx"
22 #include "PresenterButton.hxx"
23 #include "PresenterCanvasHelper.hxx"
24 #include "PresenterGeometryHelper.hxx"
25 #include <com/sun/star/awt/XWindowPeer.hpp>
26 #include <com/sun/star/container/XNameAccess.hpp>
27 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
28 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
29 #include <com/sun/star/rendering/CompositeOperation.hpp>
30 #include <com/sun/star/rendering/TextDirection.hpp>
31 #include <com/sun/star/util/Color.hpp>
32 #include <algorithm>
33 #include <numeric>
34 #include <vector>
36 using namespace ::com::sun::star;
37 using namespace ::com::sun::star::uno;
38 using namespace ::com::sun::star::drawing::framework;
39 using ::std::vector;
41 namespace sdext { namespace presenter {
43 namespace {
44 const static sal_Int32 gnHorizontalGap (20);
45 const static sal_Int32 gnVerticalBorder (30);
46 const static sal_Int32 gnVerticalButtonPadding (12);
48 class LineDescriptor
50 public:
51 LineDescriptor();
52 void AddPart (
53 const OUString& rsLine,
54 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont);
55 bool IsEmpty() const;
57 OUString msLine;
58 geometry::RealSize2D maSize;
59 double mnVerticalOffset;
61 void CalculateSize (const css::uno::Reference<css::rendering::XCanvasFont>& rxFont);
64 class LineDescriptorList
66 public:
67 LineDescriptorList (
68 const OUString& rsText,
69 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
70 const sal_Int32 nMaximalWidth);
72 void Update (
73 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
74 const sal_Int32 nMaximalWidth);
76 double Paint(
77 const Reference<rendering::XCanvas>& rxCanvas,
78 const geometry::RealRectangle2D& rBBox,
79 const bool bFlushLeft,
80 const rendering::ViewState& rViewState,
81 rendering::RenderState& rRenderState,
82 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont) const;
83 double GetHeight() const;
85 private:
86 const OUString msText;
87 std::shared_ptr<vector<LineDescriptor> > mpLineDescriptors;
89 static void SplitText (const OUString& rsText, vector<OUString>& rTextParts);
90 void FormatText (
91 const vector<OUString>& rTextParts,
92 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
93 const sal_Int32 nMaximalWidth);
96 class Block
98 public:
99 Block (
100 const OUString& rsLeftText,
101 const OUString& rsRightText,
102 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
103 const sal_Int32 nMaximalWidth);
104 Block(const Block&) = delete;
105 Block& operator=(const Block&) = delete;
106 void Update (
107 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
108 const sal_Int32 nMaximalWidth);
110 LineDescriptorList maLeft;
111 LineDescriptorList maRight;
113 } // end of anonymous namespace
115 class PresenterHelpView::TextContainer : public vector<std::shared_ptr<Block> >
119 PresenterHelpView::PresenterHelpView (
120 const Reference<uno::XComponentContext>& rxContext,
121 const Reference<XResourceId>& rxViewId,
122 const Reference<frame::XController>& rxController,
123 const ::rtl::Reference<PresenterController>& rpPresenterController)
124 : PresenterHelpViewInterfaceBase(m_aMutex),
125 mxComponentContext(rxContext),
126 mxViewId(rxViewId),
127 mxPane(),
128 mxWindow(),
129 mxCanvas(),
130 mpPresenterController(rpPresenterController),
131 mpFont(),
132 mpTextContainer(),
133 mpCloseButton(),
134 mnSeparatorY(0),
135 mnMaximalWidth(0)
139 // Get the content window via the pane anchor.
140 Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
141 Reference<XConfigurationController> xCC (
142 xCM->getConfigurationController(), UNO_SET_THROW);
143 mxPane.set(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
145 mxWindow = mxPane->getWindow();
146 ProvideCanvas();
148 mxWindow->addWindowListener(this);
149 mxWindow->addPaintListener(this);
150 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
151 if (xPeer.is())
152 xPeer->setBackground(util::Color(0xff000000));
153 mxWindow->setVisible(true);
155 if (mpPresenterController.is())
157 mpFont = mpPresenterController->GetViewFont(mxViewId->getResourceURL());
158 if (mpFont.get() != nullptr)
160 mpFont->PrepareFont(mxCanvas);
164 // Create the close button.
165 mpCloseButton = PresenterButton::Create(
166 mxComponentContext,
167 mpPresenterController,
168 mpPresenterController->GetTheme(),
169 mxWindow,
170 mxCanvas,
171 "HelpViewCloser");
173 ReadHelpStrings();
174 Resize();
176 catch (RuntimeException&)
178 mxViewId = nullptr;
179 mxWindow = nullptr;
180 throw;
184 PresenterHelpView::~PresenterHelpView()
188 void SAL_CALL PresenterHelpView::disposing()
190 mxViewId = nullptr;
192 if (mpCloseButton.is())
194 Reference<lang::XComponent> xComponent (
195 static_cast<XWeak*>(mpCloseButton.get()), UNO_QUERY);
196 mpCloseButton = nullptr;
197 if (xComponent.is())
198 xComponent->dispose();
201 if (mxWindow.is())
203 mxWindow->removeWindowListener(this);
204 mxWindow->removePaintListener(this);
208 //----- lang::XEventListener --------------------------------------------------
210 void SAL_CALL PresenterHelpView::disposing (const lang::EventObject& rEventObject)
212 if (rEventObject.Source == mxCanvas)
214 mxCanvas = nullptr;
216 else if (rEventObject.Source == mxWindow)
218 mxWindow = nullptr;
219 dispose();
223 //----- XWindowListener -------------------------------------------------------
225 void SAL_CALL PresenterHelpView::windowResized (const awt::WindowEvent&)
227 ThrowIfDisposed();
228 Resize();
231 void SAL_CALL PresenterHelpView::windowMoved (const awt::WindowEvent&)
233 ThrowIfDisposed();
236 void SAL_CALL PresenterHelpView::windowShown (const lang::EventObject&)
238 ThrowIfDisposed();
239 Resize();
242 void SAL_CALL PresenterHelpView::windowHidden (const lang::EventObject&)
244 ThrowIfDisposed();
247 //----- XPaintListener --------------------------------------------------------
249 void SAL_CALL PresenterHelpView::windowPaint (const css::awt::PaintEvent& rEvent)
251 Paint(rEvent.UpdateRect);
254 void PresenterHelpView::Paint (const awt::Rectangle& rUpdateBox)
256 ProvideCanvas();
257 if ( ! mxCanvas.is())
258 return;
260 // Clear background.
261 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
262 mpPresenterController->GetCanvasHelper()->Paint(
263 mpPresenterController->GetViewBackground(mxViewId->getResourceURL()),
264 mxCanvas,
265 rUpdateBox,
266 awt::Rectangle(0,0,aWindowBox.Width,aWindowBox.Height),
267 awt::Rectangle());
269 // Paint vertical divider.
271 rendering::ViewState aViewState(
272 geometry::AffineMatrix2D(1,0,0, 0,1,0),
273 PresenterGeometryHelper::CreatePolygon(rUpdateBox, mxCanvas->getDevice()));
275 rendering::RenderState aRenderState (
276 geometry::AffineMatrix2D(1,0,0, 0,1,0),
277 nullptr,
278 Sequence<double>(4),
279 rendering::CompositeOperation::SOURCE);
280 PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
282 mxCanvas->drawLine(
283 geometry::RealPoint2D((aWindowBox.Width/2.0), gnVerticalBorder),
284 geometry::RealPoint2D((aWindowBox.Width/2.0), mnSeparatorY - gnVerticalBorder),
285 aViewState,
286 aRenderState);
288 // Paint the horizontal separator.
289 mxCanvas->drawLine(
290 geometry::RealPoint2D(0, mnSeparatorY),
291 geometry::RealPoint2D(aWindowBox.Width, mnSeparatorY),
292 aViewState,
293 aRenderState);
295 // Paint text.
296 double nY (gnVerticalBorder);
297 for (const auto& rxBlock : *mpTextContainer)
299 sal_Int32 LeftX1 = gnHorizontalGap;
300 sal_Int32 LeftX2 = aWindowBox.Width/2 - gnHorizontalGap;
301 sal_Int32 RightX1 = aWindowBox.Width/2 + gnHorizontalGap;
302 sal_Int32 RightX2 = aWindowBox.Width - gnHorizontalGap;
303 /* check whether RTL interface or not
304 then replace the windowbox position */
305 if(AllSettings::GetLayoutRTL())
307 LeftX1 = aWindowBox.Width/2 + gnHorizontalGap;
308 LeftX2 = aWindowBox.Width - gnHorizontalGap;
309 RightX1 = gnHorizontalGap;
310 RightX2 = aWindowBox.Width/2 - gnHorizontalGap;
312 const double nLeftHeight (
313 rxBlock->maLeft.Paint(mxCanvas,
314 geometry::RealRectangle2D(
315 LeftX1,
317 LeftX2,
318 aWindowBox.Height - gnVerticalBorder),
319 false,
320 aViewState,
321 aRenderState,
322 mpFont->mxFont));
323 const double nRightHeight (
324 rxBlock->maRight.Paint(mxCanvas,
325 geometry::RealRectangle2D(
326 RightX1,
328 RightX2,
329 aWindowBox.Height - gnVerticalBorder),
330 true,
331 aViewState,
332 aRenderState,
333 mpFont->mxFont));
335 nY += ::std::max(nLeftHeight,nRightHeight);
338 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
339 if (xSpriteCanvas.is())
340 xSpriteCanvas->updateScreen(false);
343 void PresenterHelpView::ReadHelpStrings()
345 mpTextContainer.reset(new TextContainer);
346 PresenterConfigurationAccess aConfiguration (
347 mxComponentContext,
348 "/org.openoffice.Office.PresenterScreen/",
349 PresenterConfigurationAccess::READ_ONLY);
350 Reference<container::XNameAccess> xStrings (
351 aConfiguration.GetConfigurationNode("PresenterScreenSettings/HelpView/HelpStrings"),
352 UNO_QUERY);
353 PresenterConfigurationAccess::ForAll(
354 xStrings,
355 [this](OUString const&, uno::Reference<beans::XPropertySet> const& xProps)
357 return this->ProcessString(xProps);
361 void PresenterHelpView::ProcessString (
362 const Reference<beans::XPropertySet>& rsProperties)
364 if ( ! rsProperties.is())
365 return;
367 OUString sLeftText;
368 PresenterConfigurationAccess::GetProperty(rsProperties, "Left") >>= sLeftText;
369 OUString sRightText;
370 PresenterConfigurationAccess::GetProperty(rsProperties, "Right") >>= sRightText;
371 mpTextContainer->push_back(
372 std::make_shared<Block>(
373 sLeftText, sRightText, mpFont->mxFont, mnMaximalWidth));
376 void PresenterHelpView::CheckFontSize()
378 if (mpFont.get() == nullptr)
379 return;
381 sal_Int32 nBestSize (6);
383 // Scaling down and then reformatting can cause the text to be too large
384 // still. So do this again and again until the text size is
385 // small enough. Restrict the number of loops.
386 for (int nLoopCount=0; nLoopCount<5; ++nLoopCount)
388 double nY = std::accumulate(mpTextContainer->begin(), mpTextContainer->end(), double(0),
389 [](const double& sum, const std::shared_ptr<Block>& rxBlock) {
390 return sum + std::max(
391 rxBlock->maLeft.GetHeight(),
392 rxBlock->maRight.GetHeight());
395 const double nHeightDifference (nY - (mnSeparatorY-gnVerticalBorder));
396 if (nHeightDifference <= 0 && nHeightDifference > -50)
398 // We have found a good font size that is large and leaves not
399 // too much space below the help text.
400 return;
403 // Use a simple linear transformation to calculate initial guess of
404 // a size that lets all help text be shown inside the window.
405 const double nScale (double(mnSeparatorY-gnVerticalBorder) / nY);
406 if (nScale > 1.0 && nScale < 1.05)
407 break;
409 sal_Int32 nFontSizeGuess (sal_Int32(mpFont->mnSize * nScale));
410 if (nHeightDifference<=0 && mpFont->mnSize>nBestSize)
411 nBestSize = mpFont->mnSize;
412 mpFont->mnSize = nFontSizeGuess;
413 mpFont->mxFont = nullptr;
414 mpFont->PrepareFont(mxCanvas);
416 // Reformat blocks.
417 for (auto& rxBlock : *mpTextContainer)
418 rxBlock->Update(mpFont->mxFont, mnMaximalWidth);
421 if (nBestSize != mpFont->mnSize)
423 mpFont->mnSize = nBestSize;
424 mpFont->mxFont = nullptr;
425 mpFont->PrepareFont(mxCanvas);
427 // Reformat blocks.
428 for (auto& rxBlock : *mpTextContainer)
430 rxBlock->Update(mpFont->mxFont, mnMaximalWidth);
435 //----- XResourceId -----------------------------------------------------------
437 Reference<XResourceId> SAL_CALL PresenterHelpView::getResourceId()
439 ThrowIfDisposed();
440 return mxViewId;
443 sal_Bool SAL_CALL PresenterHelpView::isAnchorOnly()
445 return false;
449 void PresenterHelpView::ProvideCanvas()
451 if ( ! mxCanvas.is() && mxPane.is())
453 mxCanvas = mxPane->getCanvas();
454 if ( ! mxCanvas.is())
455 return;
456 Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
457 if (xComponent.is())
458 xComponent->addEventListener(static_cast<awt::XPaintListener*>(this));
460 if (mpCloseButton.is())
461 mpCloseButton->SetCanvas(mxCanvas, mxWindow);
465 void PresenterHelpView::Resize()
467 if (!(mpCloseButton.get() != nullptr && mxWindow.is()))
468 return;
470 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
471 mnMaximalWidth = (mxWindow->getPosSize().Width - 4*gnHorizontalGap) / 2;
473 // Place vertical separator.
474 mnSeparatorY = aWindowBox.Height
475 - mpCloseButton->GetSize().Height - gnVerticalButtonPadding;
477 mpCloseButton->SetCenter(geometry::RealPoint2D(
478 aWindowBox.Width/2.0,
479 aWindowBox.Height - mpCloseButton->GetSize().Height/2.0));
481 CheckFontSize();
484 void PresenterHelpView::ThrowIfDisposed()
486 if (rBHelper.bDisposed || rBHelper.bInDispose)
488 throw lang::DisposedException (
489 "PresenterHelpView has been already disposed",
490 static_cast<uno::XWeak*>(this));
494 //===== LineDescriptor =========================================================
496 namespace {
498 LineDescriptor::LineDescriptor()
499 : msLine(),
500 maSize(0,0),
501 mnVerticalOffset(0)
505 void LineDescriptor::AddPart (
506 const OUString& rsLine,
507 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont)
509 msLine += rsLine;
511 CalculateSize(rxFont);
514 bool LineDescriptor::IsEmpty() const
516 return msLine.isEmpty();
519 void LineDescriptor::CalculateSize (
520 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont)
522 OSL_ASSERT(rxFont.is());
524 rendering::StringContext aContext (msLine, 0, msLine.getLength());
525 Reference<rendering::XTextLayout> xLayout (
526 rxFont->createTextLayout(aContext, rendering::TextDirection::WEAK_LEFT_TO_RIGHT, 0));
527 const geometry::RealRectangle2D aTextBBox (xLayout->queryTextBounds());
528 maSize = css::geometry::RealSize2D(aTextBBox.X2 - aTextBBox.X1, aTextBBox.Y2 - aTextBBox.Y1);
529 mnVerticalOffset = aTextBBox.Y2;
532 } // end of anonymous namespace
534 //===== LineDescriptorList ====================================================
536 namespace {
538 LineDescriptorList::LineDescriptorList (
539 const OUString& rsText,
540 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
541 const sal_Int32 nMaximalWidth)
542 : msText(rsText)
544 Update(rxFont, nMaximalWidth);
547 double LineDescriptorList::Paint(
548 const Reference<rendering::XCanvas>& rxCanvas,
549 const geometry::RealRectangle2D& rBBox,
550 const bool bFlushLeft,
551 const rendering::ViewState& rViewState,
552 rendering::RenderState& rRenderState,
553 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont) const
555 if ( ! rxCanvas.is())
556 return 0;
558 double nY (rBBox.Y1);
559 for (const auto& rLine : *mpLineDescriptors)
561 double nX;
562 /// check whether RTL interface or not
563 if(!AllSettings::GetLayoutRTL())
565 nX = rBBox.X1;
566 if ( ! bFlushLeft)
567 nX = rBBox.X2 - rLine.maSize.Width;
569 else
571 nX=rBBox.X2 - rLine.maSize.Width;
572 if ( ! bFlushLeft)
573 nX = rBBox.X1;
575 rRenderState.AffineTransform.m02 = nX;
576 rRenderState.AffineTransform.m12 = nY + rLine.maSize.Height - rLine.mnVerticalOffset;
578 const rendering::StringContext aContext (rLine.msLine, 0, rLine.msLine.getLength());
579 Reference<rendering::XTextLayout> xLayout (
580 rxFont->createTextLayout(aContext, rendering::TextDirection::WEAK_LEFT_TO_RIGHT, 0));
581 rxCanvas->drawTextLayout (
582 xLayout,
583 rViewState,
584 rRenderState);
586 nY += rLine.maSize.Height * 1.2;
589 return nY - rBBox.Y1;
592 double LineDescriptorList::GetHeight() const
594 return std::accumulate(mpLineDescriptors->begin(), mpLineDescriptors->end(), double(0),
595 [](const double& nHeight, const LineDescriptor& rLine) {
596 return nHeight + rLine.maSize.Height * 1.2;
600 void LineDescriptorList::Update (
601 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
602 const sal_Int32 nMaximalWidth)
604 vector<OUString> aTextParts;
605 SplitText(msText, aTextParts);
606 FormatText(aTextParts, rxFont, nMaximalWidth);
609 void LineDescriptorList::SplitText (
610 const OUString& rsText,
611 vector<OUString>& rTextParts)
613 const sal_Char cQuote ('\'');
614 const sal_Char cSeparator (',');
616 sal_Int32 nIndex (0);
617 sal_Int32 nStart (0);
618 sal_Int32 nLength (rsText.getLength());
619 bool bIsQuoted (false);
620 while (nIndex < nLength)
622 const sal_Int32 nQuoteIndex (rsText.indexOf(cQuote, nIndex));
623 const sal_Int32 nSeparatorIndex (rsText.indexOf(cSeparator, nIndex));
624 if (nQuoteIndex>=0 && (nSeparatorIndex==-1 || nQuoteIndex<nSeparatorIndex))
626 bIsQuoted = !bIsQuoted;
627 nIndex = nQuoteIndex+1;
628 continue;
631 const sal_Int32 nNextIndex = nSeparatorIndex;
632 if (nNextIndex < 0)
634 break;
636 else if ( ! bIsQuoted)
638 rTextParts.push_back(rsText.copy(nStart, nNextIndex-nStart));
639 nStart = nNextIndex + 1;
641 nIndex = nNextIndex+1;
643 if (nStart < nLength)
644 rTextParts.push_back(rsText.copy(nStart, nLength-nStart));
647 void LineDescriptorList::FormatText (
648 const vector<OUString>& rTextParts,
649 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
650 const sal_Int32 nMaximalWidth)
652 LineDescriptor aLineDescriptor;
654 mpLineDescriptors.reset(new vector<LineDescriptor>);
656 vector<OUString>::const_iterator iPart (rTextParts.begin());
657 vector<OUString>::const_iterator iEnd (rTextParts.end());
658 while (iPart!=iEnd)
660 if (aLineDescriptor.IsEmpty())
662 // Avoid empty lines.
663 if (PresenterCanvasHelper::GetTextSize(
664 rxFont, *iPart).Width > nMaximalWidth)
666 const sal_Char cSpace (' ');
668 sal_Int32 nIndex (0);
669 sal_Int32 nStart (0);
670 sal_Int32 nLength (iPart->getLength());
671 while (nIndex < nLength)
673 sal_Int32 nSpaceIndex (iPart->indexOf(cSpace, nIndex));
674 while (nSpaceIndex >= 0 && PresenterCanvasHelper::GetTextSize(
675 rxFont, iPart->copy(nStart, nSpaceIndex-nStart)).Width <= nMaximalWidth)
677 nIndex = nSpaceIndex;
678 nSpaceIndex = iPart->indexOf(cSpace, nIndex+1);
681 if (nSpaceIndex < 0 && PresenterCanvasHelper::GetTextSize(
682 rxFont, iPart->copy(nStart, nLength-nStart)).Width <= nMaximalWidth)
684 nIndex = nLength;
687 if (nIndex == nStart)
689 nIndex = nLength;
692 aLineDescriptor.AddPart(iPart->copy(nStart, nIndex-nStart), rxFont);
693 if (nIndex != nLength)
695 mpLineDescriptors->push_back(aLineDescriptor);
696 aLineDescriptor = LineDescriptor();
698 nStart = nIndex;
701 else
703 aLineDescriptor.AddPart(*iPart, rxFont);
706 else if (PresenterCanvasHelper::GetTextSize(
707 rxFont, aLineDescriptor.msLine+", "+*iPart).Width > nMaximalWidth)
709 aLineDescriptor.AddPart(",", rxFont);
710 mpLineDescriptors->push_back(aLineDescriptor);
711 aLineDescriptor = LineDescriptor();
712 continue;
714 else
716 aLineDescriptor.AddPart(", "+*iPart, rxFont);
718 ++iPart;
720 if ( ! aLineDescriptor.IsEmpty())
722 mpLineDescriptors->push_back(aLineDescriptor);
726 } // end of anonymous namespace
728 //===== Block =================================================================
730 namespace {
732 Block::Block (
733 const OUString& rsLeftText,
734 const OUString& rsRightText,
735 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
736 const sal_Int32 nMaximalWidth)
737 : maLeft(rsLeftText, rxFont, nMaximalWidth),
738 maRight(rsRightText, rxFont, nMaximalWidth)
742 void Block::Update (
743 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
744 const sal_Int32 nMaximalWidth)
746 maLeft.Update(rxFont, nMaximalWidth);
747 maRight.Update(rxFont, nMaximalWidth);
750 } // end of anonymous namespace
752 } } // end of namespace ::sdext::presenter
754 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */