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