xref: /AOO41X/main/svtools/source/control/toolbarmenu.cxx (revision 5900e8ec128faec89519683efce668ccd8cc6084)
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 
25 // MARKER(update_precomp.py): autogen include statement, do not remove
26 #include "precompiled_svtools.hxx"
27 
28 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
29 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
30 #include <comphelper/processfactory.hxx>
31 
32 #include <vcl/dockwin.hxx>
33 #include <vcl/decoview.hxx>
34 #include <vcl/image.hxx>
35 #include <vcl/taskpanelist.hxx>
36 #include <vcl/toolbox.hxx>
37 
38 #include "svtools/valueset.hxx"
39 #include "svtools/toolbarmenu.hxx"
40 #include "toolbarmenuimp.hxx"
41 
42 using ::rtl::OUString;
43 using namespace ::com::sun::star::uno;
44 using namespace ::com::sun::star::lang;
45 using namespace ::com::sun::star::frame;
46 using namespace ::com::sun::star::accessibility;
47 
48 namespace svtools {
49 
50 // --------------------------------------------------------------------
51 
GetTopMostParentSystemWindow(Window * pWindow)52 static Window* GetTopMostParentSystemWindow( Window* pWindow )
53 {
54     OSL_ASSERT( pWindow );
55     if ( pWindow )
56     {
57         // ->manually search topmost system window
58         // required because their might be another system window between this and the top window
59         pWindow = pWindow->GetParent();
60         SystemWindow* pTopMostSysWin = NULL;
61         while ( pWindow )
62         {
63             if ( pWindow->IsSystemWindow() )
64                 pTopMostSysWin = (SystemWindow*)pWindow;
65             pWindow = pWindow->GetParent();
66         }
67         pWindow = pTopMostSysWin;
68         OSL_ASSERT( pWindow );
69         return pWindow;
70     }
71 
72     return NULL;
73 }
74 
75 // --------------------------------------------------------------------
76 
init(int nEntryId,MenuItemBits nBits)77 void ToolbarMenuEntry::init( int nEntryId, MenuItemBits nBits )
78 {
79     mnEntryId = nEntryId;
80     mnBits = nBits;
81 
82     mbHasText = false;
83     mbHasImage = false;
84     mbChecked = false;
85     mbEnabled = true;
86 
87     mpControl = NULL;
88 }
89 
90 // --------------------------------------------------------------------
91 
ToolbarMenuEntry(ToolbarMenu & rMenu,int nEntryId,const String & rText,MenuItemBits nBits)92 ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const String& rText, MenuItemBits nBits )
93 : mrMenu( rMenu )
94 {
95     init( nEntryId, nBits );
96 
97     maText = rText;
98     mbHasText = true;
99 }
100 
101 // --------------------------------------------------------------------
102 
ToolbarMenuEntry(ToolbarMenu & rMenu,int nEntryId,const Image & rImage,MenuItemBits nBits)103 ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const Image& rImage, MenuItemBits nBits )
104 : mrMenu( rMenu )
105 {
106     init( nEntryId, nBits );
107 
108     maImage = rImage;
109     mbHasImage = true;
110 }
111 
112 // --------------------------------------------------------------------
113 
ToolbarMenuEntry(ToolbarMenu & rMenu,int nEntryId,const Image & rImage,const String & rText,MenuItemBits nBits)114 ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const Image& rImage, const String& rText, MenuItemBits nBits )
115 : mrMenu( rMenu )
116 {
117     init( nEntryId, nBits );
118 
119     maText = rText;
120     mbHasText = true;
121 
122     maImage = rImage;
123     mbHasImage = true;
124 }
125 
126 // --------------------------------------------------------------------
127 
ToolbarMenuEntry(ToolbarMenu & rMenu,int nEntryId,Control * pControl,MenuItemBits nBits)128 ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, Control* pControl, MenuItemBits nBits )
129 : mrMenu( rMenu )
130 {
131     init( nEntryId, nBits );
132 
133     if( pControl )
134     {
135         mpControl = pControl;
136         mpControl->Show();
137     }
138 }
139 
140 // --------------------------------------------------------------------
141 
~ToolbarMenuEntry()142 ToolbarMenuEntry::~ToolbarMenuEntry()
143 {
144     if( mxAccContext.is() )
145     {
146         Reference< XComponent > xComponent( mxAccContext, UNO_QUERY );
147         if( xComponent.is() )
148             xComponent->dispose();
149         mxAccContext.clear();
150     }
151     delete mpControl;
152 }
153 
154 // --------------------------------------------------------------------
155 
GetAccessible(bool bCreate)156 const Reference< XAccessibleContext >& ToolbarMenuEntry::GetAccessible( bool bCreate /* = false */ )
157 {
158     if( !mxAccContext.is() && bCreate )
159     {
160         if( mpControl )
161         {
162             mxAccContext = Reference< XAccessibleContext >( mpControl->GetAccessible( sal_True ), UNO_QUERY );
163         }
164         else
165         {
166             mxAccContext = Reference< XAccessibleContext >( new ToolbarMenuEntryAcc( this ) );
167         }
168     }
169 
170     return mxAccContext;
171 }
172 
173 // --------------------------------------------------------------------
174 
getAccessibleChildCount()175 sal_Int32 ToolbarMenuEntry::getAccessibleChildCount() throw (RuntimeException)
176 {
177     if( mpControl )
178     {
179         const Reference< XAccessibleContext >& xContext = GetAccessible( true );
180         if( xContext.is() )
181         {
182             return xContext->getAccessibleChildCount();
183         }
184     }
185     return 1;
186 }
187 
188 // --------------------------------------------------------------------
189 
getAccessibleChild(sal_Int32 index)190 Reference< XAccessible > ToolbarMenuEntry::getAccessibleChild( sal_Int32 index ) throw (IndexOutOfBoundsException, RuntimeException)
191 {
192     const Reference< XAccessibleContext >& xContext = GetAccessible( true );
193     if( mpControl )
194     {
195         if( xContext.is() )
196         {
197             return xContext->getAccessibleChild(index);
198         }
199     }
200     else if( index == 0 )
201     {
202         Reference< XAccessible > xRet( xContext, UNO_QUERY );
203         if( xRet.is() )
204             return xRet;
205     }
206 
207     throw IndexOutOfBoundsException();
208 }
209 
210 // --------------------------------------------------------------------
211 
ToolbarMenu_Impl(ToolbarMenu & rMenu,const::com::sun::star::uno::Reference<::com::sun::star::frame::XFrame> & xFrame)212 ToolbarMenu_Impl::ToolbarMenu_Impl( ToolbarMenu& rMenu, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame )
213 : mrMenu( rMenu )
214 , mxFrame( xFrame )
215 , mxServiceManager( ::comphelper::getProcessServiceFactory() )
216 , mnCheckPos(0)
217 , mnImagePos(0)
218 , mnTextPos(0)
219 , mnHighlightedEntry(-1)
220 , mnSelectedEntry(-1)
221 , mnLastColumn(0)
222 {
223 }
224 
225 // --------------------------------------------------------------------
226 
~ToolbarMenu_Impl()227 ToolbarMenu_Impl::~ToolbarMenu_Impl()
228 {
229     setAccessible( 0 );
230 }
231 
232 // --------------------------------------------------------------------
233 
setAccessible(ToolbarMenuAcc * pAccessible)234 void ToolbarMenu_Impl::setAccessible( ToolbarMenuAcc* pAccessible )
235 {
236     if( mxAccessible.get() != pAccessible )
237     {
238         if( mxAccessible.is() )
239             mxAccessible->dispose();
240 
241         mxAccessible.set( pAccessible );
242     }
243 }
244 
245 // -----------------------------------------------------------------------
246 
fireAccessibleEvent(short nEventId,const::com::sun::star::uno::Any & rOldValue,const::com::sun::star::uno::Any & rNewValue)247 void ToolbarMenu_Impl::fireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue )
248 {
249     if( mxAccessible.is() )
250         mxAccessible->FireAccessibleEvent( nEventId, rOldValue, rNewValue );
251 }
252 
253 // -----------------------------------------------------------------------
254 
hasAccessibleListeners()255 bool ToolbarMenu_Impl::hasAccessibleListeners()
256 {
257     return( mxAccessible.is() && mxAccessible->HasAccessibleListeners() );
258 }
259 
260 // --------------------------------------------------------------------
261 
getAccessibleChildCount()262 sal_Int32 ToolbarMenu_Impl::getAccessibleChildCount() throw (RuntimeException)
263 {
264     sal_Int32 nCount = 0;
265     const int nEntryCount = maEntryVector.size();
266     for( int nEntry = 0; nEntry < nEntryCount; nEntry++ )
267     {
268         ToolbarMenuEntry* pEntry = maEntryVector[nEntry];
269         if( pEntry )
270         {
271             if( pEntry->mpControl )
272             {
273                 nCount += pEntry->getAccessibleChildCount();
274             }
275             else
276             {
277                 nCount += 1;
278             }
279         }
280     }
281 
282     return nCount;
283 }
284 
285 // --------------------------------------------------------------------
286 
getAccessibleChild(sal_Int32 index)287 Reference< XAccessible > ToolbarMenu_Impl::getAccessibleChild( sal_Int32 index ) throw (IndexOutOfBoundsException, RuntimeException)
288 {
289     const int nEntryCount = maEntryVector.size();
290     for( int nEntry = 0; nEntry < nEntryCount; nEntry++ )
291     {
292         ToolbarMenuEntry* pEntry = maEntryVector[nEntry];
293         if( pEntry )
294         {
295             const sal_Int32 nCount = pEntry->getAccessibleChildCount();
296             if( index < nCount )
297             {
298                 return pEntry->getAccessibleChild( index );
299             }
300             index -= nCount;
301         }
302     }
303 
304     throw IndexOutOfBoundsException();
305 }
306 
307 // --------------------------------------------------------------------
308 
getAccessibleChild(Control * pControl,sal_Int32 childIndex)309 Reference< XAccessible > ToolbarMenu_Impl::getAccessibleChild( Control* pControl, sal_Int32 childIndex ) throw (IndexOutOfBoundsException, RuntimeException)
310 {
311     const int nEntryCount = maEntryVector.size();
312     for( int nEntry = 0; nEntry < nEntryCount; nEntry++ )
313     {
314         ToolbarMenuEntry* pEntry = maEntryVector[nEntry];
315         if( pEntry && (pEntry->mpControl == pControl) )
316         {
317             return pEntry->getAccessibleChild( childIndex );
318         }
319     }
320 
321     throw IndexOutOfBoundsException();
322 }
323 
324 // --------------------------------------------------------------------
325 
selectAccessibleChild(sal_Int32 nChildIndex)326 void ToolbarMenu_Impl::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
327 {
328     const int nEntryCount = maEntryVector.size();
329     for( int nEntry = 0; nEntry < nEntryCount; nEntry++ )
330     {
331         ToolbarMenuEntry* pEntry = maEntryVector[nEntry];
332         if( pEntry )
333         {
334             const sal_Int32 nCount = pEntry->getAccessibleChildCount();
335             if( nChildIndex < nCount )
336             {
337                 if( pEntry->mpControl )
338                 {
339                     Reference< XAccessibleSelection > xSel( pEntry->GetAccessible(true), UNO_QUERY_THROW );
340                     xSel->selectAccessibleChild(nChildIndex);
341                 }
342                 else if( pEntry->mnEntryId != TITLE_ID )
343                 {
344                     mrMenu.implSelectEntry( nEntry );
345                 }
346                 return;
347             }
348             nChildIndex -= nCount;
349         }
350     }
351 
352     throw IndexOutOfBoundsException();
353 }
354 
355 // --------------------------------------------------------------------
356 
isAccessibleChildSelected(sal_Int32 nChildIndex)357 sal_Bool ToolbarMenu_Impl::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
358 {
359     const int nEntryCount = maEntryVector.size();
360     for( int nEntry = 0; nEntry < nEntryCount; nEntry++ )
361     {
362         ToolbarMenuEntry* pEntry = maEntryVector[nEntry];
363         if( pEntry )
364         {
365             const sal_Int32 nCount = pEntry->getAccessibleChildCount();
366             if( nChildIndex < nCount )
367             {
368                 if( mnHighlightedEntry == nEntry )
369                 {
370                     if( pEntry->mpControl )
371                     {
372                         Reference< XAccessibleSelection > xSel( pEntry->GetAccessible(true), UNO_QUERY_THROW );
373                         xSel->isAccessibleChildSelected(nChildIndex);
374                     }
375                     return true;
376                 }
377                 else
378                 {
379                     return false;
380                 }
381             }
382             nChildIndex -= nCount;
383         }
384     }
385 
386     throw IndexOutOfBoundsException();
387 }
388 
389 // --------------------------------------------------------------------
390 
clearAccessibleSelection()391 void ToolbarMenu_Impl::clearAccessibleSelection()
392 {
393     if( mnHighlightedEntry != -1 )
394     {
395         mrMenu.implHighlightEntry( mnHighlightedEntry, false );
396         mnHighlightedEntry = -1;
397     }
398 }
399 
400 
401 // --------------------------------------------------------------------
402 
notifyHighlightedEntry()403 void ToolbarMenu_Impl::notifyHighlightedEntry()
404 {
405     if( hasAccessibleListeners() )
406     {
407         ToolbarMenuEntry* pEntry = implGetEntry( mnHighlightedEntry );
408         if( pEntry && pEntry->mbEnabled && (pEntry->mnEntryId != TITLE_ID) )
409         {
410             Any aNew;
411             Any aOld( mxOldSelection );
412             if( pEntry->mpControl )
413             {
414                 sal_Int32 nChildIndex = 0;
415                 // todo: if other controls than ValueSet are allowed, addapt this code
416                 ValueSet* pValueSet = dynamic_cast< ValueSet* >( pEntry->mpControl );
417                 if( pValueSet )
418                     nChildIndex = static_cast< sal_Int32 >( pValueSet->GetItemPos( pValueSet->GetSelectItemId() ) );
419 
420                 if( nChildIndex >= pEntry->getAccessibleChildCount() )
421                     return;
422 
423                 aNew <<= getAccessibleChild( pEntry->mpControl, nChildIndex );
424             }
425             else
426             {
427                 aNew <<= pEntry->GetAccessible(true);
428             }
429 
430             fireAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOld, aNew );
431             fireAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, aOld, aNew );
432             fireAccessibleEvent( AccessibleEventId::STATE_CHANGED, Any(), Any( AccessibleStateType::FOCUSED ) );
433             aNew >>= mxOldSelection;
434         }
435     }
436 }
437 
438 // --------------------------------------------------------------------
439 
implGetEntry(int nEntry) const440 ToolbarMenuEntry* ToolbarMenu_Impl::implGetEntry( int nEntry ) const
441 {
442     if( (nEntry < 0) || (nEntry >= (int)maEntryVector.size() ) )
443         return NULL;
444 
445     return maEntryVector[nEntry];
446 }
447 
448 
449 // --------------------------------------------------------------------
450 
IMPL_LINK(ToolbarMenu,HighlightHdl,Control *,pControl)451 IMPL_LINK( ToolbarMenu, HighlightHdl, Control *, pControl )
452 {
453     (void)pControl;
454     mpImpl->notifyHighlightedEntry();
455     return 0;
456 }
457 
458 // ====================================================================
459 
ToolbarMenu(const Reference<XFrame> & rFrame,Window * pParentWindow,WinBits nBits)460 ToolbarMenu::ToolbarMenu( const Reference< XFrame >& rFrame, Window* pParentWindow, WinBits nBits )
461 : DockingWindow(pParentWindow, nBits)
462 {
463     implInit(rFrame);
464 }
465 
466 // --------------------------------------------------------------------
467 
ToolbarMenu(const Reference<XFrame> & rFrame,Window * pParentWindow,const ResId & rResId)468 ToolbarMenu::ToolbarMenu( const Reference< XFrame >& rFrame, Window* pParentWindow, const ResId& rResId )
469 : DockingWindow(pParentWindow, rResId)
470 {
471     implInit(rFrame);
472 }
473 
474 // --------------------------------------------------------------------
475 
implInit(const Reference<XFrame> & rFrame)476 void ToolbarMenu::implInit(const Reference< XFrame >& rFrame)
477 {
478     mpImpl = new ToolbarMenu_Impl( *this, rFrame );
479 
480     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
481     SetControlBackground( rStyleSettings.GetMenuColor() );
482 
483     initWindow();
484 
485     Window* pWindow = GetTopMostParentSystemWindow( this );
486     if ( pWindow )
487         ((SystemWindow *)pWindow)->GetTaskPaneList()->AddWindow( this );
488 }
489 
490 // --------------------------------------------------------------------
491 
~ToolbarMenu()492 ToolbarMenu::~ToolbarMenu()
493 {
494     Window* pWindow = GetTopMostParentSystemWindow( this );
495     if ( pWindow )
496         ((SystemWindow *)pWindow)->GetTaskPaneList()->RemoveWindow( this );
497 
498     if ( mpImpl->mxStatusListener.is() )
499     {
500         mpImpl->mxStatusListener->dispose();
501         mpImpl->mxStatusListener.clear();
502     }
503 
504     // delete all menu entries
505     const int nEntryCount = mpImpl->maEntryVector.size();
506     int nEntry;
507     for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
508     {
509         delete mpImpl->maEntryVector[nEntry];
510     }
511 
512     delete mpImpl;
513 }
514 
515 // --------------------------------------------------------------------
516 
getSelectedEntryId() const517 int ToolbarMenu::getSelectedEntryId() const
518 {
519     ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnSelectedEntry );
520     return pEntry ? pEntry->mnEntryId : -1;
521 }
522 
523 // --------------------------------------------------------------------
524 
getHighlightedEntryId() const525 int ToolbarMenu::getHighlightedEntryId() const
526 {
527     ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnHighlightedEntry );
528     return pEntry ? pEntry->mnEntryId : -1;
529 }
530 
531 // --------------------------------------------------------------------
532 
checkEntry(int nEntryId,bool bChecked)533 void ToolbarMenu::checkEntry( int nEntryId, bool bChecked )
534 {
535     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
536     if( pEntry && pEntry->mbChecked != bChecked )
537     {
538         pEntry->mbChecked = bChecked;
539         Invalidate();
540     }
541 }
542 
543 // --------------------------------------------------------------------
544 
isEntryChecked(int nEntryId) const545 bool ToolbarMenu::isEntryChecked( int nEntryId ) const
546 {
547     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
548     return pEntry && pEntry->mbChecked;
549 }
550 
551 // --------------------------------------------------------------------
552 
enableEntry(int nEntryId,bool bEnable)553 void ToolbarMenu::enableEntry( int nEntryId, bool bEnable )
554 {
555     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
556     if( pEntry && pEntry->mbEnabled != bEnable )
557     {
558         pEntry->mbEnabled = bEnable;
559         if( pEntry->mpControl )
560         {
561             pEntry->mpControl->Enable( bEnable );
562 
563             // hack for the valueset to make it paint itself anew
564             pEntry->mpControl->Resize();
565         }
566         Invalidate();
567     }
568 }
569 
570 // --------------------------------------------------------------------
571 
isEntryEnabled(int nEntryId) const572 bool ToolbarMenu::isEntryEnabled( int nEntryId ) const
573 {
574     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
575     return pEntry && pEntry->mbEnabled;
576 }
577 
578 // --------------------------------------------------------------------
579 
setEntryText(int nEntryId,const String & rStr)580 void ToolbarMenu::setEntryText( int nEntryId, const String& rStr )
581 {
582     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
583     if( pEntry && pEntry->maText != rStr )
584     {
585         pEntry->maText = rStr;
586         mpImpl->maSize = implCalcSize();
587         if( IsVisible() )
588             Invalidate();
589     }
590 }
591 
592 // --------------------------------------------------------------------
593 
getEntryText(int nEntryId) const594 const String& ToolbarMenu::getEntryText( int nEntryId ) const
595 {
596     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
597     if( pEntry )
598         return pEntry->maText;
599     else
600     {
601         static String aEmptyStr;
602         return aEmptyStr;
603     }
604 }
605 
606 // --------------------------------------------------------------------
607 
setEntryImage(int nEntryId,const Image & rImage)608 void ToolbarMenu::setEntryImage( int nEntryId, const Image& rImage )
609 {
610     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
611     if( pEntry && pEntry->maImage != rImage )
612     {
613         pEntry->maImage = rImage;
614         mpImpl->maSize = implCalcSize();
615         if( IsVisible() )
616             Invalidate();
617     }
618 }
619 
620 // --------------------------------------------------------------------
621 
getEntryImage(int nEntryId) const622 const Image& ToolbarMenu::getEntryImage( int nEntryId ) const
623 {
624     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
625     if( pEntry )
626         return pEntry->maImage;
627     else
628     {
629         static Image aEmptyImage;
630         return aEmptyImage;
631     }
632 }
633 
634 // --------------------------------------------------------------------
635 
initWindow()636 void ToolbarMenu::initWindow()
637 {
638     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
639 
640     SetPointFont( rStyleSettings.GetMenuFont() );
641     SetBackground( Wallpaper( GetControlBackground() ) );
642     SetTextColor( rStyleSettings.GetMenuTextColor() );
643     SetTextFillColor();
644     SetLineColor();
645 
646     mpImpl->maSize = implCalcSize();
647 }
648 
649 // --------------------------------------------------------------------
650 
implCalcSize()651 Size ToolbarMenu::implCalcSize()
652 {
653     const long nFontHeight = GetTextHeight();
654     long nExtra = nFontHeight/4;
655 
656     Size aSz;
657     Size aMaxImgSz;
658     long nMaxTextWidth = 0;
659     long nMinMenuItemHeight = nFontHeight+2;
660     sal_Bool bCheckable = sal_False;
661 
662     const int nEntryCount = mpImpl->maEntryVector.size();
663     int nEntry;
664 
665     const StyleSettings& rSettings = GetSettings().GetStyleSettings();
666     const bool bUseImages = rSettings.GetUseImagesInMenus();
667 
668     // get maximum image size
669     if( bUseImages )
670     {
671         for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
672         {
673             ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry];
674             if( pEntry && pEntry->mbHasImage )
675             {
676                 Size aImgSz( pEntry->maImage.GetSizePixel() );
677                 nMinMenuItemHeight = std::max( nMinMenuItemHeight, aImgSz.Height() + 6 );
678                 aMaxImgSz.Width() = std::max( aMaxImgSz.Width(), aImgSz.Width() );
679             }
680         }
681     }
682 
683     mpImpl->mnCheckPos = nExtra;
684     mpImpl->mnImagePos = nExtra;
685     mpImpl->mnTextPos = mpImpl->mnImagePos + aMaxImgSz.Width();
686 
687     if ( aMaxImgSz.Width() )
688         mpImpl->mnTextPos += std::max( nExtra, 7L );
689     if ( bCheckable )
690         mpImpl->mnTextPos += 16;
691 
692     // set heights, calc maximum width
693     for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
694     {
695         ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry];
696 
697         if( pEntry )
698         {
699             if ( ( pEntry->mnBits ) & ( MIB_RADIOCHECK | MIB_CHECKABLE ) )
700                 bCheckable = sal_True;
701 
702             // Text:
703             if( pEntry->mbHasText || pEntry->mbHasImage )
704             {
705                 pEntry->maSize.Height() = nMinMenuItemHeight;
706 
707                 if( pEntry->mbHasText )
708                 {
709                     long nTextWidth = GetCtrlTextWidth( pEntry->maText ) + mpImpl->mnTextPos + nExtra;
710                     nMaxTextWidth = std::max( nTextWidth, nMaxTextWidth );
711                 }
712             }
713             // Control:
714             else if( pEntry->mpControl )
715             {
716                 Size aControlSize( pEntry->mpControl->GetOutputSizePixel() );
717 
718                 nMaxTextWidth = std::max( aControlSize.Width(), nMaxTextWidth );
719                 pEntry->maSize.Height() = aControlSize.Height() + 1;
720             }
721 
722         }
723     }
724 
725     aSz.Width() = nMaxTextWidth + (BORDER_X<<1);
726 
727     // positionate controls
728     int nY = BORDER_Y;
729     for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
730     {
731         ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry];
732 
733         if( pEntry )
734         {
735             pEntry->maSize.Width() = nMaxTextWidth;
736 
737             if( pEntry->mpControl )
738             {
739                 Size aControlSize( pEntry->mpControl->GetOutputSizePixel() );
740                 Point aControlPos( (aSz.Width() - aControlSize.Width())>>1, nY);
741 
742                 pEntry->mpControl->SetPosPixel( aControlPos );
743 
744                 pEntry->maRect = Rectangle( aControlPos, aControlSize );
745             }
746             else
747             {
748                 pEntry->maRect = Rectangle( Point( 0, nY ), pEntry->maSize );
749             }
750 
751             nY += pEntry->maSize.Height();
752         }
753         else
754         {
755             nY += SEPARATOR_HEIGHT;
756         }
757     }
758 
759     aSz.Height() += nY + BORDER_Y;
760 
761     return aSz;
762 }
763 
764 // --------------------------------------------------------------------
765 
highlightFirstEntry()766 void ToolbarMenu::highlightFirstEntry()
767 {
768     implChangeHighlightEntry( 0 );
769 }
770 
771 // --------------------------------------------------------------------
772 
GetFocus()773 void ToolbarMenu::GetFocus()
774 {
775     if( mpImpl->mnHighlightedEntry == -1 )
776         implChangeHighlightEntry( 0 );
777 
778     DockingWindow::GetFocus();
779 }
780 
781 // --------------------------------------------------------------------
782 
LoseFocus()783 void ToolbarMenu::LoseFocus()
784 {
785     if( mpImpl->mnHighlightedEntry != -1 )
786         implChangeHighlightEntry( -1 );
787 
788     DockingWindow::LoseFocus();
789 }
790 
791 // --------------------------------------------------------------------
792 
appendEntry(int nEntryId,const String & rStr,MenuItemBits nItemBits)793 void ToolbarMenu::appendEntry( int nEntryId, const String& rStr, MenuItemBits nItemBits )
794 {
795     appendEntry( new ToolbarMenuEntry( *this, nEntryId, rStr, nItemBits ) );
796 }
797 
798 // --------------------------------------------------------------------
799 
appendEntry(int nEntryId,const Image & rImage,MenuItemBits nItemBits)800 void ToolbarMenu::appendEntry( int nEntryId, const Image& rImage, MenuItemBits nItemBits )
801 {
802     appendEntry( new ToolbarMenuEntry( *this, nEntryId, rImage, nItemBits ) );
803 }
804 
805 // --------------------------------------------------------------------
806 
appendEntry(int nEntryId,const String & rStr,const Image & rImage,MenuItemBits nItemBits)807 void ToolbarMenu::appendEntry( int nEntryId, const String& rStr, const Image& rImage, MenuItemBits nItemBits )
808 {
809     appendEntry( new ToolbarMenuEntry( *this, nEntryId, rImage, rStr, nItemBits ) );
810 }
811 
812 // --------------------------------------------------------------------
813 
appendEntry(int nEntryId,Control * pControl,MenuItemBits nItemBits)814 void ToolbarMenu::appendEntry( int nEntryId, Control* pControl, MenuItemBits nItemBits )
815 {
816     appendEntry( new ToolbarMenuEntry( *this, nEntryId, pControl, nItemBits ) );
817 }
818 
819 // --------------------------------------------------------------------
820 
appendEntry(ToolbarMenuEntry * pEntry)821 void ToolbarMenu::appendEntry( ToolbarMenuEntry* pEntry )
822 {
823     mpImpl->maEntryVector.push_back( pEntry );
824     mpImpl->maSize = implCalcSize();
825     if( IsVisible() )
826         Invalidate();
827 }
828 
829 // --------------------------------------------------------------------
830 
appendSeparator()831 void ToolbarMenu::appendSeparator()
832 {
833     appendEntry( 0 );
834 }
835 
836 // --------------------------------------------------------------------
837 
838 /** creates an empty ValueSet that is initialized and can be inserted with appendEntry. */
createEmptyValueSetControl()839 ValueSet* ToolbarMenu::createEmptyValueSetControl()
840 {
841     ValueSet* pSet = new ValueSet( this, WB_TABSTOP | WB_MENUSTYLEVALUESET | WB_FLATVALUESET | WB_NOBORDER | WB_NO_DIRECTSELECT );
842     pSet->EnableFullItemMode( sal_False );
843     pSet->SetColor( GetControlBackground() );
844     pSet->SetHighlightHdl( LINK( this, ToolbarMenu, HighlightHdl ) );
845     return pSet;
846 }
847 
848 // --------------------------------------------------------------------
849 
implGetEntry(int nEntry) const850 ToolbarMenuEntry* ToolbarMenu::implGetEntry( int nEntry ) const
851 {
852     return mpImpl->implGetEntry( nEntry );
853 }
854 
855 // --------------------------------------------------------------------
856 
implSearchEntry(int nEntryId) const857 ToolbarMenuEntry* ToolbarMenu::implSearchEntry( int nEntryId ) const
858 {
859     const int nEntryCount = mpImpl->maEntryVector.size();
860     int nEntry;
861     for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
862     {
863         ToolbarMenuEntry* p = mpImpl->maEntryVector[nEntry];
864         if( p && p->mnEntryId == nEntryId )
865         {
866             return p;
867         }
868     }
869 
870     return NULL;
871 }
872 
873 // --------------------------------------------------------------------
874 
implHighlightEntry(int nHighlightEntry,bool bHighlight)875 void ToolbarMenu::implHighlightEntry( int nHighlightEntry, bool bHighlight )
876 {
877     Size    aSz( GetOutputSizePixel() );
878     long    nX = 0, nY = 0;
879 
880     const int nEntryCount = mpImpl->maEntryVector.size();
881     int nEntry;
882     for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
883     {
884         ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry];
885         if( pEntry && (nEntry == nHighlightEntry) )
886         {
887             // no highlights for controls only items
888             if( pEntry->mpControl )
889             {
890                 if( !bHighlight )
891                 {
892                     ValueSet* pValueSet = dynamic_cast< ValueSet* >( pEntry->mpControl );
893                     if( pValueSet )
894                     {
895                         pValueSet->SetNoSelection();
896                     }
897                 }
898                 break;
899             }
900 
901             bool bRestoreLineColor = false;
902             Color oldLineColor;
903             bool bDrawItemRect = true;
904 
905             Rectangle aItemRect( Point( nX, nY ), Size( aSz.Width(), pEntry->maSize.Height() ) );
906             if ( pEntry->mnBits & MIB_POPUPSELECT )
907             {
908                 long nFontHeight = GetTextHeight();
909                 aItemRect.Right() -= nFontHeight + nFontHeight/4;
910             }
911 
912             if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
913             {
914                 Size aPxSize( GetOutputSizePixel() );
915                 Push( PUSH_CLIPREGION );
916                 IntersectClipRegion( Rectangle( Point( nX, nY ), Size( aSz.Width(), pEntry->maSize.Height() ) ) );
917                 Rectangle aCtrlRect( Point( nX, 0 ), Size( aPxSize.Width()-nX, aPxSize.Height() ) );
918                 DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
919                                    aCtrlRect,
920                                    CTRL_STATE_ENABLED,
921                                    ImplControlValue(),
922                                    OUString() );
923                 if( bHighlight && IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM ) )
924                 {
925                     bDrawItemRect = false;
926                     if( sal_False == DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_ITEM,
927                                                     aItemRect,
928                                                     CTRL_STATE_SELECTED | ( pEntry->mbEnabled? CTRL_STATE_ENABLED: 0 ),
929                                                     ImplControlValue(),
930                                                     OUString() ) )
931                     {
932                         bDrawItemRect = bHighlight;
933                     }
934                 }
935                 else
936                     bDrawItemRect = bHighlight;
937                 Pop();
938             }
939             if( bDrawItemRect )
940             {
941                 if ( bHighlight )
942                 {
943                     if( pEntry->mbEnabled )
944                         SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
945                     else
946                     {
947                         SetFillColor();
948                         oldLineColor = GetLineColor();
949                         SetLineColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
950                         bRestoreLineColor = true;
951                     }
952                 }
953                 else
954                     SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
955 
956                 DrawRect( aItemRect );
957             }
958             implPaint( pEntry, bHighlight );
959             if( bRestoreLineColor )
960                 SetLineColor( oldLineColor );
961             break;
962         }
963 
964         nY += pEntry ? pEntry->maSize.Height() : SEPARATOR_HEIGHT;
965     }
966 }
967 
968 // --------------------------------------------------------------------
969 
implSelectEntry(int nSelectedEntry)970 void ToolbarMenu::implSelectEntry( int nSelectedEntry )
971 {
972     mpImpl->mnSelectedEntry = nSelectedEntry;
973 
974     ToolbarMenuEntry* pEntry = NULL;
975     if( nSelectedEntry != -1 )
976         pEntry = mpImpl->maEntryVector[ nSelectedEntry ];
977 
978     if( pEntry )
979         mpImpl->maSelectHdl.Call( this );
980 }
981 
982 // --------------------------------------------------------------------
983 
MouseButtonDown(const MouseEvent & rMEvt)984 void ToolbarMenu::MouseButtonDown( const MouseEvent& rMEvt )
985 {
986     implHighlightEntry( rMEvt, true );
987 
988     implSelectEntry( mpImpl->mnHighlightedEntry );
989 }
990 
991 // --------------------------------------------------------------------
992 
MouseButtonUp(const MouseEvent &)993 void ToolbarMenu::MouseButtonUp( const MouseEvent& )
994 {
995 }
996 
997 // --------------------------------------------------------------------
998 
MouseMove(const MouseEvent & rMEvt)999 void ToolbarMenu::MouseMove( const MouseEvent& rMEvt )
1000 {
1001     if ( !IsVisible() )
1002         return;
1003 
1004     implHighlightEntry( rMEvt, false );
1005 }
1006 
1007 // --------------------------------------------------------------------
1008 
implHighlightEntry(const MouseEvent & rMEvt,bool bMBDown)1009 void ToolbarMenu::implHighlightEntry( const MouseEvent& rMEvt, bool bMBDown )
1010 {
1011     long nY = 0;
1012     long nMouseY = rMEvt.GetPosPixel().Y();
1013     Size aOutSz = GetOutputSizePixel();
1014     if ( ( nMouseY >= 0 ) && ( nMouseY < aOutSz.Height() ) )
1015     {
1016         bool bHighlighted = sal_False;
1017 
1018         const int nEntryCount = mpImpl->maEntryVector.size();
1019         int nEntry;
1020         for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
1021         {
1022             ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry];
1023             if( pEntry )
1024             {
1025                 long nOldY = nY;
1026                 nY += pEntry->maSize.Height();
1027 
1028                 if( pEntry->mnEntryId != TITLE_ID )
1029                 {
1030                     if ( ( nOldY <= nMouseY ) && ( nY > nMouseY ) )
1031                     {
1032                         if( bMBDown )
1033                         {
1034                             if( nEntry != mpImpl->mnHighlightedEntry )
1035                             {
1036                                 implChangeHighlightEntry( nEntry );
1037                             }
1038                         }
1039                         else
1040                         {
1041                             if ( nEntry != mpImpl->mnHighlightedEntry )
1042                             {
1043                                 implChangeHighlightEntry( nEntry );
1044                             }
1045                         }
1046                         bHighlighted = true;
1047                     }
1048                 }
1049             }
1050             else
1051             {
1052                 nY += SEPARATOR_HEIGHT;
1053             }
1054         }
1055         if ( !bHighlighted )
1056             implChangeHighlightEntry( -1 );
1057     }
1058     else
1059     {
1060         implChangeHighlightEntry( -1 );
1061     }
1062 }
1063 
1064 // --------------------------------------------------------------------
1065 
implChangeHighlightEntry(int nEntry)1066 void ToolbarMenu::implChangeHighlightEntry( int nEntry )
1067 {
1068     if( mpImpl->mnHighlightedEntry != -1 )
1069     {
1070         implHighlightEntry( mpImpl->mnHighlightedEntry, false );
1071     }
1072 
1073     mpImpl->mnHighlightedEntry = nEntry;
1074     Invalidate();
1075 
1076     if( mpImpl->mnHighlightedEntry != -1 )
1077     {
1078         implHighlightEntry( mpImpl->mnHighlightedEntry, true );
1079     }
1080 
1081     mpImpl->notifyHighlightedEntry();
1082 }
1083 
1084 // --------------------------------------------------------------------
1085 
implCheckSubControlCursorMove(Control * pControl,bool bUp,int & nLastColumn)1086 static bool implCheckSubControlCursorMove( Control* pControl, bool bUp, int& nLastColumn )
1087 {
1088     ValueSet* pValueSet = dynamic_cast< ValueSet* >( pControl );
1089     if( pValueSet )
1090     {
1091         sal_uInt16 nItemPos = pValueSet->GetItemPos( pValueSet->GetSelectItemId() );
1092         if( nItemPos != VALUESET_ITEM_NOTFOUND )
1093         {
1094             const sal_uInt16 nColCount = pValueSet->GetColCount();
1095             const sal_uInt16 nLine = nItemPos / nColCount;
1096 
1097             nLastColumn = nItemPos - (nLine * nColCount);
1098 
1099             if( bUp )
1100             {
1101                 return nLine > 0;
1102             }
1103             else
1104             {
1105                 const sal_uInt16 nLineCount = (pValueSet->GetItemCount() + nColCount - 1) / nColCount;
1106                 return (nLine+1) < nLineCount;
1107             }
1108         }
1109     }
1110 
1111     return false;
1112 }
1113 
1114 // --------------------------------------------------------------------
1115 
implCursorUpDown(bool bUp,bool bHomeEnd)1116 ToolbarMenuEntry* ToolbarMenu::implCursorUpDown( bool bUp, bool bHomeEnd )
1117 {
1118     int n = 0, nLoop = 0;
1119     if( !bHomeEnd )
1120     {
1121         n = mpImpl->mnHighlightedEntry;
1122         if( n == -1 )
1123         {
1124             if( bUp )
1125                 n = 0;
1126             else
1127                 n = mpImpl->maEntryVector.size()-1;
1128         }
1129         else
1130         {
1131             // if we have a currently selected entry and
1132             // cursor keys are used than check if this entry
1133             // has a control that can use those cursor keys
1134             ToolbarMenuEntry* pData = mpImpl->maEntryVector[n];
1135             if( pData && pData->mpControl && !pData->mbHasText )
1136             {
1137                 if( implCheckSubControlCursorMove( pData->mpControl, bUp, mpImpl->mnLastColumn ) )
1138                     return pData;
1139             }
1140         }
1141         nLoop = n;
1142     }
1143     else
1144     {
1145         // absolute positioning
1146         if( bUp )
1147         {
1148             n = mpImpl->maEntryVector.size();
1149             nLoop = n-1;
1150         }
1151         else
1152         {
1153             n = -1;
1154             nLoop = mpImpl->maEntryVector.size()-1;
1155         }
1156     }
1157 
1158     do
1159     {
1160         if( bUp )
1161         {
1162             if ( n )
1163                 n--;
1164             else
1165                 if( mpImpl->mnHighlightedEntry == -1 )
1166                     n = mpImpl->maEntryVector.size()-1;
1167                 else
1168                     break;
1169         }
1170         else
1171         {
1172             if( n < ((int)mpImpl->maEntryVector.size()-1) )
1173                 n++;
1174             else
1175                 if( mpImpl->mnHighlightedEntry == -1 )
1176                     n = 0;
1177                 else
1178                     break;
1179         }
1180 
1181         ToolbarMenuEntry* pData = mpImpl->maEntryVector[n];
1182         if( pData && (pData->mnEntryId != TITLE_ID) )
1183         {
1184             implChangeHighlightEntry( n );
1185             return pData;
1186         }
1187     } while ( n != nLoop );
1188 
1189     return 0;
1190 }
1191 
1192 // --------------------------------------------------------------------
1193 
implHighlightControl(sal_uInt16 nCode,Control * pControl)1194 void ToolbarMenu_Impl::implHighlightControl( sal_uInt16 nCode, Control* pControl )
1195 {
1196     ValueSet* pValueSet = dynamic_cast< ValueSet* >( pControl );
1197     if( pValueSet )
1198     {
1199         const sal_uInt16 nItemCount = pValueSet->GetItemCount();
1200         sal_uInt16 nItemPos = VALUESET_ITEM_NOTFOUND;
1201         switch( nCode )
1202         {
1203         case KEY_UP:
1204         {
1205             const sal_uInt16 nColCount = pValueSet->GetColCount();
1206             const sal_uInt16 nLastLine = nItemCount / nColCount;
1207             nItemPos = std::min( ((nLastLine-1) * nColCount) + mnLastColumn, nItemCount-1 );
1208             break;
1209         }
1210         case KEY_DOWN:
1211             nItemPos = std::min( mnLastColumn, nItemCount-1 );
1212             break;
1213         case KEY_END:
1214             nItemPos = nItemCount -1;
1215             break;
1216         case KEY_HOME:
1217             nItemPos = 0;
1218             break;
1219         }
1220         pValueSet->SelectItem( pValueSet->GetItemId( nItemPos ) );
1221         notifyHighlightedEntry();
1222     }
1223 }
1224 
1225 // --------------------------------------------------------------------
1226 
KeyInput(const KeyEvent & rKEvent)1227 void ToolbarMenu::KeyInput( const KeyEvent& rKEvent )
1228 {
1229     Control* pForwardControl = 0;
1230     sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode();
1231     switch ( nCode )
1232     {
1233         case KEY_UP:
1234         case KEY_DOWN:
1235         {
1236             int nOldEntry = mpImpl->mnHighlightedEntry;
1237             ToolbarMenuEntry*p = implCursorUpDown( nCode == KEY_UP, false );
1238             if( p && p->mpControl )
1239             {
1240                 if( nOldEntry != mpImpl->mnHighlightedEntry )
1241                 {
1242                     mpImpl->implHighlightControl( nCode, p->mpControl );
1243                 }
1244                 else
1245                 {
1246                     // in case we are in a system floating window, GrabFocus does not work :-/
1247                     pForwardControl = p->mpControl;
1248                 }
1249             }
1250         }
1251         break;
1252         case KEY_END:
1253         case KEY_HOME:
1254         {
1255             ToolbarMenuEntry* p = implCursorUpDown( nCode == KEY_END, true );
1256             if( p && p->mpControl )
1257             {
1258                 mpImpl->implHighlightControl( nCode, p->mpControl );
1259             }
1260         }
1261         break;
1262         case KEY_F6:
1263         case KEY_ESCAPE:
1264         {
1265             // Ctrl-F6 acts like ESC here, the menu bar however will then put the focus in the document
1266             if( nCode == KEY_F6 && !rKEvent.GetKeyCode().IsMod1() )
1267                 break;
1268 
1269             implSelectEntry( -1 );
1270         }
1271         break;
1272 
1273         case KEY_RETURN:
1274         {
1275             ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnHighlightedEntry );
1276             if ( pEntry && pEntry->mbEnabled && (pEntry->mnEntryId != TITLE_ID) )
1277             {
1278                 if( pEntry->mpControl )
1279                 {
1280                     pForwardControl = pEntry->mpControl;
1281                 }
1282                 else
1283                 {
1284                     implSelectEntry( mpImpl->mnHighlightedEntry );
1285                 }
1286             }
1287         }
1288         break;
1289         default:
1290         {
1291             ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnHighlightedEntry );
1292             if ( pEntry && pEntry->mbEnabled && pEntry->mpControl && !pEntry->mbHasText )
1293             {
1294                 pForwardControl = pEntry->mpControl;
1295             }
1296         }
1297 
1298     }
1299     if( pForwardControl )
1300         pForwardControl->KeyInput( rKEvent );
1301 
1302 }
1303 
1304 // --------------------------------------------------------------------
ImplPaintCheckBackground(Window * i_pWindow,const Rectangle & i_rRect,bool i_bHighlight)1305 static void ImplPaintCheckBackground( Window* i_pWindow, const Rectangle& i_rRect, bool i_bHighlight )
1306 {
1307     sal_Bool bNativeOk = sal_False;
1308     if( i_pWindow->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) )
1309     {
1310         ImplControlValue    aControlValue;
1311         ControlState        nState = CTRL_STATE_PRESSED | CTRL_STATE_ENABLED;
1312 
1313         aControlValue.setTristateVal( BUTTONVALUE_ON );
1314 
1315         bNativeOk = i_pWindow->DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON,
1316                                                   i_rRect, nState, aControlValue,
1317                                                   rtl::OUString() );
1318     }
1319 
1320     if( ! bNativeOk )
1321     {
1322         const StyleSettings& rSettings = i_pWindow->GetSettings().GetStyleSettings();
1323         Color aColor( i_bHighlight ? rSettings.GetMenuHighlightTextColor() : rSettings.GetHighlightColor() );
1324         i_pWindow->DrawSelectionBackground( i_rRect, 0, i_bHighlight, sal_True, sal_False, 2, NULL, &aColor );
1325     }
1326 }
1327 
ImplGetNativeCheckAndRadioSize(Window * pWin,long & rCheckHeight,long & rRadioHeight,long & rMaxWidth)1328 static long ImplGetNativeCheckAndRadioSize( Window* pWin, long& rCheckHeight, long& rRadioHeight, long &rMaxWidth )
1329 {
1330     rMaxWidth = rCheckHeight = rRadioHeight = 0;
1331 
1332     ImplControlValue aVal;
1333     Rectangle aNativeBounds;
1334     Rectangle aNativeContent;
1335     Point tmp( 0, 0 );
1336     Rectangle aCtrlRegion( tmp, Size( 100, 15 ) );
1337     if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_CHECK_MARK ) )
1338     {
1339         if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
1340                                           ControlPart(PART_MENU_ITEM_CHECK_MARK),
1341                                           aCtrlRegion,
1342                                           ControlState(CTRL_STATE_ENABLED),
1343                                           aVal,
1344                                           OUString(),
1345                                           aNativeBounds,
1346                                           aNativeContent )
1347         )
1348         {
1349             rCheckHeight = aNativeBounds.GetHeight();
1350             rMaxWidth = aNativeContent.GetWidth();
1351         }
1352     }
1353     if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_RADIO_MARK ) )
1354     {
1355         if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
1356                                           ControlPart(PART_MENU_ITEM_RADIO_MARK),
1357                                           aCtrlRegion,
1358                                           ControlState(CTRL_STATE_ENABLED),
1359                                           aVal,
1360                                           OUString(),
1361                                           aNativeBounds,
1362                                           aNativeContent )
1363         )
1364         {
1365             rRadioHeight = aNativeBounds.GetHeight();
1366             rMaxWidth = Max (rMaxWidth, aNativeContent.GetWidth());
1367         }
1368     }
1369     return (rCheckHeight > rRadioHeight) ? rCheckHeight : rRadioHeight;
1370 }
1371 
implPaint(ToolbarMenuEntry * pThisOnly,bool bHighlighted)1372 void ToolbarMenu::implPaint( ToolbarMenuEntry* pThisOnly, bool bHighlighted )
1373 {
1374     sal_uInt16 nBorder = 0; long nStartY = 0; // from Menu implementations, needed when we support native menu background & scrollable menu
1375 
1376     long nFontHeight = GetTextHeight();
1377 //    long nExtra = nFontHeight/4;
1378 
1379     long nCheckHeight = 0, nRadioHeight = 0, nMaxCheckWidth = 0;
1380     ImplGetNativeCheckAndRadioSize( this, nCheckHeight, nRadioHeight, nMaxCheckWidth );
1381 
1382     DecorationView aDecoView( this );
1383     const StyleSettings& rSettings = GetSettings().GetStyleSettings();
1384     const bool bUseImages = rSettings.GetUseImagesInMenus();
1385 
1386     int nOuterSpace = 0; // ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder;
1387     Point aTopLeft( nOuterSpace, nOuterSpace ), aTmpPos;
1388 
1389     Size aOutSz( GetOutputSizePixel() );
1390     const int nEntryCount = mpImpl->maEntryVector.size();
1391     int nEntry;
1392     for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
1393     {
1394         ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry];
1395 
1396         Point aPos( aTopLeft );
1397         aPos.Y() += nBorder;
1398         aPos.Y() += nStartY;
1399 
1400 
1401         if( (pEntry == 0) && !pThisOnly )
1402         {
1403             // Separator
1404             aTmpPos.Y() = aPos.Y() + ((SEPARATOR_HEIGHT-2)/2);
1405             aTmpPos.X() = aPos.X() + 2 + nOuterSpace;
1406             SetLineColor( rSettings.GetShadowColor() );
1407             DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) );
1408             aTmpPos.Y()++;
1409             SetLineColor( rSettings.GetLightColor() );
1410             DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) );
1411             SetLineColor();
1412         }
1413         else if( !pThisOnly || ( pEntry == pThisOnly ) )
1414         {
1415             const bool bTitle = pEntry->mnEntryId == TITLE_ID;
1416 
1417             if ( pThisOnly && bHighlighted )
1418                 SetTextColor( rSettings.GetMenuHighlightTextColor() );
1419 
1420             if( aPos.Y() >= 0 )
1421             {
1422                 long nTextOffsetY = ((pEntry->maSize.Height()-nFontHeight)/2);
1423 
1424                 sal_uInt16  nTextStyle   = 0;
1425                 sal_uInt16  nSymbolStyle = 0;
1426                 sal_uInt16  nImageStyle  = 0;
1427 
1428                 if( !pEntry->mbEnabled )
1429                 {
1430                     nTextStyle   |= TEXT_DRAW_DISABLE;
1431                     nSymbolStyle |= SYMBOL_DRAW_DISABLE;
1432                     nImageStyle  |= IMAGE_DRAW_DISABLE;
1433                 }
1434 
1435                 Rectangle aOuterCheckRect( Point( aPos.X()+mpImpl->mnCheckPos, aPos.Y() ), Size( pEntry->maSize.Height(), pEntry->maSize.Height() ) );
1436                 aOuterCheckRect.Left()      += 1;
1437                 aOuterCheckRect.Right()     -= 1;
1438                 aOuterCheckRect.Top()       += 1;
1439                 aOuterCheckRect.Bottom()    -= 1;
1440 
1441                 if( bTitle )
1442                 {
1443                     // fill the background
1444                     Rectangle aRect( aTopLeft, Size( aOutSz.Width(), pEntry->maSize.Height() ) );
1445                     SetFillColor(rSettings.GetDialogColor());
1446                     SetLineColor();
1447                     DrawRect(aRect);
1448                     SetLineColor( rSettings.GetLightColor() );
1449                     DrawLine( aRect.TopLeft(), aRect.TopRight() );
1450                     SetLineColor( rSettings.GetShadowColor() );
1451                     DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
1452                 }
1453 
1454                 // CheckMark
1455                 if ( pEntry->HasCheck() )
1456                 {
1457                     // draw selection transparent marker if checked
1458                     // onto that either a checkmark or the item image
1459                     // will be painted
1460                     // however do not do this if native checks will be painted since
1461                     // the selection color too often does not fit the theme's check and/or radio
1462 
1463                     if( !pEntry->mbHasImage )
1464                     {
1465                         if( this->IsNativeControlSupported( CTRL_MENU_POPUP,
1466                                                              (pEntry->mnBits & MIB_RADIOCHECK)
1467                                                              ? PART_MENU_ITEM_CHECK_MARK
1468                                                              : PART_MENU_ITEM_RADIO_MARK ) )
1469                         {
1470                             ControlPart nPart = ((pEntry->mnBits & MIB_RADIOCHECK)
1471                                                  ? PART_MENU_ITEM_RADIO_MARK
1472                                                  : PART_MENU_ITEM_CHECK_MARK);
1473 
1474                             ControlState nState = 0;
1475 
1476                             if ( pEntry->mbChecked )
1477                                 nState |= CTRL_STATE_PRESSED;
1478 
1479                             if ( pEntry->mbEnabled )
1480                                 nState |= CTRL_STATE_ENABLED;
1481 
1482                             if ( bHighlighted )
1483                                 nState |= CTRL_STATE_SELECTED;
1484 
1485                             long nCtrlHeight = (pEntry->mnBits & MIB_RADIOCHECK) ? nCheckHeight : nRadioHeight;
1486                             aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - nCtrlHeight)/2;
1487                             aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - nCtrlHeight)/2;
1488 
1489                             Rectangle aCheckRect( aTmpPos, Size( nCtrlHeight, nCtrlHeight ) );
1490                             DrawNativeControl( CTRL_MENU_POPUP, nPart, aCheckRect, nState, ImplControlValue(), OUString() );
1491                         }
1492                         else if ( pEntry->mbChecked ) // by default do nothing for unchecked items
1493                         {
1494                             ImplPaintCheckBackground( this, aOuterCheckRect, pThisOnly && bHighlighted );
1495 
1496                             SymbolType eSymbol;
1497                             Size aSymbolSize;
1498                             if ( pEntry->mnBits & MIB_RADIOCHECK )
1499                             {
1500                                 eSymbol = SYMBOL_RADIOCHECKMARK;
1501                                 aSymbolSize = Size( nFontHeight/2, nFontHeight/2 );
1502                             }
1503                             else
1504                             {
1505                                 eSymbol = SYMBOL_CHECKMARK;
1506                                 aSymbolSize = Size( (nFontHeight*25)/40, nFontHeight/2 );
1507                             }
1508                             aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - aSymbolSize.Width())/2;
1509                             aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - aSymbolSize.Height())/2;
1510                             Rectangle aRect( aTmpPos, aSymbolSize );
1511                             aDecoView.DrawSymbol( aRect, eSymbol, GetTextColor(), nSymbolStyle );
1512                         }
1513                     }
1514                 }
1515 
1516                 // Image:
1517                 if( pEntry->mbHasImage && bUseImages )
1518                 {
1519                     // Don't render an image for a check thing
1520                      /* if((nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES) || !pEntry->HasCheck() )*/
1521                     {
1522                         if( pEntry->mbChecked )
1523                             ImplPaintCheckBackground( this, aOuterCheckRect, pThisOnly && bHighlighted );
1524                         aTmpPos = aOuterCheckRect.TopLeft();
1525                         aTmpPos.X() += (aOuterCheckRect.GetWidth()-pEntry->maImage.GetSizePixel().Width())/2;
1526                         aTmpPos.Y() += (aOuterCheckRect.GetHeight()-pEntry->maImage.GetSizePixel().Height())/2;
1527                         DrawImage( aTmpPos, pEntry->maImage, nImageStyle );
1528                     }
1529                 }
1530 
1531                 // Text:
1532                 if( pEntry->mbHasText )
1533                 {
1534                     aTmpPos.X() = aPos.X() + (bTitle ? 4 : mpImpl->mnTextPos);
1535                     aTmpPos.Y() = aPos.Y();
1536                     aTmpPos.Y() += nTextOffsetY;
1537                     sal_uInt16 nStyle = nTextStyle|TEXT_DRAW_MNEMONIC;
1538 
1539                     DrawCtrlText( aTmpPos, pEntry->maText, 0, pEntry->maText.Len(), nStyle, NULL, NULL ); // pVector, pDisplayText );
1540                 }
1541 
1542 /*
1543                 // Accel
1544                 if ( !bLayout && !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() )
1545                 {
1546                     XubString aAccText = pData->aAccelKey.GetName();
1547                     aTmpPos.X() = aOutSz.Width() - this->GetTextWidth( aAccText );
1548                     aTmpPos.X() -= 4*nExtra;
1549 
1550                     aTmpPos.X() -= nOuterSpace;
1551                     aTmpPos.Y() = aPos.Y();
1552                     aTmpPos.Y() += nTextOffsetY;
1553                     this->DrawCtrlText( aTmpPos, aAccText, 0, aAccText.Len(), nTextStyle );
1554                 }
1555 */
1556 
1557 /*
1558                 // SubMenu?
1559                 if ( !bLayout && !bIsMenuBar && pData->pSubMenu )
1560                 {
1561                     aTmpPos.X() = aOutSz.Width() - nFontHeight + nExtra - nOuterSpace;
1562                     aTmpPos.Y() = aPos.Y();
1563                     aTmpPos.Y() += nExtra/2;
1564                     aTmpPos.Y() += ( pEntry->maSize.Height() / 2 ) - ( nFontHeight/4 );
1565                     if ( pEntry->mnBits & MIB_POPUPSELECT )
1566                     {
1567                         this->SetTextColor( rSettings.GetMenuTextColor() );
1568                         Point aTmpPos2( aPos );
1569                         aTmpPos2.X() = aOutSz.Width() - nFontHeight - nFontHeight/4;
1570                         aDecoView.DrawFrame(
1571                             Rectangle( aTmpPos2, Size( nFontHeight+nFontHeight/4, pEntry->maSize.Height() ) ), FRAME_DRAW_GROUP );
1572                     }
1573                     aDecoView.DrawSymbol(
1574                         Rectangle( aTmpPos, Size( nFontHeight/2, nFontHeight/2 ) ),
1575                         SYMBOL_SPIN_RIGHT, this->GetTextColor(), nSymbolStyle );
1576 //                  if ( pEntry->mnBits & MIB_POPUPSELECT )
1577 //                  {
1578 //                      aTmpPos.Y() += nFontHeight/2 ;
1579 //                      this->SetLineColor( rSettings.GetShadowColor() );
1580 //                      this->DrawLine( aTmpPos, Point( aTmpPos.X() + nFontHeight/3, aTmpPos.Y() ) );
1581 //                      this->SetLineColor( rSettings.GetLightColor() );
1582 //                      aTmpPos.Y()++;
1583 //                      this->DrawLine( aTmpPos, Point( aTmpPos.X() + nFontHeight/3, aTmpPos.Y() ) );
1584 //                      this->SetLineColor();
1585 //                  }
1586                 }
1587 */
1588 
1589                 if ( pThisOnly && bHighlighted )
1590                 {
1591                     // This restores the normal menu or menu bar text
1592                     // color for when it is no longer highlighted.
1593                     SetTextColor( rSettings.GetMenuTextColor() );
1594                  }
1595             }
1596         }
1597 
1598         aTopLeft.Y() += pEntry ? pEntry->maSize.Height() : SEPARATOR_HEIGHT;
1599     }
1600 }
1601 
1602 // --------------------------------------------------------------------
1603 
Paint(const Rectangle &)1604 void ToolbarMenu::Paint( const Rectangle& )
1605 {
1606     SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
1607 
1608     implPaint();
1609 
1610     if( mpImpl->mnHighlightedEntry != -1 )
1611         implHighlightEntry( mpImpl->mnHighlightedEntry, true );
1612 }
1613 
1614 // --------------------------------------------------------------------
1615 
RequestHelp(const HelpEvent & rHEvt)1616 void ToolbarMenu::RequestHelp( const HelpEvent& rHEvt )
1617 {
1618     DockingWindow::RequestHelp( rHEvt );
1619 }
1620 
1621 // --------------------------------------------------------------------
1622 
StateChanged(StateChangedType nType)1623 void ToolbarMenu::StateChanged( StateChangedType nType )
1624 {
1625     DockingWindow::StateChanged( nType );
1626 
1627     if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) || ( nType == STATE_CHANGE_CONTROLBACKGROUND ) )
1628     {
1629         initWindow();
1630         Invalidate();
1631     }
1632 }
1633 
1634 // --------------------------------------------------------------------
1635 
DataChanged(const DataChangedEvent & rDCEvt)1636 void ToolbarMenu::DataChanged( const DataChangedEvent& rDCEvt )
1637 {
1638     DockingWindow::DataChanged( rDCEvt );
1639 
1640     if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
1641          (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
1642          ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
1643           (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
1644     {
1645         initWindow();
1646         Invalidate();
1647     }
1648 }
1649 
1650 // --------------------------------------------------------------------
1651 
Command(const CommandEvent & rCEvt)1652 void ToolbarMenu::Command( const CommandEvent& rCEvt )
1653 {
1654     if ( rCEvt.GetCommand() == COMMAND_WHEEL )
1655     {
1656         const CommandWheelData* pData = rCEvt.GetWheelData();
1657         if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
1658         {
1659             implCursorUpDown( pData->GetDelta() > 0L, false );
1660         }
1661     }
1662 }
1663 
1664 // --------------------------------------------------------------------
1665 
CreateAccessible()1666 Reference< ::com::sun::star::accessibility::XAccessible > ToolbarMenu::CreateAccessible()
1667 {
1668     mpImpl->setAccessible( new ToolbarMenuAcc( *mpImpl ) );
1669     return Reference< XAccessible >( mpImpl->mxAccessible.get() );
1670 }
1671 
1672 // --------------------------------------------------------------------
1673 
1674 // todo: move to new base class that will replace SfxPopupWindo
AddStatusListener(const rtl::OUString & rCommandURL)1675 void ToolbarMenu::AddStatusListener( const rtl::OUString& rCommandURL )
1676 {
1677     initStatusListener();
1678     mpImpl->mxStatusListener->addStatusListener( rCommandURL );
1679 }
1680 
1681 // --------------------------------------------------------------------
1682 
RemoveStatusListener(const rtl::OUString & rCommandURL)1683 void ToolbarMenu::RemoveStatusListener( const rtl::OUString& rCommandURL )
1684 {
1685     mpImpl->mxStatusListener->removeStatusListener( rCommandURL );
1686 }
1687 // --------------------------------------------------------------------
1688 
1689 
UpdateStatus(const rtl::OUString & rCommandURL)1690 void ToolbarMenu::UpdateStatus( const rtl::OUString& rCommandURL )
1691 {
1692     mpImpl->mxStatusListener->updateStatus( rCommandURL );
1693 }
1694 
1695 // --------------------------------------------------------------------
1696 
1697 // XStatusListener (subclasses must override this one to get the status updates
statusChanged(const::com::sun::star::frame::FeatureStateEvent &)1698 void SAL_CALL ToolbarMenu::statusChanged( const ::com::sun::star::frame::FeatureStateEvent& /*Event*/ ) throw ( ::com::sun::star::uno::RuntimeException )
1699 {
1700 }
1701 
1702 // --------------------------------------------------------------------
1703 
1704 class ToolbarMenuStatusListener : public svt::FrameStatusListener
1705 {
1706 public:
1707     ToolbarMenuStatusListener( const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& xServiceManager,
1708                                const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame,
1709                                ToolbarMenu& rToolbarMenu );
1710 
1711     virtual void SAL_CALL dispose() throw (::com::sun::star::uno::RuntimeException);
1712     virtual void SAL_CALL statusChanged( const ::com::sun::star::frame::FeatureStateEvent& Event ) throw ( ::com::sun::star::uno::RuntimeException );
1713 
1714     ToolbarMenu* mpMenu;
1715 };
1716 
1717 // --------------------------------------------------------------------
1718 
ToolbarMenuStatusListener(const com::sun::star::uno::Reference<com::sun::star::lang::XMultiServiceFactory> & xServiceManager,const::com::sun::star::uno::Reference<::com::sun::star::frame::XFrame> & xFrame,ToolbarMenu & rToolbarMenu)1719 ToolbarMenuStatusListener::ToolbarMenuStatusListener(
1720     const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& xServiceManager,
1721     const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame,
1722     ToolbarMenu& rToolbarMenu )
1723 : svt::FrameStatusListener( xServiceManager, xFrame )
1724 , mpMenu( &rToolbarMenu )
1725 {
1726 }
1727 
1728 // --------------------------------------------------------------------
1729 
dispose()1730 void SAL_CALL ToolbarMenuStatusListener::dispose() throw (::com::sun::star::uno::RuntimeException)
1731 {
1732     mpMenu = 0;
1733     svt::FrameStatusListener::dispose();
1734 }
1735 
1736 // --------------------------------------------------------------------
1737 
statusChanged(const::com::sun::star::frame::FeatureStateEvent & Event)1738 void SAL_CALL ToolbarMenuStatusListener::statusChanged( const ::com::sun::star::frame::FeatureStateEvent& Event ) throw ( ::com::sun::star::uno::RuntimeException )
1739 {
1740     if( mpMenu )
1741         mpMenu->statusChanged( Event );
1742 }
1743 
1744 // --------------------------------------------------------------------
1745 
initStatusListener()1746 void ToolbarMenu::initStatusListener()
1747 {
1748     if( !mpImpl->mxStatusListener.is() )
1749         mpImpl->mxStatusListener.set( new ToolbarMenuStatusListener( mpImpl->mxServiceManager, mpImpl->mxFrame, *this ) );
1750 }
1751 
1752 // --------------------------------------------------------------------
1753 
IsInPopupMode()1754 bool ToolbarMenu::IsInPopupMode()
1755 {
1756     return GetDockingManager()->IsInPopupMode(this);
1757 }
1758 
1759 // --------------------------------------------------------------------
1760 
EndPopupMode()1761 void ToolbarMenu::EndPopupMode()
1762 {
1763     GetDockingManager()->EndPopupMode(this);
1764 }
1765 
1766 // --------------------------------------------------------------------
1767 
getMenuSize() const1768 const Size& ToolbarMenu::getMenuSize() const
1769 {
1770     return mpImpl->maSize;
1771 }
1772 
1773 // --------------------------------------------------------------------
1774 
SetSelectHdl(const Link & rLink)1775 void ToolbarMenu::SetSelectHdl( const Link& rLink )
1776 {
1777     mpImpl->maSelectHdl = rLink;
1778 }
1779 
1780 // --------------------------------------------------------------------
1781 
GetSelectHdl() const1782 const Link& ToolbarMenu::GetSelectHdl() const
1783 {
1784     return mpImpl->maSelectHdl;
1785 }
1786 
1787 // --------------------------------------------------------------------
1788 
GetFrame() const1789 Reference< XFrame > ToolbarMenu::GetFrame() const
1790 {
1791     return mpImpl->mxFrame;
1792 }
1793 
1794 // --------------------------------------------------------------------
1795 
1796 
1797 // --------------------------------------------------------------------
1798 
1799 }
1800 
1801 
1802