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 <sal/config.h>
21 
22 #include <o3tl/safeint.hxx>
23 #include <tools/debug.hxx>
24 #include <comphelper/base64.hxx>
25 #include <vcl/decoview.hxx>
26 #include <vcl/event.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/settings.hxx>
29 #include <vcl/virdev.hxx>
30 
31 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
32 #include <com/sun/star/lang/XComponent.hpp>
33 #include <rtl/ustring.hxx>
34 #include <sal/log.hxx>
35 #include "valueimp.hxx"
36 
37 #include <svtools/valueset.hxx>
38 
39 #include <uiobject.hxx>
40 #include <vcl/uitest/logger.hxx>
41 #include <vcl/uitest/eventdescription.hxx>
42 
43 using namespace css::uno;
44 using namespace css::lang;
45 using namespace css::accessibility;
46 
47 namespace
48 {
collectUIInformation(const OUString & aID,const OUString & aParentID,const OUString & aPos)49 void collectUIInformation( const OUString& aID , const OUString& aParentID , const OUString& aPos )
50 {
51     EventDescription aDescription;
52     aDescription.aID = aID ;
53     aDescription.aParameters = {{"POS", aPos }};
54     aDescription.aAction = "SELECT";
55     aDescription.aKeyWord = "ValueSet";
56     aDescription.aParent = aParentID;
57     UITestLogger::getInstance().logEvent(aDescription);
58 }
59 
60 enum
61 {
62     ITEM_OFFSET = 4,
63     ITEM_OFFSET_DOUBLE = 6,
64     NAME_LINE_OFF_X = 2,
65     NAME_LINE_OFF_Y = 2,
66     NAME_LINE_HEIGHT = 2,
67     NAME_OFFSET = 2,
68 };
69 
70 }
71 
ValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)72 ValueSet::ValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)
73     : maVirDev( VclPtr<VirtualDevice>::Create())
74     , mxScrolledWindow(std::move(pScrolledWindow))
75     , mnHighItemId(0)
76     , maColor(COL_TRANSPARENT)
77     , mnStyle(0)
78     , mbFormat(true)
79     , mbHighlight(false)
80 {
81     maVirDev->SetBackground(Application::GetSettings().GetStyleSettings().GetFaceColor());
82 
83     mnItemWidth         = 0;
84     mnItemHeight        = 0;
85     mnTextOffset        = 0;
86     mnVisLines          = 0;
87     mnLines             = 0;
88     mnUserItemWidth     = 0;
89     mnUserItemHeight    = 0;
90     mnFirstLine         = 0;
91     mnSelItemId         = 0;
92     mnSavedItemId       = -1;
93     mnCols              = 0;
94     mnCurCol            = 0;
95     mnUserCols          = 0;
96     mnUserVisLines      = 0;
97     mnSpacing           = 0;
98     mnFrameStyle        = DrawFrameStyle::NONE;
99     mbNoSelection       = true;
100     mbDrawSelection     = true;
101     mbBlackSel          = false;
102     mbDoubleSel         = false;
103     mbScroll            = false;
104     mbFullMode          = true;
105     mbEdgeBlending      = false;
106     mbHasVisibleItems   = false;
107 
108     if (mxScrolledWindow)
109         mxScrolledWindow->connect_vadjustment_changed(LINK(this, ValueSet, ImplScrollHdl));
110 }
111 
SetDrawingArea(weld::DrawingArea * pDrawingArea)112 void ValueSet::SetDrawingArea(weld::DrawingArea* pDrawingArea)
113 {
114     CustomWidgetController::SetDrawingArea(pDrawingArea);
115     // #106446#, #106601# force mirroring of virtual device
116     maVirDev->EnableRTL(pDrawingArea->get_direction());
117 }
118 
CreateAccessible()119 Reference<XAccessible> ValueSet::CreateAccessible()
120 {
121     if (!mxAccessible)
122         mxAccessible.set(new ValueSetAcc(this));
123     return mxAccessible;
124 }
125 
~ValueSet()126 ValueSet::~ValueSet()
127 {
128     Reference<XComponent> xComponent(mxAccessible, UNO_QUERY);
129     if (xComponent.is())
130         xComponent->dispose();
131 
132     ImplDeleteItems();
133 }
134 
ImplDeleteItems()135 void ValueSet::ImplDeleteItems()
136 {
137     const size_t n = mItemList.size();
138 
139     for ( size_t i = 0; i < n; ++i )
140     {
141         ValueSetItem* pItem = mItemList[i].get();
142         if ( pItem->mbVisible && ImplHasAccessibleListeners() )
143         {
144             Any aOldAny;
145             Any aNewAny;
146 
147             aOldAny <<= pItem->GetAccessible( false/*bIsTransientChildrenDisabled*/ );
148             ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny);
149         }
150 
151         mItemList[i].reset();
152     }
153 
154     mItemList.clear();
155 }
156 
Select()157 void ValueSet::Select()
158 {
159     collectUIInformation(OStringToOUString(GetDrawingArea()->get_buildable_name(),RTL_TEXTENCODING_UTF8) , OStringToOUString(GetDrawingArea()->get_help_id(),RTL_TEXTENCODING_UTF8) , OUString::number(GetSelectedItemId()));
160     maSelectHdl.Call( this );
161 }
162 
UserDraw(const UserDrawEvent &)163 void ValueSet::UserDraw( const UserDrawEvent& )
164 {
165 }
166 
ImplGetItem(const Point & rPos) const167 size_t ValueSet::ImplGetItem( const Point& rPos ) const
168 {
169     if (!mbHasVisibleItems)
170     {
171         return VALUESET_ITEM_NOTFOUND;
172     }
173 
174     if (mpNoneItem && maNoneItemRect.IsInside(rPos))
175     {
176         return VALUESET_ITEM_NONEITEM;
177     }
178 
179     if (maItemListRect.IsInside(rPos))
180     {
181         const int xc = rPos.X() - maItemListRect.Left();
182         const int yc = rPos.Y() - maItemListRect.Top();
183         // The point is inside the area of item list,
184         // let's find the containing item.
185         const int col = xc / (mnItemWidth + mnSpacing);
186         const int x = xc % (mnItemWidth + mnSpacing);
187         const int row = yc / (mnItemHeight + mnSpacing);
188         const int y = yc % (mnItemHeight + mnSpacing);
189 
190         if (x < mnItemWidth && y < mnItemHeight)
191         {
192             // the point is inside item rect and not inside spacing
193             const size_t item = (mnFirstLine + row) * static_cast<size_t>(mnCols) + col;
194             if (item < mItemList.size())
195             {
196                 return item;
197             }
198         }
199     }
200 
201     return VALUESET_ITEM_NOTFOUND;
202 }
203 
ImplGetItem(size_t nPos)204 ValueSetItem* ValueSet::ImplGetItem( size_t nPos )
205 {
206     if (nPos == VALUESET_ITEM_NONEITEM)
207         return mpNoneItem.get();
208     else
209         return (nPos < mItemList.size()) ? mItemList[nPos].get() : nullptr;
210 }
211 
ImplGetFirstItem()212 ValueSetItem* ValueSet::ImplGetFirstItem()
213 {
214     return !mItemList.empty() ? mItemList[0].get() : nullptr;
215 }
216 
ImplGetVisibleItemCount() const217 sal_uInt16 ValueSet::ImplGetVisibleItemCount() const
218 {
219     sal_uInt16 nRet = 0;
220     const size_t nItemCount = mItemList.size();
221 
222     for ( size_t n = 0; n < nItemCount; ++n )
223     {
224         if ( mItemList[n]->mbVisible )
225             ++nRet;
226     }
227 
228     return nRet;
229 }
230 
ImplFireAccessibleEvent(short nEventId,const Any & rOldValue,const Any & rNewValue)231 void ValueSet::ImplFireAccessibleEvent( short nEventId, const Any& rOldValue, const Any& rNewValue )
232 {
233     ValueSetAcc* pAcc = ValueSetAcc::getImplementation(mxAccessible);
234 
235     if( pAcc )
236         pAcc->FireAccessibleEvent( nEventId, rOldValue, rNewValue );
237 }
238 
ImplHasAccessibleListeners()239 bool ValueSet::ImplHasAccessibleListeners()
240 {
241     ValueSetAcc* pAcc = ValueSetAcc::getImplementation(mxAccessible);
242     return( pAcc && pAcc->HasAccessibleListeners() );
243 }
244 
IMPL_LINK(ValueSet,ImplScrollHdl,weld::ScrolledWindow &,rScrollWin,void)245 IMPL_LINK(ValueSet, ImplScrollHdl, weld::ScrolledWindow&, rScrollWin, void)
246 {
247     auto nNewFirstLine = rScrollWin.vadjustment_get_value();
248     if ( nNewFirstLine != mnFirstLine )
249     {
250         mnFirstLine = nNewFirstLine;
251         mbFormat = true;
252         Invalidate();
253     }
254 }
255 
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle &)256 void ValueSet::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
257 {
258     if (GetStyle() & WB_FLATVALUESET)
259     {
260         const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
261         rRenderContext.SetLineColor();
262         rRenderContext.SetFillColor(rStyleSettings.GetFaceColor());
263         tools::Long nOffY = maVirDev->GetOutputSizePixel().Height();
264         Size aWinSize(GetOutputSizePixel());
265         rRenderContext.DrawRect(tools::Rectangle(Point(0, nOffY ), Point( aWinSize.Width(), aWinSize.Height())));
266     }
267 
268     ImplDraw(rRenderContext);
269 }
270 
GetFocus()271 void ValueSet::GetFocus()
272 {
273     SAL_INFO("svtools", "value set getting focus");
274     Invalidate();
275     CustomWidgetController::GetFocus();
276 
277     // Tell the accessible object that we got the focus.
278     ValueSetAcc* pAcc = ValueSetAcc::getImplementation(mxAccessible);
279     if (pAcc)
280         pAcc->GetFocus();
281 }
282 
LoseFocus()283 void ValueSet::LoseFocus()
284 {
285     SAL_INFO("svtools", "value set losing focus");
286     Invalidate();
287     CustomWidgetController::LoseFocus();
288 
289     // Tell the accessible object that we lost the focus.
290     ValueSetAcc* pAcc = ValueSetAcc::getImplementation(mxAccessible);
291     if( pAcc )
292         pAcc->LoseFocus();
293 }
294 
Resize()295 void ValueSet::Resize()
296 {
297     mbFormat = true;
298     if ( IsReallyVisible() && IsUpdateMode() )
299         Invalidate();
300     CustomWidgetController::Resize();
301 }
302 
KeyInput(const KeyEvent & rKeyEvent)303 bool ValueSet::KeyInput( const KeyEvent& rKeyEvent )
304 {
305     size_t nLastItem = mItemList.size();
306 
307     if ( !nLastItem || !ImplGetFirstItem() )
308         return CustomWidgetController::KeyInput(rKeyEvent);
309 
310     if (mbFormat)
311         Invalidate();
312 
313     --nLastItem;
314 
315     const size_t nCurPos
316         = mnSelItemId ? GetItemPos(mnSelItemId) : (mpNoneItem ? VALUESET_ITEM_NONEITEM : 0);
317     size_t nItemPos = VALUESET_ITEM_NOTFOUND;
318     size_t nVStep = mnCols;
319 
320     switch (rKeyEvent.GetKeyCode().GetCode())
321     {
322         case KEY_HOME:
323             nItemPos = mpNoneItem ? VALUESET_ITEM_NONEITEM : 0;
324             break;
325 
326         case KEY_END:
327             nItemPos = nLastItem;
328             break;
329 
330         case KEY_LEFT:
331             if (nCurPos != VALUESET_ITEM_NONEITEM)
332             {
333                 if (nCurPos)
334                 {
335                     nItemPos = nCurPos-1;
336                 }
337                 else if (mpNoneItem)
338                 {
339                     nItemPos = VALUESET_ITEM_NONEITEM;
340                 }
341             }
342             break;
343 
344         case KEY_RIGHT:
345             if (nCurPos < nLastItem)
346             {
347                 if (nCurPos == VALUESET_ITEM_NONEITEM)
348                 {
349                     nItemPos = 0;
350                 }
351                 else
352                 {
353                     nItemPos = nCurPos+1;
354                 }
355             }
356             break;
357 
358         case KEY_PAGEUP:
359             if (rKeyEvent.GetKeyCode().IsShift() || rKeyEvent.GetKeyCode().IsMod1() || rKeyEvent.GetKeyCode().IsMod2())
360             {
361                 return CustomWidgetController::KeyInput(rKeyEvent);
362             }
363             nVStep *= mnVisLines;
364             [[fallthrough]];
365         case KEY_UP:
366             if (nCurPos != VALUESET_ITEM_NONEITEM)
367             {
368                 if (nCurPos == nLastItem)
369                 {
370                     const size_t nCol = mnCols ? nLastItem % mnCols : 0;
371                     if (nCol < mnCurCol)
372                     {
373                         // Move to previous row/page, keeping the old column
374                         nVStep -= mnCurCol - nCol;
375                     }
376                 }
377                 if (nCurPos >= nVStep)
378                 {
379                     // Go up of a whole page
380                     nItemPos = nCurPos-nVStep;
381                 }
382                 else if (mpNoneItem)
383                 {
384                     nItemPos = VALUESET_ITEM_NONEITEM;
385                 }
386                 else if (nCurPos > mnCols)
387                 {
388                     // Go to same column in first row
389                     nItemPos = nCurPos % mnCols;
390                 }
391             }
392             break;
393 
394         case KEY_PAGEDOWN:
395             if (rKeyEvent.GetKeyCode().IsShift() || rKeyEvent.GetKeyCode().IsMod1() || rKeyEvent.GetKeyCode().IsMod2())
396             {
397                 return CustomWidgetController::KeyInput(rKeyEvent);
398             }
399             nVStep *= mnVisLines;
400             [[fallthrough]];
401         case KEY_DOWN:
402             if (nCurPos != nLastItem)
403             {
404                 if (nCurPos == VALUESET_ITEM_NONEITEM)
405                 {
406                     nItemPos = nVStep-mnCols+mnCurCol;
407                 }
408                 else
409                 {
410                     nItemPos = nCurPos+nVStep;
411                 }
412                 if (nItemPos > nLastItem)
413                 {
414                     nItemPos = nLastItem;
415                 }
416             }
417             break;
418 
419         case KEY_RETURN:
420             if (GetStyle() & WB_NO_DIRECTSELECT)
421             {
422                 // tdf#142479 on return select the entry the cursor is in
423                 // before calling Select
424                 if (nCurPos != VALUESET_ITEM_NONEITEM)
425                 {
426                     const sal_uInt16 nItemId = GetItemId(nCurPos);
427                     if (nItemId != mnSelItemId)
428                         SelectItem(nItemId);
429                 }
430                 Select();
431                 break;
432             }
433             [[fallthrough]];
434         default:
435             return CustomWidgetController::KeyInput(rKeyEvent);
436     }
437 
438     if ( nItemPos == VALUESET_ITEM_NOTFOUND )
439         return true;
440 
441     if ( nItemPos!=VALUESET_ITEM_NONEITEM && nItemPos<nLastItem )
442     {
443         // update current column only in case of a new position
444         // which is also not a "specially" handled one.
445         mnCurCol = mnCols ? nItemPos % mnCols : 0;
446     }
447     const sal_uInt16 nItemId = (nItemPos != VALUESET_ITEM_NONEITEM) ? GetItemId( nItemPos ) : 0;
448     if ( nItemId != mnSelItemId )
449     {
450         SelectItem( nItemId );
451         if (!(GetStyle() & WB_NO_DIRECTSELECT))
452         {
453             // select only if WB_NO_DIRECTSELECT is not set
454             Select();
455         }
456     }
457 
458     return true;
459 }
460 
ImplTracking(const Point & rPos)461 void ValueSet::ImplTracking(const Point& rPos)
462 {
463     ValueSetItem* pItem = ImplGetItem( ImplGetItem( rPos ) );
464     if ( pItem )
465     {
466         if( GetStyle() & WB_MENUSTYLEVALUESET || GetStyle() & WB_FLATVALUESET )
467             mbHighlight = true;
468 
469         ImplHighlightItem( pItem->mnId );
470     }
471     else
472     {
473         if( GetStyle() & WB_MENUSTYLEVALUESET || GetStyle() & WB_FLATVALUESET )
474             mbHighlight = true;
475 
476         ImplHighlightItem( mnSelItemId, false );
477     }
478 }
479 
MouseButtonDown(const MouseEvent & rMouseEvent)480 bool ValueSet::MouseButtonDown( const MouseEvent& rMouseEvent )
481 {
482     if ( rMouseEvent.IsLeft() )
483     {
484         ValueSetItem* pItem = ImplGetItem( ImplGetItem( rMouseEvent.GetPosPixel() ) );
485         if (pItem && !rMouseEvent.IsMod2())
486         {
487             if (rMouseEvent.GetClicks() == 1)
488             {
489                 SelectItem( pItem->mnId );
490                 if (!(GetStyle() & WB_NOPOINTERFOCUS))
491                     GrabFocus();
492             }
493             else if ( rMouseEvent.GetClicks() == 2 )
494                 maDoubleClickHdl.Call( this );
495 
496             return true;
497         }
498     }
499 
500     return CustomWidgetController::MouseButtonDown( rMouseEvent );
501 }
502 
MouseButtonUp(const MouseEvent & rMouseEvent)503 bool ValueSet::MouseButtonUp( const MouseEvent& rMouseEvent )
504 {
505     if (rMouseEvent.IsLeft() && !rMouseEvent.IsMod2())
506     {
507         // tdf#142150 MouseUp seen without previous MouseDown
508         if (mnSelItemId)
509             Select();
510         return true;
511     }
512 
513     return CustomWidgetController::MouseButtonUp( rMouseEvent );
514 }
515 
MouseMove(const MouseEvent & rMouseEvent)516 bool ValueSet::MouseMove(const MouseEvent& rMouseEvent)
517 {
518     // because of SelectionMode
519     if ((GetStyle() & WB_MENUSTYLEVALUESET) || (GetStyle() & WB_FLATVALUESET))
520         ImplTracking(rMouseEvent.GetPosPixel());
521     return CustomWidgetController::MouseMove(rMouseEvent);
522 }
523 
QueueReformat()524 void ValueSet::QueueReformat()
525 {
526     queue_resize();
527     RecalcScrollBar();
528     mbFormat = true;
529     if ( IsReallyVisible() && IsUpdateMode() )
530         Invalidate();
531 }
532 
RemoveItem(sal_uInt16 nItemId)533 void ValueSet::RemoveItem( sal_uInt16 nItemId )
534 {
535     size_t nPos = GetItemPos( nItemId );
536 
537     if ( nPos == VALUESET_ITEM_NOTFOUND )
538         return;
539 
540     if ( nPos < mItemList.size() ) {
541         mItemList.erase( mItemList.begin() + nPos );
542     }
543 
544     // reset variables
545     if (mnHighItemId == nItemId || mnSelItemId == nItemId)
546     {
547         mnCurCol        = 0;
548         mnHighItemId    = 0;
549         mnSelItemId     = 0;
550         mbNoSelection   = true;
551     }
552 
553     QueueReformat();
554 }
555 
TurnOffScrollBar()556 bool ValueSet::TurnOffScrollBar()
557 {
558     if (mxScrolledWindow->get_vpolicy() == VclPolicyType::NEVER)
559         return false;
560     mxScrolledWindow->set_vpolicy(VclPolicyType::NEVER);
561     weld::DrawingArea* pDrawingArea = GetDrawingArea();
562     Size aPrefSize(pDrawingArea->get_preferred_size());
563     pDrawingArea->set_size_request(aPrefSize.Width() + GetScrollWidth(), aPrefSize.Height());
564     return true;
565 }
566 
TurnOnScrollBar()567 void ValueSet::TurnOnScrollBar()
568 {
569     if (mxScrolledWindow->get_vpolicy() == VclPolicyType::ALWAYS)
570         return;
571     mxScrolledWindow->set_vpolicy(VclPolicyType::ALWAYS);
572     weld::DrawingArea* pDrawingArea = GetDrawingArea();
573     Size aPrefSize(pDrawingArea->get_preferred_size());
574     pDrawingArea->set_size_request(aPrefSize.Width() - GetScrollWidth(), aPrefSize.Height());
575 }
576 
RecalcScrollBar()577 void ValueSet::RecalcScrollBar()
578 {
579     if (!mxScrolledWindow)
580         return;
581     const bool bScrollAllowed = GetStyle() & WB_VSCROLL;
582     if (!bScrollAllowed)
583         return;
584     // reset scrolled window state to initial value so it will get configured
585     // to the right adjustment on the next format which we toggle on to happen
586     // if the scrolledwindow wasn't in its initial state already
587     if (TurnOffScrollBar())
588         mbFormat = true;
589 }
590 
Clear()591 void ValueSet::Clear()
592 {
593     ImplDeleteItems();
594 
595     // reset variables
596     mnFirstLine     = 0;
597     mnCurCol        = 0;
598     mnHighItemId    = 0;
599     mnSelItemId     = 0;
600     mbNoSelection   = true;
601 
602     RecalcScrollBar();
603 
604     mbFormat = true;
605     if ( IsReallyVisible() && IsUpdateMode() )
606         Invalidate();
607 }
608 
GetItemCount() const609 size_t ValueSet::GetItemCount() const
610 {
611     return mItemList.size();
612 }
613 
GetItemPos(sal_uInt16 nItemId) const614 size_t ValueSet::GetItemPos( sal_uInt16 nItemId ) const
615 {
616     for ( size_t i = 0, n = mItemList.size(); i < n; ++i ) {
617         if ( mItemList[i]->mnId == nItemId ) {
618             return i;
619         }
620     }
621     return VALUESET_ITEM_NOTFOUND;
622 }
623 
GetItemId(size_t nPos) const624 sal_uInt16 ValueSet::GetItemId( size_t nPos ) const
625 {
626     return ( nPos < mItemList.size() ) ? mItemList[nPos]->mnId : 0 ;
627 }
628 
GetItemId(const Point & rPos) const629 sal_uInt16 ValueSet::GetItemId( const Point& rPos ) const
630 {
631     size_t nItemPos = ImplGetItem( rPos );
632     if ( nItemPos != VALUESET_ITEM_NOTFOUND )
633         return GetItemId( nItemPos );
634 
635     return 0;
636 }
637 
GetItemRect(sal_uInt16 nItemId) const638 tools::Rectangle ValueSet::GetItemRect( sal_uInt16 nItemId ) const
639 {
640     const size_t nPos = GetItemPos( nItemId );
641 
642     if ( nPos!=VALUESET_ITEM_NOTFOUND && mItemList[nPos]->mbVisible )
643         return ImplGetItemRect( nPos );
644 
645     return tools::Rectangle();
646 }
647 
ImplGetItemRect(size_t nPos) const648 tools::Rectangle ValueSet::ImplGetItemRect( size_t nPos ) const
649 {
650     const size_t nVisibleBegin = static_cast<size_t>(mnFirstLine)*mnCols;
651     const size_t nVisibleEnd = nVisibleBegin + static_cast<size_t>(mnVisLines)*mnCols;
652 
653     // Check if the item is inside the range of the displayed ones,
654     // taking into account that last row could be incomplete
655     if ( nPos<nVisibleBegin || nPos>=nVisibleEnd || nPos>=mItemList.size() )
656         return tools::Rectangle();
657 
658     nPos -= nVisibleBegin;
659 
660     const size_t row = mnCols ? nPos/mnCols : 0;
661     const size_t col = mnCols ? nPos%mnCols : 0;
662     const tools::Long x = maItemListRect.Left()+col*(mnItemWidth+mnSpacing);
663     const tools::Long y = maItemListRect.Top()+row*(mnItemHeight+mnSpacing);
664 
665     return tools::Rectangle( Point(x, y), Size(mnItemWidth, mnItemHeight) );
666 }
667 
ImplHighlightItem(sal_uInt16 nItemId,bool bIsSelection)668 void ValueSet::ImplHighlightItem( sal_uInt16 nItemId, bool bIsSelection )
669 {
670     if ( mnHighItemId == nItemId )
671         return;
672 
673     // remember the old item to delete the previous selection
674     mnHighItemId = nItemId;
675 
676     // don't draw the selection if nothing is selected
677     if ( !bIsSelection && mbNoSelection )
678         mbDrawSelection = false;
679 
680     // remove the old selection and draw the new one
681     Invalidate();
682     mbDrawSelection = true;
683 }
684 
ImplDraw(vcl::RenderContext & rRenderContext)685 void ValueSet::ImplDraw(vcl::RenderContext& rRenderContext)
686 {
687     if (mbFormat)
688         Format(rRenderContext);
689 
690     Point aDefPos;
691     Size aSize = maVirDev->GetOutputSizePixel();
692 
693     rRenderContext.DrawOutDev(aDefPos, aSize, aDefPos, aSize, *maVirDev);
694 
695     // draw parting line to the Namefield
696     if (GetStyle() & WB_NAMEFIELD)
697     {
698         if (!(GetStyle() & WB_FLATVALUESET))
699         {
700             const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
701             Size aWinSize(GetOutputSizePixel());
702             Point aPos1(NAME_LINE_OFF_X, mnTextOffset + NAME_LINE_OFF_Y);
703             Point aPos2(aWinSize.Width() - (NAME_LINE_OFF_X * 2), mnTextOffset + NAME_LINE_OFF_Y);
704             if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
705             {
706                 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
707                 rRenderContext.DrawLine(aPos1, aPos2);
708                 aPos1.AdjustY( 1 );
709                 aPos2.AdjustY( 1 );
710                 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
711             }
712             else
713                 rRenderContext.SetLineColor(rStyleSettings.GetWindowTextColor());
714             rRenderContext.DrawLine(aPos1, aPos2);
715         }
716     }
717 
718     ImplDrawSelect(rRenderContext);
719 }
720 
721 /**
722  * An inelegant method; sets the item width & height such that
723  * all of the included items and their labels fit; if we can
724  * calculate that.
725  */
RecalculateItemSizes()726 void ValueSet::RecalculateItemSizes()
727 {
728     Size aLargestItem = GetLargestItemSize();
729 
730     if ( mnUserItemWidth != aLargestItem.Width() ||
731          mnUserItemHeight != aLargestItem.Height() )
732     {
733         mnUserItemWidth = aLargestItem.Width();
734         mnUserItemHeight = aLargestItem.Height();
735         QueueReformat();
736     }
737 }
738 
SetFirstLine(sal_uInt16 nNewFirstLine)739 void ValueSet::SetFirstLine(sal_uInt16 nNewFirstLine)
740 {
741     if (nNewFirstLine != mnFirstLine)
742     {
743         mnFirstLine = nNewFirstLine;
744         if (mxScrolledWindow)
745             mxScrolledWindow->vadjustment_set_value(mnFirstLine);
746     }
747 }
748 
SelectItem(sal_uInt16 nItemId)749 void ValueSet::SelectItem( sal_uInt16 nItemId )
750 {
751     size_t nItemPos = 0;
752 
753     if ( nItemId )
754     {
755         nItemPos = GetItemPos( nItemId );
756         if ( nItemPos == VALUESET_ITEM_NOTFOUND )
757             return;
758     }
759 
760     if ( !((mnSelItemId != nItemId) || mbNoSelection) )
761         return;
762 
763     const sal_uInt16 nOldItem = mnSelItemId;
764     mnSelItemId = nItemId;
765     mbNoSelection = false;
766 
767     bool bNewOut = !mbFormat && IsReallyVisible() && IsUpdateMode();
768     bool bNewLine = false;
769 
770     if (weld::DrawingArea* pNeedsFormatToScroll = !mnCols ? GetDrawingArea() : nullptr)
771     {
772         Format(pNeedsFormatToScroll->get_ref_device());
773         // reset scrollbar so its set to the later calculated mnFirstLine on
774         // the next Format
775         RecalcScrollBar(); // reset scrollbar so its set to the later calculated
776     }
777 
778     // if necessary scroll to the visible area
779     if (mbScroll && nItemId && mnCols)
780     {
781         sal_uInt16 nNewLine = static_cast<sal_uInt16>(nItemPos / mnCols);
782         if ( nNewLine < mnFirstLine )
783         {
784             SetFirstLine(nNewLine);
785             bNewLine = true;
786         }
787         else if ( nNewLine > o3tl::make_unsigned(mnFirstLine+mnVisLines-1) )
788         {
789             SetFirstLine(static_cast<sal_uInt16>(nNewLine-mnVisLines+1));
790             bNewLine = true;
791         }
792     }
793 
794     if ( bNewOut )
795     {
796         if ( bNewLine )
797         {
798             // redraw everything if the visible area has changed
799             mbFormat = true;
800         }
801         Invalidate();
802     }
803 
804     if( !ImplHasAccessibleListeners() )
805         return;
806 
807     // focus event (deselect)
808     if( nOldItem )
809     {
810         const size_t nPos = GetItemPos( nItemId );
811 
812         if( nPos != VALUESET_ITEM_NOTFOUND )
813         {
814             ValueItemAcc* pItemAcc = ValueItemAcc::getImplementation(
815                 mItemList[nPos]->GetAccessible( false/*bIsTransientChildrenDisabled*/ ) );
816 
817             if( pItemAcc )
818             {
819                 Any aOldAny;
820                 Any aNewAny;
821                 aOldAny <<= Reference<XInterface>(static_cast<cppu::OWeakObject*>(pItemAcc));
822                 ImplFireAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny );
823             }
824         }
825     }
826 
827     // focus event (select)
828     const size_t nPos = GetItemPos( mnSelItemId );
829 
830     ValueSetItem* pItem;
831     if( nPos != VALUESET_ITEM_NOTFOUND )
832         pItem = mItemList[nPos].get();
833     else
834         pItem = mpNoneItem.get();
835 
836     ValueItemAcc* pItemAcc = nullptr;
837     if (pItem != nullptr)
838         pItemAcc = ValueItemAcc::getImplementation( pItem->GetAccessible( false/*bIsTransientChildrenDisabled*/ ) );
839 
840     if( pItemAcc )
841     {
842         Any aOldAny;
843         Any aNewAny;
844         aNewAny <<= Reference<XInterface>(static_cast<cppu::OWeakObject*>(pItemAcc));
845         ImplFireAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny);
846     }
847 
848     // selection event
849     Any aOldAny;
850     Any aNewAny;
851     ImplFireAccessibleEvent(AccessibleEventId::SELECTION_CHANGED, aOldAny, aNewAny);
852 }
853 
SetNoSelection()854 void ValueSet::SetNoSelection()
855 {
856     mbNoSelection   = true;
857     mbHighlight     = false;
858 
859     if (IsReallyVisible() && IsUpdateMode())
860         Invalidate();
861 }
862 
SetStyle(WinBits nStyle)863 void ValueSet::SetStyle(WinBits nStyle)
864 {
865     if (nStyle != mnStyle)
866     {
867         mnStyle = nStyle;
868         mbFormat = true;
869         Invalidate();
870     }
871 }
872 
Format(vcl::RenderContext const & rRenderContext)873 void ValueSet::Format(vcl::RenderContext const & rRenderContext)
874 {
875     Size aWinSize(GetOutputSizePixel());
876     size_t nItemCount = mItemList.size();
877     WinBits nStyle = GetStyle();
878     tools::Long nTxtHeight = rRenderContext.GetTextHeight();
879     tools::Long nOff;
880     tools::Long nNoneHeight;
881     tools::Long nNoneSpace;
882 
883     if (mxScrolledWindow && !(nStyle & WB_VSCROLL) && mxScrolledWindow->get_vpolicy() != VclPolicyType::NEVER)
884         TurnOffScrollBar();
885 
886     // calculate item offset
887     if (nStyle & WB_ITEMBORDER)
888     {
889         if (nStyle & WB_DOUBLEBORDER)
890             nOff = ITEM_OFFSET_DOUBLE;
891         else
892             nOff = ITEM_OFFSET;
893     }
894     else
895         nOff = 0;
896 
897     // consider size, if NameField does exist
898     if (nStyle & WB_NAMEFIELD)
899     {
900         mnTextOffset = aWinSize.Height() - nTxtHeight - NAME_OFFSET;
901         aWinSize.AdjustHeight( -(nTxtHeight + NAME_OFFSET) );
902 
903         if (!(nStyle & WB_FLATVALUESET))
904         {
905             mnTextOffset -= NAME_LINE_HEIGHT + NAME_LINE_OFF_Y;
906             aWinSize.AdjustHeight( -(NAME_LINE_HEIGHT + NAME_LINE_OFF_Y) );
907         }
908     }
909     else
910         mnTextOffset = 0;
911 
912     // consider offset and size, if NoneField does exist
913     if (nStyle & WB_NONEFIELD)
914     {
915         nNoneHeight = nTxtHeight + nOff;
916         nNoneSpace = mnSpacing;
917     }
918     else
919     {
920         nNoneHeight = 0;
921         nNoneSpace = 0;
922         mpNoneItem.reset();
923     }
924 
925     // calculate number of columns
926     if (!mnUserCols)
927     {
928         if (mnUserItemWidth)
929         {
930             mnCols = static_cast<sal_uInt16>((aWinSize.Width() - mnSpacing) / (mnUserItemWidth + mnSpacing));
931             if (mnCols <= 0)
932                 mnCols = 1;
933         }
934         else
935         {
936             mnCols = 1;
937         }
938     }
939     else
940     {
941         mnCols = mnUserCols;
942     }
943 
944     // calculate number of rows
945     mbScroll = false;
946 
947     auto nOldLines = mnLines;
948     // Floor( (M+N-1)/N )==Ceiling( M/N )
949     mnLines = (static_cast<tools::Long>(nItemCount) + mnCols - 1) / mnCols;
950     if (mnLines <= 0)
951         mnLines = 1;
952 
953     bool bAdjustmentOutOfDate = nOldLines != mnLines;
954 
955     auto nOldVisLines = mnVisLines;
956 
957     tools::Long nCalcHeight = aWinSize.Height() - nNoneHeight;
958     if (mnUserVisLines)
959     {
960         mnVisLines = mnUserVisLines;
961     }
962     else if (mnUserItemHeight)
963     {
964         mnVisLines = (nCalcHeight - nNoneSpace + mnSpacing) / (mnUserItemHeight + mnSpacing);
965         if (!mnVisLines)
966             mnVisLines = 1;
967     }
968     else
969     {
970         mnVisLines = mnLines;
971     }
972 
973     bAdjustmentOutOfDate |= nOldVisLines != mnVisLines;
974 
975     if (mnLines > mnVisLines)
976         mbScroll = true;
977 
978     if (mnLines <= mnVisLines)
979     {
980         SetFirstLine(0);
981     }
982     else
983     {
984         if (mnFirstLine > o3tl::make_unsigned(mnLines - mnVisLines))
985             SetFirstLine(static_cast<sal_uInt16>(mnLines - mnVisLines));
986     }
987 
988     // calculate item size
989     const tools::Long nColSpace  = (mnCols - 1) * static_cast<tools::Long>(mnSpacing);
990     const tools::Long nLineSpace = ((mnVisLines - 1) * mnSpacing) + nNoneSpace;
991     if (mnUserItemWidth && !mnUserCols)
992     {
993         mnItemWidth = mnUserItemWidth;
994         if (mnItemWidth > aWinSize.Width() - nColSpace)
995             mnItemWidth = aWinSize.Width() - nColSpace;
996     }
997     else
998         mnItemWidth = (aWinSize.Width() - nColSpace) / mnCols;
999     if (mnUserItemHeight && !mnUserVisLines)
1000     {
1001         mnItemHeight = mnUserItemHeight;
1002         if (mnItemHeight > nCalcHeight - nNoneSpace)
1003             mnItemHeight = nCalcHeight - nNoneSpace;
1004     }
1005     else
1006     {
1007         nCalcHeight -= nLineSpace;
1008         mnItemHeight = nCalcHeight / mnVisLines;
1009     }
1010 
1011     // Init VirDev
1012     maVirDev->SetSettings(rRenderContext.GetSettings());
1013     maVirDev->SetOutputSizePixel(aWinSize);
1014 
1015     // nothing is changed in case of too small items
1016     if ((mnItemWidth <= 0) ||
1017         (mnItemHeight <= ((nStyle & WB_ITEMBORDER) ? 4 : 2)) ||
1018         !nItemCount)
1019     {
1020         mbHasVisibleItems = false;
1021 
1022         if ((nStyle & WB_NONEFIELD) && mpNoneItem)
1023         {
1024             mpNoneItem->mbVisible = false;
1025             mpNoneItem->maText = GetText();
1026         }
1027 
1028         for (size_t i = 0; i < nItemCount; i++)
1029         {
1030             mItemList[i]->mbVisible = false;
1031         }
1032 
1033         if (mxScrolledWindow && mxScrolledWindow->get_vpolicy() != VclPolicyType::NEVER)
1034             TurnOffScrollBar();
1035     }
1036     else
1037     {
1038         mbHasVisibleItems = true;
1039 
1040         // determine Frame-Style
1041         if (nStyle & WB_DOUBLEBORDER)
1042             mnFrameStyle = DrawFrameStyle::DoubleIn;
1043         else
1044             mnFrameStyle = DrawFrameStyle::In;
1045 
1046         // determine selected color and width
1047         // if necessary change the colors, to make the selection
1048         // better detectable
1049         const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1050         Color aHighColor(rStyleSettings.GetHighlightColor());
1051         if (((aHighColor.GetRed() > 0x80) || (aHighColor.GetGreen() > 0x80) ||
1052              (aHighColor.GetBlue() > 0x80)) ||
1053             ((aHighColor.GetRed() == 0x80) && (aHighColor.GetGreen() == 0x80) &&
1054              (aHighColor.GetBlue() == 0x80)))
1055         {
1056             mbBlackSel = true;
1057         }
1058         else
1059         {
1060             mbBlackSel = false;
1061         }
1062         // draw the selection with double width if the items are bigger
1063         if ((nStyle & WB_DOUBLEBORDER) &&
1064             ((mnItemWidth >= 25) && (mnItemHeight >= 20)))
1065         {
1066             mbDoubleSel = true;
1067         }
1068         else
1069         {
1070             mbDoubleSel = false;
1071         }
1072 
1073         // calculate offsets
1074         tools::Long nStartX;
1075         tools::Long nStartY;
1076         if (mbFullMode)
1077         {
1078             tools::Long nAllItemWidth = (mnItemWidth * mnCols) + nColSpace;
1079             tools::Long nAllItemHeight = (mnItemHeight * mnVisLines) + nNoneHeight + nLineSpace;
1080             nStartX = (aWinSize.Width() - nAllItemWidth) / 2;
1081             nStartY = (aWinSize.Height() - nAllItemHeight) / 2;
1082         }
1083         else
1084         {
1085             nStartX = 0;
1086             nStartY = 0;
1087         }
1088 
1089         // calculate and draw items
1090         maVirDev->SetLineColor();
1091         tools::Long x = nStartX;
1092         tools::Long y = nStartY;
1093 
1094         // create NoSelection field and show it
1095         if (nStyle & WB_NONEFIELD)
1096         {
1097             if (!mpNoneItem)
1098                 mpNoneItem.reset(new ValueSetItem(*this));
1099 
1100             mpNoneItem->mnId = 0;
1101             mpNoneItem->meType = VALUESETITEM_NONE;
1102             mpNoneItem->mbVisible = true;
1103             maNoneItemRect.SetLeft( x );
1104             maNoneItemRect.SetTop( y );
1105             maNoneItemRect.SetRight( maNoneItemRect.Left() + aWinSize.Width() - x - 1 );
1106             maNoneItemRect.SetBottom( y + nNoneHeight - 1 );
1107 
1108             ImplFormatItem(rRenderContext, mpNoneItem.get(), maNoneItemRect);
1109 
1110             y += nNoneHeight + nNoneSpace;
1111         }
1112 
1113         // draw items
1114         sal_uLong nFirstItem = static_cast<sal_uLong>(mnFirstLine) * mnCols;
1115         sal_uLong nLastItem = nFirstItem + (mnVisLines * mnCols);
1116 
1117         maItemListRect.SetLeft( x );
1118         maItemListRect.SetTop( y );
1119         maItemListRect.SetRight( x + mnCols * (mnItemWidth + mnSpacing) - mnSpacing - 1 );
1120         maItemListRect.SetBottom( y + mnVisLines * (mnItemHeight + mnSpacing) - mnSpacing - 1 );
1121 
1122         if (!mbFullMode)
1123         {
1124             // If want also draw parts of items in the last line,
1125             // then we add one more line if parts of these line are
1126             // visible
1127             if (y + (mnVisLines * (mnItemHeight + mnSpacing)) < aWinSize.Height())
1128                 nLastItem += mnCols;
1129             maItemListRect.SetBottom( aWinSize.Height() - y );
1130         }
1131         for (size_t i = 0; i < nItemCount; i++)
1132         {
1133             ValueSetItem* pItem = mItemList[i].get();
1134 
1135             if (i >= nFirstItem && i < nLastItem)
1136             {
1137                 if (!pItem->mbVisible && ImplHasAccessibleListeners())
1138                 {
1139                     Any aOldAny;
1140                     Any aNewAny;
1141 
1142                     aNewAny <<= pItem->GetAccessible(false/*bIsTransientChildrenDisabled*/);
1143                     ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny);
1144                 }
1145 
1146                 pItem->mbVisible = true;
1147                 ImplFormatItem(rRenderContext, pItem, tools::Rectangle(Point(x, y), Size(mnItemWidth, mnItemHeight)));
1148 
1149                 if (!((i + 1) % mnCols))
1150                 {
1151                     x = nStartX;
1152                     y += mnItemHeight + mnSpacing;
1153                 }
1154                 else
1155                     x += mnItemWidth + mnSpacing;
1156             }
1157             else
1158             {
1159                 if (pItem->mbVisible && ImplHasAccessibleListeners())
1160                 {
1161                     Any aOldAny;
1162                     Any aNewAny;
1163 
1164                     aOldAny <<= pItem->GetAccessible(false/*bIsTransientChildrenDisabled*/);
1165                     ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny);
1166                 }
1167 
1168                 pItem->mbVisible = false;
1169             }
1170         }
1171 
1172         // arrange ScrollBar, set values and show it
1173         if (mxScrolledWindow && (nStyle & WB_VSCROLL))
1174         {
1175             bool bTurnScrollbarOn = mxScrolledWindow->get_vpolicy() != VclPolicyType::ALWAYS;
1176             if (bAdjustmentOutOfDate || bTurnScrollbarOn)
1177             {
1178                 tools::Long nPageSize = mnVisLines;
1179                 if (nPageSize < 1)
1180                     nPageSize = 1;
1181                 mxScrolledWindow->vadjustment_configure(mnFirstLine, 0, mnLines, 1,
1182                                                         mnVisLines, nPageSize);
1183             }
1184 
1185             if (bTurnScrollbarOn)
1186                 TurnOnScrollBar();
1187         }
1188     }
1189 
1190     // waiting for the next since the formatting is finished
1191     mbFormat = false;
1192 }
1193 
ImplDrawSelect(vcl::RenderContext & rRenderContext)1194 void ValueSet::ImplDrawSelect(vcl::RenderContext& rRenderContext)
1195 {
1196     if (!IsReallyVisible())
1197         return;
1198 
1199     const bool bFocus = HasFocus();
1200     const bool bDrawSel = !((mbNoSelection && !mbHighlight) || (!mbDrawSelection && mbHighlight));
1201 
1202     if (!bFocus && !bDrawSel)
1203     {
1204         ImplDrawItemText(rRenderContext, OUString());
1205         return;
1206     }
1207 
1208     ImplDrawSelect(rRenderContext, mnSelItemId, bFocus, bDrawSel);
1209     if (mbHighlight)
1210     {
1211         ImplDrawSelect(rRenderContext, mnHighItemId, bFocus, bDrawSel);
1212     }
1213 }
1214 
ImplDrawSelect(vcl::RenderContext & rRenderContext,sal_uInt16 nItemId,const bool bFocus,const bool bDrawSel)1215 void ValueSet::ImplDrawSelect(vcl::RenderContext& rRenderContext, sal_uInt16 nItemId, const bool bFocus, const bool bDrawSel )
1216 {
1217     ValueSetItem* pItem;
1218     tools::Rectangle aRect;
1219     if (nItemId)
1220     {
1221         const size_t nPos = GetItemPos( nItemId );
1222         pItem = mItemList[ nPos ].get();
1223         aRect = ImplGetItemRect( nPos );
1224     }
1225     else if (mpNoneItem)
1226     {
1227         pItem = mpNoneItem.get();
1228         aRect = maNoneItemRect;
1229     }
1230     else if (bFocus && (pItem = ImplGetFirstItem()))
1231     {
1232         aRect = ImplGetItemRect(0);
1233     }
1234     else
1235     {
1236         return;
1237     }
1238 
1239     if (!pItem->mbVisible)
1240         return;
1241 
1242     // draw selection
1243     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1244     rRenderContext.SetFillColor();
1245 
1246     Color aDoubleColor(rStyleSettings.GetHighlightColor());
1247     Color aSingleColor(rStyleSettings.GetHighlightTextColor());
1248     if (!mbDoubleSel)
1249     {
1250         /*
1251         *  #99777# contrast enhancement for thin mode
1252         */
1253         const Wallpaper& rWall = maVirDev->GetBackground();
1254         if (!rWall.IsBitmap() && ! rWall.IsGradient())
1255         {
1256             const Color& rBack = rWall.GetColor();
1257             if (rBack.IsDark() && ! aDoubleColor.IsBright())
1258             {
1259                 aDoubleColor = COL_WHITE;
1260                 aSingleColor = COL_BLACK;
1261             }
1262             else if (rBack.IsBright() && !aDoubleColor.IsDark())
1263             {
1264                 aDoubleColor = COL_BLACK;
1265                 aSingleColor = COL_WHITE;
1266             }
1267         }
1268     }
1269 
1270     // specify selection output
1271     WinBits nStyle = GetStyle();
1272     if (nStyle & WB_MENUSTYLEVALUESET)
1273     {
1274         if (bFocus)
1275             InvertFocusRect(rRenderContext, aRect);
1276         if (bDrawSel)
1277         {
1278             rRenderContext.SetLineColor(mbBlackSel ? COL_BLACK : aDoubleColor);
1279             rRenderContext.DrawRect(aRect);
1280         }
1281     }
1282     else
1283     {
1284         if (bDrawSel)
1285         {
1286             rRenderContext.SetLineColor(mbBlackSel ? COL_BLACK : aDoubleColor);
1287             rRenderContext.DrawRect(aRect);
1288         }
1289         if (mbDoubleSel)
1290         {
1291             aRect.AdjustLeft( 1 );
1292             aRect.AdjustTop( 1 );
1293             aRect.AdjustRight( -1 );
1294             aRect.AdjustBottom( -1 );
1295             if (bDrawSel)
1296                 rRenderContext.DrawRect(aRect);
1297         }
1298         aRect.AdjustLeft( 1 );
1299         aRect.AdjustTop( 1 );
1300         aRect.AdjustRight( -1 );
1301         aRect.AdjustBottom( -1 );
1302         tools::Rectangle aRect2 = aRect;
1303         aRect.AdjustLeft( 1 );
1304         aRect.AdjustTop( 1 );
1305         aRect.AdjustRight( -1 );
1306         aRect.AdjustBottom( -1 );
1307         if (bDrawSel)
1308             rRenderContext.DrawRect(aRect);
1309         if (mbDoubleSel)
1310         {
1311             aRect.AdjustLeft( 1 );
1312             aRect.AdjustTop( 1 );
1313             aRect.AdjustRight( -1 );
1314             aRect.AdjustBottom( -1 );
1315             if (bDrawSel)
1316                 rRenderContext.DrawRect(aRect);
1317         }
1318 
1319         if (bDrawSel)
1320         {
1321             rRenderContext.SetLineColor(mbBlackSel ? COL_WHITE : aSingleColor);
1322         }
1323         else
1324         {
1325             rRenderContext.SetLineColor(COL_LIGHTGRAY);
1326         }
1327         rRenderContext.DrawRect(aRect2);
1328         if (bFocus)
1329             InvertFocusRect(rRenderContext, aRect2);
1330     }
1331 
1332     ImplDrawItemText(rRenderContext, pItem->maText);
1333 }
1334 
ImplFormatItem(vcl::RenderContext const & rRenderContext,ValueSetItem * pItem,tools::Rectangle aRect)1335 void ValueSet::ImplFormatItem(vcl::RenderContext const & rRenderContext, ValueSetItem* pItem, tools::Rectangle aRect)
1336 {
1337     WinBits nStyle = GetStyle();
1338     if (nStyle & WB_ITEMBORDER)
1339     {
1340         aRect.AdjustLeft(1 );
1341         aRect.AdjustTop(1 );
1342         aRect.AdjustRight( -1 );
1343         aRect.AdjustBottom( -1 );
1344 
1345         if (nStyle & WB_FLATVALUESET)
1346         {
1347             sal_Int32 nBorder = (nStyle & WB_DOUBLEBORDER) ? 2 : 1;
1348 
1349             aRect.AdjustLeft(nBorder );
1350             aRect.AdjustTop(nBorder );
1351             aRect.AdjustRight( -nBorder );
1352             aRect.AdjustBottom( -nBorder );
1353         }
1354         else
1355         {
1356             DecorationView aView(maVirDev.get());
1357             aRect = aView.DrawFrame(aRect, mnFrameStyle);
1358         }
1359     }
1360 
1361     if (pItem == mpNoneItem.get())
1362         pItem->maText = GetText();
1363 
1364     if ((aRect.GetHeight() <= 0) || (aRect.GetWidth() <= 0))
1365         return;
1366 
1367     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1368 
1369     if (pItem == mpNoneItem.get())
1370     {
1371         maVirDev->SetFont(rRenderContext.GetFont());
1372         maVirDev->SetTextColor((nStyle & WB_MENUSTYLEVALUESET) ? rStyleSettings.GetMenuTextColor() : rStyleSettings.GetWindowTextColor());
1373         maVirDev->SetTextFillColor();
1374         maVirDev->SetFillColor((nStyle & WB_MENUSTYLEVALUESET) ? rStyleSettings.GetMenuColor() : rStyleSettings.GetWindowColor());
1375         maVirDev->DrawRect(aRect);
1376         Point aTxtPos(aRect.Left() + 2, aRect.Top());
1377         tools::Long nTxtWidth = rRenderContext.GetTextWidth(pItem->maText);
1378         if ((aTxtPos.X() + nTxtWidth) > aRect.Right())
1379         {
1380             maVirDev->SetClipRegion(vcl::Region(aRect));
1381             maVirDev->DrawText(aTxtPos, pItem->maText);
1382             maVirDev->SetClipRegion();
1383         }
1384         else
1385             maVirDev->DrawText(aTxtPos, pItem->maText);
1386     }
1387     else if (pItem->meType == VALUESETITEM_COLOR)
1388     {
1389         maVirDev->SetFillColor(pItem->maColor);
1390         maVirDev->DrawRect(aRect);
1391     }
1392     else
1393     {
1394         if (IsColor())
1395             maVirDev->SetFillColor(maColor);
1396         else if (nStyle & WB_MENUSTYLEVALUESET)
1397             maVirDev->SetFillColor(rStyleSettings.GetMenuColor());
1398         else if (IsEnabled())
1399             maVirDev->SetFillColor(rStyleSettings.GetWindowColor());
1400         else
1401             maVirDev->SetFillColor(rStyleSettings.GetFaceColor());
1402         maVirDev->DrawRect(aRect);
1403 
1404         if (pItem->meType == VALUESETITEM_USERDRAW)
1405         {
1406             UserDrawEvent aUDEvt(maVirDev.get(), aRect, pItem->mnId);
1407             UserDraw(aUDEvt);
1408         }
1409         else
1410         {
1411             Size aImageSize = pItem->maImage.GetSizePixel();
1412             Size  aRectSize = aRect.GetSize();
1413             Point aPos(aRect.Left(), aRect.Top());
1414             aPos.AdjustX((aRectSize.Width() - aImageSize.Width()) / 2 );
1415 
1416             if (pItem->meType != VALUESETITEM_IMAGE_AND_TEXT)
1417                 aPos.AdjustY((aRectSize.Height() - aImageSize.Height()) / 2 );
1418 
1419             DrawImageFlags  nImageStyle  = DrawImageFlags::NONE;
1420             if (!IsEnabled())
1421                 nImageStyle  |= DrawImageFlags::Disable;
1422 
1423             if (aImageSize.Width()  > aRectSize.Width() ||
1424                 aImageSize.Height() > aRectSize.Height())
1425             {
1426                 maVirDev->SetClipRegion(vcl::Region(aRect));
1427                 maVirDev->DrawImage(aPos, pItem->maImage, nImageStyle);
1428                 maVirDev->SetClipRegion();
1429             }
1430             else
1431                 maVirDev->DrawImage(aPos, pItem->maImage, nImageStyle);
1432 
1433             if (pItem->meType == VALUESETITEM_IMAGE_AND_TEXT)
1434             {
1435                 maVirDev->SetFont(rRenderContext.GetFont());
1436                 maVirDev->SetTextColor((nStyle & WB_MENUSTYLEVALUESET) ? rStyleSettings.GetMenuTextColor() : rStyleSettings.GetWindowTextColor());
1437                 maVirDev->SetTextFillColor();
1438 
1439                 tools::Long nTxtWidth = maVirDev->GetTextWidth(pItem->maText);
1440 
1441                 if (nTxtWidth > aRect.GetWidth())
1442                     maVirDev->SetClipRegion(vcl::Region(aRect));
1443 
1444                 maVirDev->DrawText(Point(aRect.Left() +
1445                                          (aRect.GetWidth() - nTxtWidth) / 2,
1446                                          aRect.Bottom() - maVirDev->GetTextHeight()),
1447                                    pItem->maText);
1448 
1449                 if (nTxtWidth > aRect.GetWidth())
1450                     maVirDev->SetClipRegion();
1451             }
1452         }
1453     }
1454 
1455     const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
1456 
1457     if (nEdgeBlendingPercent)
1458     {
1459         const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
1460         const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
1461         const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
1462         const BitmapEx aBlendFrame(createBlendFrame(aRect.GetSize(), nAlpha, rTopLeft, rBottomRight));
1463 
1464         if (!aBlendFrame.IsEmpty())
1465         {
1466             maVirDev->DrawBitmapEx(aRect.TopLeft(), aBlendFrame);
1467         }
1468     }
1469 }
1470 
ImplDrawItemText(vcl::RenderContext & rRenderContext,const OUString & rText)1471 void ValueSet::ImplDrawItemText(vcl::RenderContext& rRenderContext, const OUString& rText)
1472 {
1473     if (!(GetStyle() & WB_NAMEFIELD))
1474         return;
1475 
1476     Size aWinSize(GetOutputSizePixel());
1477     tools::Long nTxtWidth = rRenderContext.GetTextWidth(rText);
1478     tools::Long nTxtOffset = mnTextOffset;
1479 
1480     // delete rectangle and show text
1481     if (GetStyle() & WB_FLATVALUESET)
1482     {
1483         const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1484         rRenderContext.SetLineColor();
1485         rRenderContext.SetFillColor(rStyleSettings.GetFaceColor());
1486         rRenderContext.DrawRect(tools::Rectangle(Point(0, nTxtOffset), Point(aWinSize.Width(), aWinSize.Height())));
1487         rRenderContext.SetTextColor(rStyleSettings.GetButtonTextColor());
1488     }
1489     else
1490     {
1491         nTxtOffset += NAME_LINE_HEIGHT+NAME_LINE_OFF_Y;
1492         rRenderContext.SetBackground(Application::GetSettings().GetStyleSettings().GetFaceColor());
1493         rRenderContext.Erase(tools::Rectangle(Point(0, nTxtOffset), Point(aWinSize.Width(), aWinSize.Height())));
1494     }
1495     rRenderContext.DrawText(Point((aWinSize.Width() - nTxtWidth) / 2, nTxtOffset + (NAME_OFFSET / 2)), rText);
1496 }
1497 
StyleUpdated()1498 void ValueSet::StyleUpdated()
1499 {
1500     mbFormat = true;
1501     CustomWidgetController::StyleUpdated();
1502 }
1503 
EnableFullItemMode(bool bFullMode)1504 void ValueSet::EnableFullItemMode( bool bFullMode )
1505 {
1506     mbFullMode = bFullMode;
1507 }
1508 
SetColCount(sal_uInt16 nNewCols)1509 void ValueSet::SetColCount( sal_uInt16 nNewCols )
1510 {
1511     if ( mnUserCols != nNewCols )
1512     {
1513         mnUserCols = nNewCols;
1514         QueueReformat();
1515     }
1516 }
1517 
SetItemImage(sal_uInt16 nItemId,const Image & rImage)1518 void ValueSet::SetItemImage( sal_uInt16 nItemId, const Image& rImage )
1519 {
1520     size_t nPos = GetItemPos( nItemId );
1521 
1522     if ( nPos == VALUESET_ITEM_NOTFOUND )
1523         return;
1524 
1525     ValueSetItem* pItem = mItemList[nPos].get();
1526     pItem->meType  = VALUESETITEM_IMAGE;
1527     pItem->maImage = rImage;
1528 
1529     if ( !mbFormat && IsReallyVisible() && IsUpdateMode() )
1530     {
1531         const tools::Rectangle aRect = ImplGetItemRect(nPos);
1532         Invalidate(aRect);
1533     }
1534     else
1535         mbFormat = true;
1536 }
1537 
SetItemColor(sal_uInt16 nItemId,const Color & rColor)1538 void ValueSet::SetItemColor( sal_uInt16 nItemId, const Color& rColor )
1539 {
1540     size_t nPos = GetItemPos( nItemId );
1541 
1542     if ( nPos == VALUESET_ITEM_NOTFOUND )
1543         return;
1544 
1545     ValueSetItem* pItem = mItemList[nPos].get();
1546     pItem->meType  = VALUESETITEM_COLOR;
1547     pItem->maColor = rColor;
1548 
1549     if ( !mbFormat && IsReallyVisible() && IsUpdateMode() )
1550     {
1551         const tools::Rectangle aRect = ImplGetItemRect(nPos);
1552         Invalidate( aRect );
1553     }
1554     else
1555         mbFormat = true;
1556 }
1557 
GetItemColor(sal_uInt16 nItemId) const1558 Color ValueSet::GetItemColor( sal_uInt16 nItemId ) const
1559 {
1560     size_t nPos = GetItemPos( nItemId );
1561 
1562     if ( nPos != VALUESET_ITEM_NOTFOUND )
1563         return mItemList[nPos]->maColor;
1564     else
1565         return Color();
1566 }
1567 
CalcWindowSizePixel(const Size & rItemSize,sal_uInt16 nDesireCols,sal_uInt16 nDesireLines) const1568 Size ValueSet::CalcWindowSizePixel( const Size& rItemSize, sal_uInt16 nDesireCols,
1569                                     sal_uInt16 nDesireLines ) const
1570 {
1571     size_t nCalcCols = nDesireCols;
1572     size_t nCalcLines = nDesireLines;
1573 
1574     if ( !nCalcCols )
1575     {
1576         if ( mnUserCols )
1577             nCalcCols = mnUserCols;
1578         else
1579             nCalcCols = 1;
1580     }
1581 
1582     if ( !nCalcLines )
1583     {
1584         nCalcLines = mnVisLines;
1585 
1586         if ( mbFormat )
1587         {
1588             if ( mnUserVisLines )
1589                 nCalcLines = mnUserVisLines;
1590             else
1591             {
1592                 // Floor( (M+N-1)/N )==Ceiling( M/N )
1593                 nCalcLines = (mItemList.size()+nCalcCols-1) / nCalcCols;
1594                 if ( !nCalcLines )
1595                     nCalcLines = 1;
1596             }
1597         }
1598     }
1599 
1600     Size        aSize( rItemSize.Width() * nCalcCols, rItemSize.Height() * nCalcLines );
1601     WinBits     nStyle = GetStyle();
1602     tools::Long        nTxtHeight = GetTextHeight();
1603     tools::Long        n;
1604 
1605     if ( nStyle & WB_ITEMBORDER )
1606     {
1607         if ( nStyle & WB_DOUBLEBORDER )
1608             n = ITEM_OFFSET_DOUBLE;
1609         else
1610             n = ITEM_OFFSET;
1611 
1612         aSize.AdjustWidth(n * nCalcCols );
1613         aSize.AdjustHeight(n * nCalcLines );
1614     }
1615     else
1616         n = 0;
1617 
1618     if ( mnSpacing )
1619     {
1620         aSize.AdjustWidth(mnSpacing * (nCalcCols - 1) );
1621         aSize.AdjustHeight(mnSpacing * (nCalcLines - 1) );
1622     }
1623 
1624     if ( nStyle & WB_NAMEFIELD )
1625     {
1626         aSize.AdjustHeight(nTxtHeight + NAME_OFFSET );
1627         if ( !(nStyle & WB_FLATVALUESET) )
1628             aSize.AdjustHeight(NAME_LINE_HEIGHT + NAME_LINE_OFF_Y );
1629     }
1630 
1631     if ( nStyle & WB_NONEFIELD )
1632     {
1633         aSize.AdjustHeight(nTxtHeight + n + mnSpacing );
1634     }
1635 
1636     return aSize;
1637 }
1638 
InsertItem(sal_uInt16 nItemId,const Image & rImage)1639 void ValueSet::InsertItem( sal_uInt16 nItemId, const Image& rImage )
1640 {
1641     std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1642     pItem->mnId     = nItemId;
1643     pItem->meType   = VALUESETITEM_IMAGE;
1644     pItem->maImage  = rImage;
1645     ImplInsertItem( std::move(pItem), VALUESET_APPEND );
1646 }
1647 
InsertItem(sal_uInt16 nItemId,const Image & rImage,const OUString & rText,size_t nPos,bool bShowLegend)1648 void ValueSet::InsertItem( sal_uInt16 nItemId, const Image& rImage,
1649                            const OUString& rText, size_t nPos,
1650                            bool bShowLegend )
1651 {
1652     std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1653     pItem->mnId     = nItemId;
1654     pItem->meType   = bShowLegend ? VALUESETITEM_IMAGE_AND_TEXT : VALUESETITEM_IMAGE;
1655     pItem->maImage  = rImage;
1656     pItem->maText   = rText;
1657     ImplInsertItem( std::move(pItem), nPos );
1658 }
1659 
InsertItem(sal_uInt16 nItemId,size_t nPos)1660 void ValueSet::InsertItem( sal_uInt16 nItemId, size_t nPos )
1661 {
1662     std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1663     pItem->mnId     = nItemId;
1664     pItem->meType   = VALUESETITEM_USERDRAW;
1665     ImplInsertItem( std::move(pItem), nPos );
1666 }
1667 
InsertItem(sal_uInt16 nItemId,const Color & rColor,const OUString & rText)1668 void ValueSet::InsertItem( sal_uInt16 nItemId, const Color& rColor,
1669                            const OUString& rText )
1670 {
1671     std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1672     pItem->mnId     = nItemId;
1673     pItem->meType   = VALUESETITEM_COLOR;
1674     pItem->maColor  = rColor;
1675     pItem->maText   = rText;
1676     ImplInsertItem( std::move(pItem), VALUESET_APPEND );
1677 }
1678 
ImplInsertItem(std::unique_ptr<ValueSetItem> pItem,const size_t nPos)1679 void ValueSet::ImplInsertItem( std::unique_ptr<ValueSetItem> pItem, const size_t nPos )
1680 {
1681     DBG_ASSERT( pItem->mnId, "ValueSet::InsertItem(): ItemId == 0" );
1682     DBG_ASSERT( GetItemPos( pItem->mnId ) == VALUESET_ITEM_NOTFOUND,
1683                 "ValueSet::InsertItem(): ItemId already exists" );
1684 
1685     if ( nPos < mItemList.size() ) {
1686         mItemList.insert( mItemList.begin() + nPos, std::move(pItem) );
1687     } else {
1688         mItemList.push_back( std::move(pItem) );
1689     }
1690 
1691     QueueReformat();
1692 }
1693 
GetScrollWidth() const1694 int ValueSet::GetScrollWidth() const
1695 {
1696     if (mxScrolledWindow)
1697         return mxScrolledWindow->get_scroll_thickness();
1698     return 0;
1699 }
1700 
SetEdgeBlending(bool bNew)1701 void ValueSet::SetEdgeBlending(bool bNew)
1702 {
1703     if(mbEdgeBlending != bNew)
1704     {
1705         mbEdgeBlending = bNew;
1706         mbFormat = true;
1707 
1708         if (GetDrawingArea() && IsReallyVisible() && IsUpdateMode())
1709         {
1710             Invalidate();
1711         }
1712     }
1713 }
1714 
CalcItemSizePixel(const Size & rItemSize) const1715 Size ValueSet::CalcItemSizePixel( const Size& rItemSize) const
1716 {
1717     Size aSize = rItemSize;
1718 
1719     WinBits nStyle = GetStyle();
1720     if ( nStyle & WB_ITEMBORDER )
1721     {
1722         tools::Long n;
1723 
1724         if ( nStyle & WB_DOUBLEBORDER )
1725             n = ITEM_OFFSET_DOUBLE;
1726         else
1727             n = ITEM_OFFSET;
1728 
1729         aSize.AdjustWidth(n );
1730         aSize.AdjustHeight(n );
1731     }
1732 
1733     return aSize;
1734 }
1735 
SetLineCount(sal_uInt16 nNewLines)1736 void ValueSet::SetLineCount( sal_uInt16 nNewLines )
1737 {
1738     if ( mnUserVisLines != nNewLines )
1739     {
1740         mnUserVisLines = nNewLines;
1741         QueueReformat();
1742     }
1743 }
1744 
SetItemWidth(tools::Long nNewItemWidth)1745 void ValueSet::SetItemWidth( tools::Long nNewItemWidth )
1746 {
1747     if ( mnUserItemWidth != nNewItemWidth )
1748     {
1749         mnUserItemWidth = nNewItemWidth;
1750         QueueReformat();
1751     }
1752 }
1753 
1754 //method to set accessible when the style is user draw.
InsertItem(sal_uInt16 nItemId,const OUString & rText,size_t nPos)1755 void ValueSet::InsertItem( sal_uInt16 nItemId, const OUString& rText, size_t nPos  )
1756 {
1757     DBG_ASSERT( nItemId, "ValueSet::InsertItem(): ItemId == 0" );
1758     DBG_ASSERT( GetItemPos( nItemId ) == VALUESET_ITEM_NOTFOUND,
1759                 "ValueSet::InsertItem(): ItemId already exists" );
1760     std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1761     pItem->mnId     = nItemId;
1762     pItem->meType   = VALUESETITEM_USERDRAW;
1763     pItem->maText   = rText;
1764     ImplInsertItem( std::move(pItem), nPos );
1765 }
1766 
SetItemHeight(tools::Long nNewItemHeight)1767 void ValueSet::SetItemHeight( tools::Long nNewItemHeight )
1768 {
1769     if ( mnUserItemHeight != nNewItemHeight )
1770     {
1771         mnUserItemHeight = nNewItemHeight;
1772         QueueReformat();
1773     }
1774 }
1775 
RequestHelp(tools::Rectangle & rHelpRect)1776 OUString ValueSet::RequestHelp(tools::Rectangle& rHelpRect)
1777 {
1778     Point aPos = rHelpRect.TopLeft();
1779     const size_t nItemPos = ImplGetItem( aPos );
1780     OUString sRet;
1781     if (nItemPos != VALUESET_ITEM_NOTFOUND)
1782     {
1783         rHelpRect = ImplGetItemRect(nItemPos);
1784         sRet = GetItemText(ImplGetItem(nItemPos)->mnId);
1785     }
1786     return sRet;
1787 }
1788 
GetItemText(sal_uInt16 nItemId) const1789 OUString ValueSet::GetItemText(sal_uInt16 nItemId) const
1790 {
1791     const size_t nPos = GetItemPos(nItemId);
1792 
1793     if ( nPos != VALUESET_ITEM_NOTFOUND )
1794         return mItemList[nPos]->maText;
1795 
1796     return OUString();
1797 }
1798 
SetExtraSpacing(sal_uInt16 nNewSpacing)1799 void ValueSet::SetExtraSpacing( sal_uInt16 nNewSpacing )
1800 {
1801     if ( GetStyle() & WB_ITEMBORDER )
1802     {
1803         mnSpacing = nNewSpacing;
1804         QueueReformat();
1805     }
1806 }
1807 
SetFormat()1808 void ValueSet::SetFormat()
1809 {
1810     mbFormat = true;
1811 }
1812 
SetItemData(sal_uInt16 nItemId,void * pData)1813 void ValueSet::SetItemData( sal_uInt16 nItemId, void* pData )
1814 {
1815     size_t nPos = GetItemPos( nItemId );
1816 
1817     if ( nPos == VALUESET_ITEM_NOTFOUND )
1818         return;
1819 
1820     ValueSetItem* pItem = mItemList[nPos].get();
1821     pItem->mpData = pData;
1822 
1823     if ( pItem->meType == VALUESETITEM_USERDRAW )
1824     {
1825         if ( !mbFormat && IsReallyVisible() && IsUpdateMode() )
1826         {
1827             const tools::Rectangle aRect = ImplGetItemRect(nPos);
1828             Invalidate(aRect);
1829         }
1830         else
1831             mbFormat = true;
1832     }
1833 }
1834 
GetItemData(sal_uInt16 nItemId) const1835 void* ValueSet::GetItemData( sal_uInt16 nItemId ) const
1836 {
1837     size_t nPos = GetItemPos( nItemId );
1838 
1839     if ( nPos != VALUESET_ITEM_NOTFOUND )
1840         return mItemList[nPos]->mpData;
1841     else
1842         return nullptr;
1843 }
1844 
SetItemText(sal_uInt16 nItemId,const OUString & rText)1845 void ValueSet::SetItemText(sal_uInt16 nItemId, const OUString& rText)
1846 {
1847     size_t nPos = GetItemPos( nItemId );
1848 
1849     if ( nPos == VALUESET_ITEM_NOTFOUND )
1850         return;
1851 
1852     ValueSetItem* pItem = mItemList[nPos].get();
1853 
1854     // Remember old and new name for accessibility event.
1855     Any aOldName;
1856     Any aNewName;
1857     OUString sString (pItem->maText);
1858     aOldName <<= sString;
1859     sString = rText;
1860     aNewName <<= sString;
1861 
1862     pItem->maText = rText;
1863 
1864     if (!mbFormat && IsReallyVisible() && IsUpdateMode())
1865     {
1866         sal_uInt16 nTempId = mnSelItemId;
1867 
1868         if (mbHighlight)
1869             nTempId = mnHighItemId;
1870 
1871         if (nTempId == nItemId)
1872             Invalidate();
1873     }
1874 
1875     if (ImplHasAccessibleListeners())
1876     {
1877         Reference<XAccessible> xAccessible(pItem->GetAccessible( false/*bIsTransientChildrenDisabled*/));
1878         ValueItemAcc* pValueItemAcc = static_cast<ValueItemAcc*>(xAccessible.get());
1879         pValueItemAcc->FireAccessibleEvent(AccessibleEventId::NAME_CHANGED, aOldName, aNewName);
1880     }
1881 }
1882 
GetLargestItemSize()1883 Size ValueSet::GetLargestItemSize()
1884 {
1885     Size aLargestItem;
1886 
1887     for (const std::unique_ptr<ValueSetItem>& pItem : mItemList)
1888     {
1889         if (!pItem->mbVisible)
1890             continue;
1891 
1892         if (pItem->meType != VALUESETITEM_IMAGE &&
1893             pItem->meType != VALUESETITEM_IMAGE_AND_TEXT)
1894         {
1895             // handle determining an optimal size for this case
1896             continue;
1897         }
1898 
1899         Size aSize = pItem->maImage.GetSizePixel();
1900         if (pItem->meType == VALUESETITEM_IMAGE_AND_TEXT)
1901         {
1902             aSize.AdjustHeight(3 * NAME_LINE_HEIGHT +
1903                 maVirDev->GetTextHeight() );
1904             aSize.setWidth( std::max(aSize.Width(),
1905                                      maVirDev->GetTextWidth(pItem->maText) + NAME_OFFSET) );
1906         }
1907 
1908         aLargestItem.setWidth( std::max(aLargestItem.Width(), aSize.Width()) );
1909         aLargestItem.setHeight( std::max(aLargestItem.Height(), aSize.Height()) );
1910     }
1911 
1912     return aLargestItem;
1913 }
1914 
SetOptimalSize()1915 void ValueSet::SetOptimalSize()
1916 {
1917     Size aLargestSize(GetLargestItemSize());
1918     aLargestSize.setWidth(std::max(aLargestSize.Width(), mnUserItemWidth));
1919     aLargestSize.setHeight(std::max(aLargestSize.Height(), mnUserItemHeight));
1920     Size aPrefSize(CalcWindowSizePixel(aLargestSize));
1921     GetDrawingArea()->set_size_request(aPrefSize.Width(), aPrefSize.Height());
1922 }
1923 
GetItemImage(sal_uInt16 nItemId) const1924 Image ValueSet::GetItemImage(sal_uInt16 nItemId) const
1925 {
1926     size_t nPos = GetItemPos( nItemId );
1927 
1928     if ( nPos != VALUESET_ITEM_NOTFOUND )
1929         return mItemList[nPos]->maImage;
1930     else
1931         return Image();
1932 }
1933 
SetColor(const Color & rColor)1934 void ValueSet::SetColor(const Color& rColor)
1935 {
1936     maColor  = rColor;
1937     mbFormat = true;
1938     if (IsReallyVisible() && IsUpdateMode())
1939         Invalidate();
1940 }
1941 
Show()1942 void ValueSet::Show()
1943 {
1944     if (mxScrolledWindow)
1945         mxScrolledWindow->show();
1946     CustomWidgetController::Show();
1947 }
1948 
Hide()1949 void ValueSet::Hide()
1950 {
1951     CustomWidgetController::Hide();
1952     if (mxScrolledWindow)
1953         mxScrolledWindow->hide();
1954 }
1955 
GetUITestFactory() const1956 FactoryFunction ValueSet::GetUITestFactory() const
1957 {
1958     return ValueSetUIObject::create;
1959 }
1960 
1961 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1962