/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// Create the mouse over manager.
mpMouseOverManager.reset(new MouseOverManager(
Reference<container::XIndexAccess>(mxSlideShowController, UNO_QUERY),
mpPresenterController->GetTheme(),
mxWindow,
mpPresenterController->GetPaintManager()));
// Listen for changes of the current slide.
rxController->addPropertyChangeListener(
u"CurrentPage"_ustr, this);
// Move the current slide in the center of the window. const awt::Rectangle aCurrentSlideBBox (mpLayout->GetBoundingBox(mnCurrentSlideIndex)); const awt::Rectangle aWindowBox (mxWindow->getPosSize());
SetHorizontalOffset(aCurrentSlideBBox.X - aWindowBox.Width/2.0);
} catch (RuntimeException&)
{
disposing(); throw;
}
}
void SAL_CALL PresenterSlideSorter::windowPaint (const css::awt::PaintEvent& rEvent)
{ // Deactivated views must not be painted. if ( ! mbIsPresenterViewActive) return;
Paint(rEvent.UpdateRect);
Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY); if (xSpriteCanvas.is())
xSpriteCanvas->updateScreen(false);
}
const sal_Int32 nNewCurrentSlideIndex (mxSlideShowController->getCurrentSlideIndex()); if (nNewCurrentSlideIndex == mnCurrentSlideIndex) return;
mnCurrentSlideIndex = nNewCurrentSlideIndex;
// Request a repaint of the previous current slide to hide its // current slide indicator.
mpPresenterController->GetPaintManager()->Invalidate(
mxWindow,
maCurrentSlideFrameBoundingBox);
// Request a repaint of the new current slide to show its // current slide indicator.
maCurrentSlideFrameBoundingBox = mpCurrentSlideFrameRenderer->GetBoundingBox(
mpLayout->GetBoundingBox(mnCurrentSlideIndex));
mpPresenterController->GetPaintManager()->Invalidate(
mxWindow,
maCurrentSlideFrameBoundingBox);
// Get border width.
PresenterPaneContainer::SharedPaneDescriptor pPane (
mpPresenterController->GetPaneContainer()->FindViewURL(
mxViewId->getResourceURL())); do
{ if (!pPane) break; if ( ! pPane->mxPane.is()) break;
// Tell the preview cache about some of the values.
mxPreviewCache->setPreviewSize(mpLayout->maPreviewSize);
mxPreviewCache->setVisibleRange(
mpLayout->GetFirstVisibleSlideIndex(),
mpLayout->GetLastVisibleSlideIndex());
// Clear the frame polygon so that it is re-created on the next paint.
mxPreviewFrame = nullptr;
}
geometry::RealRectangle2D PresenterSlideSorter::PlaceScrollBars ( const geometry::RealRectangle2D& rUpperBox)
{
mpLayout->Update(rUpperBox, GetSlideAspectRatio()); bool bIsScrollBarNeeded (false);
Reference<container::XIndexAccess> xSlides (mxSlideShowController, UNO_QUERY_THROW);
bIsScrollBarNeeded = mpLayout->IsScrollBarNeeded(xSlides->getCount()); if (mpVerticalScrollBar)
{ if (bIsScrollBarNeeded)
{ if(AllSettings::GetLayoutRTL())
{
mpVerticalScrollBar->SetPosSize(geometry::RealRectangle2D(
rUpperBox.X1,
rUpperBox.Y1,
rUpperBox.X1 + mpVerticalScrollBar->GetSize(),
rUpperBox.Y2));
mpVerticalScrollBar->SetVisible(true); // Reduce area covered by the scroll bar from the available // space. return geometry::RealRectangle2D(
rUpperBox.X1 + gnHorizontalGap + mpVerticalScrollBar->GetSize(),
rUpperBox.Y1,
rUpperBox.X2,
rUpperBox.Y2);
} else
{ // if it's not RTL place vertical scroll bar at right border.
mpVerticalScrollBar->SetPosSize(geometry::RealRectangle2D(
rUpperBox.X2 - mpVerticalScrollBar->GetSize(),
rUpperBox.Y1,
rUpperBox.X2,
rUpperBox.Y2));
mpVerticalScrollBar->SetVisible(true); // Reduce area covered by the scroll bar from the available // space. return geometry::RealRectangle2D(
rUpperBox.X1,
rUpperBox.Y1,
rUpperBox.X2 - mpVerticalScrollBar->GetSize() - gnHorizontalGap,
rUpperBox.Y2);
}
} else
mpVerticalScrollBar->SetVisible(false);
} return rUpperBox;
}
void PresenterSlideSorter::PlaceCloseButton ( const PresenterPaneContainer::SharedPaneDescriptor& rpPane, const awt::Rectangle& rCenterBox, const sal_Int32 nLeftBorderWidth)
{ // Place button. When the callout is near the center then the button is // centered over the callout. Otherwise it is centered with respect to // the whole window.
sal_Int32 nCloseButtonCenter (rCenterBox.Width/2); if (rpPane && rpPane->mxPane.is())
{ const sal_Int32 nCalloutCenter (-nLeftBorderWidth); const sal_Int32 nDistanceFromWindowCenter (abs(nCalloutCenter - rCenterBox.Width/2)); const sal_Int32 nButtonWidth (mpCloseButton->GetSize().Width); conststatic sal_Int32 nMaxDistanceForCalloutCentering (nButtonWidth * 2); if (nDistanceFromWindowCenter < nMaxDistanceForCalloutCentering)
{ if (nCalloutCenter < nButtonWidth/2)
nCloseButtonCenter = nButtonWidth/2; elseif (nCalloutCenter > rCenterBox.Width-nButtonWidth/2)
nCloseButtonCenter = rCenterBox.Width-nButtonWidth/2; else
nCloseButtonCenter = nCalloutCenter;
}
}
mpCloseButton->SetCenter(geometry::RealPoint2D(
nCloseButtonCenter,
rCenterBox.Height - mpCloseButton->GetSize().Height/ 2));
}
// Create clip rectangle as intersection of the current update area and // the bounding box of all previews.
geometry::RealRectangle2D aBoundingBox (mpLayout->maBoundingBox);
aBoundingBox.Y2 += 1; const geometry::RealRectangle2D aClipBox (
PresenterGeometryHelper::Intersection(
PresenterGeometryHelper::ConvertRectangle(rUpdateBox),
aBoundingBox));
Reference<rendering::XPolyPolygon2D> xClip (
PresenterGeometryHelper::CreatePolygon(aClipBox, rxCanvas->getDevice()));
// Create a polygon that is used to paint a frame around previews. Its // coordinates are chosen in the local coordinate system of a preview. if ( ! mxPreviewFrame.is())
mxPreviewFrame = PresenterGeometryHelper::CreatePolygon(
awt::Rectangle(-1, -1, aSize.Width+2, aSize.Height+2),
rxCanvas->getDevice());
// Paint a border around the preview. if (mxPreviewFrame.is())
{ const util::Color aFrameColor (0x00000000);
PresenterCanvasHelper::SetDeviceColor(aRenderState, aFrameColor);
rxCanvas->drawPolyPolygon(mxPreviewFrame, aViewState, aRenderState);
}
// Paint mouse over effect.
mpMouseOverManager->Paint(nSlideIndex, mxCanvas, xClip);
}
if (mpLayout->mnRowCount<=0 || mpLayout->mnColumnCount<=0)
{
OSL_ASSERT(mpLayout->mnRowCount>0 || mpLayout->mnColumnCount>0); return;
}
ClearBackground(mxCanvas, rUpdateBox);
// Give the canvas to the controls. if (bCanvasChanged)
{ if (mpVerticalScrollBar.is())
mpVerticalScrollBar->SetCanvas(mxCanvas); if (mpCloseButton.is())
mpCloseButton->SetCanvas(mxCanvas, mxWindow);
}
// Now that the controls have a canvas we can do the layouting. if (mbIsLayoutPending)
UpdateLayout();
bool PresenterSlideSorter::ProvideCanvas()
{ if ( ! mxCanvas.is())
{ if (mxPane.is())
mxCanvas = mxPane->getCanvas();
// Register as event listener so that we are informed when the // canvas is disposed (and we have to fetch another one).
Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY); if (xComponent.is())
xComponent->addEventListener(static_cast<awt::XWindowListener*>(this));
// Determine column count, preview width, and horizontal gap (borders // are half the gap). Try to use the preferred values. Try more to // stay in the valid intervals. This last constraint may be not // fulfilled in some cases. constdouble nElementWidth = nWidth / gnPreferredColumnCount; if (nElementWidth < gnMinimalPreviewWidth + gnMinimalHorizontalPreviewGap)
{ // The preferred column count is too large. // Can we use the preferred preview width? if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth)
{ // Yes.
nPreviewWidth = gnPreferredPreviewWidth;
mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap)
/ (nPreviewWidth+gnPreferredHorizontalPreviewGap));
mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
} else
{ // No. Set the column count to 1 and adapt preview width and // gap.
mnColumnCount = 1;
mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap); if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth)
nPreviewWidth = nWidth - gnMinimalHorizontalPreviewGap; else
nPreviewWidth = ::std::max(gnMinimalPreviewWidth, nWidth-mnHorizontalGap);
}
} elseif (nElementWidth > gnMaximalPreviewWidth + gnMaximalHorizontalPreviewGap)
{ // The preferred column count is too small.
nPreviewWidth = gnPreferredPreviewWidth;
mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap)
/ (nPreviewWidth+gnPreferredHorizontalPreviewGap));
mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
} else
{ // The preferred column count is possible. Determine gap and // preview width.
mnColumnCount = gnPreferredColumnCount; if (nElementWidth - gnPreferredPreviewWidth < gnMinimalHorizontalPreviewGap)
{ // Use the minimal gap and adapt the preview width.
mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap);
nPreviewWidth = (nWidth - mnColumnCount*mnHorizontalGap) / mnColumnCount;
} elseif (nElementWidth - gnPreferredPreviewWidth <= gnMaximalHorizontalPreviewGap)
{ // Use the maximal gap and adapt the preview width.
mnHorizontalGap = round(gnMaximalHorizontalPreviewGap);
nPreviewWidth = (nWidth - mnColumnCount*mnHorizontalGap) / mnColumnCount;
} else
{ // Use the preferred preview width and adapt the gap.
nPreviewWidth = gnPreferredPreviewWidth;
mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
}
}
// Now determine the row count, preview height, and vertical gap. constdouble nPreviewHeight = nPreviewWidth / nSlideAspectRatio;
mnRowCount = ::std::max(
sal_Int32(1),
sal_Int32(ceil((nHeight+gnPreferredVerticalPreviewGap)
/ (nPreviewHeight + gnPreferredVerticalPreviewGap))));
mnVerticalGap = round(gnPreferredVerticalPreviewGap);
if (!mpFont || !mpFont->mxFont.is()) return nullptr;
// Long text has to be shortened. const OUString sText (GetFittingText(rsText, nMaximalWidth
- 2*gnHorizontalLabelBorder
- 2*gnHorizontalLabelPadding));
// Determine the size of the label. Its height is defined by the // bitmaps that are used to paints its background. The width is defined // by the text.
geometry::IntegerSize2D aLabelSize (CalculateLabelSize(sText));
// Create a new bitmap that will contain the complete label.
Reference<rendering::XBitmap> xBitmap (
mxCanvas->getDevice()->createCompatibleAlphaBitmap(aLabelSize));
if ( ! xBitmap.is()) return nullptr;
Reference<rendering::XBitmapCanvas> xBitmapCanvas (xBitmap, UNO_QUERY); if ( ! xBitmapCanvas.is()) return nullptr;
// Paint the background.
PaintButtonBackground(xBitmapCanvas, aLabelSize);
OUString PresenterSlideSorter::MouseOverManager::GetFittingText ( const OUString& rsText, constdouble nMaximalWidth) const
{ constdouble nTextWidth (
PresenterCanvasHelper::GetTextSize(mpFont->mxFont, rsText).Width); if (nTextWidth > nMaximalWidth)
{ // Text is too wide. Shorten it by removing characters from the end // and replacing them by ellipses.
// Guess a start value of the final string length. double nBestWidth (0);
OUString sBestCandidate;
sal_Int32 nLength (round(rsText.getLength() * nMaximalWidth / nTextWidth)); static constexpr OUStringLiteral sEllipses (u"..."); while (true)
{ const OUString sCandidate (rsText.subView(0,nLength) + sEllipses); constdouble nWidth (
PresenterCanvasHelper::GetTextSize(mpFont->mxFont, sCandidate).Width); if (nWidth > nMaximalWidth)
{ // Candidate still too wide, shorten it.
nLength -= 1; if (nLength <= 0) break;
} elseif (nWidth < nMaximalWidth)
{ // Candidate short enough. if (nWidth > nBestWidth)
{ // Best length so far.
sBestCandidate = sCandidate;
nBestWidth = nWidth;
nLength += 1; if (nLength >= rsText.getLength()) break;
} else break;
} else
{ // Candidate is exactly as long as it may be. Use it // without looking any further.
sBestCandidate = sCandidate; break;
}
} return sBestCandidate;
} else return rsText;
}
geometry::IntegerSize2D PresenterSlideSorter::MouseOverManager::CalculateLabelSize ( const OUString& rsText) const
{ // Height is specified by the label bitmaps.
sal_Int32 nHeight (32); if (mpCenterLabelBitmap)
{
Reference<rendering::XBitmap> xBitmap (mpCenterLabelBitmap->GetNormalBitmap()); if (xBitmap.is())
nHeight = xBitmap->getSize().Height;
}
// Width is specified by text width and maximal width. const geometry::RealSize2D aTextSize (
PresenterCanvasHelper::GetTextSize(mpFont->mxFont, rsText));
// Determine size of frame. if (mpTop)
mnTopFrameSize = mpTop->mnHeight; if (mpLeft)
mnLeftFrameSize = mpLeft->mnWidth; if (mpRight)
mnRightFrameSize = mpRight->mnWidth; if (mpBottom)
mnBottomFrameSize = mpBottom->mnHeight;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.