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