1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "precompiled_sd.hxx"
25 
26 #include "view/SlsPageObjectPainter.hxx"
27 
28 #include "model/SlsPageDescriptor.hxx"
29 #include "view/SlideSorterView.hxx"
30 #include "view/SlsPageObjectLayouter.hxx"
31 #include "view/SlsLayouter.hxx"
32 #include "view/SlsTheme.hxx"
33 #include "view/SlsButtonBar.hxx"
34 #include "SlsFramePainter.hxx"
35 #include "cache/SlsPageCache.hxx"
36 #include "controller/SlsProperties.hxx"
37 #include "Window.hxx"
38 #include "sdpage.hxx"
39 #include "sdresid.hxx"
40 #include <vcl/svapp.hxx>
41 #include <vcl/vclenum.hxx>
42 #include <vcl/virdev.hxx>
43 #include <boost/scoped_ptr.hpp>
44 
45 using namespace ::drawinglayer::primitive2d;
46 
47 namespace sd { namespace slidesorter { namespace view {
48 
49 namespace {
50 
Blend(const sal_uInt8 nValue1,const sal_uInt8 nValue2,const double nWeight)51 sal_uInt8 Blend (
52 	const sal_uInt8 nValue1,
53 	const sal_uInt8 nValue2,
54 	const double nWeight)
55 {
56 	const double nValue (nValue1*(1-nWeight) + nValue2 * nWeight);
57 	if (nValue < 0)
58 		return 0;
59 	else if (nValue > 255)
60 		return 255;
61 	else
62 		return (sal_uInt8)nValue;
63 }
64 
ClampColorChannel(const double nValue)65 sal_uInt8 ClampColorChannel (const double nValue)
66 {
67 	if (nValue <= 0)
68 		return 0;
69 	else if (nValue >= 255)
70 		return 255;
71 	else
72 		return sal_uInt8(nValue);
73 }
74 
CalculateColorChannel(const double nColor1,const double nColor2,const double nAlpha1,const double nAlpha2,const double nAlpha0)75 sal_uInt8 CalculateColorChannel(
76 	const double nColor1,
77 	const double nColor2,
78 	const double nAlpha1,
79 	const double nAlpha2,
80 	const double nAlpha0)
81 {
82 	if (nAlpha0 == 0)
83 		return 0;
84 
85 	const double nColor0 ((nAlpha1*nColor1 + nAlpha1*nAlpha2*nColor1 + nAlpha2*nColor2) / nAlpha0);
86 	return ClampColorChannel(255 * nColor0);
87 }
88 
89 } // end of anonymous namespace
90 
91 
92 
93 
94 //===== PageObjectPainter =====================================================
95 
PageObjectPainter(const SlideSorter & rSlideSorter)96 PageObjectPainter::PageObjectPainter (
97 	const SlideSorter& rSlideSorter)
98 	: mrLayouter(rSlideSorter.GetView().GetLayouter()),
99 	  mpPageObjectLayouter(),
100 	  mpCache(rSlideSorter.GetView().GetPreviewCache()),
101 	  mpProperties(rSlideSorter.GetProperties()),
102 	  mpTheme(rSlideSorter.GetTheme()),
103 	  mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber, *rSlideSorter.GetContentWindow())),
104 	  mpShadowPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_RawShadow))),
105 	  mpFocusBorderPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_FocusBorder))),
106 	  maNormalBackground(),
107 	  maSelectionBackground(),
108 	  maFocusedSelectionBackground(),
109 	  maMouseOverBackground(),
110 	  maMouseOverFocusedBackground(),
111 	  msUnhideString(mpTheme->GetString(Theme::String_Unhide)),
112 	  mrButtonBar(rSlideSorter.GetView().GetButtonBar()),
113 	  maSize()
114 {
115 	// Replace the color (not the alpha values) in the focus border with a
116 	// color derived from the current selection color.
117 	Color aColor (mpTheme->GetColor(Theme::Color_Selection));
118 	sal_uInt16 nHue, nSat, nBri;
119 	aColor.RGBtoHSB(nHue, nSat, nBri);
120 	aColor = Color::HSBtoRGB(nHue, 28, 65);
121 	mpFocusBorderPainter->AdaptColor(aColor, true);
122 }
123 
124 
125 
126 
~PageObjectPainter(void)127 PageObjectPainter::~PageObjectPainter (void)
128 {
129 }
130 
131 
132 
133 
PaintPageObject(OutputDevice & rDevice,const model::SharedPageDescriptor & rpDescriptor)134 void PageObjectPainter::PaintPageObject (
135 	OutputDevice& rDevice,
136 	const model::SharedPageDescriptor& rpDescriptor)
137 {
138 	if (UpdatePageObjectLayouter())
139 	{
140 		// Turn off antialiasing to avoid the bitmaps from being
141 		// shifted by fractions of a pixel and thus show blurry edges.
142 		const sal_uInt16 nSavedAntialiasingMode (rDevice.GetAntialiasing());
143 		rDevice.SetAntialiasing(nSavedAntialiasingMode & ~ANTIALIASING_ENABLE_B2DDRAW);
144 
145 		PaintBackground(rDevice, rpDescriptor);
146 		PaintPreview(rDevice, rpDescriptor);
147 		PaintPageNumber(rDevice, rpDescriptor);
148 		PaintTransitionEffect(rDevice, rpDescriptor);
149 		mrButtonBar.Paint(rDevice, rpDescriptor);
150 
151 		rDevice.SetAntialiasing(nSavedAntialiasingMode);
152 	}
153 }
154 
155 
156 
157 
UpdatePageObjectLayouter(void)158 bool PageObjectPainter::UpdatePageObjectLayouter (void)
159 {
160 	// The page object layouter is quite volatile. It may have been replaced
161 	// since the last call. Update it now.
162 	mpPageObjectLayouter = mrLayouter.GetPageObjectLayouter();
163 	if ( ! mpPageObjectLayouter)
164 	{
165 		OSL_ASSERT(mpPageObjectLayouter);
166 		return false;
167 	}
168 	else
169 		return true;
170 }
171 
172 
173 
174 
NotifyResize(const bool bForce)175 void PageObjectPainter::NotifyResize (const bool bForce)
176 {
177 	if (bForce || ! mpPageObjectLayouter)
178 		InvalidateBitmaps();
179 	else if (UpdatePageObjectLayouter())
180 	{
181 		const Size aSize (mpPageObjectLayouter->GetSize(
182 				PageObjectLayouter::FocusIndicator,
183 				PageObjectLayouter::WindowCoordinateSystem));
184 		if ( maSize!=aSize)
185 		{
186 			maSize = aSize;
187 			InvalidateBitmaps();
188 		}
189 	}
190 }
191 
192 
193 
194 
InvalidateBitmaps(void)195 void PageObjectPainter::InvalidateBitmaps (void)
196 {
197 	maNormalBackground.SetEmpty();
198 	maSelectionBackground.SetEmpty();
199 	maFocusedSelectionBackground.SetEmpty();
200 	maFocusedBackground.SetEmpty();
201 	maMouseOverBackground.SetEmpty();
202 	maMouseOverFocusedBackground.SetEmpty();
203 	maMouseOverSelectedAndFocusedBackground.SetEmpty();
204 }
205 
206 
207 
208 
SetTheme(const::boost::shared_ptr<view::Theme> & rpTheme)209 void PageObjectPainter::SetTheme (const ::boost::shared_ptr<view::Theme>& rpTheme)
210 {
211 	mpTheme = rpTheme;
212 	NotifyResize(true);
213 }
214 
215 
216 
217 
PaintBackground(OutputDevice & rDevice,const model::SharedPageDescriptor & rpDescriptor)218 void PageObjectPainter::PaintBackground (
219 	OutputDevice& rDevice,
220 	const model::SharedPageDescriptor& rpDescriptor)
221 {
222 	const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox(
223 		rpDescriptor,
224 		PageObjectLayouter::FocusIndicator,
225 		PageObjectLayouter::ModelCoordinateSystem));
226 
227 	const Bitmap& rBackground (GetBackgroundForState(rpDescriptor, rDevice));
228 	rDevice.DrawBitmap(aBox.TopLeft(), rBackground);
229 
230 	// Fill the interior of the preview area with the default background
231 	// color of the page.
232 	SdPage* pPage = rpDescriptor->GetPage();
233 	if (pPage != NULL)
234 	{
235 		rDevice.SetFillColor(pPage->GetPageBackgroundColor(NULL));
236 		rDevice.SetLineColor(pPage->GetPageBackgroundColor(NULL));
237 		const Rectangle aPreviewBox (mpPageObjectLayouter->GetBoundingBox(
238 			rpDescriptor,
239 			PageObjectLayouter::Preview,
240 			PageObjectLayouter::ModelCoordinateSystem));
241 		rDevice.DrawRect(aPreviewBox);
242 	}
243 }
244 
245 
246 
247 
PaintPreview(OutputDevice & rDevice,const model::SharedPageDescriptor & rpDescriptor) const248 void PageObjectPainter::PaintPreview (
249 	OutputDevice& rDevice,
250 	const model::SharedPageDescriptor& rpDescriptor) const
251 {
252 	const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox(
253 		rpDescriptor,
254 		PageObjectLayouter::Preview,
255 		PageObjectLayouter::ModelCoordinateSystem));
256 
257 	if( bool(mpCache))
258 	{
259 		const SdrPage* pPage = rpDescriptor->GetPage();
260 		mpCache->SetPreciousFlag(pPage, true);
261 
262 		const Bitmap aPreview (GetPreviewBitmap(rpDescriptor, &rDevice));
263 		if ( ! aPreview.IsEmpty())
264 		{
265 			if (aPreview.GetSizePixel() != aBox.GetSize())
266 				rDevice.DrawBitmap(aBox.TopLeft(), aBox.GetSize(), aPreview);
267 			else
268 				rDevice.DrawBitmap(aBox.TopLeft(), aPreview);
269 		}
270 	}
271 }
272 
273 
274 
275 
CreateMarkedPreview(const Size & rSize,const Bitmap & rPreview,const BitmapEx & rOverlay,const OutputDevice * pReferenceDevice) const276 Bitmap PageObjectPainter::CreateMarkedPreview (
277 	const Size& rSize,
278 	const Bitmap& rPreview,
279 	const BitmapEx& rOverlay,
280 	const OutputDevice* pReferenceDevice) const
281 {
282 	::boost::scoped_ptr<VirtualDevice> pDevice;
283 	if (pReferenceDevice != NULL)
284 		pDevice.reset(new VirtualDevice(*pReferenceDevice));
285 	else
286 		pDevice.reset(new VirtualDevice());
287 	pDevice->SetOutputSizePixel(rSize);
288 
289 	pDevice->DrawBitmap(Point(0,0), rSize, rPreview);
290 
291 	// Paint bitmap tiled over the preview to mark it as excluded.
292 	const sal_Int32 nIconWidth (rOverlay.GetSizePixel().Width());
293 	const sal_Int32 nIconHeight (rOverlay.GetSizePixel().Height());
294 	if (nIconWidth>0 && nIconHeight>0)
295 	{
296 		for (sal_Int32 nX=0; nX<rSize.Width(); nX+=nIconWidth)
297 			for (sal_Int32 nY=0; nY<rSize.Height(); nY+=nIconHeight)
298 				pDevice->DrawBitmapEx(Point(nX,nY), rOverlay);
299 	}
300 	return pDevice->GetBitmap(Point(0,0), rSize);
301 }
302 
303 
304 
305 
GetPreviewBitmap(const model::SharedPageDescriptor & rpDescriptor,const OutputDevice * pReferenceDevice) const306 Bitmap PageObjectPainter::GetPreviewBitmap (
307 	const model::SharedPageDescriptor& rpDescriptor,
308 	const OutputDevice* pReferenceDevice) const
309 {
310 	const SdrPage* pPage = rpDescriptor->GetPage();
311 	const bool bIsExcluded (rpDescriptor->HasState(model::PageDescriptor::ST_Excluded));
312 
313 	if (bIsExcluded)
314 	{
315 		Bitmap aMarkedPreview (mpCache->GetMarkedPreviewBitmap(pPage,false));
316 		const Rectangle aPreviewBox (mpPageObjectLayouter->GetBoundingBox(
317 			rpDescriptor,
318 			PageObjectLayouter::Preview,
319 			PageObjectLayouter::ModelCoordinateSystem));
320 		if (aMarkedPreview.IsEmpty() || aMarkedPreview.GetSizePixel()!=aPreviewBox.GetSize())
321 		{
322 			aMarkedPreview = CreateMarkedPreview(
323 				aPreviewBox.GetSize(),
324 				mpCache->GetPreviewBitmap(pPage,true),
325 				mpTheme->GetIcon(Theme::Icon_HideSlideOverlay),
326 				pReferenceDevice);
327 			mpCache->SetMarkedPreviewBitmap(pPage, aMarkedPreview);
328 		}
329 		return aMarkedPreview;
330 	}
331 	else
332 	{
333 		return mpCache->GetPreviewBitmap(pPage,false);
334 	}
335 }
336 
337 
338 
339 
PaintPageNumber(OutputDevice & rDevice,const model::SharedPageDescriptor & rpDescriptor) const340 void PageObjectPainter::PaintPageNumber (
341 	OutputDevice& rDevice,
342 	const model::SharedPageDescriptor& rpDescriptor) const
343 {
344 	const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox(
345 		rpDescriptor,
346 		PageObjectLayouter::PageNumber,
347 		PageObjectLayouter::ModelCoordinateSystem));
348 
349 	// Determine the color of the page number.
350 	Color aPageNumberColor (mpTheme->GetColor(Theme::Color_PageNumberDefault));
351 	if (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ||
352 		rpDescriptor->HasState(model::PageDescriptor::ST_Selected))
353 	{
354 		// Page number is painted on background for hover or selection or
355 		// both. Each of these background colors has a predefined luminance
356 		// which is compatible with the PageNumberHover color.
357 		aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberHover));
358 	}
359 	else
360 	{
361 		const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background));
362 		const sal_Int32 nBackgroundLuminance (aBackgroundColor.GetLuminance());
363 		// When the background color is black then this is interpreted as
364 		// high contrast mode and the font color is set to white.
365 		if (nBackgroundLuminance == 0)
366 			aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberHighContrast));
367 		else
368 		{
369 			// Compare luminance of default page number color and background
370 			// color. When the two are similar then use a darker
371 			// (preferred) or brighter font color.
372 			const sal_Int32 nFontLuminance (aPageNumberColor.GetLuminance());
373 			if (abs(nBackgroundLuminance - nFontLuminance) < 60)
374 			{
375 				if (nBackgroundLuminance > nFontLuminance-30)
376 					aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberBrightBackground));
377 				else
378 					aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberDarkBackground));
379 			}
380 		}
381 	}
382 
383 	// Paint the page number.
384 	OSL_ASSERT(rpDescriptor->GetPage()!=NULL);
385 	const sal_Int32 nPageNumber ((rpDescriptor->GetPage()->GetPageNum() - 1) / 2 + 1);
386 	const String sPageNumber (String::CreateFromInt32(nPageNumber));
387 	rDevice.SetFont(*mpPageNumberFont);
388 	rDevice.SetTextColor(aPageNumberColor);
389 	rDevice.DrawText(aBox, sPageNumber, TEXT_DRAW_RIGHT | TEXT_DRAW_VCENTER);
390 }
391 
392 
393 
394 
PaintTransitionEffect(OutputDevice & rDevice,const model::SharedPageDescriptor & rpDescriptor) const395 void PageObjectPainter::PaintTransitionEffect (
396 	OutputDevice& rDevice,
397 	const model::SharedPageDescriptor& rpDescriptor) const
398 {
399 	const SdPage* pPage = rpDescriptor->GetPage();
400 	if (pPage!=NULL && pPage->getTransitionType() > 0)
401 	{
402 		const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox(
403 			rpDescriptor,
404 			PageObjectLayouter::TransitionEffectIndicator,
405 			PageObjectLayouter::ModelCoordinateSystem));
406 
407 		rDevice.DrawBitmapEx(
408 			aBox.TopLeft(),
409 			mpPageObjectLayouter->GetTransitionEffectIcon().GetBitmapEx());
410 	}
411 }
412 
413 
414 
415 
GetBackgroundForState(const model::SharedPageDescriptor & rpDescriptor,const OutputDevice & rReferenceDevice)416 Bitmap& PageObjectPainter::GetBackgroundForState (
417 	const model::SharedPageDescriptor& rpDescriptor,
418 	const OutputDevice& rReferenceDevice)
419 {
420 	enum State { None = 0x00, Selected = 0x01, MouseOver = 0x02, Focused = 0x04 };
421 	const int eState =
422 		  (rpDescriptor->HasState(model::PageDescriptor::ST_Selected) ? Selected : None)
423 		| (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ? MouseOver : None)
424 		| (rpDescriptor->HasState(model::PageDescriptor::ST_Focused) ? Focused : None);
425 
426 	switch (eState)
427 	{
428 		case MouseOver | Selected | Focused:
429 			return GetBackground(
430 				maMouseOverSelectedAndFocusedBackground,
431 				Theme::Gradient_MouseOverSelectedAndFocusedPage,
432 				rReferenceDevice,
433 				true);
434 
435 		case MouseOver | Selected:
436 		case MouseOver:
437 			return GetBackground(
438 				maMouseOverBackground,
439 				Theme::Gradient_MouseOverPage,
440 				rReferenceDevice,
441 				false);
442 
443 		case MouseOver | Focused:
444 			return GetBackground(
445 				maMouseOverFocusedBackground,
446 				Theme::Gradient_MouseOverPage,
447 				rReferenceDevice,
448 				true);
449 
450 		case Selected | Focused:
451 			return GetBackground(
452 				maFocusedSelectionBackground,
453 				Theme::Gradient_SelectedAndFocusedPage,
454 				rReferenceDevice,
455 				true);
456 
457 		case Selected:
458 			return GetBackground(
459 				maSelectionBackground,
460 				Theme::Gradient_SelectedPage,
461 				rReferenceDevice,
462 				false);
463 
464 		case Focused:
465 			return GetBackground(
466 				maFocusedBackground,
467 				Theme::Gradient_FocusedPage,
468 				rReferenceDevice,
469 				true);
470 
471 		case None:
472 		default:
473 			return GetBackground(
474 				maNormalBackground,
475 				Theme::Gradient_NormalPage,
476 				rReferenceDevice,
477 				false);
478 	}
479 }
480 
481 
482 
483 
GetBackground(Bitmap & rBackground,Theme::GradientColorType eType,const OutputDevice & rReferenceDevice,const bool bHasFocusBorder)484 Bitmap& PageObjectPainter::GetBackground(
485 	Bitmap& rBackground,
486 	Theme::GradientColorType eType,
487 	const OutputDevice& rReferenceDevice,
488 	const bool bHasFocusBorder)
489 {
490 	if (rBackground.IsEmpty())
491 		rBackground = CreateBackgroundBitmap(rReferenceDevice, eType, bHasFocusBorder);
492 	return rBackground;
493 }
494 
495 
496 
497 
CreateBackgroundBitmap(const OutputDevice & rReferenceDevice,const Theme::GradientColorType eColorType,const bool bHasFocusBorder) const498 Bitmap PageObjectPainter::CreateBackgroundBitmap(
499 	const OutputDevice& rReferenceDevice,
500 	const Theme::GradientColorType eColorType,
501 	const bool bHasFocusBorder) const
502 {
503 	const Size aSize (mpPageObjectLayouter->GetSize(
504 		PageObjectLayouter::FocusIndicator,
505 		PageObjectLayouter::WindowCoordinateSystem));
506 	const Rectangle aPageObjectBox (mpPageObjectLayouter->GetBoundingBox(
507 		Point(0,0),
508 		PageObjectLayouter::PageObject,
509 		PageObjectLayouter::ModelCoordinateSystem));
510 	VirtualDevice aBitmapDevice (rReferenceDevice);
511 	aBitmapDevice.SetOutputSizePixel(aSize);
512 
513 	// Fill the background with the background color of the slide sorter.
514 	const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background));
515 	aBitmapDevice.SetFillColor(aBackgroundColor);
516 	aBitmapDevice.SetLineColor(aBackgroundColor);
517 	aBitmapDevice.DrawRect(Rectangle(Point(0,0), aSize));
518 
519 	// Paint the slide area with a linear gradient that starts some pixels
520 	// below the top and ends some pixels above the bottom.
521 	const Color aTopColor(mpTheme->GetGradientColor(eColorType, Theme::Fill1));
522 	const Color aBottomColor(mpTheme->GetGradientColor(eColorType, Theme::Fill2));
523 	if (aTopColor != aBottomColor)
524 	{
525 		const sal_Int32 nHeight (aPageObjectBox.GetHeight());
526 		const sal_Int32 nDefaultConstantSize(nHeight/4);
527 		const sal_Int32 nMinimalGradientSize(40);
528 		const sal_Int32 nY1 (
529 			::std::max<sal_Int32>(
530 				0,
531 				::std::min<sal_Int32>(
532 					nDefaultConstantSize,
533 					(nHeight - nMinimalGradientSize)/2)));
534 		const sal_Int32 nY2 (nHeight-nY1);
535 		const sal_Int32 nTop (aPageObjectBox.Top());
536 		for (sal_Int32 nY=0; nY<nHeight; ++nY)
537 		{
538 			if (nY<=nY1)
539 				aBitmapDevice.SetLineColor(aTopColor);
540 			else if (nY>=nY2)
541 				aBitmapDevice.SetLineColor(aBottomColor);
542 			else
543 			{
544 				Color aColor (aTopColor);
545 				aColor.Merge(aBottomColor, 255 * (nY2-nY) / (nY2-nY1));
546 				aBitmapDevice.SetLineColor(aColor);
547 			}
548 			aBitmapDevice.DrawLine(
549 				Point(aPageObjectBox.Left(), nY+nTop),
550 				Point(aPageObjectBox.Right(), nY+nTop));
551 		}
552 	}
553 	else
554 	{
555 		aBitmapDevice.SetFillColor(aTopColor);
556 		aBitmapDevice.DrawRect(aPageObjectBox);
557 	}
558 
559 	// Paint the simple border and, for some backgrounds, the focus border.
560 	if (bHasFocusBorder)
561 		mpFocusBorderPainter->PaintFrame(aBitmapDevice, aPageObjectBox);
562 	else
563 		PaintBorder(aBitmapDevice, eColorType, aPageObjectBox);
564 
565 	// Get bounding box of the preview around which a shadow is painted.
566 	// Compensate for the border around the preview.
567 	const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox(
568 		Point(0,0),
569 		PageObjectLayouter::Preview,
570 		PageObjectLayouter::ModelCoordinateSystem));
571 	Rectangle aFrameBox (aBox.Left()-1,aBox.Top()-1,aBox.Right()+1,aBox.Bottom()+1);
572 	mpShadowPainter->PaintFrame(aBitmapDevice, aFrameBox);
573 
574 	return aBitmapDevice.GetBitmap (Point(0,0),aSize);
575 }
576 
577 
578 
579 
PaintBorder(OutputDevice & rDevice,const Theme::GradientColorType eColorType,const Rectangle & rBox) const580 void PageObjectPainter::PaintBorder (
581 	OutputDevice& rDevice,
582 	const Theme::GradientColorType eColorType,
583 	const Rectangle& rBox) const
584 {
585 	rDevice.SetFillColor();
586 	const sal_Int32 nBorderWidth (1);
587 	for (int nIndex=0; nIndex<nBorderWidth; ++nIndex)
588 	{
589 		const int nDelta (nIndex);
590 		rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::Border2));
591 		rDevice.DrawLine(
592 			Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
593 			Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta));
594 		rDevice.DrawLine(
595 			Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta),
596 			Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta));
597 		rDevice.DrawLine(
598 			Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta),
599 			Point(rBox.Right()+nDelta, rBox.Top()-nDelta));
600 
601 		rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::Border1));
602 		rDevice.DrawLine(
603 			Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
604 			Point(rBox.Right()+nDelta, rBox.Top()-nDelta));
605 	}
606 }
607 
608 
609 
610 } } } // end of namespace sd::slidesorter::view
611