nss: upgrade to release 3.73
[LibreOffice.git] / svtools / source / control / valueset.cxx
blob5ce7298bf1b89c2ab1614689294ccc6e9633d498
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <o3tl/safeint.hxx>
23 #include <tools/debug.hxx>
24 #include <tools/stream.hxx>
25 #include <comphelper/base64.hxx>
26 #include <vcl/decoview.hxx>
27 #include <vcl/event.hxx>
28 #include <vcl/graph.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/cvtgrf.hxx>
31 #include <vcl/help.hxx>
32 #include <vcl/settings.hxx>
33 #include <vcl/commandevent.hxx>
34 #include <vcl/virdev.hxx>
36 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
37 #include <com/sun/star/lang/XComponent.hpp>
38 #include <rtl/ustring.hxx>
39 #include <sal/log.hxx>
40 #include "valueimp.hxx"
42 #include <svtools/valueset.hxx>
43 #include <boost/property_tree/ptree.hpp>
45 #include <uiobject.hxx>
46 #include <vcl/uitest/logger.hxx>
47 #include <vcl/uitest/eventdescription.hxx>
49 using namespace css::uno;
50 using namespace css::lang;
51 using namespace css::accessibility;
53 namespace
55 void collectUIInformation( const OUString& aID , const OUString& aParentID , const OUString& aPos )
57 EventDescription aDescription;
58 aDescription.aID = aID ;
59 aDescription.aParameters = {{"POS", aPos }};
60 aDescription.aAction = "SELECT";
61 aDescription.aKeyWord = "ValueSet";
62 aDescription.aParent = aParentID;
63 UITestLogger::getInstance().logEvent(aDescription);
66 enum
68 ITEM_OFFSET = 4,
69 ITEM_OFFSET_DOUBLE = 6,
70 NAME_LINE_OFF_X = 2,
71 NAME_LINE_OFF_Y = 2,
72 NAME_LINE_HEIGHT = 2,
73 NAME_OFFSET = 2,
78 ValueSet::ValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)
79 : maVirDev( VclPtr<VirtualDevice>::Create())
80 , mxScrolledWindow(std::move(pScrolledWindow))
81 , mnHighItemId(0)
82 , maColor(COL_TRANSPARENT)
83 , mnStyle(0)
84 , mbFormat(true)
85 , mbHighlight(false)
87 maVirDev->SetBackground(Application::GetSettings().GetStyleSettings().GetFaceColor());
89 mnItemWidth = 0;
90 mnItemHeight = 0;
91 mnTextOffset = 0;
92 mnVisLines = 0;
93 mnLines = 0;
94 mnUserItemWidth = 0;
95 mnUserItemHeight = 0;
96 mnFirstLine = 0;
97 mnSelItemId = 0;
98 mnSavedItemId = -1;
99 mnCols = 0;
100 mnCurCol = 0;
101 mnUserCols = 0;
102 mnUserVisLines = 0;
103 mnSpacing = 0;
104 mnFrameStyle = DrawFrameStyle::NONE;
105 mbNoSelection = true;
106 mbDrawSelection = true;
107 mbBlackSel = false;
108 mbDoubleSel = false;
109 mbScroll = false;
110 mbFullMode = true;
111 mbEdgeBlending = false;
112 mbHasVisibleItems = false;
114 if (mxScrolledWindow)
115 mxScrolledWindow->connect_vadjustment_changed(LINK(this, ValueSet, ImplScrollHdl));
118 void ValueSet::SetDrawingArea(weld::DrawingArea* pDrawingArea)
120 CustomWidgetController::SetDrawingArea(pDrawingArea);
121 // #106446#, #106601# force mirroring of virtual device
122 maVirDev->EnableRTL(pDrawingArea->get_direction());
125 Reference<XAccessible> ValueSet::CreateAccessible()
127 if (!mxAccessible)
128 mxAccessible.set(new ValueSetAcc(this));
129 return mxAccessible;
132 ValueSet::~ValueSet()
134 Reference<XComponent> xComponent(mxAccessible, UNO_QUERY);
135 if (xComponent.is())
136 xComponent->dispose();
138 ImplDeleteItems();
141 void ValueSet::ImplDeleteItems()
143 const size_t n = mItemList.size();
145 for ( size_t i = 0; i < n; ++i )
147 ValueSetItem* pItem = mItemList[i].get();
148 if ( pItem->mbVisible && ImplHasAccessibleListeners() )
150 Any aOldAny;
151 Any aNewAny;
153 aOldAny <<= pItem->GetAccessible( false/*bIsTransientChildrenDisabled*/ );
154 ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny);
157 mItemList[i].reset();
160 mItemList.clear();
163 void ValueSet::Select()
165 collectUIInformation(OStringToOUString(GetDrawingArea()->get_buildable_name(),RTL_TEXTENCODING_UTF8) , OStringToOUString(GetDrawingArea()->get_help_id(),RTL_TEXTENCODING_UTF8) , OUString::number(GetSelectedItemId()));
166 maSelectHdl.Call( this );
169 void ValueSet::UserDraw( const UserDrawEvent& )
173 size_t ValueSet::ImplGetItem( const Point& rPos ) const
175 if (!mbHasVisibleItems)
177 return VALUESET_ITEM_NOTFOUND;
180 if (mpNoneItem && maNoneItemRect.IsInside(rPos))
182 return VALUESET_ITEM_NONEITEM;
185 if (maItemListRect.IsInside(rPos))
187 const int xc = rPos.X() - maItemListRect.Left();
188 const int yc = rPos.Y() - maItemListRect.Top();
189 // The point is inside the area of item list,
190 // let's find the containing item.
191 const int col = xc / (mnItemWidth + mnSpacing);
192 const int x = xc % (mnItemWidth + mnSpacing);
193 const int row = yc / (mnItemHeight + mnSpacing);
194 const int y = yc % (mnItemHeight + mnSpacing);
196 if (x < mnItemWidth && y < mnItemHeight)
198 // the point is inside item rect and not inside spacing
199 const size_t item = (mnFirstLine + row) * static_cast<size_t>(mnCols) + col;
200 if (item < mItemList.size())
202 return item;
207 return VALUESET_ITEM_NOTFOUND;
210 ValueSetItem* ValueSet::ImplGetItem( size_t nPos )
212 if (nPos == VALUESET_ITEM_NONEITEM)
213 return mpNoneItem.get();
214 else
215 return (nPos < mItemList.size()) ? mItemList[nPos].get() : nullptr;
218 ValueSetItem* ValueSet::ImplGetFirstItem()
220 return !mItemList.empty() ? mItemList[0].get() : nullptr;
223 sal_uInt16 ValueSet::ImplGetVisibleItemCount() const
225 sal_uInt16 nRet = 0;
226 const size_t nItemCount = mItemList.size();
228 for ( size_t n = 0; n < nItemCount; ++n )
230 if ( mItemList[n]->mbVisible )
231 ++nRet;
234 return nRet;
237 void ValueSet::ImplFireAccessibleEvent( short nEventId, const Any& rOldValue, const Any& rNewValue )
239 ValueSetAcc* pAcc = ValueSetAcc::getImplementation(mxAccessible);
241 if( pAcc )
242 pAcc->FireAccessibleEvent( nEventId, rOldValue, rNewValue );
245 bool ValueSet::ImplHasAccessibleListeners()
247 ValueSetAcc* pAcc = ValueSetAcc::getImplementation(mxAccessible);
248 return( pAcc && pAcc->HasAccessibleListeners() );
251 IMPL_LINK(ValueSet, ImplScrollHdl, weld::ScrolledWindow&, rScrollWin, void)
253 auto nNewFirstLine = rScrollWin.vadjustment_get_value();
254 if ( nNewFirstLine != mnFirstLine )
256 mnFirstLine = nNewFirstLine;
257 mbFormat = true;
258 Invalidate();
262 void ValueSet::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
264 if (GetStyle() & WB_FLATVALUESET)
266 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
267 rRenderContext.SetLineColor();
268 rRenderContext.SetFillColor(rStyleSettings.GetFaceColor());
269 tools::Long nOffY = maVirDev->GetOutputSizePixel().Height();
270 Size aWinSize(GetOutputSizePixel());
271 rRenderContext.DrawRect(tools::Rectangle(Point(0, nOffY ), Point( aWinSize.Width(), aWinSize.Height())));
274 ImplDraw(rRenderContext);
277 void ValueSet::GetFocus()
279 SAL_INFO("svtools", "value set getting focus");
280 Invalidate();
281 CustomWidgetController::GetFocus();
283 // Tell the accessible object that we got the focus.
284 ValueSetAcc* pAcc = ValueSetAcc::getImplementation(mxAccessible);
285 if (pAcc)
286 pAcc->GetFocus();
289 void ValueSet::LoseFocus()
291 SAL_INFO("svtools", "value set losing focus");
292 Invalidate();
293 CustomWidgetController::LoseFocus();
295 // Tell the accessible object that we lost the focus.
296 ValueSetAcc* pAcc = ValueSetAcc::getImplementation(mxAccessible);
297 if( pAcc )
298 pAcc->LoseFocus();
301 void ValueSet::Resize()
303 mbFormat = true;
304 if ( IsReallyVisible() && IsUpdateMode() )
305 Invalidate();
306 CustomWidgetController::Resize();
309 bool ValueSet::KeyInput( const KeyEvent& rKeyEvent )
311 size_t nLastItem = mItemList.size();
313 if ( !nLastItem || !ImplGetFirstItem() )
314 return CustomWidgetController::KeyInput(rKeyEvent);
316 if (mbFormat)
317 Invalidate();
319 --nLastItem;
321 const size_t nCurPos
322 = mnSelItemId ? GetItemPos(mnSelItemId) : (mpNoneItem ? VALUESET_ITEM_NONEITEM : 0);
323 size_t nItemPos = VALUESET_ITEM_NOTFOUND;
324 size_t nVStep = mnCols;
326 switch (rKeyEvent.GetKeyCode().GetCode())
328 case KEY_HOME:
329 nItemPos = mpNoneItem ? VALUESET_ITEM_NONEITEM : 0;
330 break;
332 case KEY_END:
333 nItemPos = nLastItem;
334 break;
336 case KEY_LEFT:
337 if (nCurPos != VALUESET_ITEM_NONEITEM)
339 if (nCurPos)
341 nItemPos = nCurPos-1;
343 else if (mpNoneItem)
345 nItemPos = VALUESET_ITEM_NONEITEM;
348 break;
350 case KEY_RIGHT:
351 if (nCurPos < nLastItem)
353 if (nCurPos == VALUESET_ITEM_NONEITEM)
355 nItemPos = 0;
357 else
359 nItemPos = nCurPos+1;
362 break;
364 case KEY_PAGEUP:
365 if (rKeyEvent.GetKeyCode().IsShift() || rKeyEvent.GetKeyCode().IsMod1() || rKeyEvent.GetKeyCode().IsMod2())
367 return CustomWidgetController::KeyInput(rKeyEvent);
369 nVStep *= mnVisLines;
370 [[fallthrough]];
371 case KEY_UP:
372 if (nCurPos != VALUESET_ITEM_NONEITEM)
374 if (nCurPos == nLastItem)
376 const size_t nCol = mnCols ? nLastItem % mnCols : 0;
377 if (nCol < mnCurCol)
379 // Move to previous row/page, keeping the old column
380 nVStep -= mnCurCol - nCol;
383 if (nCurPos >= nVStep)
385 // Go up of a whole page
386 nItemPos = nCurPos-nVStep;
388 else if (mpNoneItem)
390 nItemPos = VALUESET_ITEM_NONEITEM;
392 else if (nCurPos > mnCols)
394 // Go to same column in first row
395 nItemPos = nCurPos % mnCols;
398 break;
400 case KEY_PAGEDOWN:
401 if (rKeyEvent.GetKeyCode().IsShift() || rKeyEvent.GetKeyCode().IsMod1() || rKeyEvent.GetKeyCode().IsMod2())
403 return CustomWidgetController::KeyInput(rKeyEvent);
405 nVStep *= mnVisLines;
406 [[fallthrough]];
407 case KEY_DOWN:
408 if (nCurPos != nLastItem)
410 if (nCurPos == VALUESET_ITEM_NONEITEM)
412 nItemPos = nVStep-mnCols+mnCurCol;
414 else
416 nItemPos = nCurPos+nVStep;
418 if (nItemPos > nLastItem)
420 nItemPos = nLastItem;
423 break;
425 case KEY_RETURN:
426 if (GetStyle() & WB_NO_DIRECTSELECT)
428 // tdf#142479 on return select the entry the cursor is in
429 // before calling Select
430 if (nCurPos != VALUESET_ITEM_NONEITEM)
432 const sal_uInt16 nItemId = GetItemId(nCurPos);
433 if (nItemId != mnSelItemId)
434 SelectItem(nItemId);
436 Select();
437 break;
439 [[fallthrough]];
440 default:
441 return CustomWidgetController::KeyInput(rKeyEvent);
444 if ( nItemPos == VALUESET_ITEM_NOTFOUND )
445 return true;
447 if ( nItemPos!=VALUESET_ITEM_NONEITEM && nItemPos<nLastItem )
449 // update current column only in case of a new position
450 // which is also not a "specially" handled one.
451 mnCurCol = mnCols ? nItemPos % mnCols : 0;
453 const sal_uInt16 nItemId = (nItemPos != VALUESET_ITEM_NONEITEM) ? GetItemId( nItemPos ) : 0;
454 if ( nItemId != mnSelItemId )
456 SelectItem( nItemId );
457 if (!(GetStyle() & WB_NO_DIRECTSELECT))
459 // select only if WB_NO_DIRECTSELECT is not set
460 Select();
464 return true;
467 void ValueSet::ImplTracking(const Point& rPos)
469 ValueSetItem* pItem = ImplGetItem( ImplGetItem( rPos ) );
470 if ( pItem )
472 if( GetStyle() & WB_MENUSTYLEVALUESET || GetStyle() & WB_FLATVALUESET )
473 mbHighlight = true;
475 ImplHighlightItem( pItem->mnId );
477 else
479 if( GetStyle() & WB_MENUSTYLEVALUESET || GetStyle() & WB_FLATVALUESET )
480 mbHighlight = true;
482 ImplHighlightItem( mnSelItemId, false );
486 bool ValueSet::MouseButtonDown( const MouseEvent& rMouseEvent )
488 if ( rMouseEvent.IsLeft() )
490 ValueSetItem* pItem = ImplGetItem( ImplGetItem( rMouseEvent.GetPosPixel() ) );
491 if (pItem && !rMouseEvent.IsMod2())
493 if (rMouseEvent.GetClicks() == 1)
495 SelectItem( pItem->mnId );
496 if (!(GetStyle() & WB_NOPOINTERFOCUS))
497 GrabFocus();
499 else if ( rMouseEvent.GetClicks() == 2 )
500 maDoubleClickHdl.Call( this );
502 return true;
506 return CustomWidgetController::MouseButtonDown( rMouseEvent );
509 bool ValueSet::MouseButtonUp( const MouseEvent& rMouseEvent )
511 if (rMouseEvent.IsLeft() && !rMouseEvent.IsMod2())
513 // tdf#142150 MouseUp seen without previous MouseDown
514 if (mnSelItemId)
515 Select();
516 return true;
519 return CustomWidgetController::MouseButtonUp( rMouseEvent );
522 bool ValueSet::MouseMove(const MouseEvent& rMouseEvent)
524 // because of SelectionMode
525 if ((GetStyle() & WB_MENUSTYLEVALUESET) || (GetStyle() & WB_FLATVALUESET))
526 ImplTracking(rMouseEvent.GetPosPixel());
527 return CustomWidgetController::MouseMove(rMouseEvent);
530 void ValueSet::QueueReformat()
532 queue_resize();
533 RecalcScrollBar();
534 mbFormat = true;
535 if ( IsReallyVisible() && IsUpdateMode() )
536 Invalidate();
539 void ValueSet::RemoveItem( sal_uInt16 nItemId )
541 size_t nPos = GetItemPos( nItemId );
543 if ( nPos == VALUESET_ITEM_NOTFOUND )
544 return;
546 if ( nPos < mItemList.size() ) {
547 mItemList.erase( mItemList.begin() + nPos );
550 // reset variables
551 if (mnHighItemId == nItemId || mnSelItemId == nItemId)
553 mnCurCol = 0;
554 mnHighItemId = 0;
555 mnSelItemId = 0;
556 mbNoSelection = true;
559 QueueReformat();
562 bool ValueSet::TurnOffScrollBar()
564 if (mxScrolledWindow->get_vpolicy() == VclPolicyType::NEVER)
565 return false;
566 mxScrolledWindow->set_vpolicy(VclPolicyType::NEVER);
567 weld::DrawingArea* pDrawingArea = GetDrawingArea();
568 Size aPrefSize(pDrawingArea->get_preferred_size());
569 pDrawingArea->set_size_request(aPrefSize.Width() + GetScrollWidth(), aPrefSize.Height());
570 return true;
573 void ValueSet::TurnOnScrollBar()
575 if (mxScrolledWindow->get_vpolicy() == VclPolicyType::ALWAYS)
576 return;
577 mxScrolledWindow->set_vpolicy(VclPolicyType::ALWAYS);
578 weld::DrawingArea* pDrawingArea = GetDrawingArea();
579 Size aPrefSize(pDrawingArea->get_preferred_size());
580 pDrawingArea->set_size_request(aPrefSize.Width() - GetScrollWidth(), aPrefSize.Height());
583 void ValueSet::RecalcScrollBar()
585 if (!mxScrolledWindow)
586 return;
587 const bool bScrollAllowed = GetStyle() & WB_VSCROLL;
588 if (!bScrollAllowed)
589 return;
590 // reset scrolled window state to initial value so it will get configured
591 // to the right adjustment on the next format which we toggle on to happen
592 // if the scrolledwindow wasn't in its initial state already
593 if (TurnOffScrollBar())
594 mbFormat = true;
597 void ValueSet::Clear()
599 ImplDeleteItems();
601 // reset variables
602 mnFirstLine = 0;
603 mnCurCol = 0;
604 mnHighItemId = 0;
605 mnSelItemId = 0;
606 mbNoSelection = true;
608 RecalcScrollBar();
610 mbFormat = true;
611 if ( IsReallyVisible() && IsUpdateMode() )
612 Invalidate();
615 size_t ValueSet::GetItemCount() const
617 return mItemList.size();
620 size_t ValueSet::GetItemPos( sal_uInt16 nItemId ) const
622 for ( size_t i = 0, n = mItemList.size(); i < n; ++i ) {
623 if ( mItemList[i]->mnId == nItemId ) {
624 return i;
627 return VALUESET_ITEM_NOTFOUND;
630 sal_uInt16 ValueSet::GetItemId( size_t nPos ) const
632 return ( nPos < mItemList.size() ) ? mItemList[nPos]->mnId : 0 ;
635 sal_uInt16 ValueSet::GetItemId( const Point& rPos ) const
637 size_t nItemPos = ImplGetItem( rPos );
638 if ( nItemPos != VALUESET_ITEM_NOTFOUND )
639 return GetItemId( nItemPos );
641 return 0;
644 tools::Rectangle ValueSet::GetItemRect( sal_uInt16 nItemId ) const
646 const size_t nPos = GetItemPos( nItemId );
648 if ( nPos!=VALUESET_ITEM_NOTFOUND && mItemList[nPos]->mbVisible )
649 return ImplGetItemRect( nPos );
651 return tools::Rectangle();
654 tools::Rectangle ValueSet::ImplGetItemRect( size_t nPos ) const
656 const size_t nVisibleBegin = static_cast<size_t>(mnFirstLine)*mnCols;
657 const size_t nVisibleEnd = nVisibleBegin + static_cast<size_t>(mnVisLines)*mnCols;
659 // Check if the item is inside the range of the displayed ones,
660 // taking into account that last row could be incomplete
661 if ( nPos<nVisibleBegin || nPos>=nVisibleEnd || nPos>=mItemList.size() )
662 return tools::Rectangle();
664 nPos -= nVisibleBegin;
666 const size_t row = mnCols ? nPos/mnCols : 0;
667 const size_t col = mnCols ? nPos%mnCols : 0;
668 const tools::Long x = maItemListRect.Left()+col*(mnItemWidth+mnSpacing);
669 const tools::Long y = maItemListRect.Top()+row*(mnItemHeight+mnSpacing);
671 return tools::Rectangle( Point(x, y), Size(mnItemWidth, mnItemHeight) );
674 void ValueSet::ImplHighlightItem( sal_uInt16 nItemId, bool bIsSelection )
676 if ( mnHighItemId == nItemId )
677 return;
679 // remember the old item to delete the previous selection
680 mnHighItemId = nItemId;
682 // don't draw the selection if nothing is selected
683 if ( !bIsSelection && mbNoSelection )
684 mbDrawSelection = false;
686 // remove the old selection and draw the new one
687 Invalidate();
688 mbDrawSelection = true;
691 void ValueSet::ImplDraw(vcl::RenderContext& rRenderContext)
693 if (mbFormat)
694 Format(rRenderContext);
696 Point aDefPos;
697 Size aSize = maVirDev->GetOutputSizePixel();
699 rRenderContext.DrawOutDev(aDefPos, aSize, aDefPos, aSize, *maVirDev);
701 // draw parting line to the Namefield
702 if (GetStyle() & WB_NAMEFIELD)
704 if (!(GetStyle() & WB_FLATVALUESET))
706 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
707 Size aWinSize(GetOutputSizePixel());
708 Point aPos1(NAME_LINE_OFF_X, mnTextOffset + NAME_LINE_OFF_Y);
709 Point aPos2(aWinSize.Width() - (NAME_LINE_OFF_X * 2), mnTextOffset + NAME_LINE_OFF_Y);
710 if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
712 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
713 rRenderContext.DrawLine(aPos1, aPos2);
714 aPos1.AdjustY( 1 );
715 aPos2.AdjustY( 1 );
716 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
718 else
719 rRenderContext.SetLineColor(rStyleSettings.GetWindowTextColor());
720 rRenderContext.DrawLine(aPos1, aPos2);
724 ImplDrawSelect(rRenderContext);
728 * An inelegant method; sets the item width & height such that
729 * all of the included items and their labels fit; if we can
730 * calculate that.
732 void ValueSet::RecalculateItemSizes()
734 Size aLargestItem = GetLargestItemSize();
736 if ( mnUserItemWidth != aLargestItem.Width() ||
737 mnUserItemHeight != aLargestItem.Height() )
739 mnUserItemWidth = aLargestItem.Width();
740 mnUserItemHeight = aLargestItem.Height();
741 QueueReformat();
745 void ValueSet::SetFirstLine(sal_uInt16 nNewFirstLine)
747 if (nNewFirstLine != mnFirstLine)
749 mnFirstLine = nNewFirstLine;
750 if (mxScrolledWindow)
751 mxScrolledWindow->vadjustment_set_value(mnFirstLine);
755 void ValueSet::SelectItem( sal_uInt16 nItemId )
757 size_t nItemPos = 0;
759 if ( nItemId )
761 nItemPos = GetItemPos( nItemId );
762 if ( nItemPos == VALUESET_ITEM_NOTFOUND )
763 return;
766 if ( !((mnSelItemId != nItemId) || mbNoSelection) )
767 return;
769 const sal_uInt16 nOldItem = mnSelItemId;
770 mnSelItemId = nItemId;
771 mbNoSelection = false;
773 bool bNewOut = !mbFormat && IsReallyVisible() && IsUpdateMode();
774 bool bNewLine = false;
776 if (weld::DrawingArea* pNeedsFormatToScroll = !mnCols ? GetDrawingArea() : nullptr)
778 Format(pNeedsFormatToScroll->get_ref_device());
779 // reset scrollbar so its set to the later calculated mnFirstLine on
780 // the next Format
781 RecalcScrollBar(); // reset scrollbar so its set to the later calculated
784 // if necessary scroll to the visible area
785 if (mbScroll && nItemId && mnCols)
787 sal_uInt16 nNewLine = static_cast<sal_uInt16>(nItemPos / mnCols);
788 if ( nNewLine < mnFirstLine )
790 SetFirstLine(nNewLine);
791 bNewLine = true;
793 else if ( nNewLine > o3tl::make_unsigned(mnFirstLine+mnVisLines-1) )
795 SetFirstLine(static_cast<sal_uInt16>(nNewLine-mnVisLines+1));
796 bNewLine = true;
800 if ( bNewOut )
802 if ( bNewLine )
804 // redraw everything if the visible area has changed
805 mbFormat = true;
807 Invalidate();
810 if( !ImplHasAccessibleListeners() )
811 return;
813 // focus event (deselect)
814 if( nOldItem )
816 const size_t nPos = GetItemPos( nItemId );
818 if( nPos != VALUESET_ITEM_NOTFOUND )
820 ValueItemAcc* pItemAcc = ValueItemAcc::getImplementation(
821 mItemList[nPos]->GetAccessible( false/*bIsTransientChildrenDisabled*/ ) );
823 if( pItemAcc )
825 Any aOldAny;
826 Any aNewAny;
827 aOldAny <<= Reference<XInterface>(static_cast<cppu::OWeakObject*>(pItemAcc));
828 ImplFireAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny );
833 // focus event (select)
834 const size_t nPos = GetItemPos( mnSelItemId );
836 ValueSetItem* pItem;
837 if( nPos != VALUESET_ITEM_NOTFOUND )
838 pItem = mItemList[nPos].get();
839 else
840 pItem = mpNoneItem.get();
842 ValueItemAcc* pItemAcc = nullptr;
843 if (pItem != nullptr)
844 pItemAcc = ValueItemAcc::getImplementation( pItem->GetAccessible( false/*bIsTransientChildrenDisabled*/ ) );
846 if( pItemAcc )
848 Any aOldAny;
849 Any aNewAny;
850 aNewAny <<= Reference<XInterface>(static_cast<cppu::OWeakObject*>(pItemAcc));
851 ImplFireAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny);
854 // selection event
855 Any aOldAny;
856 Any aNewAny;
857 ImplFireAccessibleEvent(AccessibleEventId::SELECTION_CHANGED, aOldAny, aNewAny);
860 void ValueSet::SetNoSelection()
862 mbNoSelection = true;
863 mbHighlight = false;
865 if (IsReallyVisible() && IsUpdateMode())
866 Invalidate();
869 void ValueSet::SetStyle(WinBits nStyle)
871 if (nStyle != mnStyle)
873 mnStyle = nStyle;
874 mbFormat = true;
875 Invalidate();
879 void ValueSet::Format(vcl::RenderContext const & rRenderContext)
881 Size aWinSize(GetOutputSizePixel());
882 size_t nItemCount = mItemList.size();
883 WinBits nStyle = GetStyle();
884 tools::Long nTxtHeight = rRenderContext.GetTextHeight();
885 tools::Long nOff;
886 tools::Long nNoneHeight;
887 tools::Long nNoneSpace;
889 if (mxScrolledWindow && !(nStyle & WB_VSCROLL) && mxScrolledWindow->get_vpolicy() != VclPolicyType::NEVER)
890 TurnOffScrollBar();
892 // calculate item offset
893 if (nStyle & WB_ITEMBORDER)
895 if (nStyle & WB_DOUBLEBORDER)
896 nOff = ITEM_OFFSET_DOUBLE;
897 else
898 nOff = ITEM_OFFSET;
900 else
901 nOff = 0;
903 // consider size, if NameField does exist
904 if (nStyle & WB_NAMEFIELD)
906 mnTextOffset = aWinSize.Height() - nTxtHeight - NAME_OFFSET;
907 aWinSize.AdjustHeight( -(nTxtHeight + NAME_OFFSET) );
909 if (!(nStyle & WB_FLATVALUESET))
911 mnTextOffset -= NAME_LINE_HEIGHT + NAME_LINE_OFF_Y;
912 aWinSize.AdjustHeight( -(NAME_LINE_HEIGHT + NAME_LINE_OFF_Y) );
915 else
916 mnTextOffset = 0;
918 // consider offset and size, if NoneField does exist
919 if (nStyle & WB_NONEFIELD)
921 nNoneHeight = nTxtHeight + nOff;
922 nNoneSpace = mnSpacing;
924 else
926 nNoneHeight = 0;
927 nNoneSpace = 0;
928 mpNoneItem.reset();
931 // calculate number of columns
932 if (!mnUserCols)
934 if (mnUserItemWidth)
936 mnCols = static_cast<sal_uInt16>((aWinSize.Width() - mnSpacing) / (mnUserItemWidth + mnSpacing));
937 if (mnCols <= 0)
938 mnCols = 1;
940 else
942 mnCols = 1;
945 else
947 mnCols = mnUserCols;
950 // calculate number of rows
951 mbScroll = false;
953 auto nOldLines = mnLines;
954 // Floor( (M+N-1)/N )==Ceiling( M/N )
955 mnLines = (static_cast<tools::Long>(nItemCount) + mnCols - 1) / mnCols;
956 if (mnLines <= 0)
957 mnLines = 1;
959 bool bAdjustmentOutOfDate = nOldLines != mnLines;
961 auto nOldVisLines = mnVisLines;
963 tools::Long nCalcHeight = aWinSize.Height() - nNoneHeight;
964 if (mnUserVisLines)
966 mnVisLines = mnUserVisLines;
968 else if (mnUserItemHeight)
970 mnVisLines = (nCalcHeight - nNoneSpace + mnSpacing) / (mnUserItemHeight + mnSpacing);
971 if (!mnVisLines)
972 mnVisLines = 1;
974 else
976 mnVisLines = mnLines;
979 bAdjustmentOutOfDate |= nOldVisLines != mnVisLines;
981 if (mnLines > mnVisLines)
982 mbScroll = true;
984 if (mnLines <= mnVisLines)
986 SetFirstLine(0);
988 else
990 if (mnFirstLine > o3tl::make_unsigned(mnLines - mnVisLines))
991 SetFirstLine(static_cast<sal_uInt16>(mnLines - mnVisLines));
994 // calculate item size
995 const tools::Long nColSpace = (mnCols - 1) * static_cast<tools::Long>(mnSpacing);
996 const tools::Long nLineSpace = ((mnVisLines - 1) * mnSpacing) + nNoneSpace;
997 if (mnUserItemWidth && !mnUserCols)
999 mnItemWidth = mnUserItemWidth;
1000 if (mnItemWidth > aWinSize.Width() - nColSpace)
1001 mnItemWidth = aWinSize.Width() - nColSpace;
1003 else
1004 mnItemWidth = (aWinSize.Width() - nColSpace) / mnCols;
1005 if (mnUserItemHeight && !mnUserVisLines)
1007 mnItemHeight = mnUserItemHeight;
1008 if (mnItemHeight > nCalcHeight - nNoneSpace)
1009 mnItemHeight = nCalcHeight - nNoneSpace;
1011 else
1013 nCalcHeight -= nLineSpace;
1014 mnItemHeight = nCalcHeight / mnVisLines;
1017 // Init VirDev
1018 maVirDev->SetSettings(rRenderContext.GetSettings());
1019 maVirDev->SetOutputSizePixel(aWinSize);
1021 // nothing is changed in case of too small items
1022 if ((mnItemWidth <= 0) ||
1023 (mnItemHeight <= ((nStyle & WB_ITEMBORDER) ? 4 : 2)) ||
1024 !nItemCount)
1026 mbHasVisibleItems = false;
1028 if ((nStyle & WB_NONEFIELD) && mpNoneItem)
1030 mpNoneItem->mbVisible = false;
1031 mpNoneItem->maText = GetText();
1034 for (size_t i = 0; i < nItemCount; i++)
1036 mItemList[i]->mbVisible = false;
1039 if (mxScrolledWindow && mxScrolledWindow->get_vpolicy() != VclPolicyType::NEVER)
1040 TurnOffScrollBar();
1042 else
1044 mbHasVisibleItems = true;
1046 // determine Frame-Style
1047 if (nStyle & WB_DOUBLEBORDER)
1048 mnFrameStyle = DrawFrameStyle::DoubleIn;
1049 else
1050 mnFrameStyle = DrawFrameStyle::In;
1052 // determine selected color and width
1053 // if necessary change the colors, to make the selection
1054 // better detectable
1055 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1056 Color aHighColor(rStyleSettings.GetHighlightColor());
1057 if (((aHighColor.GetRed() > 0x80) || (aHighColor.GetGreen() > 0x80) ||
1058 (aHighColor.GetBlue() > 0x80)) ||
1059 ((aHighColor.GetRed() == 0x80) && (aHighColor.GetGreen() == 0x80) &&
1060 (aHighColor.GetBlue() == 0x80)))
1062 mbBlackSel = true;
1064 else
1066 mbBlackSel = false;
1068 // draw the selection with double width if the items are bigger
1069 if ((nStyle & WB_DOUBLEBORDER) &&
1070 ((mnItemWidth >= 25) && (mnItemHeight >= 20)))
1072 mbDoubleSel = true;
1074 else
1076 mbDoubleSel = false;
1079 // calculate offsets
1080 tools::Long nStartX;
1081 tools::Long nStartY;
1082 if (mbFullMode)
1084 tools::Long nAllItemWidth = (mnItemWidth * mnCols) + nColSpace;
1085 tools::Long nAllItemHeight = (mnItemHeight * mnVisLines) + nNoneHeight + nLineSpace;
1086 nStartX = (aWinSize.Width() - nAllItemWidth) / 2;
1087 nStartY = (aWinSize.Height() - nAllItemHeight) / 2;
1089 else
1091 nStartX = 0;
1092 nStartY = 0;
1095 // calculate and draw items
1096 maVirDev->SetLineColor();
1097 tools::Long x = nStartX;
1098 tools::Long y = nStartY;
1100 // create NoSelection field and show it
1101 if (nStyle & WB_NONEFIELD)
1103 if (!mpNoneItem)
1104 mpNoneItem.reset(new ValueSetItem(*this));
1106 mpNoneItem->mnId = 0;
1107 mpNoneItem->meType = VALUESETITEM_NONE;
1108 mpNoneItem->mbVisible = true;
1109 maNoneItemRect.SetLeft( x );
1110 maNoneItemRect.SetTop( y );
1111 maNoneItemRect.SetRight( maNoneItemRect.Left() + aWinSize.Width() - x - 1 );
1112 maNoneItemRect.SetBottom( y + nNoneHeight - 1 );
1114 ImplFormatItem(rRenderContext, mpNoneItem.get(), maNoneItemRect);
1116 y += nNoneHeight + nNoneSpace;
1119 // draw items
1120 sal_uLong nFirstItem = static_cast<sal_uLong>(mnFirstLine) * mnCols;
1121 sal_uLong nLastItem = nFirstItem + (mnVisLines * mnCols);
1123 maItemListRect.SetLeft( x );
1124 maItemListRect.SetTop( y );
1125 maItemListRect.SetRight( x + mnCols * (mnItemWidth + mnSpacing) - mnSpacing - 1 );
1126 maItemListRect.SetBottom( y + mnVisLines * (mnItemHeight + mnSpacing) - mnSpacing - 1 );
1128 if (!mbFullMode)
1130 // If want also draw parts of items in the last line,
1131 // then we add one more line if parts of these line are
1132 // visible
1133 if (y + (mnVisLines * (mnItemHeight + mnSpacing)) < aWinSize.Height())
1134 nLastItem += mnCols;
1135 maItemListRect.SetBottom( aWinSize.Height() - y );
1137 for (size_t i = 0; i < nItemCount; i++)
1139 ValueSetItem* pItem = mItemList[i].get();
1141 if (i >= nFirstItem && i < nLastItem)
1143 if (!pItem->mbVisible && ImplHasAccessibleListeners())
1145 Any aOldAny;
1146 Any aNewAny;
1148 aNewAny <<= pItem->GetAccessible(false/*bIsTransientChildrenDisabled*/);
1149 ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny);
1152 pItem->mbVisible = true;
1153 ImplFormatItem(rRenderContext, pItem, tools::Rectangle(Point(x, y), Size(mnItemWidth, mnItemHeight)));
1155 if (!((i + 1) % mnCols))
1157 x = nStartX;
1158 y += mnItemHeight + mnSpacing;
1160 else
1161 x += mnItemWidth + mnSpacing;
1163 else
1165 if (pItem->mbVisible && ImplHasAccessibleListeners())
1167 Any aOldAny;
1168 Any aNewAny;
1170 aOldAny <<= pItem->GetAccessible(false/*bIsTransientChildrenDisabled*/);
1171 ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny);
1174 pItem->mbVisible = false;
1178 // arrange ScrollBar, set values and show it
1179 if (mxScrolledWindow && (nStyle & WB_VSCROLL))
1181 bool bTurnScrollbarOn = mxScrolledWindow->get_vpolicy() != VclPolicyType::ALWAYS;
1182 if (bAdjustmentOutOfDate || bTurnScrollbarOn)
1184 tools::Long nPageSize = mnVisLines;
1185 if (nPageSize < 1)
1186 nPageSize = 1;
1187 mxScrolledWindow->vadjustment_configure(mnFirstLine, 0, mnLines, 1,
1188 mnVisLines, nPageSize);
1191 if (bTurnScrollbarOn)
1192 TurnOnScrollBar();
1196 // waiting for the next since the formatting is finished
1197 mbFormat = false;
1200 void ValueSet::ImplDrawSelect(vcl::RenderContext& rRenderContext)
1202 if (!IsReallyVisible())
1203 return;
1205 const bool bFocus = HasFocus();
1206 const bool bDrawSel = !((mbNoSelection && !mbHighlight) || (!mbDrawSelection && mbHighlight));
1208 if (!bFocus && !bDrawSel)
1210 ImplDrawItemText(rRenderContext, OUString());
1211 return;
1214 ImplDrawSelect(rRenderContext, mnSelItemId, bFocus, bDrawSel);
1215 if (mbHighlight)
1217 ImplDrawSelect(rRenderContext, mnHighItemId, bFocus, bDrawSel);
1221 void ValueSet::ImplDrawSelect(vcl::RenderContext& rRenderContext, sal_uInt16 nItemId, const bool bFocus, const bool bDrawSel )
1223 ValueSetItem* pItem;
1224 tools::Rectangle aRect;
1225 if (nItemId)
1227 const size_t nPos = GetItemPos( nItemId );
1228 pItem = mItemList[ nPos ].get();
1229 aRect = ImplGetItemRect( nPos );
1231 else if (mpNoneItem)
1233 pItem = mpNoneItem.get();
1234 aRect = maNoneItemRect;
1236 else if (bFocus && (pItem = ImplGetFirstItem()))
1238 aRect = ImplGetItemRect(0);
1240 else
1242 return;
1245 if (!pItem->mbVisible)
1246 return;
1248 // draw selection
1249 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1250 rRenderContext.SetFillColor();
1252 Color aDoubleColor(rStyleSettings.GetHighlightColor());
1253 Color aSingleColor(rStyleSettings.GetHighlightTextColor());
1254 if (!mbDoubleSel)
1257 * #99777# contrast enhancement for thin mode
1259 const Wallpaper& rWall = maVirDev->GetBackground();
1260 if (!rWall.IsBitmap() && ! rWall.IsGradient())
1262 const Color& rBack = rWall.GetColor();
1263 if (rBack.IsDark() && ! aDoubleColor.IsBright())
1265 aDoubleColor = COL_WHITE;
1266 aSingleColor = COL_BLACK;
1268 else if (rBack.IsBright() && !aDoubleColor.IsDark())
1270 aDoubleColor = COL_BLACK;
1271 aSingleColor = COL_WHITE;
1276 // specify selection output
1277 WinBits nStyle = GetStyle();
1278 if (nStyle & WB_MENUSTYLEVALUESET)
1280 if (bFocus)
1281 DrawFocusRect(rRenderContext, aRect);
1282 if (bDrawSel)
1284 rRenderContext.SetLineColor(mbBlackSel ? COL_BLACK : aDoubleColor);
1285 rRenderContext.DrawRect(aRect);
1288 else
1290 if (bDrawSel)
1292 rRenderContext.SetLineColor(mbBlackSel ? COL_BLACK : aDoubleColor);
1293 rRenderContext.DrawRect(aRect);
1295 if (mbDoubleSel)
1297 aRect.AdjustLeft( 1 );
1298 aRect.AdjustTop( 1 );
1299 aRect.AdjustRight( -1 );
1300 aRect.AdjustBottom( -1 );
1301 if (bDrawSel)
1302 rRenderContext.DrawRect(aRect);
1304 aRect.AdjustLeft( 1 );
1305 aRect.AdjustTop( 1 );
1306 aRect.AdjustRight( -1 );
1307 aRect.AdjustBottom( -1 );
1308 tools::Rectangle aRect2 = aRect;
1309 aRect.AdjustLeft( 1 );
1310 aRect.AdjustTop( 1 );
1311 aRect.AdjustRight( -1 );
1312 aRect.AdjustBottom( -1 );
1313 if (bDrawSel)
1314 rRenderContext.DrawRect(aRect);
1315 if (mbDoubleSel)
1317 aRect.AdjustLeft( 1 );
1318 aRect.AdjustTop( 1 );
1319 aRect.AdjustRight( -1 );
1320 aRect.AdjustBottom( -1 );
1321 if (bDrawSel)
1322 rRenderContext.DrawRect(aRect);
1325 if (bDrawSel)
1327 rRenderContext.SetLineColor(mbBlackSel ? COL_WHITE : aSingleColor);
1329 else
1331 rRenderContext.SetLineColor(COL_LIGHTGRAY);
1333 rRenderContext.DrawRect(aRect2);
1334 if (bFocus)
1335 DrawFocusRect(rRenderContext, aRect2);
1338 ImplDrawItemText(rRenderContext, pItem->maText);
1341 void ValueSet::ImplFormatItem(vcl::RenderContext const & rRenderContext, ValueSetItem* pItem, tools::Rectangle aRect)
1343 WinBits nStyle = GetStyle();
1344 if (nStyle & WB_ITEMBORDER)
1346 aRect.AdjustLeft(1 );
1347 aRect.AdjustTop(1 );
1348 aRect.AdjustRight( -1 );
1349 aRect.AdjustBottom( -1 );
1351 if (nStyle & WB_FLATVALUESET)
1353 sal_Int32 nBorder = (nStyle & WB_DOUBLEBORDER) ? 2 : 1;
1355 aRect.AdjustLeft(nBorder );
1356 aRect.AdjustTop(nBorder );
1357 aRect.AdjustRight( -nBorder );
1358 aRect.AdjustBottom( -nBorder );
1360 else
1362 DecorationView aView(maVirDev.get());
1363 aRect = aView.DrawFrame(aRect, mnFrameStyle);
1367 if (pItem == mpNoneItem.get())
1368 pItem->maText = GetText();
1370 if ((aRect.GetHeight() <= 0) || (aRect.GetWidth() <= 0))
1371 return;
1373 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1375 if (pItem == mpNoneItem.get())
1377 maVirDev->SetFont(rRenderContext.GetFont());
1378 maVirDev->SetTextColor((nStyle & WB_MENUSTYLEVALUESET) ? rStyleSettings.GetMenuTextColor() : rStyleSettings.GetWindowTextColor());
1379 maVirDev->SetTextFillColor();
1380 maVirDev->SetFillColor((nStyle & WB_MENUSTYLEVALUESET) ? rStyleSettings.GetMenuColor() : rStyleSettings.GetWindowColor());
1381 maVirDev->DrawRect(aRect);
1382 Point aTxtPos(aRect.Left() + 2, aRect.Top());
1383 tools::Long nTxtWidth = rRenderContext.GetTextWidth(pItem->maText);
1384 if ((aTxtPos.X() + nTxtWidth) > aRect.Right())
1386 maVirDev->SetClipRegion(vcl::Region(aRect));
1387 maVirDev->DrawText(aTxtPos, pItem->maText);
1388 maVirDev->SetClipRegion();
1390 else
1391 maVirDev->DrawText(aTxtPos, pItem->maText);
1393 else if (pItem->meType == VALUESETITEM_COLOR)
1395 maVirDev->SetFillColor(pItem->maColor);
1396 maVirDev->DrawRect(aRect);
1398 else
1400 if (IsColor())
1401 maVirDev->SetFillColor(maColor);
1402 else if (nStyle & WB_MENUSTYLEVALUESET)
1403 maVirDev->SetFillColor(rStyleSettings.GetMenuColor());
1404 else if (IsEnabled())
1405 maVirDev->SetFillColor(rStyleSettings.GetWindowColor());
1406 else
1407 maVirDev->SetFillColor(rStyleSettings.GetFaceColor());
1408 maVirDev->DrawRect(aRect);
1410 if (pItem->meType == VALUESETITEM_USERDRAW)
1412 UserDrawEvent aUDEvt(nullptr, maVirDev.get(), aRect, pItem->mnId);
1413 UserDraw(aUDEvt);
1415 else
1417 Size aImageSize = pItem->maImage.GetSizePixel();
1418 Size aRectSize = aRect.GetSize();
1419 Point aPos(aRect.Left(), aRect.Top());
1420 aPos.AdjustX((aRectSize.Width() - aImageSize.Width()) / 2 );
1422 if (pItem->meType != VALUESETITEM_IMAGE_AND_TEXT)
1423 aPos.AdjustY((aRectSize.Height() - aImageSize.Height()) / 2 );
1425 DrawImageFlags nImageStyle = DrawImageFlags::NONE;
1426 if (!IsEnabled())
1427 nImageStyle |= DrawImageFlags::Disable;
1429 if (aImageSize.Width() > aRectSize.Width() ||
1430 aImageSize.Height() > aRectSize.Height())
1432 maVirDev->SetClipRegion(vcl::Region(aRect));
1433 maVirDev->DrawImage(aPos, pItem->maImage, nImageStyle);
1434 maVirDev->SetClipRegion();
1436 else
1437 maVirDev->DrawImage(aPos, pItem->maImage, nImageStyle);
1439 if (pItem->meType == VALUESETITEM_IMAGE_AND_TEXT)
1441 maVirDev->SetFont(rRenderContext.GetFont());
1442 maVirDev->SetTextColor((nStyle & WB_MENUSTYLEVALUESET) ? rStyleSettings.GetMenuTextColor() : rStyleSettings.GetWindowTextColor());
1443 maVirDev->SetTextFillColor();
1445 tools::Long nTxtWidth = maVirDev->GetTextWidth(pItem->maText);
1447 if (nTxtWidth > aRect.GetWidth())
1448 maVirDev->SetClipRegion(vcl::Region(aRect));
1450 maVirDev->DrawText(Point(aRect.Left() +
1451 (aRect.GetWidth() - nTxtWidth) / 2,
1452 aRect.Bottom() - maVirDev->GetTextHeight()),
1453 pItem->maText);
1455 if (nTxtWidth > aRect.GetWidth())
1456 maVirDev->SetClipRegion();
1461 const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
1463 if (nEdgeBlendingPercent)
1465 const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
1466 const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
1467 const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
1468 const BitmapEx aBlendFrame(createBlendFrame(aRect.GetSize(), nAlpha, rTopLeft, rBottomRight));
1470 if (!aBlendFrame.IsEmpty())
1472 maVirDev->DrawBitmapEx(aRect.TopLeft(), aBlendFrame);
1477 void ValueSet::ImplDrawItemText(vcl::RenderContext& rRenderContext, const OUString& rText)
1479 if (!(GetStyle() & WB_NAMEFIELD))
1480 return;
1482 Size aWinSize(GetOutputSizePixel());
1483 tools::Long nTxtWidth = rRenderContext.GetTextWidth(rText);
1484 tools::Long nTxtOffset = mnTextOffset;
1486 // delete rectangle and show text
1487 if (GetStyle() & WB_FLATVALUESET)
1489 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1490 rRenderContext.SetLineColor();
1491 rRenderContext.SetFillColor(rStyleSettings.GetFaceColor());
1492 rRenderContext.DrawRect(tools::Rectangle(Point(0, nTxtOffset), Point(aWinSize.Width(), aWinSize.Height())));
1493 rRenderContext.SetTextColor(rStyleSettings.GetButtonTextColor());
1495 else
1497 nTxtOffset += NAME_LINE_HEIGHT+NAME_LINE_OFF_Y;
1498 rRenderContext.SetBackground(Application::GetSettings().GetStyleSettings().GetFaceColor());
1499 rRenderContext.Erase(tools::Rectangle(Point(0, nTxtOffset), Point(aWinSize.Width(), aWinSize.Height())));
1501 rRenderContext.DrawText(Point((aWinSize.Width() - nTxtWidth) / 2, nTxtOffset + (NAME_OFFSET / 2)), rText);
1504 void ValueSet::StyleUpdated()
1506 mbFormat = true;
1507 CustomWidgetController::StyleUpdated();
1510 void ValueSet::EnableFullItemMode( bool bFullMode )
1512 mbFullMode = bFullMode;
1515 void ValueSet::SetColCount( sal_uInt16 nNewCols )
1517 if ( mnUserCols != nNewCols )
1519 mnUserCols = nNewCols;
1520 QueueReformat();
1524 void ValueSet::SetItemImage( sal_uInt16 nItemId, const Image& rImage )
1526 size_t nPos = GetItemPos( nItemId );
1528 if ( nPos == VALUESET_ITEM_NOTFOUND )
1529 return;
1531 ValueSetItem* pItem = mItemList[nPos].get();
1532 pItem->meType = VALUESETITEM_IMAGE;
1533 pItem->maImage = rImage;
1535 if ( !mbFormat && IsReallyVisible() && IsUpdateMode() )
1537 const tools::Rectangle aRect = ImplGetItemRect(nPos);
1538 Invalidate(aRect);
1540 else
1541 mbFormat = true;
1544 void ValueSet::SetItemColor( sal_uInt16 nItemId, const Color& rColor )
1546 size_t nPos = GetItemPos( nItemId );
1548 if ( nPos == VALUESET_ITEM_NOTFOUND )
1549 return;
1551 ValueSetItem* pItem = mItemList[nPos].get();
1552 pItem->meType = VALUESETITEM_COLOR;
1553 pItem->maColor = rColor;
1555 if ( !mbFormat && IsReallyVisible() && IsUpdateMode() )
1557 const tools::Rectangle aRect = ImplGetItemRect(nPos);
1558 Invalidate( aRect );
1560 else
1561 mbFormat = true;
1564 Color ValueSet::GetItemColor( sal_uInt16 nItemId ) const
1566 size_t nPos = GetItemPos( nItemId );
1568 if ( nPos != VALUESET_ITEM_NOTFOUND )
1569 return mItemList[nPos]->maColor;
1570 else
1571 return Color();
1574 Size ValueSet::CalcWindowSizePixel( const Size& rItemSize, sal_uInt16 nDesireCols,
1575 sal_uInt16 nDesireLines ) const
1577 size_t nCalcCols = nDesireCols;
1578 size_t nCalcLines = nDesireLines;
1580 if ( !nCalcCols )
1582 if ( mnUserCols )
1583 nCalcCols = mnUserCols;
1584 else
1585 nCalcCols = 1;
1588 if ( !nCalcLines )
1590 nCalcLines = mnVisLines;
1592 if ( mbFormat )
1594 if ( mnUserVisLines )
1595 nCalcLines = mnUserVisLines;
1596 else
1598 // Floor( (M+N-1)/N )==Ceiling( M/N )
1599 nCalcLines = (mItemList.size()+nCalcCols-1) / nCalcCols;
1600 if ( !nCalcLines )
1601 nCalcLines = 1;
1606 Size aSize( rItemSize.Width() * nCalcCols, rItemSize.Height() * nCalcLines );
1607 WinBits nStyle = GetStyle();
1608 tools::Long nTxtHeight = GetTextHeight();
1609 tools::Long n;
1611 if ( nStyle & WB_ITEMBORDER )
1613 if ( nStyle & WB_DOUBLEBORDER )
1614 n = ITEM_OFFSET_DOUBLE;
1615 else
1616 n = ITEM_OFFSET;
1618 aSize.AdjustWidth(n * nCalcCols );
1619 aSize.AdjustHeight(n * nCalcLines );
1621 else
1622 n = 0;
1624 if ( mnSpacing )
1626 aSize.AdjustWidth(mnSpacing * (nCalcCols - 1) );
1627 aSize.AdjustHeight(mnSpacing * (nCalcLines - 1) );
1630 if ( nStyle & WB_NAMEFIELD )
1632 aSize.AdjustHeight(nTxtHeight + NAME_OFFSET );
1633 if ( !(nStyle & WB_FLATVALUESET) )
1634 aSize.AdjustHeight(NAME_LINE_HEIGHT + NAME_LINE_OFF_Y );
1637 if ( nStyle & WB_NONEFIELD )
1639 aSize.AdjustHeight(nTxtHeight + n + mnSpacing );
1642 return aSize;
1645 void ValueSet::InsertItem( sal_uInt16 nItemId, const Image& rImage )
1647 std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1648 pItem->mnId = nItemId;
1649 pItem->meType = VALUESETITEM_IMAGE;
1650 pItem->maImage = rImage;
1651 ImplInsertItem( std::move(pItem), VALUESET_APPEND );
1654 void ValueSet::InsertItem( sal_uInt16 nItemId, const Image& rImage,
1655 const OUString& rText, size_t nPos,
1656 bool bShowLegend )
1658 std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1659 pItem->mnId = nItemId;
1660 pItem->meType = bShowLegend ? VALUESETITEM_IMAGE_AND_TEXT : VALUESETITEM_IMAGE;
1661 pItem->maImage = rImage;
1662 pItem->maText = rText;
1663 ImplInsertItem( std::move(pItem), nPos );
1666 void ValueSet::InsertItem( sal_uInt16 nItemId, size_t nPos )
1668 std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1669 pItem->mnId = nItemId;
1670 pItem->meType = VALUESETITEM_USERDRAW;
1671 ImplInsertItem( std::move(pItem), nPos );
1674 void ValueSet::InsertItem( sal_uInt16 nItemId, const Color& rColor,
1675 const OUString& rText )
1677 std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1678 pItem->mnId = nItemId;
1679 pItem->meType = VALUESETITEM_COLOR;
1680 pItem->maColor = rColor;
1681 pItem->maText = rText;
1682 ImplInsertItem( std::move(pItem), VALUESET_APPEND );
1685 void ValueSet::ImplInsertItem( std::unique_ptr<ValueSetItem> pItem, const size_t nPos )
1687 DBG_ASSERT( pItem->mnId, "ValueSet::InsertItem(): ItemId == 0" );
1688 DBG_ASSERT( GetItemPos( pItem->mnId ) == VALUESET_ITEM_NOTFOUND,
1689 "ValueSet::InsertItem(): ItemId already exists" );
1691 if ( nPos < mItemList.size() ) {
1692 mItemList.insert( mItemList.begin() + nPos, std::move(pItem) );
1693 } else {
1694 mItemList.push_back( std::move(pItem) );
1697 QueueReformat();
1700 int ValueSet::GetScrollWidth() const
1702 if (mxScrolledWindow)
1703 return mxScrolledWindow->get_vscroll_width();
1704 return 0;
1707 void ValueSet::SetEdgeBlending(bool bNew)
1709 if(mbEdgeBlending != bNew)
1711 mbEdgeBlending = bNew;
1712 mbFormat = true;
1714 if (GetDrawingArea() && IsReallyVisible() && IsUpdateMode())
1716 Invalidate();
1721 Size ValueSet::CalcItemSizePixel( const Size& rItemSize) const
1723 Size aSize = rItemSize;
1725 WinBits nStyle = GetStyle();
1726 if ( nStyle & WB_ITEMBORDER )
1728 tools::Long n;
1730 if ( nStyle & WB_DOUBLEBORDER )
1731 n = ITEM_OFFSET_DOUBLE;
1732 else
1733 n = ITEM_OFFSET;
1735 aSize.AdjustWidth(n );
1736 aSize.AdjustHeight(n );
1739 return aSize;
1742 void ValueSet::SetLineCount( sal_uInt16 nNewLines )
1744 if ( mnUserVisLines != nNewLines )
1746 mnUserVisLines = nNewLines;
1747 QueueReformat();
1751 void ValueSet::SetItemWidth( tools::Long nNewItemWidth )
1753 if ( mnUserItemWidth != nNewItemWidth )
1755 mnUserItemWidth = nNewItemWidth;
1756 QueueReformat();
1760 //method to set accessible when the style is user draw.
1761 void ValueSet::InsertItem( sal_uInt16 nItemId, const OUString& rText, size_t nPos )
1763 DBG_ASSERT( nItemId, "ValueSet::InsertItem(): ItemId == 0" );
1764 DBG_ASSERT( GetItemPos( nItemId ) == VALUESET_ITEM_NOTFOUND,
1765 "ValueSet::InsertItem(): ItemId already exists" );
1766 std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1767 pItem->mnId = nItemId;
1768 pItem->meType = VALUESETITEM_USERDRAW;
1769 pItem->maText = rText;
1770 ImplInsertItem( std::move(pItem), nPos );
1773 void ValueSet::SetItemHeight( tools::Long nNewItemHeight )
1775 if ( mnUserItemHeight != nNewItemHeight )
1777 mnUserItemHeight = nNewItemHeight;
1778 QueueReformat();
1782 OUString ValueSet::RequestHelp(tools::Rectangle& rHelpRect)
1784 Point aPos = rHelpRect.TopLeft();
1785 const size_t nItemPos = ImplGetItem( aPos );
1786 OUString sRet;
1787 if (nItemPos != VALUESET_ITEM_NOTFOUND)
1789 rHelpRect = ImplGetItemRect(nItemPos);
1790 sRet = GetItemText(ImplGetItem(nItemPos)->mnId);
1792 return sRet;
1795 OUString ValueSet::GetItemText(sal_uInt16 nItemId) const
1797 const size_t nPos = GetItemPos(nItemId);
1799 if ( nPos != VALUESET_ITEM_NOTFOUND )
1800 return mItemList[nPos]->maText;
1802 return OUString();
1805 void ValueSet::SetExtraSpacing( sal_uInt16 nNewSpacing )
1807 if ( GetStyle() & WB_ITEMBORDER )
1809 mnSpacing = nNewSpacing;
1810 QueueReformat();
1814 void ValueSet::SetFormat()
1816 mbFormat = true;
1819 void ValueSet::SetItemData( sal_uInt16 nItemId, void* pData )
1821 size_t nPos = GetItemPos( nItemId );
1823 if ( nPos == VALUESET_ITEM_NOTFOUND )
1824 return;
1826 ValueSetItem* pItem = mItemList[nPos].get();
1827 pItem->mpData = pData;
1829 if ( pItem->meType == VALUESETITEM_USERDRAW )
1831 if ( !mbFormat && IsReallyVisible() && IsUpdateMode() )
1833 const tools::Rectangle aRect = ImplGetItemRect(nPos);
1834 Invalidate(aRect);
1836 else
1837 mbFormat = true;
1841 void* ValueSet::GetItemData( sal_uInt16 nItemId ) const
1843 size_t nPos = GetItemPos( nItemId );
1845 if ( nPos != VALUESET_ITEM_NOTFOUND )
1846 return mItemList[nPos]->mpData;
1847 else
1848 return nullptr;
1851 void ValueSet::SetItemText(sal_uInt16 nItemId, const OUString& rText)
1853 size_t nPos = GetItemPos( nItemId );
1855 if ( nPos == VALUESET_ITEM_NOTFOUND )
1856 return;
1858 ValueSetItem* pItem = mItemList[nPos].get();
1860 // Remember old and new name for accessibility event.
1861 Any aOldName;
1862 Any aNewName;
1863 OUString sString (pItem->maText);
1864 aOldName <<= sString;
1865 sString = rText;
1866 aNewName <<= sString;
1868 pItem->maText = rText;
1870 if (!mbFormat && IsReallyVisible() && IsUpdateMode())
1872 sal_uInt16 nTempId = mnSelItemId;
1874 if (mbHighlight)
1875 nTempId = mnHighItemId;
1877 if (nTempId == nItemId)
1878 Invalidate();
1881 if (ImplHasAccessibleListeners())
1883 Reference<XAccessible> xAccessible(pItem->GetAccessible( false/*bIsTransientChildrenDisabled*/));
1884 ValueItemAcc* pValueItemAcc = static_cast<ValueItemAcc*>(xAccessible.get());
1885 pValueItemAcc->FireAccessibleEvent(AccessibleEventId::NAME_CHANGED, aOldName, aNewName);
1889 Size ValueSet::GetLargestItemSize()
1891 Size aLargestItem;
1893 for (const std::unique_ptr<ValueSetItem>& pItem : mItemList)
1895 if (!pItem->mbVisible)
1896 continue;
1898 if (pItem->meType != VALUESETITEM_IMAGE &&
1899 pItem->meType != VALUESETITEM_IMAGE_AND_TEXT)
1901 // handle determining an optimal size for this case
1902 continue;
1905 Size aSize = pItem->maImage.GetSizePixel();
1906 if (pItem->meType == VALUESETITEM_IMAGE_AND_TEXT)
1908 aSize.AdjustHeight(3 * NAME_LINE_HEIGHT +
1909 maVirDev->GetTextHeight() );
1910 aSize.setWidth( std::max(aSize.Width(),
1911 maVirDev->GetTextWidth(pItem->maText) + NAME_OFFSET) );
1914 aLargestItem.setWidth( std::max(aLargestItem.Width(), aSize.Width()) );
1915 aLargestItem.setHeight( std::max(aLargestItem.Height(), aSize.Height()) );
1918 return aLargestItem;
1921 void ValueSet::SetOptimalSize()
1923 Size aLargestSize(GetLargestItemSize());
1924 aLargestSize.setWidth(std::max(aLargestSize.Width(), mnUserItemWidth));
1925 aLargestSize.setHeight(std::max(aLargestSize.Height(), mnUserItemHeight));
1926 Size aPrefSize(CalcWindowSizePixel(aLargestSize));
1927 GetDrawingArea()->set_size_request(aPrefSize.Width(), aPrefSize.Height());
1930 Image ValueSet::GetItemImage(sal_uInt16 nItemId) const
1932 size_t nPos = GetItemPos( nItemId );
1934 if ( nPos != VALUESET_ITEM_NOTFOUND )
1935 return mItemList[nPos]->maImage;
1936 else
1937 return Image();
1940 void ValueSet::SetColor(const Color& rColor)
1942 maColor = rColor;
1943 mbFormat = true;
1944 if (IsReallyVisible() && IsUpdateMode())
1945 Invalidate();
1948 void ValueSet::Show()
1950 if (mxScrolledWindow)
1951 mxScrolledWindow->show();
1952 CustomWidgetController::Show();
1955 void ValueSet::Hide()
1957 CustomWidgetController::Hide();
1958 if (mxScrolledWindow)
1959 mxScrolledWindow->hide();
1962 FactoryFunction ValueSet::GetUITestFactory() const
1964 return ValueSetUIObject::create;
1967 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */