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