xref: /AOO41X/main/sd/source/ui/slidesorter/view/SlsButtonBar.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "precompiled_sd.hxx"
29 
30 #include "view/SlsButtonBar.hxx"
31 
32 #include "SlideSorter.hxx"
33 #include "model/SlsPageDescriptor.hxx"
34 #include "model/SlideSorterModel.hxx"
35 #include "view/SlsTheme.hxx"
36 #include "view/SlideSorterView.hxx"
37 #include "view/SlsToolTip.hxx"
38 #include "controller/SlideSorterController.hxx"
39 #include "controller/SlsSlotManager.hxx"
40 #include "controller/SlsCurrentSlideManager.hxx"
41 #include "controller/SlsPageSelector.hxx"
42 #include "controller/SlsAnimator.hxx"
43 #include "controller/SlsAnimationFunction.hxx"
44 #include "app.hrc"
45 #include "drawdoc.hxx"
46 #include <svx/svxids.hrc>
47 #include <sfx2/dispatch.hxx>
48 #include <vcl/bmpacc.hxx>
49 #include <vcl/virdev.hxx>
50 #include <basegfx/polygon/b2dpolygontools.hxx>
51 #include <basegfx/polygon/b2dpolygon.hxx>
52 #include <com/sun/star/presentation/XPresentation2.hpp>
53 #include <boost/bind.hpp>
54 
55 using ::com::sun::star::uno::Any;
56 using ::com::sun::star::uno::Reference;
57 using ::com::sun::star::uno::Sequence;
58 using ::com::sun::star::beans::PropertyValue;
59 using ::com::sun::star::presentation::XPresentation2;
60 
61 namespace sd { namespace slidesorter { namespace view {
62 
63 /** Base class for the painter of the background bar onto which the buttons
64     are painted.  It also provides some size information.
65 */
66 class ButtonBar::BackgroundTheme
67 {
68 public:
69     BackgroundTheme(
70         const ::boost::shared_ptr<Theme>& rpTheme,
71         const ::std::vector<SharedButton>& rButtons);
72     /** Set the preview bounding box, the maximal area in which to display
73         buttons.  A call to this method triggers a call to Layout().
74     */
75     void SetPreviewBoundingBox (const Rectangle& rPreviewBoundingBox);
76     Button::IconSize GetIconSize (void) const;
77 
78     virtual BitmapEx CreateBackground (
79         const OutputDevice& rTemplateDevice,
80         const bool bIsButtonDown) const = 0;
81     virtual Point GetBackgroundLocation (void) = 0;
82     virtual Rectangle GetButtonArea (void) = 0;
83 
84 protected:
85     ::boost::shared_ptr<Theme> mpTheme;
86     Rectangle maPreviewBoundingBox;
87     Size maMinimumLargeButtonAreaSize;
88     Size maMinimumMediumButtonAreaSize;
89     Size maMinimumSmallButtonAreaSize;
90     Button::IconSize meIconSize;
91 
92     virtual void Layout (void) = 0;
93 
94 private:
95     void UpdateMinimumIconSizes(const ::std::vector<SharedButton>& rButtons);
96 };
97 
98 
99 namespace {
100     /** Rectangular button bar that covers the whole width of the preview.
101     */
102     class RectangleBackgroundTheme : public ButtonBar::BackgroundTheme
103     {
104     public:
105         RectangleBackgroundTheme(
106             const ::boost::shared_ptr<Theme>& rpTheme,
107             const ::std::vector<SharedButton>& rButtons);
108         virtual BitmapEx CreateBackground (
109             const OutputDevice& rTemplateDevice,
110             const bool bIsButtonDown) const;
111         virtual Point GetBackgroundLocation (void);
112         virtual Rectangle GetButtonArea (void);
113     protected:
114         virtual void Layout (void);
115     private:
116         sal_Int32 mnBarHeight;
117     };
118 
119     /** Button bar is composed of three images, the left and right end of
120         the bar and the center image.  Buttons are only placed over the
121         center image.  The center image is painted as is, it is not scaled.
122     */
123     class BitmapBackgroundTheme : public ButtonBar::BackgroundTheme
124     {
125     public:
126         BitmapBackgroundTheme(
127             const ::boost::shared_ptr<Theme>& rpTheme,
128             const ::std::vector<SharedButton>& rButtons);
129         virtual BitmapEx CreateBackground (
130             const OutputDevice& rTemplateDevice,
131             const bool bIsButtonDown) const;
132         virtual Point GetBackgroundLocation (void);
133         virtual Rectangle GetButtonArea (void);
134     protected:
135         virtual void Layout (void);
136     private:
137         Rectangle maButtonArea;
138         Point maBackgroundLocation;
139     };
140 
141     /** The source mask is essentially multiplied with the given alpha value.
142         The result is writen to the result mask.
143     */
144     void AdaptTransparency (AlphaMask& rMask, const AlphaMask& rSourceMask, const double nAlpha)
145     {
146         BitmapWriteAccess* pBitmap = rMask.AcquireWriteAccess();
147         const BitmapReadAccess* pSourceBitmap = const_cast<AlphaMask&>(rSourceMask).AcquireReadAccess();
148 
149         if (pBitmap!=NULL && pSourceBitmap!=NULL)
150         {
151             const sal_Int32 nWidth (pBitmap->Width());
152             const sal_Int32 nHeight (pBitmap->Height());
153 
154             for (sal_Int32 nY = 0; nY<nHeight; ++nY)
155                 for (sal_Int32 nX = 0; nX<nWidth; ++nX)
156                 {
157                     const sal_uInt8 nValue (255 - pSourceBitmap->GetPixel(nY, nX).GetBlueOrIndex());
158                     const sal_uInt8 nNewValue (nValue * (1-nAlpha));
159                     pBitmap->SetPixel(nY, nX, 255-nNewValue);
160                 }
161         }
162     }
163 
164 } // end of anonymous namespace
165 
166 
167 //===== ButtonBar::Lock =======================================================
168 
169 ButtonBar::Lock::Lock (SlideSorter& rSlideSorter)
170     : mrButtonBar(rSlideSorter.GetView().GetButtonBar())
171 {
172     mrButtonBar.AcquireLock();
173 }
174 
175 
176 
177 
178 ButtonBar::Lock::~Lock (void)
179 {
180     mrButtonBar.ReleaseLock();
181 }
182 
183 
184 
185 
186 //===== ButtonBar =============================================================
187 
188 ButtonBar::ButtonBar (SlideSorter& rSlideSorter)
189     : mrSlideSorter(rSlideSorter),
190       maPageObjectSize(0,0),
191       maButtonBoundingBox(),
192       maBackgroundLocation(),
193       mpDescriptor(),
194       mbIsExcluded(false),
195       mpButtonUnderMouse(),
196       mpDownButton(),
197       maRegularButtons(),
198       maExcludedButtons(),
199       maNormalBackground(),
200       maButtonDownBackground(),
201       mbIsMouseOverBar(false),
202       mpBackgroundTheme(),
203       mnLockCount(0)
204 {
205     HandleDataChangeEvent();
206 }
207 
208 
209 
210 
211 ButtonBar::~ButtonBar (void)
212 {
213 }
214 
215 
216 
217 
218 void ButtonBar::ProcessButtonDownEvent (
219     const model::SharedPageDescriptor& rpDescriptor,
220     const Point aMouseModelLocation)
221 {
222     SetButtonUnderMouse(GetButtonAt(aMouseModelLocation));
223     if (mpButtonUnderMouse)
224         mpButtonUnderMouse->SetState(Button::State_Down);
225     mpDownButton = mpButtonUnderMouse;
226 
227     mrSlideSorter.GetView().RequestRepaint(rpDescriptor);
228 }
229 
230 
231 
232 
233 void ButtonBar::ProcessButtonUpEvent (
234     const model::SharedPageDescriptor& rpDescriptor,
235     const Point aMouseModelLocation)
236 {
237     SetButtonUnderMouse(GetButtonAt(aMouseModelLocation));
238     if (mpButtonUnderMouse)
239     {
240         mpButtonUnderMouse->SetState(Button::State_Hover);
241         if (mpButtonUnderMouse == mpDownButton)
242         {
243             // This is done only when the buttons are sufficiently visible.
244             if (mpDescriptor->GetVisualState().GetButtonAlpha()<0.7)
245             {
246                 mpButtonUnderMouse->ProcessClick(mpDescriptor);
247                 mbIsExcluded = mpDescriptor->HasState(model::PageDescriptor::ST_Excluded);
248                 ProcessMouseMotionEvent (rpDescriptor, aMouseModelLocation, false);
249             }
250         }
251     }
252     mpDownButton.reset();
253     mrSlideSorter.GetView().RequestRepaint(rpDescriptor);
254 }
255 
256 
257 
258 
259 void ButtonBar::ProcessMouseMotionEvent (
260     const model::SharedPageDescriptor& rpDescriptor,
261     const Point aMouseModelLocation,
262     const bool bIsMouseButtonDown)
263 {
264     model::SharedPageDescriptor pOldDescriptor (mpDescriptor);
265     bool bPageHasChanged (false);
266     bool bButtonHasChanged (false);
267     bool bButtonStateHasChanged (false);
268 
269     // Update the page object for which to manage the buttons.
270     bPageHasChanged = SetPage(rpDescriptor);
271     mbIsMouseOverBar = IsMouseOverBar(aMouseModelLocation);
272 
273     // Update button under mouse.
274     if (rpDescriptor)
275     {
276         bButtonHasChanged = SetButtonUnderMouse(GetButtonAt(aMouseModelLocation));
277 
278         if (mpButtonUnderMouse)
279         {
280             // When the mouse button is down, mark the button under the
281             // mouse only as pressed when it is the same button the mouse
282             // button was pressed over, and where the button release would
283             // lead to a click action.
284             if (bIsMouseButtonDown)
285             {
286                 if (mpButtonUnderMouse==mpDownButton)
287                     bButtonStateHasChanged = mpButtonUnderMouse->SetState(Button::State_Down);
288             }
289             else
290                 bButtonStateHasChanged = mpButtonUnderMouse->SetState(Button::State_Hover);
291         }
292     }
293 
294     // Show a quick help text when the mouse is over a button.
295     if (bButtonHasChanged)
296     {
297         SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
298         if (pWindow)
299         {
300             if (mpButtonUnderMouse)
301                 mrSlideSorter.GetView().GetToolTip().ShowHelpText(mpButtonUnderMouse->GetHelpText());
302             else
303                 mrSlideSorter.GetView().GetToolTip().ShowDefaultHelpText();
304         }
305     }
306 
307     if (bPageHasChanged || bButtonHasChanged || bButtonStateHasChanged)
308     {
309         if (pOldDescriptor)
310             mrSlideSorter.GetView().RequestRepaint(pOldDescriptor);
311         if (mpDescriptor && pOldDescriptor!=mpDescriptor)
312             mrSlideSorter.GetView().RequestRepaint(mpDescriptor);
313     }
314 }
315 
316 
317 
318 
319 void ButtonBar::ResetPage (void)
320 {
321     SetPage(model::SharedPageDescriptor());
322 }
323 
324 
325 
326 
327 bool ButtonBar::SetPage (const model::SharedPageDescriptor& rpDescriptor)
328 {
329     if (mpDescriptor != rpDescriptor)
330     {
331         mpDescriptor = rpDescriptor;
332 
333         if (mpDescriptor)
334             mbIsExcluded = mpDescriptor->HasState(model::PageDescriptor::ST_Excluded);
335         else
336             mbIsExcluded = false;
337         SetButtonUnderMouse();
338         mpDownButton.reset();
339 
340         return true;
341     }
342     else
343         return false;
344 }
345 
346 
347 
348 
349 sal_Int32 ButtonBar::GetButtonCount (const bool bIsExcluded) const
350 {
351     if (bIsExcluded)
352         return maExcludedButtons.size();
353     else
354         return maRegularButtons.size();
355 }
356 
357 
358 
359 
360 ::boost::shared_ptr<Button> ButtonBar::GetButton (
361     const bool bIsExcluded,
362     const sal_Int32 nIndex) const
363 {
364     const ::std::vector<boost::shared_ptr<Button> >& rButtons (bIsExcluded
365         ? maExcludedButtons
366         : maRegularButtons);
367 
368     if (nIndex<0 || sal_uInt32(nIndex)>=rButtons.size())
369     {
370         OSL_ASSERT(nIndex<0 || sal_uInt32(nIndex)>=rButtons.size());
371         return ::boost::shared_ptr<Button>();
372     }
373     else
374         return rButtons[sal_uInt32(nIndex)];
375 }
376 
377 
378 
379 
380 SharedButton ButtonBar::GetButtonAt (const Point aModelLocation)
381 {
382     if (IsMouseOverBar(aModelLocation))
383     {
384         const Point aLocalLocation (aModelLocation - mpDescriptor->GetBoundingBox().TopLeft());
385         ::std::vector<SharedButton>& rButtons (
386             mbIsExcluded ? maExcludedButtons : maRegularButtons);
387         for (sal_uInt32 nIndex=0; nIndex<rButtons.size(); ++nIndex)
388         {
389             if (rButtons[sal_uInt32(nIndex)]->GetBoundingBox().IsInside(aLocalLocation))
390             {
391                 if (rButtons[sal_uInt32(nIndex)]->IsEnabled())
392                     return rButtons[sal_uInt32(nIndex)];
393                 else
394                     return SharedButton();
395             }
396         }
397     }
398 
399     return SharedButton();
400 }
401 
402 
403 
404 
405 bool ButtonBar::IsMouseOverBar (void) const
406 {
407     return mbIsMouseOverBar;
408 }
409 
410 
411 
412 
413 bool ButtonBar::SetButtonUnderMouse (const SharedButton& rButton)
414 {
415     if (mpButtonUnderMouse != rButton)
416     {
417         if (mpButtonUnderMouse)
418             mpButtonUnderMouse->SetState(Button::State_Normal);
419 
420         mpButtonUnderMouse = rButton;
421 
422         return true;
423     }
424     else
425         return false;
426 }
427 
428 
429 
430 
431 void ButtonBar::Paint (
432     OutputDevice& rDevice,
433     const model::SharedPageDescriptor& rpDescriptor)
434 {
435     if ( ! rpDescriptor)
436         return;
437 
438     const double nButtonBarAlpha (rpDescriptor->GetVisualState().GetButtonBarAlpha());
439     if (nButtonBarAlpha >= 1)
440         return;
441 
442     LayoutButtons(rpDescriptor->GetBoundingBox().GetSize());
443 
444     const Point aOffset (rpDescriptor->GetBoundingBox().TopLeft());
445 
446     // Paint the background.
447     PaintButtonBackground(rDevice, rpDescriptor, aOffset);
448 
449     // Paint the buttons.
450     const ::std::vector<SharedButton>& rButtons (
451         rpDescriptor->HasState(model::PageDescriptor::ST_Excluded)
452             ? maExcludedButtons
453             : maRegularButtons);
454 
455 
456     const double nButtonAlpha (rpDescriptor->GetVisualState().GetButtonAlpha());
457     for (sal_uInt32 nIndex=0; nIndex<rButtons.size(); ++nIndex)
458         rButtons[nIndex]->Paint(
459             rDevice,
460             aOffset,
461             nButtonAlpha,
462             mrSlideSorter.GetTheme());
463 }
464 
465 
466 
467 
468 bool ButtonBar::IsMouseOverButton (void) const
469 {
470     return mpButtonUnderMouse;
471 }
472 
473 
474 
475 
476 void ButtonBar::PaintButtonBackground (
477     OutputDevice& rDevice,
478     const model::SharedPageDescriptor& rpDescriptor,
479     const Point aOffset)
480 {
481     BitmapEx* pBitmap = NULL;
482     if (maButtonDownBackground.IsEmpty() || maNormalBackground.IsEmpty())
483     {
484         if (mpBackgroundTheme)
485         {
486             maButtonDownBackground = mpBackgroundTheme->CreateBackground(rDevice, true);
487             maNormalBackground = mpBackgroundTheme->CreateBackground(rDevice, false);
488         }
489     }
490     if (mpButtonUnderMouse && mpButtonUnderMouse->IsDown())
491         pBitmap = &maButtonDownBackground;
492     else
493         pBitmap = &maNormalBackground;
494     if (pBitmap != NULL)
495     {
496         AlphaMask aMask (pBitmap->GetSizePixel());
497         AdaptTransparency(
498             aMask,
499             pBitmap->GetAlpha(),
500             rpDescriptor->GetVisualState().GetButtonBarAlpha());
501         rDevice.DrawBitmapEx(maBackgroundLocation+aOffset, BitmapEx(pBitmap->GetBitmap(), aMask));
502     }
503 }
504 
505 
506 
507 
508 bool ButtonBar::IsMouseOverBar (const Point aModelLocation) const
509 {
510     if ( ! mpDescriptor || ! mpDescriptor->GetBoundingBox().IsInside(aModelLocation))
511         return false;
512 
513     if ( ! maButtonBoundingBox.IsInside(aModelLocation - mpDescriptor->GetBoundingBox().TopLeft()))
514         return false;
515 
516     return true;
517 }
518 
519 
520 
521 
522 void ButtonBar::RequestLayout (void)
523 {
524     maPageObjectSize = Size(0,0);
525 }
526 
527 
528 
529 
530 void ButtonBar::LayoutButtons (const Size aPageObjectSize)
531 {
532     if (maPageObjectSize != aPageObjectSize)
533     {
534         maPageObjectSize = aPageObjectSize;
535 
536         if (mpBackgroundTheme)
537         {
538             mpBackgroundTheme->SetPreviewBoundingBox(
539                 mrSlideSorter.GetView().GetLayouter().GetPageObjectLayouter()->GetBoundingBox(
540                     Point(0,0),
541                     PageObjectLayouter::Preview,
542                     PageObjectLayouter::ModelCoordinateSystem));
543             LayoutButtons();
544         }
545 
546         // Release the background bitmaps so that on the next paint
547         // they are created anew in the right size.
548         maNormalBackground.SetEmpty();
549         maButtonDownBackground.SetEmpty();
550     }
551 }
552 
553 
554 
555 
556 bool ButtonBar::LayoutButtons (void)
557 {
558     const sal_Int32 nGap (mrSlideSorter.GetTheme()->GetIntegerValue(Theme::Integer_ButtonGap));
559     const sal_Int32 nBorder (mrSlideSorter.GetTheme()->GetIntegerValue(Theme::Integer_ButtonBorder));
560 
561     const Button::IconSize eIconSize (mpBackgroundTheme->GetIconSize());
562 
563     // Tell buttons which size they are.
564     for (sal_uInt32 nIndex=0; nIndex<maExcludedButtons.size(); ++nIndex)
565         maExcludedButtons[nIndex]->SetIconSize(eIconSize);
566     for (sal_uInt32 nIndex=0; nIndex<maRegularButtons.size(); ++nIndex)
567         maRegularButtons[nIndex]->SetIconSize(eIconSize);
568 
569     // Determine maximal height and total width of the buttons.
570     // Start with the buttons used for the excluded state.
571     sal_Int32 nMaximumHeight (0);
572     sal_Int32 nExcludedTotalWidth ((maExcludedButtons.size()-1) * nGap + 2*nBorder);
573     for (sal_uInt32 nIndex=0; nIndex<maExcludedButtons.size(); ++nIndex)
574     {
575         const Size aSize (maExcludedButtons[nIndex]->GetSize());
576         if (aSize.Height() > nMaximumHeight)
577             nMaximumHeight = aSize.Height();
578         nExcludedTotalWidth += aSize.Width();
579     }
580 
581     // Do the same for the regular buttons.
582     sal_Int32 nRegularTotalWidth ((maRegularButtons.size()-1) * nGap + 2*nBorder);
583     for (sal_uInt32 nIndex=0; nIndex<maRegularButtons.size(); ++nIndex)
584     {
585         const Size aSize (maRegularButtons[nIndex]->GetSize());
586         if (aSize.Height() > nMaximumHeight)
587             nMaximumHeight = aSize.Height();
588         nRegularTotalWidth += aSize.Width();
589     }
590     nMaximumHeight += 2*nBorder;
591 
592     // Set up the bounding box of the button bar.
593     maButtonBoundingBox = mpBackgroundTheme->GetButtonArea();
594     maBackgroundLocation = mpBackgroundTheme->GetBackgroundLocation();
595     if (mrSlideSorter.GetTheme()->GetIntegerValue(Theme::Integer_ButtonPaintType) == 1)
596     {
597         // Center the buttons.
598         maButtonBoundingBox.Left() += (maButtonBoundingBox.GetWidth() - nRegularTotalWidth)/2;
599         maButtonBoundingBox.Right() = maButtonBoundingBox.Left() + nRegularTotalWidth - 1;
600     }
601 
602     // Place the buttons.
603     Rectangle aBox (maButtonBoundingBox);
604     aBox.Right() -= nBorder;
605     for (sal_Int32 nIndex=maRegularButtons.size()-1; nIndex>=0; --nIndex)
606     {
607         maRegularButtons[nIndex]->Place(aBox);
608         aBox.Right() = maRegularButtons[nIndex]->GetBoundingBox().Left() - nGap;
609     }
610 
611     // For slides excluded from the show there is only one icon placed
612     // exactly like the second of the regular icons.
613     if (maRegularButtons.size()>=2 && maExcludedButtons.size()>=1)
614     {
615         aBox = maRegularButtons[1]->GetBoundingBox();
616         maExcludedButtons[0]->Place(aBox);
617     }
618 
619     // We return true only when there is no inactive button.
620     for (sal_uInt32 nIndex=0; nIndex<maExcludedButtons.size(); ++nIndex)
621         if ( ! maExcludedButtons[nIndex]->IsActive())
622             return false;
623     for (sal_uInt32 nIndex=0; nIndex<maRegularButtons.size(); ++nIndex)
624         if ( ! maRegularButtons[nIndex]->IsActive())
625             return false;
626 
627     return true;
628 }
629 
630 
631 
632 
633 void ButtonBar::RequestFadeIn (
634     const model::SharedPageDescriptor& rpDescriptor,
635     const bool bAnimate)
636 {
637     if ( ! rpDescriptor)
638         return;
639     if (mnLockCount > 0)
640         return;
641 
642     const double nMinAlpha (0);
643     if ( ! bAnimate)
644     {
645         rpDescriptor->GetVisualState().SetButtonAlpha(nMinAlpha);
646         rpDescriptor->GetVisualState().SetButtonBarAlpha(nMinAlpha);
647     }
648     else
649         StartFadeAnimation(rpDescriptor, nMinAlpha, true);
650 }
651 
652 
653 
654 
655 void ButtonBar::RequestFadeOut (
656     const model::SharedPageDescriptor& rpDescriptor,
657     const bool bAnimate)
658 {
659     if ( ! rpDescriptor)
660         return;
661     if (mnLockCount > 0)
662         return;
663 
664     const double nMaxAlpha (1);
665     if ( ! bAnimate)
666     {
667         rpDescriptor->GetVisualState().SetButtonAlpha(nMaxAlpha);
668         rpDescriptor->GetVisualState().SetButtonBarAlpha(nMaxAlpha);
669     }
670     else
671         StartFadeAnimation(rpDescriptor, nMaxAlpha, false);
672 }
673 
674 
675 
676 
677 bool ButtonBar::IsVisible (const model::SharedPageDescriptor& rpDescriptor)
678 {
679     const double nMaxAlpha (1);
680     return rpDescriptor && rpDescriptor->GetVisualState().GetButtonBarAlpha() < nMaxAlpha;
681 }
682 
683 
684 
685 
686 void ButtonBar::HandleDataChangeEvent (void)
687 {
688     maExcludedButtons.clear();
689     maExcludedButtons.push_back(::boost::shared_ptr<Button>(new UnhideButton(mrSlideSorter)));
690 
691     maRegularButtons.clear();
692     maRegularButtons.push_back(::boost::shared_ptr<Button>(new StartShowButton(mrSlideSorter)));
693     maRegularButtons.push_back(::boost::shared_ptr<Button>(new HideButton(mrSlideSorter)));
694     maRegularButtons.push_back(::boost::shared_ptr<Button>(new DuplicateButton(mrSlideSorter)));
695 
696     mpBackgroundTheme.reset(
697         new BitmapBackgroundTheme(
698             mrSlideSorter.GetTheme(),
699             maRegularButtons));
700 
701     // Force layout on next Paint().
702     maPageObjectSize = Size(0,0);
703 }
704 
705 
706 
707 
708 void ButtonBar::StartFadeAnimation (
709     const model::SharedPageDescriptor& rpDescriptor,
710     const double nTargetAlpha,
711     const bool bFadeIn)
712 {
713     model::SharedPageDescriptor pDescriptor (rpDescriptor);
714 
715     const double nCurrentButtonAlpha (pDescriptor->GetVisualState().GetButtonAlpha());
716     const double nCurrentButtonBarAlpha (pDescriptor->GetVisualState().GetButtonBarAlpha());
717 
718     // Stop a running animation.
719     const controller::Animator::AnimationId nId (
720         pDescriptor->GetVisualState().GetButtonAlphaAnimationId());
721     if (nId != controller::Animator::NotAnAnimationId)
722         mrSlideSorter.GetController().GetAnimator()->RemoveAnimation(nId);
723 
724     // Prepare the blending functors that translate [0,1] animation
725     // times into alpha values of buttons and button bar.
726     const ::boost::function<double(double)> aButtonBlendFunctor (
727         ::boost::bind(
728             controller::AnimationFunction::Blend,
729             nCurrentButtonAlpha,
730             nTargetAlpha,
731             ::boost::bind(controller::AnimationFunction::Linear, _1)));
732     const ::boost::function<double(double)> aButtonBarBlendFunctor (
733         ::boost::bind(
734             controller::AnimationFunction::Blend,
735             nCurrentButtonBarAlpha,
736             nTargetAlpha,
737             ::boost::bind(controller::AnimationFunction::Linear, _1)));
738 
739     // Delay the fade in a little bit when the buttons are not visible at
740     // all so that we do not leave a trail of half-visible buttons when the
741     // mouse is moved across the screen.  No delay on fade out or when the
742     // buttons are already showing.  Fade out is faster than fade in.
743     const double nDelay (nCurrentButtonBarAlpha>0 && nCurrentButtonBarAlpha<1
744         ? 0
745         : (mrSlideSorter.GetTheme()->GetIntegerValue(bFadeIn
746             ?  Theme::Integer_ButtonFadeInDelay
747             :  Theme::Integer_ButtonFadeOutDelay)));
748     const double nDuration (mrSlideSorter.GetTheme()->GetIntegerValue(bFadeIn
749             ?  Theme::Integer_ButtonFadeInDuration
750             :  Theme::Integer_ButtonFadeOutDuration));
751     pDescriptor->GetVisualState().SetButtonAlphaAnimationId(
752         mrSlideSorter.GetController().GetAnimator()->AddAnimation(
753             ::boost::bind(
754                 controller::AnimationFunction::ApplyButtonAlphaChange,
755                 pDescriptor,
756                 ::boost::ref(mrSlideSorter.GetView()),
757                 ::boost::bind(aButtonBlendFunctor, _1),
758                 ::boost::bind(aButtonBarBlendFunctor, _1)),
759             nDelay,
760             nDuration,
761             ::boost::bind(
762                 &model::VisualState::SetButtonAlphaAnimationId,
763                 ::boost::ref(pDescriptor->GetVisualState()),
764                 controller::Animator::NotAnAnimationId)
765             ));
766 }
767 
768 
769 
770 
771 void ButtonBar::AcquireLock (void)
772 {
773     if (mnLockCount == 0 && mpDescriptor)
774         RequestFadeOut(mpDescriptor, true);
775 
776     ++mnLockCount;
777 }
778 
779 
780 
781 
782 void ButtonBar::ReleaseLock (void)
783 {
784     --mnLockCount;
785 
786     if (mnLockCount == 0 && mpDescriptor)
787         RequestFadeIn(mpDescriptor, true);
788 }
789 
790 
791 
792 
793 //===== BackgroundTheme =====================================================
794 
795 ButtonBar::BackgroundTheme::BackgroundTheme (
796     const ::boost::shared_ptr<Theme>& rpTheme,
797     const ::std::vector<SharedButton>& rButtons)
798     : mpTheme(rpTheme)
799 {
800     UpdateMinimumIconSizes(rButtons);
801 }
802 
803 
804 
805 
806 void ButtonBar::BackgroundTheme::SetPreviewBoundingBox (const Rectangle& rPreviewBoundingBox)
807 {
808     maPreviewBoundingBox = rPreviewBoundingBox;
809     Layout();
810 }
811 
812 
813 
814 
815 void ButtonBar::BackgroundTheme::UpdateMinimumIconSizes (
816     const ::std::vector<SharedButton>& rButtons)
817 {
818     OSL_ASSERT(mpTheme);
819 
820     sal_Int32 nMaximumHeightLarge (0);
821     sal_Int32 nMaximumHeightMedium (0);
822     sal_Int32 nMaximumHeightSmall (0);
823     const sal_Int32 nGap (mpTheme->GetIntegerValue(Theme::Integer_ButtonGap));
824     const sal_Int32 nBorder (mpTheme->GetIntegerValue(Theme::Integer_ButtonBorder));
825     sal_Int32 nTotalWidthLarge ((rButtons.size()-1) * nGap + 2*nBorder);
826     sal_Int32 nTotalWidthMedium ((rButtons.size()-1) * nGap + 2*nBorder);
827     sal_Int32 nTotalWidthSmall ((rButtons.size()-1) * nGap + 2*nBorder);
828     for (sal_uInt32 nIndex=0; nIndex<rButtons.size(); ++nIndex)
829     {
830         // Update large size.
831         Size aSize = rButtons[nIndex]->GetSize(Button::IconSize_Large);
832         if (aSize.Height() > nMaximumHeightLarge)
833             nMaximumHeightLarge = aSize.Height();
834         nTotalWidthLarge += aSize.Width();
835 
836         // Update medium size.
837         aSize = rButtons[nIndex]->GetSize(Button::IconSize_Medium);
838         if (aSize.Height() > nMaximumHeightMedium)
839             nMaximumHeightMedium = aSize.Height();
840         nTotalWidthMedium += aSize.Width();
841 
842         // Update small size.
843         aSize = rButtons[nIndex]->GetSize(Button::IconSize_Small);
844         if (aSize.Height() > nMaximumHeightSmall)
845             nMaximumHeightSmall = aSize.Height();
846         nTotalWidthSmall += aSize.Width();
847     }
848     maMinimumLargeButtonAreaSize = Size(nTotalWidthLarge, nMaximumHeightLarge+2*nBorder);
849     maMinimumMediumButtonAreaSize = Size(nTotalWidthMedium, nMaximumHeightMedium+2*nBorder);
850     maMinimumSmallButtonAreaSize = Size(nTotalWidthSmall, nMaximumHeightSmall+2*nBorder);
851 }
852 
853 
854 
855 
856 Button::IconSize ButtonBar::BackgroundTheme::GetIconSize (void) const
857 {
858     return meIconSize;
859 }
860 
861 
862 
863 
864 //===== RectangleBackgroundTheme ============================================
865 
866 RectangleBackgroundTheme::RectangleBackgroundTheme (
867     const ::boost::shared_ptr<Theme>& rpTheme,
868     const ::std::vector<SharedButton>& rButtons)
869     : BackgroundTheme(rpTheme, rButtons),
870       mnBarHeight(0)
871 {
872 }
873 
874 
875 
876 
877 BitmapEx RectangleBackgroundTheme::CreateBackground (
878     const OutputDevice& rTemplateDevice,
879     const bool bIsButtonDown) const
880 {
881     OSL_ASSERT(mpTheme);
882 
883     // Setup background color.
884     Color aTopFillColor (mpTheme->GetGradientColor(
885         Theme::Gradient_ButtonBackground,
886         Theme::Fill1));
887     Color aTopBorderColor (mpTheme->GetGradientColor(
888         Theme::Gradient_ButtonBackground,
889         Theme::Border1));
890     Color aBottomFillColor (mpTheme->GetGradientColor(
891         Theme::Gradient_ButtonBackground,
892         Theme::Fill2));
893     Color aBottomBorderColor (mpTheme->GetGradientColor(
894         Theme::Gradient_ButtonBackground,
895         Theme::Border2));
896     if (bIsButtonDown)
897     {
898         aTopFillColor.DecreaseLuminance(50);
899         aTopBorderColor.DecreaseLuminance(50);
900         aBottomFillColor.DecreaseLuminance(50);
901         aBottomBorderColor.DecreaseLuminance(50);
902     }
903 
904     const int nWidth (maPreviewBoundingBox.GetWidth()+2);
905     const int nHeight (mnBarHeight);
906     const int nCenter (nHeight / 2);
907 
908     VirtualDevice aDevice (rTemplateDevice, 0, 8);
909     aDevice.SetOutputSizePixel(Size(nWidth,nHeight));
910 
911     // Fill upper and lower half.
912     aDevice.SetLineColor();
913     aDevice.SetFillColor(aTopFillColor);
914     aDevice.DrawRect(Rectangle(0,0,nWidth-1,nCenter));
915     aDevice.SetFillColor(aBottomFillColor);
916     aDevice.DrawRect(Rectangle(0,nCenter,nWidth-1,nHeight-1));
917 
918     // Draw border.
919     aDevice.SetFillColor();
920     aDevice.SetLineColor(aTopBorderColor);
921     aDevice.DrawLine(Point(0,nCenter),Point(0,0));
922     aDevice.DrawLine(Point(0,0), Point(nWidth-1,0));
923     aDevice.DrawLine(Point(nWidth-1,0),Point(nWidth-1,nCenter));
924     aDevice.SetLineColor(aBottomBorderColor);
925     aDevice.DrawLine(Point(0,nCenter),Point(0,nHeight-1));
926     aDevice.DrawLine(Point(0,nHeight-1), Point(nWidth-1,nHeight-1));
927     aDevice.DrawLine(Point(nWidth-1,nHeight-1),Point(nWidth-1,nCenter));
928 
929     return aDevice.GetBitmapEx(Point(0,0), Size(nWidth,nHeight));
930 }
931 
932 
933 
934 
935 Point RectangleBackgroundTheme::GetBackgroundLocation (void)
936 {
937     return Point(
938         maPreviewBoundingBox.Left()-1,
939         maPreviewBoundingBox.Bottom() - mnBarHeight + 2);
940 }
941 
942 
943 
944 
945 Rectangle RectangleBackgroundTheme::GetButtonArea (void)
946 {
947     return Rectangle(
948         maPreviewBoundingBox.Left(),
949         maPreviewBoundingBox.Bottom() - mnBarHeight + 2,
950         maPreviewBoundingBox.Right(),
951         maPreviewBoundingBox.Bottom());
952 }
953 
954 
955 
956 
957 void RectangleBackgroundTheme::Layout (void)
958 {
959     if (maPreviewBoundingBox.GetWidth() < maMinimumLargeButtonAreaSize.Width())
960         if (maPreviewBoundingBox.GetWidth() < maMinimumMediumButtonAreaSize.Width())
961         {
962             meIconSize = Button::IconSize_Small;
963             mnBarHeight = maMinimumSmallButtonAreaSize.Height();
964         }
965         else
966         {
967             meIconSize = Button::IconSize_Medium;
968             mnBarHeight = maMinimumMediumButtonAreaSize.Height();
969         }
970     else
971     {
972         meIconSize = Button::IconSize_Large;
973         mnBarHeight = maMinimumLargeButtonAreaSize.Height();
974     }
975 }
976 
977 
978 
979 
980 //===== BitmapBackgroundTheme =================================================
981 
982 BitmapBackgroundTheme::BitmapBackgroundTheme (
983     const ::boost::shared_ptr<Theme>& rpTheme,
984     const ::std::vector<SharedButton>& rButtons)
985     : BackgroundTheme(rpTheme, rButtons),
986       maButtonArea(),
987       maBackgroundLocation()
988 {
989 }
990 
991 
992 
993 
994 BitmapEx BitmapBackgroundTheme::CreateBackground (
995     const OutputDevice& rTemplateDevice,
996     const bool bIsButtonDown) const
997 {
998     (void)rTemplateDevice;
999     (void)bIsButtonDown;
1000 
1001     OSL_ASSERT(mpTheme);
1002 
1003     // Get images.
1004     switch (meIconSize)
1005     {
1006         case Button::IconSize_Large:
1007         default:
1008             return mpTheme->GetIcon(Theme::Icon_ButtonBarLarge);
1009 
1010         case Button::IconSize_Medium:
1011             return mpTheme->GetIcon(Theme::Icon_ButtonBarMedium);
1012 
1013         case Button::IconSize_Small:
1014             return mpTheme->GetIcon(Theme::Icon_ButtonBarSmall);
1015     }
1016 }
1017 
1018 
1019 
1020 
1021 Point BitmapBackgroundTheme::GetBackgroundLocation (void)
1022 {
1023     return maBackgroundLocation;
1024 }
1025 
1026 
1027 
1028 
1029 Rectangle BitmapBackgroundTheme::GetButtonArea (void)
1030 {
1031     return maButtonArea;
1032 }
1033 
1034 
1035 
1036 
1037 void BitmapBackgroundTheme::Layout (void)
1038 {
1039     Size aImageSize (mpTheme->GetIcon(Theme::Icon_ButtonBarLarge).GetSizePixel());
1040     if (aImageSize.Width() >= maPreviewBoundingBox.GetWidth())
1041     {
1042         aImageSize = mpTheme->GetIcon(Theme::Icon_ButtonBarMedium).GetSizePixel();
1043         if (aImageSize.Width() >= maPreviewBoundingBox.GetWidth())
1044         {
1045             meIconSize = Button::IconSize_Small;
1046             aImageSize = mpTheme->GetIcon(Theme::Icon_ButtonBarSmall).GetSizePixel();
1047         }
1048         else
1049             meIconSize = Button::IconSize_Medium;
1050     }
1051     else
1052     {
1053         meIconSize = Button::IconSize_Large;
1054     }
1055 
1056     maBackgroundLocation = Point(
1057         maPreviewBoundingBox.Left()
1058             + (maPreviewBoundingBox.GetWidth()-aImageSize.Width())/2,
1059         maPreviewBoundingBox.Bottom() - aImageSize.Height());
1060     maButtonArea = Rectangle(maBackgroundLocation, aImageSize);
1061 }
1062 
1063 
1064 
1065 
1066 //===== Button ================================================================
1067 
1068 Button::Button (
1069     SlideSorter& rSlideSorter,
1070     const ::rtl::OUString& rsHelpText)
1071     : mrSlideSorter(rSlideSorter),
1072       meState(State_Normal),
1073       maBoundingBox(),
1074       msHelpText(rsHelpText),
1075       mbIsActive(false),
1076       meIconSize(IconSize_Large)
1077 {
1078 }
1079 
1080 
1081 
1082 
1083 Button::~Button (void)
1084 {
1085 }
1086 
1087 
1088 
1089 
1090 bool Button::SetState (const State eState)
1091 {
1092     if (meState != eState)
1093     {
1094         meState = eState;
1095         return true;
1096     }
1097     else
1098         return false;
1099 }
1100 
1101 
1102 
1103 
1104 Button::State Button::GetState (void) const
1105 {
1106     return meState;
1107 }
1108 
1109 
1110 
1111 
1112 Rectangle Button::GetBoundingBox (void) const
1113 {
1114     if (mbIsActive)
1115         return maBoundingBox;
1116     else
1117         return Rectangle();
1118 }
1119 
1120 
1121 
1122 
1123 ::rtl::OUString Button::GetHelpText (void) const
1124 {
1125     if (mbIsActive)
1126         return msHelpText;
1127     else
1128         return ::rtl::OUString();
1129 }
1130 
1131 
1132 
1133 
1134 bool Button::IsDown (void) const
1135 {
1136     return mbIsActive && meState==State_Down;
1137 }
1138 
1139 
1140 
1141 
1142 void Button::SetActiveState (const bool bIsActive)
1143 {
1144     mbIsActive = bIsActive;
1145 }
1146 
1147 
1148 
1149 
1150 bool Button::IsActive (void) const
1151 {
1152     return mbIsActive;
1153 }
1154 
1155 
1156 
1157 
1158 void Button::SetIconSize (const IconSize eIconSize)
1159 {
1160     meIconSize = eIconSize;
1161 }
1162 
1163 
1164 
1165 
1166 Button::IconSize Button::GetIconSize (void) const
1167 {
1168     return meIconSize;
1169 }
1170 
1171 
1172 
1173 
1174 bool Button::IsEnabled (void) const
1175 {
1176     return true;
1177 }
1178 
1179 
1180 
1181 
1182 //===== TextButton ============================================================
1183 
1184 TextButton::TextButton (
1185     SlideSorter& rSlideSorter,
1186     const ::rtl::OUString& rsText,
1187     const ::rtl::OUString& rsHelpText)
1188     : Button(rSlideSorter, rsHelpText),
1189       msText(rsText)
1190 {
1191 }
1192 
1193 
1194 
1195 
1196 void TextButton::Place (const Rectangle aButtonBarBox)
1197 {
1198     maBoundingBox = aButtonBarBox;
1199     SetActiveState(true);
1200 }
1201 
1202 
1203 
1204 
1205 void TextButton::Paint (
1206     OutputDevice& rDevice,
1207     const Point aOffset,
1208     const double nAlpha,
1209     const ::boost::shared_ptr<Theme>& rpTheme) const
1210 {
1211     (void)nAlpha;
1212 
1213     if (mbIsActive)
1214     {
1215         // Paint text over the button background.
1216         if (meState == State_Normal)
1217             rDevice.SetTextColor(rpTheme->GetColor(Theme::Color_ButtonText));
1218         else
1219             rDevice.SetTextColor(rpTheme->GetColor(Theme::Color_ButtonTextHover));
1220         Rectangle aBox (maBoundingBox);
1221         aBox += aOffset;
1222         rDevice.DrawText(aBox, msText, TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER);
1223     }
1224 }
1225 
1226 
1227 
1228 
1229 Size TextButton::GetSize (void) const
1230 {
1231     return Size();
1232 }
1233 
1234 
1235 
1236 
1237 Size TextButton::GetSize (const Button::IconSize) const
1238 {
1239     return Size();
1240 }
1241 
1242 
1243 
1244 
1245 //===== ImageButon ============================================================
1246 
1247 ImageButton::ImageButton (
1248     SlideSorter& rSlideSorter,
1249     const BitmapEx& rLargeIcon,
1250     const BitmapEx& rLargeHoverIcon,
1251     const BitmapEx& rMediumIcon,
1252     const BitmapEx& rMediumHoverIcon,
1253     const BitmapEx& rSmallIcon,
1254     const BitmapEx& rSmallHoverIcon,
1255     const ::rtl::OUString& rsHelpText)
1256     : Button(rSlideSorter, rsHelpText),
1257       maLargeIcon(rLargeIcon),
1258       maLargeHoverIcon(rLargeHoverIcon.IsEmpty() ? rLargeIcon : rLargeHoverIcon),
1259       maMediumIcon(rMediumIcon),
1260       maMediumHoverIcon(rMediumHoverIcon.IsEmpty() ? rMediumIcon : rMediumHoverIcon),
1261       maSmallIcon(rSmallIcon),
1262       maSmallHoverIcon(rSmallHoverIcon.IsEmpty() ? rSmallIcon : rSmallHoverIcon)
1263 {
1264 }
1265 
1266 
1267 
1268 
1269 void ImageButton::Place (const Rectangle aButtonBarBox)
1270 {
1271     const sal_Int32 nWidth (GetSize().Width());
1272     maBoundingBox = Rectangle(
1273         aButtonBarBox.Right() - nWidth,
1274         aButtonBarBox.Top(),
1275         aButtonBarBox.Right(),
1276         aButtonBarBox.Bottom());
1277     SetActiveState(aButtonBarBox.IsInside(maBoundingBox));
1278 }
1279 
1280 
1281 
1282 
1283 void ImageButton::Paint (
1284     OutputDevice& rDevice,
1285     const Point aOffset,
1286     const double nAlpha,
1287     const ::boost::shared_ptr<Theme>& rpTheme) const
1288 {
1289     (void)rpTheme;
1290 
1291     if ( ! mbIsActive)
1292         return;
1293 
1294     const sal_uInt16 nSavedAntialiasingMode (rDevice.GetAntialiasing());
1295     rDevice.SetAntialiasing(nSavedAntialiasingMode | ANTIALIASING_ENABLE_B2DDRAW);
1296 
1297     rDevice.SetLineColor();
1298 
1299     // Choose icon.
1300     BitmapEx aIcon;
1301     switch (meIconSize)
1302     {
1303         case IconSize_Large:
1304         default:
1305             if (meState == State_Normal)
1306                 aIcon = maLargeIcon;
1307             else
1308                 aIcon = maLargeHoverIcon;
1309             break;
1310 
1311         case IconSize_Medium:
1312             if (meState == State_Normal)
1313                 aIcon = maMediumIcon;
1314             else
1315                 aIcon = maMediumHoverIcon;
1316             break;
1317 
1318         case IconSize_Small:
1319             if (meState == State_Normal)
1320                 aIcon = maSmallIcon;
1321             else
1322                 aIcon = maSmallHoverIcon;
1323             break;
1324     }
1325 
1326     // Paint icon.
1327     if ( ! aIcon.IsEmpty())
1328     {
1329         AlphaMask aMask (aIcon.GetSizePixel());
1330         AdaptTransparency(aMask, aIcon.GetAlpha(), nAlpha);
1331         rDevice.DrawBitmapEx(
1332             Point(
1333                 maBoundingBox.Left()
1334                     + aOffset.X()
1335                     + (maBoundingBox.GetWidth()-aIcon.GetSizePixel().Width())/2,
1336                 maBoundingBox.Top()
1337                     + aOffset.Y()
1338                     + (maBoundingBox.GetHeight()-aIcon.GetSizePixel().Height())/2),
1339             BitmapEx(aIcon.GetBitmap(), aMask));
1340     }
1341 
1342     rDevice.SetAntialiasing(nSavedAntialiasingMode);
1343 }
1344 
1345 
1346 
1347 
1348 Size ImageButton::GetSize (void) const
1349 {
1350     return GetSize(meIconSize);
1351 }
1352 
1353 
1354 
1355 
1356 Size ImageButton::GetSize (const Button::IconSize eIconSize) const
1357 {
1358     switch (eIconSize)
1359     {
1360         case IconSize_Large:
1361         default:
1362             return maLargeIcon.GetSizePixel();
1363 
1364         case IconSize_Medium:
1365             return maMediumIcon.GetSizePixel();
1366 
1367         case IconSize_Small:
1368             return maSmallIcon.GetSizePixel();
1369     }
1370 }
1371 
1372 
1373 
1374 
1375 //===== UnhideButton ==========================================================
1376 
1377 UnhideButton::UnhideButton (SlideSorter& rSlideSorter)
1378     : ImageButton(
1379         rSlideSorter,
1380         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BLarge),
1381         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BLargeHover),
1382         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BMedium),
1383         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BMediumHover),
1384         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BSmall),
1385         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BSmallHover),
1386         rSlideSorter.GetTheme()->GetString(Theme::String_Command2B))
1387 {
1388 }
1389 
1390 
1391 
1392 
1393 void UnhideButton::ProcessClick (const model::SharedPageDescriptor& rpDescriptor)
1394 {
1395     if ( ! rpDescriptor)
1396         return;
1397     mrSlideSorter.GetController().GetSlotManager()->ChangeSlideExclusionState(
1398         (rpDescriptor->HasState(model::PageDescriptor::ST_Selected)
1399             ? model::SharedPageDescriptor()
1400             : rpDescriptor),
1401         false);
1402 }
1403 
1404 
1405 
1406 
1407 //===== StartSlideShowButton ==================================================
1408 
1409 StartShowButton::StartShowButton (SlideSorter& rSlideSorter)
1410     : ImageButton(
1411         rSlideSorter,
1412         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1Large),
1413         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1LargeHover),
1414         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1Medium),
1415         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1MediumHover),
1416         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1Small),
1417         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1SmallHover),
1418         rSlideSorter.GetTheme()->GetString(Theme::String_Command1))
1419 {
1420 }
1421 
1422 
1423 
1424 
1425 bool StartShowButton::IsEnabled (void) const
1426 {
1427     ViewShell* pViewShell = mrSlideSorter.GetViewShell();
1428     if (pViewShell == NULL)
1429         return false;
1430     SfxDispatcher* pDispatcher = pViewShell->GetDispatcher();
1431     if (pDispatcher == NULL)
1432         return false;
1433 
1434     const SfxPoolItem* pState = NULL;
1435 	const SfxItemState eState (pDispatcher->QueryState(SID_PRESENTATION, pState));
1436     return (eState & SFX_ITEM_DISABLED) == 0;
1437 }
1438 
1439 
1440 
1441 
1442 void StartShowButton::ProcessClick (const model::SharedPageDescriptor& rpDescriptor)
1443 {
1444     // Hide the tool tip early, while the slide show still intializes.
1445     mrSlideSorter.GetView().GetToolTip().SetPage(model::SharedPageDescriptor());
1446 
1447     Reference< XPresentation2 > xPresentation(
1448         mrSlideSorter.GetModel().GetDocument()->getPresentation());
1449     if (xPresentation.is())
1450     {
1451         Sequence<PropertyValue> aProperties (1);
1452         aProperties[0].Name = ::rtl::OUString::createFromAscii("FirstPage");
1453         const ::rtl::OUString sName (rpDescriptor->GetPage()->GetName());
1454         aProperties[0].Value = Any(sName);
1455         xPresentation->startWithArguments(aProperties);
1456     }
1457 }
1458 
1459 
1460 
1461 
1462 //===== HideButton ============================================================
1463 
1464 HideButton::HideButton (SlideSorter& rSlideSorter)
1465     : ImageButton(
1466         rSlideSorter,
1467         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2Large),
1468         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2LargeHover),
1469         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2Medium),
1470         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2MediumHover),
1471         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2Small),
1472         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2SmallHover),
1473         rSlideSorter.GetTheme()->GetString(Theme::String_Command2))
1474 {
1475 }
1476 
1477 
1478 
1479 
1480 void HideButton::ProcessClick (const model::SharedPageDescriptor& rpDescriptor)
1481 {
1482     if ( ! rpDescriptor)
1483         return;
1484     mrSlideSorter.GetController().GetSlotManager()->ChangeSlideExclusionState(
1485         (rpDescriptor->HasState(model::PageDescriptor::ST_Selected)
1486             ? model::SharedPageDescriptor()
1487             : rpDescriptor),
1488         true);
1489 }
1490 
1491 
1492 
1493 
1494 //===== DuplicateButton =======================================================
1495 
1496 DuplicateButton::DuplicateButton (SlideSorter& rSlideSorter)
1497     : ImageButton(
1498         rSlideSorter,
1499         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3Large),
1500         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3LargeHover),
1501         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3Medium),
1502         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3MediumHover),
1503         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3Small),
1504         rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3SmallHover),
1505         rSlideSorter.GetTheme()->GetString(Theme::String_Command3))
1506 {
1507 }
1508 
1509 
1510 
1511 
1512 bool DuplicateButton::IsEnabled (void) const
1513 {
1514     ViewShell* pViewShell = mrSlideSorter.GetViewShell();
1515     if (pViewShell == NULL)
1516         return false;
1517     SfxDispatcher* pDispatcher = pViewShell->GetDispatcher();
1518     if (pDispatcher == NULL)
1519         return false;
1520 
1521     const SfxPoolItem* pState = NULL;
1522 	const SfxItemState eState (pDispatcher->QueryState(
1523         SID_DUPLICATE_PAGE,
1524         pState));
1525     return (eState & SFX_ITEM_DISABLED) == 0;
1526 }
1527 
1528 
1529 
1530 
1531 void DuplicateButton::ProcessClick (const model::SharedPageDescriptor& rpDescriptor)
1532 {
1533     if ( ! rpDescriptor)
1534         return;
1535 
1536     mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor(),false);
1537 
1538     // When the page under the button is not selected then set the
1539     // selection to just this page.
1540     if ( ! rpDescriptor->HasState(model::PageDescriptor::ST_Selected))
1541     {
1542         mrSlideSorter.GetController().GetPageSelector().DeselectAllPages();
1543         mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor);
1544     }
1545     // Duplicate the selected pages.  Insert the new pages right
1546     // after the current selection and select them
1547     if (mrSlideSorter.GetViewShell() != NULL
1548         && mrSlideSorter.GetViewShell()->GetDispatcher() != NULL)
1549     {
1550         mrSlideSorter.GetViewShell()->GetDispatcher()->Execute(
1551             SID_DUPLICATE_PAGE,
1552             SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD);
1553     }
1554 }
1555 
1556 
1557 
1558 } } } // end of namespace ::sd::slidesorter::view
1559