6dc092045c
Change-Id: I7e48be1962d1e643c49c8cc0d6ca01ffbbb97429 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165567 Tested-by: Jenkins Reviewed-by: Gabor Kelemen <gabor.kelemen.extern@allotropia.de>
440 lines
17 KiB
C++
440 lines
17 KiB
C++
/* -*- 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 .
|
|
*/
|
|
|
|
#include <view/SlsPageObjectPainter.hxx>
|
|
|
|
#include <model/SlsPageDescriptor.hxx>
|
|
#include <view/SlideSorterView.hxx>
|
|
#include <view/SlsPageObjectLayouter.hxx>
|
|
#include <view/SlsLayouter.hxx>
|
|
#include <view/SlsTheme.hxx>
|
|
#include <SlideSorter.hxx>
|
|
#include "SlsFramePainter.hxx"
|
|
#include <cache/SlsPageCache.hxx>
|
|
#include <Window.hxx>
|
|
#include <sdpage.hxx>
|
|
#include <vcl/virdev.hxx>
|
|
#include <CustomAnimationEffect.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <memory>
|
|
|
|
namespace sd::slidesorter::view {
|
|
|
|
//===== PageObjectPainter =====================================================
|
|
|
|
PageObjectPainter::PageObjectPainter (
|
|
const SlideSorter& rSlideSorter)
|
|
: mrLayouter(rSlideSorter.GetView().GetLayouter()),
|
|
mpCache(rSlideSorter.GetView().GetPreviewCache()),
|
|
mpTheme(rSlideSorter.GetTheme()),
|
|
mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber, *rSlideSorter.GetContentWindow()->GetOutDev())),
|
|
mpShadowPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_RawShadow))),
|
|
mpFocusBorderPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_FocusBorder)))
|
|
{
|
|
// Replace the color (not the alpha values) in the focus border with a
|
|
// color derived from the current selection color.
|
|
Color aColor (mpTheme->GetColor(Theme::Color_Selection));
|
|
sal_uInt16 nHue, nSat, nBri;
|
|
aColor.RGBtoHSB(nHue, nSat, nBri);
|
|
aColor = Color::HSBtoRGB(nHue, 28, 65);
|
|
mpFocusBorderPainter->AdaptColor(aColor);
|
|
}
|
|
|
|
PageObjectPainter::~PageObjectPainter()
|
|
{
|
|
}
|
|
|
|
void PageObjectPainter::PaintPageObject (
|
|
OutputDevice& rDevice,
|
|
const model::SharedPageDescriptor& rpDescriptor)
|
|
{
|
|
if (!UpdatePageObjectLayouter())
|
|
return;
|
|
|
|
PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
|
|
// Turn off antialiasing to avoid the bitmaps from being
|
|
// shifted by fractions of a pixel and thus show blurry edges.
|
|
const AntialiasingFlags nSavedAntialiasingMode (rDevice.GetAntialiasing());
|
|
rDevice.SetAntialiasing(nSavedAntialiasingMode & ~AntialiasingFlags::Enable);
|
|
|
|
PaintBackground(pPageObjectLayouter, rDevice, rpDescriptor);
|
|
PaintPreview(pPageObjectLayouter, rDevice, rpDescriptor);
|
|
PaintPageNumber(pPageObjectLayouter, rDevice, rpDescriptor);
|
|
PaintTransitionEffect(pPageObjectLayouter, rDevice, rpDescriptor);
|
|
if (rpDescriptor->GetPage()->hasAnimationNode())
|
|
PaintCustomAnimationEffect(pPageObjectLayouter, rDevice, rpDescriptor);
|
|
rDevice.SetAntialiasing(nSavedAntialiasingMode);
|
|
}
|
|
|
|
bool PageObjectPainter::UpdatePageObjectLayouter()
|
|
{
|
|
// The page object layouter is quite volatile. It may have been replaced
|
|
// since the last call. Update it now.
|
|
PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
|
|
if ( ! pPageObjectLayouter)
|
|
{
|
|
OSL_FAIL("no page object layouter");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void PageObjectPainter::SetTheme (const std::shared_ptr<view::Theme>& rpTheme)
|
|
{
|
|
mpTheme = rpTheme;
|
|
}
|
|
|
|
void PageObjectPainter::PaintBackground (
|
|
PageObjectLayouter *pPageObjectLayouter,
|
|
OutputDevice& rDevice,
|
|
const model::SharedPageDescriptor& rpDescriptor) const
|
|
{
|
|
PaintBackgroundDetail(pPageObjectLayouter, rDevice, rpDescriptor);
|
|
|
|
// Fill the interior of the preview area with the default background
|
|
// color of the page.
|
|
SdPage* pPage = rpDescriptor->GetPage();
|
|
if (pPage != nullptr)
|
|
{
|
|
rDevice.SetFillColor(pPage->GetPageBackgroundColor(nullptr));
|
|
rDevice.SetLineColor(pPage->GetPageBackgroundColor(nullptr));
|
|
const ::tools::Rectangle aPreviewBox (pPageObjectLayouter->GetBoundingBox(
|
|
rpDescriptor,
|
|
PageObjectLayouter::Part::Preview,
|
|
PageObjectLayouter::ModelCoordinateSystem));
|
|
rDevice.DrawRect(aPreviewBox);
|
|
}
|
|
}
|
|
|
|
void PageObjectPainter::PaintPreview (
|
|
PageObjectLayouter *pPageObjectLayouter,
|
|
OutputDevice& rDevice,
|
|
const model::SharedPageDescriptor& rpDescriptor) const
|
|
{
|
|
const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
|
|
rpDescriptor,
|
|
PageObjectLayouter::Part::Preview,
|
|
PageObjectLayouter::ModelCoordinateSystem));
|
|
|
|
if (mpCache == nullptr)
|
|
return;
|
|
|
|
const SdrPage* pPage = rpDescriptor->GetPage();
|
|
mpCache->SetPreciousFlag(pPage, true);
|
|
|
|
const BitmapEx aPreview (GetPreviewBitmap(rpDescriptor, &rDevice));
|
|
if ( ! aPreview.IsEmpty())
|
|
{
|
|
if (aPreview.GetSizePixel() != aBox.GetSize())
|
|
rDevice.DrawBitmapEx(aBox.TopLeft(), aBox.GetSize(), aPreview);
|
|
else
|
|
rDevice.DrawBitmapEx(aBox.TopLeft(), aPreview);
|
|
}
|
|
}
|
|
|
|
BitmapEx PageObjectPainter::CreateMarkedPreview (
|
|
const Size& rSize,
|
|
const BitmapEx& rPreview,
|
|
const BitmapEx& rOverlay,
|
|
const OutputDevice* pReferenceDevice)
|
|
{
|
|
ScopedVclPtr<VirtualDevice> pDevice;
|
|
if (pReferenceDevice != nullptr)
|
|
pDevice.disposeAndReset(VclPtr<VirtualDevice>::Create(*pReferenceDevice));
|
|
else
|
|
pDevice.disposeAndReset(VclPtr<VirtualDevice>::Create());
|
|
pDevice->SetOutputSizePixel(rSize);
|
|
|
|
pDevice->DrawBitmapEx(Point(0,0), rSize, rPreview);
|
|
|
|
// Paint bitmap tiled over the preview to mark it as excluded.
|
|
const sal_Int32 nIconWidth (rOverlay.GetSizePixel().Width());
|
|
const sal_Int32 nIconHeight (rOverlay.GetSizePixel().Height());
|
|
if (nIconWidth>0 && nIconHeight>0)
|
|
{
|
|
for (::tools::Long nX=0; nX<rSize.Width(); nX+=nIconWidth)
|
|
for (::tools::Long nY=0; nY<rSize.Height(); nY+=nIconHeight)
|
|
pDevice->DrawBitmapEx(Point(nX,nY), rOverlay);
|
|
}
|
|
return pDevice->GetBitmapEx(Point(0,0), rSize);
|
|
}
|
|
|
|
BitmapEx PageObjectPainter::GetPreviewBitmap (
|
|
const model::SharedPageDescriptor& rpDescriptor,
|
|
const OutputDevice* pReferenceDevice) const
|
|
{
|
|
const SdrPage* pPage = rpDescriptor->GetPage();
|
|
const bool bIsExcluded (rpDescriptor->HasState(model::PageDescriptor::ST_Excluded));
|
|
|
|
if (bIsExcluded)
|
|
{
|
|
PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
|
|
|
|
BitmapEx aMarkedPreview (mpCache->GetMarkedPreviewBitmap(pPage));
|
|
const ::tools::Rectangle aPreviewBox (pPageObjectLayouter->GetBoundingBox(
|
|
rpDescriptor,
|
|
PageObjectLayouter::Part::Preview,
|
|
PageObjectLayouter::ModelCoordinateSystem));
|
|
if (aMarkedPreview.IsEmpty() || aMarkedPreview.GetSizePixel()!=aPreviewBox.GetSize())
|
|
{
|
|
aMarkedPreview = CreateMarkedPreview(
|
|
aPreviewBox.GetSize(),
|
|
mpCache->GetPreviewBitmap(pPage,true),
|
|
mpTheme->GetIcon(Theme::Icon_HideSlideOverlay),
|
|
pReferenceDevice);
|
|
mpCache->SetMarkedPreviewBitmap(pPage, aMarkedPreview);
|
|
}
|
|
return aMarkedPreview;
|
|
}
|
|
else
|
|
{
|
|
return mpCache->GetPreviewBitmap(pPage,false);
|
|
}
|
|
}
|
|
|
|
void PageObjectPainter::PaintPageNumber (
|
|
PageObjectLayouter *pPageObjectLayouter,
|
|
OutputDevice& rDevice,
|
|
const model::SharedPageDescriptor& rpDescriptor) const
|
|
{
|
|
const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
|
|
rpDescriptor,
|
|
PageObjectLayouter::Part::PageNumber,
|
|
PageObjectLayouter::ModelCoordinateSystem));
|
|
|
|
// Determine the color of the page number.
|
|
Color aPageNumberColor (mpTheme->GetColor(Theme::Color_PageNumberDefault));
|
|
if (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ||
|
|
rpDescriptor->HasState(model::PageDescriptor::ST_Selected))
|
|
{
|
|
// Page number is painted on background for hover or selection or
|
|
// both. Each of these background colors has a predefined luminance
|
|
// which is compatible with the PageNumberHover color.
|
|
aPageNumberColor = mpTheme->GetColor(Theme::Color_PageNumberHover);
|
|
}
|
|
else
|
|
{
|
|
const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background));
|
|
const sal_Int32 nBackgroundLuminance (aBackgroundColor.GetLuminance());
|
|
// When the background color is black then this is interpreted as
|
|
// high contrast mode and the font color is set to white.
|
|
if (nBackgroundLuminance == 0)
|
|
aPageNumberColor = mpTheme->GetColor(Theme::Color_PageNumberHighContrast);
|
|
else
|
|
{
|
|
// Compare luminance of default page number color and background
|
|
// color. When the two are similar then use a darker
|
|
// (preferred) or brighter font color.
|
|
const sal_Int32 nFontLuminance (aPageNumberColor.GetLuminance());
|
|
if (abs(nBackgroundLuminance - nFontLuminance) < 60)
|
|
{
|
|
if (nBackgroundLuminance > nFontLuminance-30)
|
|
aPageNumberColor = mpTheme->GetColor(Theme::Color_PageNumberBrightBackground);
|
|
else
|
|
aPageNumberColor = mpTheme->GetColor(Theme::Color_PageNumberDarkBackground);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Paint the page number.
|
|
OSL_ASSERT(rpDescriptor->GetPage()!=nullptr);
|
|
const sal_Int32 nPageNumber ((rpDescriptor->GetPage()->GetPageNum() - 1) / 2 + 1);
|
|
const OUString sPageNumber(OUString::number(nPageNumber));
|
|
rDevice.SetFont(*mpPageNumberFont);
|
|
rDevice.SetTextColor(aPageNumberColor);
|
|
rDevice.DrawText(aBox, sPageNumber, DrawTextFlags::Right | DrawTextFlags::VCenter);
|
|
}
|
|
|
|
void PageObjectPainter::PaintTransitionEffect (
|
|
PageObjectLayouter *pPageObjectLayouter,
|
|
OutputDevice& rDevice,
|
|
const model::SharedPageDescriptor& rpDescriptor)
|
|
{
|
|
const SdPage* pPage = rpDescriptor->GetPage();
|
|
if (pPage!=nullptr && pPage->getTransitionType() > 0)
|
|
{
|
|
const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
|
|
rpDescriptor,
|
|
PageObjectLayouter::Part::TransitionEffectIndicator,
|
|
PageObjectLayouter::ModelCoordinateSystem));
|
|
|
|
rDevice.DrawBitmapEx(
|
|
aBox.TopCenter(),
|
|
pPageObjectLayouter->GetTransitionEffectIcon().GetBitmapEx());
|
|
}
|
|
}
|
|
|
|
void PageObjectPainter::PaintCustomAnimationEffect (
|
|
PageObjectLayouter *pPageObjectLayouter,
|
|
OutputDevice& rDevice,
|
|
const model::SharedPageDescriptor& rpDescriptor)
|
|
{
|
|
SdPage* pPage = rpDescriptor->GetPage();
|
|
std::shared_ptr< MainSequence > aMainSequence = pPage->getMainSequence();
|
|
EffectSequence::iterator aIter = aMainSequence->getBegin();
|
|
EffectSequence::iterator aEnd = aMainSequence->getEnd();
|
|
if ( aIter != aEnd )
|
|
{
|
|
const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
|
|
rpDescriptor,
|
|
PageObjectLayouter::Part::CustomAnimationEffectIndicator,
|
|
PageObjectLayouter::ModelCoordinateSystem));
|
|
rDevice.DrawBitmapEx(
|
|
aBox.TopCenter(),
|
|
pPageObjectLayouter->GetCustomAnimationEffectIcon().GetBitmapEx());
|
|
}
|
|
}
|
|
|
|
void PageObjectPainter::PaintBackgroundDetail (
|
|
PageObjectLayouter *pPageObjectLayouter,
|
|
OutputDevice& rDevice,
|
|
const model::SharedPageDescriptor& rpDescriptor) const
|
|
{
|
|
enum State { None = 0x00, Selected = 0x01, MouseOver = 0x02, Focused = 0x04 };
|
|
const int eState =
|
|
(rpDescriptor->HasState(model::PageDescriptor::ST_Selected) ? Selected : None)
|
|
| (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ? MouseOver : None)
|
|
| (rpDescriptor->HasState(model::PageDescriptor::ST_Focused) ? Focused : None);
|
|
|
|
bool bHasFocusBorder;
|
|
Theme::GradientColorType eColorType;
|
|
|
|
switch (eState)
|
|
{
|
|
case MouseOver | Selected | Focused:
|
|
eColorType = Theme::Gradient_MouseOverSelectedAndFocusedPage;
|
|
bHasFocusBorder = true;
|
|
break;
|
|
|
|
case MouseOver | Selected:
|
|
eColorType = Theme::Gradient_MouseOverSelected;
|
|
bHasFocusBorder = false;
|
|
break;
|
|
|
|
case MouseOver:
|
|
eColorType = Theme::Gradient_MouseOverPage;
|
|
bHasFocusBorder = false;
|
|
break;
|
|
|
|
case MouseOver | Focused:
|
|
eColorType = Theme::Gradient_MouseOverPage;
|
|
bHasFocusBorder = true;
|
|
break;
|
|
|
|
case Selected | Focused:
|
|
eColorType = Theme::Gradient_SelectedAndFocusedPage;
|
|
bHasFocusBorder = true;
|
|
break;
|
|
|
|
case Selected:
|
|
eColorType = Theme::Gradient_SelectedPage;
|
|
bHasFocusBorder = false;
|
|
break;
|
|
|
|
case Focused:
|
|
eColorType = Theme::Gradient_FocusedPage;
|
|
bHasFocusBorder = true;
|
|
break;
|
|
|
|
case None:
|
|
default:
|
|
eColorType = Theme::Gradient_NormalPage;
|
|
bHasFocusBorder = false;
|
|
break;
|
|
}
|
|
|
|
const ::tools::Rectangle aFocusSize (pPageObjectLayouter->GetBoundingBox(
|
|
rpDescriptor,
|
|
PageObjectLayouter::Part::FocusIndicator,
|
|
PageObjectLayouter::ModelCoordinateSystem));
|
|
|
|
const ::tools::Rectangle aPageObjectBox (pPageObjectLayouter->GetBoundingBox(
|
|
rpDescriptor,
|
|
PageObjectLayouter::Part::PageObject,
|
|
PageObjectLayouter::ModelCoordinateSystem));
|
|
|
|
// Fill the background with the background color of the slide sorter.
|
|
const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background));
|
|
rDevice.SetFillColor(aBackgroundColor);
|
|
rDevice.SetLineColor(aBackgroundColor);
|
|
rDevice.DrawRect(aFocusSize);
|
|
|
|
// Paint the slide area with a linear gradient that starts some pixels
|
|
// below the top and ends some pixels above the bottom.
|
|
const Color aTopColor(mpTheme->GetGradientColor(eColorType, Theme::GradientColorClass::Fill1));
|
|
const Color aBottomColor(mpTheme->GetGradientColor(eColorType, Theme::GradientColorClass::Fill2));
|
|
if (aTopColor != aBottomColor)
|
|
{
|
|
Gradient gradient(css::awt::GradientStyle_LINEAR, aTopColor, aBottomColor);
|
|
rDevice.DrawGradient(aPageObjectBox, gradient);
|
|
}
|
|
else
|
|
{
|
|
rDevice.SetFillColor(aTopColor);
|
|
rDevice.DrawRect(aPageObjectBox);
|
|
}
|
|
|
|
// Paint the simple border and, for some backgrounds, the focus border.
|
|
if (bHasFocusBorder)
|
|
mpFocusBorderPainter->PaintFrame(rDevice, aPageObjectBox);
|
|
else
|
|
PaintBorder(rDevice, eColorType, aPageObjectBox);
|
|
|
|
// Get bounding box of the preview around which a shadow is painted.
|
|
// Compensate for the border around the preview.
|
|
const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
|
|
rpDescriptor,
|
|
PageObjectLayouter::Part::Preview,
|
|
PageObjectLayouter::ModelCoordinateSystem));
|
|
::tools::Rectangle aFrameBox (aBox.Left()-1,aBox.Top()-1,aBox.Right()+1,aBox.Bottom()+1);
|
|
mpShadowPainter->PaintFrame(rDevice, aFrameBox);
|
|
}
|
|
|
|
void PageObjectPainter::PaintBorder (
|
|
OutputDevice& rDevice,
|
|
const Theme::GradientColorType eColorType,
|
|
const ::tools::Rectangle& rBox) const
|
|
{
|
|
rDevice.SetFillColor();
|
|
const sal_Int32 nBorderWidth (1);
|
|
for (int nIndex=0; nIndex<nBorderWidth; ++nIndex)
|
|
{
|
|
const int nDelta (nIndex);
|
|
rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::GradientColorClass::Border2));
|
|
rDevice.DrawLine(
|
|
Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
|
|
Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta));
|
|
rDevice.DrawLine(
|
|
Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta),
|
|
Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta));
|
|
rDevice.DrawLine(
|
|
Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta),
|
|
Point(rBox.Right()+nDelta, rBox.Top()-nDelta));
|
|
|
|
rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::GradientColorClass::Border1));
|
|
rDevice.DrawLine(
|
|
Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
|
|
Point(rBox.Right()+nDelta, rBox.Top()-nDelta));
|
|
}
|
|
}
|
|
|
|
} // end of namespace sd::slidesorter::view
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|