diff options
Diffstat (limited to 'sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx')
-rw-r--r-- | sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx | 580 |
1 files changed, 580 insertions, 0 deletions
diff --git a/sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx b/sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx new file mode 100644 index 000000000000..8d5b1cfbcdc8 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx @@ -0,0 +1,580 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#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 "view/SlsButtonBar.hxx" +#include "SlsFramePainter.hxx" +#include "cache/SlsPageCache.hxx" +#include "controller/SlsProperties.hxx" +#include "Window.hxx" +#include "sdpage.hxx" +#include "sdresid.hxx" +#include <vcl/svapp.hxx> +#include <vcl/vclenum.hxx> +#include <vcl/virdev.hxx> +#include <boost/scoped_ptr.hpp> + +using namespace ::drawinglayer::primitive2d; + +namespace sd { namespace slidesorter { namespace view { + +namespace { + +UINT8 Blend ( + const UINT8 nValue1, + const UINT8 nValue2, + const double nWeight) +{ + const double nValue (nValue1*(1-nWeight) + nValue2 * nWeight); + if (nValue < 0) + return 0; + else if (nValue > 255) + return 255; + else + return (UINT8)nValue; +} + +sal_uInt8 ClampColorChannel (const double nValue) +{ + if (nValue <= 0) + return 0; + else if (nValue >= 255) + return 255; + else + return sal_uInt8(nValue); +} + +sal_uInt8 CalculateColorChannel( + const double nColor1, + const double nColor2, + const double nAlpha1, + const double nAlpha2, + const double nAlpha0) +{ + if (nAlpha0 == 0) + return 0; + + const double nColor0 ((nAlpha1*nColor1 + nAlpha1*nAlpha2*nColor1 + nAlpha2*nColor2) / nAlpha0); + return ClampColorChannel(255 * nColor0); +} + +} // end of anonymous namespace + + + + +//===== PageObjectPainter ===================================================== + +PageObjectPainter::PageObjectPainter ( + const SlideSorter& rSlideSorter) + : mrLayouter(rSlideSorter.GetView().GetLayouter()), + mpPageObjectLayouter(), + mpCache(rSlideSorter.GetView().GetPreviewCache()), + mpProperties(rSlideSorter.GetProperties()), + mpTheme(rSlideSorter.GetTheme()), + mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber, *rSlideSorter.GetContentWindow())), + mpShadowPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_RawShadow))), + mpFocusBorderPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_FocusBorder))), + maNormalBackground(), + maSelectionBackground(), + maFocusedSelectionBackground(), + maMouseOverBackground(), + maMouseOverFocusedBackground(), + msUnhideString(mpTheme->GetString(Theme::String_Unhide)), + mrButtonBar(rSlideSorter.GetView().GetButtonBar()) +{ + // 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)); + USHORT nHue, nSat, nBri; + aColor.RGBtoHSB(nHue, nSat, nBri); + aColor = Color::HSBtoRGB(nHue, 28, 65); + mpFocusBorderPainter->AdaptColor(aColor, true); +} + + + + +PageObjectPainter::~PageObjectPainter (void) +{ +} + + + + +void PageObjectPainter::PaintPageObject ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) +{ + // The page object layouter is quite volatile. It may have been replaced + // since the last call. Update it now. + mpPageObjectLayouter = mrLayouter.GetPageObjectLayouter(); + if ( ! mpPageObjectLayouter) + { + OSL_ASSERT(mpPageObjectLayouter); + return; + } + + // Turn off antialiasing to avoid the bitmaps from being shifted by + // fractions of a pixel and thus show blurry edges. + const USHORT nSavedAntialiasingMode (rDevice.GetAntialiasing()); + rDevice.SetAntialiasing(nSavedAntialiasingMode & ~ANTIALIASING_ENABLE_B2DDRAW); + + PaintBackground(rDevice, rpDescriptor); + PaintPreview(rDevice, rpDescriptor); + PaintPageNumber(rDevice, rpDescriptor); + PaintTransitionEffect(rDevice, rpDescriptor); + mrButtonBar.Paint(rDevice, rpDescriptor); + + rDevice.SetAntialiasing(nSavedAntialiasingMode); +} + + + + +void PageObjectPainter::NotifyResize (const bool bForce) +{ + (void)bForce; + maNormalBackground.SetEmpty(); + maSelectionBackground.SetEmpty(); + maFocusedSelectionBackground.SetEmpty(); + maFocusedBackground.SetEmpty(); + maMouseOverBackground.SetEmpty(); + maMouseOverFocusedBackground.SetEmpty(); + maMouseOverSelectedAndFocusedBackground.SetEmpty(); +} + + + + +void PageObjectPainter::SetTheme (const ::boost::shared_ptr<view::Theme>& rpTheme) +{ + mpTheme = rpTheme; + NotifyResize(true); +} + + + + +void PageObjectPainter::PaintBackground ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) +{ + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::FocusIndicator, + PageObjectLayouter::ModelCoordinateSystem)); + + const Bitmap& rBackground (GetBackgroundForState(rpDescriptor, rDevice)); + rDevice.DrawBitmap(aBox.TopLeft(), rBackground); + + // Fill the interior of the preview area with the default background + // color of the page. + SdPage* pPage = rpDescriptor->GetPage(); + if (pPage != NULL) + { + rDevice.SetFillColor(pPage->GetPageBackgroundColor(NULL)); + rDevice.SetLineColor(pPage->GetPageBackgroundColor(NULL)); + const Rectangle aPreviewBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem)); + rDevice.DrawRect(aPreviewBox); + } +} + + + + +void PageObjectPainter::PaintPreview ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const +{ + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem)); + + if (mpCache != NULL) + { + const SdrPage* pPage = rpDescriptor->GetPage(); + mpCache->SetPreciousFlag(pPage, true); + + const Bitmap aPreview (GetPreviewBitmap(rpDescriptor, &rDevice)); + if ( ! aPreview.IsEmpty()) + if (aPreview.GetSizePixel() != aBox.GetSize()) + rDevice.DrawBitmap(aBox.TopLeft(), aBox.GetSize(), aPreview); + else + rDevice.DrawBitmap(aBox.TopLeft(), aPreview); + } +} + + + + +Bitmap PageObjectPainter::CreateMarkedPreview ( + const Size& rSize, + const Bitmap& rPreview, + const BitmapEx& rOverlay, + const OutputDevice* pReferenceDevice) const +{ + ::boost::scoped_ptr<VirtualDevice> pDevice; + if (pReferenceDevice != NULL) + pDevice.reset(new VirtualDevice(*pReferenceDevice)); + else + pDevice.reset(new VirtualDevice()); + pDevice->SetOutputSizePixel(rSize); + + pDevice->DrawBitmap(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 (sal_Int32 nX=0; nX<rSize.Width(); nX+=nIconWidth) + for (sal_Int32 nY=0; nY<rSize.Height(); nY+=nIconHeight) + pDevice->DrawBitmapEx(Point(nX,nY), rOverlay); + } + return pDevice->GetBitmap(Point(0,0), rSize); +} + + + + +Bitmap 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) + { + Bitmap aMarkedPreview (mpCache->GetMarkedPreviewBitmap(pPage,false)); + const Rectangle aPreviewBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::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 ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const +{ + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::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 = Color(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 = Color(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 = Color(mpTheme->GetColor(Theme::Color_PageNumberBrightBackground)); + else + aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberDarkBackground)); + } + } + + // Paint the page number. + OSL_ASSERT(rpDescriptor->GetPage()!=NULL); + const sal_Int32 nPageNumber ((rpDescriptor->GetPage()->GetPageNum() - 1) / 2 + 1); + const String sPageNumber (String::CreateFromInt32(nPageNumber)); + rDevice.SetFont(*mpPageNumberFont); + rDevice.SetTextColor(aPageNumberColor); + rDevice.DrawText(aBox, sPageNumber, TEXT_DRAW_RIGHT | TEXT_DRAW_VCENTER); +} + + + + +void PageObjectPainter::PaintTransitionEffect ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const +{ + const SdPage* pPage = rpDescriptor->GetPage(); + if (pPage!=NULL && pPage->getTransitionType() > 0) + { + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::TransitionEffectIndicator, + PageObjectLayouter::ModelCoordinateSystem)); + + rDevice.DrawBitmapEx( + aBox.TopLeft(), + mpPageObjectLayouter->GetTransitionEffectIcon().GetBitmapEx()); + } +} + + + + +Bitmap& PageObjectPainter::GetBackgroundForState ( + const model::SharedPageDescriptor& rpDescriptor, + const OutputDevice& rReferenceDevice) +{ + enum State { None = 0x00, Selected = 0x01, MouseOver = 0x02, Focused = 0x04 }; + const State eState (State( + (rpDescriptor->HasState(model::PageDescriptor::ST_Selected) ? Selected : None) + | (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ? MouseOver : None) + | (rpDescriptor->HasState(model::PageDescriptor::ST_Focused) ? Focused : None))); + + switch (eState) + { + case MouseOver | Selected | Focused: + return GetBackground( + maMouseOverSelectedAndFocusedBackground, + Theme::Gradient_MouseOverSelectedAndFocusedPage, + rReferenceDevice, + true); + + case MouseOver | Selected: + case MouseOver: + return GetBackground( + maMouseOverBackground, + Theme::Gradient_MouseOverPage, + rReferenceDevice, + false); + + case MouseOver | Focused: + return GetBackground( + maMouseOverFocusedBackground, + Theme::Gradient_MouseOverPage, + rReferenceDevice, + true); + + case Selected | Focused: + return GetBackground( + maFocusedSelectionBackground, + Theme::Gradient_SelectedAndFocusedPage, + rReferenceDevice, + true); + + case Selected: + return GetBackground( + maSelectionBackground, + Theme::Gradient_SelectedPage, + rReferenceDevice, + false); + + case Focused: + return GetBackground( + maFocusedBackground, + Theme::Gradient_FocusedPage, + rReferenceDevice, + true); + + case None: + default: + return GetBackground( + maNormalBackground, + Theme::Gradient_NormalPage, + rReferenceDevice, + false); + } +} + + + + +Bitmap& PageObjectPainter::GetBackground( + Bitmap& rBackground, + Theme::GradientColorType eType, + const OutputDevice& rReferenceDevice, + const bool bHasFocusBorder) +{ + if (rBackground.IsEmpty()) + rBackground = CreateBackgroundBitmap(rReferenceDevice, eType, bHasFocusBorder); + return rBackground; +} + + + + +Bitmap PageObjectPainter::CreateBackgroundBitmap( + const OutputDevice& rReferenceDevice, + const Theme::GradientColorType eColorType, + const bool bHasFocusBorder) const +{ + const Size aSize (mpPageObjectLayouter->GetSize( + PageObjectLayouter::FocusIndicator, + PageObjectLayouter::WindowCoordinateSystem)); + const Rectangle aPageObjectBox (mpPageObjectLayouter->GetBoundingBox( + Point(0,0), + PageObjectLayouter::PageObject, + PageObjectLayouter::ModelCoordinateSystem)); + VirtualDevice aBitmapDevice (rReferenceDevice); + aBitmapDevice.SetOutputSizePixel(aSize); + + // Fill the background with the background color of the slide sorter. + const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background)); + OSL_TRACE("filling background of page object bitmap with color %x", aBackgroundColor.GetColor()); + aBitmapDevice.SetFillColor(aBackgroundColor); + aBitmapDevice.SetLineColor(aBackgroundColor); + aBitmapDevice.DrawRect(Rectangle(Point(0,0), aSize)); + + // 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::Fill1)); + const Color aBottomColor(mpTheme->GetGradientColor(eColorType, Theme::Fill2)); + if (aTopColor != aBottomColor) + { + const sal_Int32 nHeight (aPageObjectBox.GetHeight()); + const sal_Int32 nDefaultConstantSize(nHeight/4); + const sal_Int32 nMinimalGradientSize(40); + const sal_Int32 nY1 ( + ::std::max<sal_Int32>( + 0, + ::std::min<sal_Int32>( + nDefaultConstantSize, + (nHeight - nMinimalGradientSize)/2))); + const sal_Int32 nY2 (nHeight-nY1); + const sal_Int32 nTop (aPageObjectBox.Top()); + for (sal_Int32 nY=0; nY<nHeight; ++nY) + { + if (nY<=nY1) + aBitmapDevice.SetLineColor(aTopColor); + else if (nY>=nY2) + aBitmapDevice.SetLineColor(aBottomColor); + else + { + Color aColor (aTopColor); + aColor.Merge(aBottomColor, 255 * (nY2-nY) / (nY2-nY1)); + aBitmapDevice.SetLineColor(aColor); + } + aBitmapDevice.DrawLine( + Point(aPageObjectBox.Left(), nY+nTop), + Point(aPageObjectBox.Right(), nY+nTop)); + } + } + else + { + aBitmapDevice.SetFillColor(aTopColor); + aBitmapDevice.DrawRect(aPageObjectBox); + } + + // Paint the simple border and, for some backgrounds, the focus border. + if (bHasFocusBorder) + mpFocusBorderPainter->PaintFrame(aBitmapDevice, aPageObjectBox); + else + PaintBorder(aBitmapDevice, eColorType, aPageObjectBox); + + // Get bounding box of the preview around which a shadow is painted. + // Compensate for the border around the preview. + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + Point(0,0), + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem)); + Rectangle aFrameBox (aBox.Left()-1,aBox.Top()-1,aBox.Right()+1,aBox.Bottom()+1); + mpShadowPainter->PaintFrame(aBitmapDevice, aFrameBox); + + return aBitmapDevice.GetBitmap (Point(0,0),aSize); +} + + + + +void PageObjectPainter::PaintBorder ( + OutputDevice& rDevice, + const Theme::GradientColorType eColorType, + const 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::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::Border1)); + rDevice.DrawLine( + Point(rBox.Left()-nDelta, rBox.Top()-nDelta), + Point(rBox.Right()+nDelta, rBox.Top()-nDelta)); + } +} + + + +} } } // end of namespace sd::slidesorter::view |