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 there 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