1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <basegfx/matrix/b2dhommatrix.hxx>
24 #include <basegfx/polygon/b2dpolygontools.hxx>
25 #include <tools/debug.hxx>
26 #include <vcl/canvastools.hxx>
27 #include <vcl/decoview.hxx>
28 #include <vcl/event.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/settings.hxx>
31 #include <vcl/virdev.hxx>
33 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
34 #include <com/sun/star/lang/XComponent.hpp>
35 #include <rtl/ustring.hxx>
36 #include <sal/log.hxx>
37 #include "valueimp.hxx"
39 #include <svtools/valueset.hxx>
41 #include <uiobject.hxx>
42 #include <vcl/uitest/logger.hxx>
43 #include <vcl/uitest/eventdescription.hxx>
45 using namespace css::uno
;
46 using namespace css::lang
;
47 using namespace css::accessibility
;
51 void collectUIInformation( const OUString
& aID
, const OUString
& aParentID
, const OUString
& aPos
)
53 EventDescription aDescription
;
54 aDescription
.aID
= aID
;
55 aDescription
.aParameters
= {{"POS", aPos
}};
56 aDescription
.aAction
= "SELECT";
57 aDescription
.aKeyWord
= "ValueSet";
58 aDescription
.aParent
= aParentID
;
59 UITestLogger::getInstance().logEvent(aDescription
);
65 ITEM_OFFSET_DOUBLE
= 6,
74 ValueSet::ValueSet(std::unique_ptr
<weld::ScrolledWindow
> pScrolledWindow
)
75 : maVirDev( VclPtr
<VirtualDevice
>::Create())
76 , mxScrolledWindow(std::move(pScrolledWindow
))
78 , maColor(COL_TRANSPARENT
)
98 mnFrameStyle
= DrawFrameStyle::NONE
;
103 mbEdgeBlending
= false;
104 mbHasVisibleItems
= false;
106 if (mxScrolledWindow
)
107 mxScrolledWindow
->connect_vadjustment_changed(LINK(this, ValueSet
, ImplScrollHdl
));
110 void ValueSet::SetDrawingArea(weld::DrawingArea
* pDrawingArea
)
112 CustomWidgetController::SetDrawingArea(pDrawingArea
);
113 // #106446#, #106601# force mirroring of virtual device
114 maVirDev
->EnableRTL(pDrawingArea
->get_direction());
117 Reference
<XAccessible
> ValueSet::CreateAccessible()
120 mxAccessible
.set(new ValueSetAcc(this));
124 ValueSet::~ValueSet()
126 Reference
<XComponent
> xComponent(mxAccessible
, UNO_QUERY
);
128 xComponent
->dispose();
133 void ValueSet::ImplDeleteItems()
135 const size_t n
= mItemList
.size();
137 for ( size_t i
= 0; i
< n
; ++i
)
139 ValueSetItem
* pItem
= mItemList
[i
].get();
140 if ( pItem
->mbVisible
&& ImplHasAccessibleListeners() )
145 aOldAny
<<= pItem
->GetAccessible( false/*bIsTransientChildrenDisabled*/ );
146 ImplFireAccessibleEvent(AccessibleEventId::CHILD
, aOldAny
, aNewAny
);
149 mItemList
[i
].reset();
155 void ValueSet::Select()
157 collectUIInformation(GetDrawingArea()->get_buildable_name() , GetDrawingArea()->get_help_id() , OUString::number(GetSelectedItemId()));
158 maSelectHdl
.Call( this );
161 void ValueSet::UserDraw( const UserDrawEvent
& )
165 size_t ValueSet::ImplGetItem( const Point
& rPos
) const
167 if (!mbHasVisibleItems
)
169 return VALUESET_ITEM_NOTFOUND
;
172 if (mpNoneItem
&& maNoneItemRect
.Contains(rPos
))
174 return VALUESET_ITEM_NONEITEM
;
177 if (maItemListRect
.Contains(rPos
))
179 const int xc
= rPos
.X() - maItemListRect
.Left();
180 const int yc
= rPos
.Y() - maItemListRect
.Top();
181 // The point is inside the area of item list,
182 // let's find the containing item.
183 const int col
= xc
/ (mnItemWidth
+ mnSpacing
);
184 const int x
= xc
% (mnItemWidth
+ mnSpacing
);
185 const int row
= yc
/ (mnItemHeight
+ mnSpacing
);
186 const int y
= yc
% (mnItemHeight
+ mnSpacing
);
188 if (x
< mnItemWidth
&& y
< mnItemHeight
)
190 // the point is inside item rect and not inside spacing
191 const size_t item
= (mnFirstLine
+ row
) * static_cast<size_t>(mnCols
) + col
;
192 if (item
< mItemList
.size())
199 return VALUESET_ITEM_NOTFOUND
;
202 ValueSetItem
* ValueSet::ImplGetItem( size_t nPos
)
204 if (nPos
== VALUESET_ITEM_NONEITEM
)
205 return mpNoneItem
.get();
207 return (nPos
< mItemList
.size()) ? mItemList
[nPos
].get() : nullptr;
210 ValueSetItem
* ValueSet::ImplGetFirstItem()
212 return !mItemList
.empty() ? mItemList
[0].get() : nullptr;
215 sal_uInt16
ValueSet::ImplGetVisibleItemCount() const
218 const size_t nItemCount
= mItemList
.size();
220 for ( size_t n
= 0; n
< nItemCount
; ++n
)
222 if ( mItemList
[n
]->mbVisible
)
229 void ValueSet::ImplFireAccessibleEvent( short nEventId
, const Any
& rOldValue
, const Any
& rNewValue
)
231 ValueSetAcc
* pAcc
= ValueSetAcc::getImplementation(mxAccessible
);
234 pAcc
->FireAccessibleEvent( nEventId
, rOldValue
, rNewValue
);
237 bool ValueSet::ImplHasAccessibleListeners() const
239 ValueSetAcc
* pAcc
= ValueSetAcc::getImplementation(mxAccessible
);
240 return( pAcc
&& pAcc
->HasAccessibleListeners() );
243 IMPL_LINK(ValueSet
, ImplScrollHdl
, weld::ScrolledWindow
&, rScrollWin
, void)
245 auto nNewFirstLine
= rScrollWin
.vadjustment_get_value();
246 if ( nNewFirstLine
!= mnFirstLine
)
248 mnFirstLine
= nNewFirstLine
;
254 void ValueSet::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
256 rRenderContext
.SetBackground(Application::GetSettings().GetStyleSettings().GetFaceColor());
257 rRenderContext
.Erase();
258 ImplDraw(rRenderContext
);
261 void ValueSet::GetFocus()
263 SAL_INFO("svtools", "value set getting focus");
265 CustomWidgetController::GetFocus();
267 // Tell the accessible object that we got the focus.
268 ValueSetAcc
* pAcc
= ValueSetAcc::getImplementation(mxAccessible
);
273 void ValueSet::LoseFocus()
275 SAL_INFO("svtools", "value set losing focus");
277 CustomWidgetController::LoseFocus();
279 // Tell the accessible object that we lost the focus.
280 ValueSetAcc
* pAcc
= ValueSetAcc::getImplementation(mxAccessible
);
285 void ValueSet::Resize()
288 if ( IsReallyVisible() && IsUpdateMode() )
290 CustomWidgetController::Resize();
293 bool ValueSet::KeyInput( const KeyEvent
& rKeyEvent
)
295 size_t nLastItem
= mItemList
.size();
297 if ( !nLastItem
|| !ImplGetFirstItem() )
298 return CustomWidgetController::KeyInput(rKeyEvent
);
306 = mnSelItemId
? GetItemPos(mnSelItemId
) : (mpNoneItem
? VALUESET_ITEM_NONEITEM
: 0);
307 size_t nItemPos
= VALUESET_ITEM_NOTFOUND
;
308 size_t nVStep
= mnCols
;
310 switch (rKeyEvent
.GetKeyCode().GetCode())
313 nItemPos
= mpNoneItem
? VALUESET_ITEM_NONEITEM
: 0;
317 nItemPos
= nLastItem
;
321 if (nCurPos
!= VALUESET_ITEM_NONEITEM
)
325 nItemPos
= nCurPos
-1;
329 nItemPos
= VALUESET_ITEM_NONEITEM
;
335 if (nCurPos
< nLastItem
)
337 if (nCurPos
== VALUESET_ITEM_NONEITEM
)
343 nItemPos
= nCurPos
+1;
349 if (rKeyEvent
.GetKeyCode().IsShift() || rKeyEvent
.GetKeyCode().IsMod1() || rKeyEvent
.GetKeyCode().IsMod2())
351 return CustomWidgetController::KeyInput(rKeyEvent
);
353 nVStep
*= mnVisLines
;
356 if (nCurPos
!= VALUESET_ITEM_NONEITEM
)
358 if (nCurPos
== nLastItem
)
360 const size_t nCol
= mnCols
? nLastItem
% mnCols
: 0;
363 // Move to previous row/page, keeping the old column
364 nVStep
-= mnCurCol
- nCol
;
367 if (nCurPos
>= nVStep
)
369 // Go up of a whole page
370 nItemPos
= nCurPos
-nVStep
;
374 nItemPos
= VALUESET_ITEM_NONEITEM
;
376 else if (nCurPos
> mnCols
)
378 // Go to same column in first row
379 nItemPos
= nCurPos
% mnCols
;
385 if (rKeyEvent
.GetKeyCode().IsShift() || rKeyEvent
.GetKeyCode().IsMod1() || rKeyEvent
.GetKeyCode().IsMod2())
387 return CustomWidgetController::KeyInput(rKeyEvent
);
389 nVStep
*= mnVisLines
;
392 if (nCurPos
!= nLastItem
)
394 if (nCurPos
== VALUESET_ITEM_NONEITEM
)
396 nItemPos
= nVStep
-mnCols
+mnCurCol
;
400 nItemPos
= nCurPos
+nVStep
;
402 if (nItemPos
> nLastItem
)
404 nItemPos
= nLastItem
;
410 if (GetStyle() & WB_NO_DIRECTSELECT
)
412 // tdf#142479 on return select the entry the cursor is in
413 // before calling Select
414 if (nCurPos
!= VALUESET_ITEM_NONEITEM
)
416 const sal_uInt16 nItemId
= GetItemId(nCurPos
);
417 if (nItemId
!= mnSelItemId
)
425 return CustomWidgetController::KeyInput(rKeyEvent
);
428 if ( nItemPos
== VALUESET_ITEM_NOTFOUND
)
431 if ( nItemPos
!=VALUESET_ITEM_NONEITEM
&& nItemPos
<nLastItem
)
433 // update current column only in case of a new position
434 // which is also not a "specially" handled one.
435 mnCurCol
= mnCols
? nItemPos
% mnCols
: 0;
437 const sal_uInt16 nItemId
= (nItemPos
!= VALUESET_ITEM_NONEITEM
) ? GetItemId( nItemPos
) : 0;
438 if ( nItemId
!= mnSelItemId
)
440 SelectItem( nItemId
);
441 if (!(GetStyle() & WB_NO_DIRECTSELECT
))
443 // select only if WB_NO_DIRECTSELECT is not set
451 void ValueSet::ImplTracking(bool bLeaveWindow
, const Point
& rPos
)
453 ValueSetItem
* pItem
= bLeaveWindow
? nullptr : ImplGetItem(ImplGetItem(rPos
));
456 if( GetStyle() & WB_MENUSTYLEVALUESET
|| GetStyle() & WB_FLATVALUESET
)
459 ImplHighlightItem(pItem
->mnId
);
463 if( GetStyle() & WB_MENUSTYLEVALUESET
|| GetStyle() & WB_FLATVALUESET
)
466 ImplHighlightItem(0);
470 bool ValueSet::MouseButtonDown( const MouseEvent
& rMouseEvent
)
472 if (rMouseEvent
.IsLeft() && !rMouseEvent
.IsMod2())
474 bool bConsumed
= false;
475 ValueSetItem
* pItem
= ImplGetItem( ImplGetItem( rMouseEvent
.GetPosPixel() ) );
476 if (rMouseEvent
.GetClicks() == 1)
479 SelectItem(pItem
->mnId
);
483 else if (pItem
&& rMouseEvent
.GetClicks() == 2)
485 maDoubleClickHdl
.Call(this);
491 return CustomWidgetController::MouseButtonDown( rMouseEvent
);
494 bool ValueSet::MouseButtonUp( const MouseEvent
& rMouseEvent
)
496 if (rMouseEvent
.IsLeft() && !rMouseEvent
.IsMod2())
498 // tdf#142150 MouseUp seen without previous MouseDown
504 return CustomWidgetController::MouseButtonUp( rMouseEvent
);
507 bool ValueSet::MouseMove(const MouseEvent
& rMouseEvent
)
509 // because of SelectionMode
510 if ((GetStyle() & WB_MENUSTYLEVALUESET
) || (GetStyle() & WB_FLATVALUESET
))
511 ImplTracking(rMouseEvent
.IsLeaveWindow(), rMouseEvent
.GetPosPixel());
512 return CustomWidgetController::MouseMove(rMouseEvent
);
515 void ValueSet::QueueReformat()
520 if ( IsReallyVisible() && IsUpdateMode() )
524 void ValueSet::RemoveItem( sal_uInt16 nItemId
)
526 size_t nPos
= GetItemPos( nItemId
);
528 if ( nPos
== VALUESET_ITEM_NOTFOUND
)
531 if ( nPos
< mItemList
.size() ) {
532 mItemList
.erase( mItemList
.begin() + nPos
);
536 if (mnHighItemId
== nItemId
|| mnSelItemId
== nItemId
)
541 mbNoSelection
= true;
547 bool ValueSet::TurnOffScrollBar()
549 if (mxScrolledWindow
->get_vpolicy() == VclPolicyType::NEVER
)
551 mxScrolledWindow
->set_vpolicy(VclPolicyType::NEVER
);
552 weld::DrawingArea
* pDrawingArea
= GetDrawingArea();
553 Size
aPrefSize(pDrawingArea
->get_preferred_size());
554 pDrawingArea
->set_size_request(aPrefSize
.Width() + GetScrollWidth(), aPrefSize
.Height());
558 void ValueSet::TurnOnScrollBar()
560 if (mxScrolledWindow
->get_vpolicy() == VclPolicyType::ALWAYS
)
562 mxScrolledWindow
->set_vpolicy(VclPolicyType::ALWAYS
);
563 weld::DrawingArea
* pDrawingArea
= GetDrawingArea();
564 Size
aPrefSize(pDrawingArea
->get_preferred_size());
565 pDrawingArea
->set_size_request(aPrefSize
.Width() - GetScrollWidth(), aPrefSize
.Height());
568 void ValueSet::RecalcScrollBar()
570 if (!mxScrolledWindow
)
572 const bool bScrollAllowed
= GetStyle() & WB_VSCROLL
;
575 // reset scrolled window state to initial value so it will get configured
576 // to the right adjustment on the next format which we toggle on to happen
577 // if the scrolledwindow wasn't in its initial state already
578 if (TurnOffScrollBar())
582 void ValueSet::Clear()
591 mbNoSelection
= true;
596 if ( IsReallyVisible() && IsUpdateMode() )
600 size_t ValueSet::GetItemCount() const
602 return mItemList
.size();
605 size_t ValueSet::GetItemPos( sal_uInt16 nItemId
) const
607 for ( size_t i
= 0, n
= mItemList
.size(); i
< n
; ++i
) {
608 if ( mItemList
[i
]->mnId
== nItemId
) {
612 return VALUESET_ITEM_NOTFOUND
;
615 sal_uInt16
ValueSet::GetItemId( size_t nPos
) const
617 return ( nPos
< mItemList
.size() ) ? mItemList
[nPos
]->mnId
: 0 ;
620 sal_uInt16
ValueSet::GetItemId( const Point
& rPos
) const
622 size_t nItemPos
= ImplGetItem( rPos
);
623 if ( nItemPos
!= VALUESET_ITEM_NOTFOUND
)
624 return GetItemId( nItemPos
);
629 tools::Rectangle
ValueSet::GetItemRect( sal_uInt16 nItemId
) const
631 const size_t nPos
= GetItemPos( nItemId
);
633 if ( nPos
!=VALUESET_ITEM_NOTFOUND
&& mItemList
[nPos
]->mbVisible
)
634 return ImplGetItemRect( nPos
);
636 return tools::Rectangle();
639 tools::Rectangle
ValueSet::ImplGetItemRect( size_t nPos
) const
641 const size_t nVisibleBegin
= static_cast<size_t>(mnFirstLine
)*mnCols
;
642 const size_t nVisibleEnd
= nVisibleBegin
+ static_cast<size_t>(mnVisLines
)*mnCols
;
644 // Check if the item is inside the range of the displayed ones,
645 // taking into account that last row could be incomplete
646 if ( nPos
<nVisibleBegin
|| nPos
>=nVisibleEnd
|| nPos
>=mItemList
.size() )
647 return tools::Rectangle();
649 nPos
-= nVisibleBegin
;
651 const size_t row
= mnCols
? nPos
/mnCols
: 0;
652 const size_t col
= mnCols
? nPos
%mnCols
: 0;
653 const tools::Long x
= maItemListRect
.Left()+col
*(mnItemWidth
+mnSpacing
);
654 const tools::Long y
= maItemListRect
.Top()+row
*(mnItemHeight
+mnSpacing
);
656 return tools::Rectangle( Point(x
, y
), Size(mnItemWidth
, mnItemHeight
) );
659 void ValueSet::ImplHighlightItem(sal_uInt16 nItemId
)
661 if ( mnHighItemId
== nItemId
)
664 // remember the old item to delete the previous selection
665 mnHighItemId
= nItemId
;
667 // remove the old selection and draw the new one
671 void ValueSet::ImplDraw(vcl::RenderContext
& rRenderContext
)
674 Format(rRenderContext
);
677 Size aSize
= maVirDev
->GetOutputSizePixel();
679 rRenderContext
.DrawOutDev(aDefPos
, aSize
, aDefPos
, aSize
, *maVirDev
);
681 // draw parting line to the Namefield
682 if (GetStyle() & WB_NAMEFIELD
)
684 if (!(GetStyle() & WB_FLATVALUESET
))
686 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
687 Size
aWinSize(GetOutputSizePixel());
688 Point
aPos1(NAME_LINE_OFF_X
, mnTextOffset
+ NAME_LINE_OFF_Y
);
689 Point
aPos2(aWinSize
.Width() - (NAME_LINE_OFF_X
* 2), mnTextOffset
+ NAME_LINE_OFF_Y
);
690 if (!(rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
))
692 rRenderContext
.SetLineColor(rStyleSettings
.GetShadowColor());
693 rRenderContext
.DrawLine(aPos1
, aPos2
);
696 rRenderContext
.SetLineColor(rStyleSettings
.GetLightColor());
699 rRenderContext
.SetLineColor(rStyleSettings
.GetWindowTextColor());
700 rRenderContext
.DrawLine(aPos1
, aPos2
);
704 ImplDrawSelect(rRenderContext
);
708 * An inelegant method; sets the item width & height such that
709 * all of the included items and their labels fit; if we can
712 void ValueSet::RecalculateItemSizes()
714 Size aLargestItem
= GetLargestItemSize();
716 if ( mnUserItemWidth
!= aLargestItem
.Width() ||
717 mnUserItemHeight
!= aLargestItem
.Height() )
719 mnUserItemWidth
= aLargestItem
.Width();
720 mnUserItemHeight
= aLargestItem
.Height();
725 void ValueSet::SetFirstLine(sal_uInt16 nNewFirstLine
)
727 if (nNewFirstLine
!= mnFirstLine
)
729 mnFirstLine
= nNewFirstLine
;
730 if (mxScrolledWindow
)
731 mxScrolledWindow
->vadjustment_set_value(mnFirstLine
);
735 void ValueSet::SelectItem( sal_uInt16 nItemId
)
741 nItemPos
= GetItemPos( nItemId
);
742 if ( nItemPos
== VALUESET_ITEM_NOTFOUND
)
746 if ( !((mnSelItemId
!= nItemId
) || mbNoSelection
) )
749 const sal_uInt16 nOldItem
= mnSelItemId
;
750 mnSelItemId
= nItemId
;
751 mbNoSelection
= false;
753 bool bNewOut
= !mbFormat
&& IsReallyVisible() && IsUpdateMode();
754 bool bNewLine
= false;
756 if (weld::DrawingArea
* pNeedsFormatToScroll
= !mnCols
? GetDrawingArea() : nullptr)
758 Format(pNeedsFormatToScroll
->get_ref_device());
759 // reset scrollbar so it's set to the later calculated mnFirstLine on
764 // if necessary scroll to the visible area
765 if (mbScroll
&& nItemId
&& mnCols
)
767 sal_uInt16 nNewLine
= static_cast<sal_uInt16
>(nItemPos
/ mnCols
);
768 if ( nNewLine
< mnFirstLine
)
770 SetFirstLine(nNewLine
);
773 else if ( nNewLine
> o3tl::make_unsigned(mnFirstLine
+mnVisLines
-1) )
775 SetFirstLine(static_cast<sal_uInt16
>(nNewLine
-mnVisLines
+1));
784 // redraw everything if the visible area has changed
790 if( !ImplHasAccessibleListeners() )
793 // focus event (deselect)
796 const size_t nPos
= GetItemPos( nItemId
);
798 if( nPos
!= VALUESET_ITEM_NOTFOUND
)
800 ValueItemAcc
* pItemAcc
= ValueItemAcc::getImplementation(
801 mItemList
[nPos
]->GetAccessible( false/*bIsTransientChildrenDisabled*/ ) );
807 aOldAny
<<= Reference(getXWeak(pItemAcc
));
808 ImplFireAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
, aOldAny
, aNewAny
);
813 // focus event (select)
814 const size_t nPos
= GetItemPos( mnSelItemId
);
817 if( nPos
!= VALUESET_ITEM_NOTFOUND
)
818 pItem
= mItemList
[nPos
].get();
820 pItem
= mpNoneItem
.get();
822 ValueItemAcc
* pItemAcc
= nullptr;
823 if (pItem
!= nullptr)
824 pItemAcc
= ValueItemAcc::getImplementation( pItem
->GetAccessible( false/*bIsTransientChildrenDisabled*/ ) );
830 aNewAny
<<= Reference(getXWeak(pItemAcc
));
831 ImplFireAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
, aOldAny
, aNewAny
);
837 ImplFireAccessibleEvent(AccessibleEventId::SELECTION_CHANGED
, aOldAny
, aNewAny
);
840 void ValueSet::SetNoSelection()
842 mbNoSelection
= true;
845 if (IsReallyVisible() && IsUpdateMode())
849 void ValueSet::SetStyle(WinBits nStyle
)
851 if (nStyle
!= mnStyle
)
859 void ValueSet::Format(vcl::RenderContext
const & rRenderContext
)
861 Size
aWinSize(GetOutputSizePixel());
862 size_t nItemCount
= mItemList
.size();
863 WinBits nStyle
= GetStyle();
864 tools::Long nTxtHeight
= rRenderContext
.GetTextHeight();
866 tools::Long nNoneHeight
;
867 tools::Long nNoneSpace
;
869 if (mxScrolledWindow
&& !(nStyle
& WB_VSCROLL
) && mxScrolledWindow
->get_vpolicy() != VclPolicyType::NEVER
)
872 // calculate item offset
873 if (nStyle
& WB_ITEMBORDER
)
875 if (nStyle
& WB_DOUBLEBORDER
)
876 nOff
= ITEM_OFFSET_DOUBLE
;
883 // consider size, if NameField does exist
884 if (nStyle
& WB_NAMEFIELD
)
886 mnTextOffset
= aWinSize
.Height() - nTxtHeight
- NAME_OFFSET
;
887 aWinSize
.AdjustHeight( -(nTxtHeight
+ NAME_OFFSET
) );
889 if (!(nStyle
& WB_FLATVALUESET
))
891 mnTextOffset
-= NAME_LINE_HEIGHT
+ NAME_LINE_OFF_Y
;
892 aWinSize
.AdjustHeight( -(NAME_LINE_HEIGHT
+ NAME_LINE_OFF_Y
) );
898 // consider offset and size, if NoneField does exist
899 if (nStyle
& WB_NONEFIELD
)
901 nNoneHeight
= nTxtHeight
+ nOff
;
902 nNoneSpace
= mnSpacing
;
911 // calculate number of columns
916 mnCols
= static_cast<sal_uInt16
>((aWinSize
.Width() - mnSpacing
) / (mnUserItemWidth
+ mnSpacing
));
930 // calculate number of rows
933 auto nOldLines
= mnLines
;
934 // Floor( (M+N-1)/N )==Ceiling( M/N )
935 mnLines
= (static_cast<tools::Long
>(nItemCount
) + mnCols
- 1) / mnCols
;
939 bool bAdjustmentOutOfDate
= nOldLines
!= mnLines
;
941 auto nOldVisLines
= mnVisLines
;
943 tools::Long nCalcHeight
= aWinSize
.Height() - nNoneHeight
;
946 mnVisLines
= mnUserVisLines
;
948 else if (mnUserItemHeight
)
950 mnVisLines
= (nCalcHeight
- nNoneSpace
+ mnSpacing
) / (mnUserItemHeight
+ mnSpacing
);
956 mnVisLines
= mnLines
;
959 bAdjustmentOutOfDate
|= nOldVisLines
!= mnVisLines
;
961 if (mnLines
> mnVisLines
)
964 if (mnLines
<= mnVisLines
)
970 if (mnFirstLine
> o3tl::make_unsigned(mnLines
- mnVisLines
))
971 SetFirstLine(static_cast<sal_uInt16
>(mnLines
- mnVisLines
));
974 // calculate item size
975 const tools::Long nColSpace
= (mnCols
- 1) * static_cast<tools::Long
>(mnSpacing
);
976 const tools::Long nLineSpace
= ((mnVisLines
- 1) * mnSpacing
) + nNoneSpace
;
977 if (mnUserItemWidth
&& !mnUserCols
)
979 mnItemWidth
= mnUserItemWidth
;
980 if (mnItemWidth
> aWinSize
.Width() - nColSpace
)
981 mnItemWidth
= aWinSize
.Width() - nColSpace
;
984 mnItemWidth
= (aWinSize
.Width() - nColSpace
) / mnCols
;
985 if (mnUserItemHeight
&& !mnUserVisLines
)
987 mnItemHeight
= mnUserItemHeight
;
988 if (mnItemHeight
> nCalcHeight
- nNoneSpace
)
989 mnItemHeight
= nCalcHeight
- nNoneSpace
;
993 nCalcHeight
-= nLineSpace
;
994 mnItemHeight
= nCalcHeight
/ mnVisLines
;
998 maVirDev
->SetBackground(Application::GetSettings().GetStyleSettings().GetFaceColor());
999 maVirDev
->SetOutputSizePixel(aWinSize
);
1002 // nothing is changed in case of too small items
1003 if ((mnItemWidth
<= 0) ||
1004 (mnItemHeight
<= ((nStyle
& WB_ITEMBORDER
) ? 4 : 2)) ||
1007 mbHasVisibleItems
= false;
1009 if ((nStyle
& WB_NONEFIELD
) && mpNoneItem
)
1011 mpNoneItem
->mbVisible
= false;
1012 mpNoneItem
->maText
= GetText();
1015 for (size_t i
= 0; i
< nItemCount
; i
++)
1017 mItemList
[i
]->mbVisible
= false;
1020 if (mxScrolledWindow
&& mxScrolledWindow
->get_vpolicy() != VclPolicyType::NEVER
)
1025 mbHasVisibleItems
= true;
1027 // determine Frame-Style
1028 if (nStyle
& WB_DOUBLEBORDER
)
1029 mnFrameStyle
= DrawFrameStyle::DoubleIn
;
1031 mnFrameStyle
= DrawFrameStyle::In
;
1033 // draw the selection with double width if the items are bigger
1034 if ((nStyle
& WB_DOUBLEBORDER
) &&
1035 ((mnItemWidth
>= 25) && (mnItemHeight
>= 20)))
1041 mbDoubleSel
= false;
1044 // calculate offsets
1045 tools::Long nStartX
;
1046 tools::Long nStartY
;
1049 tools::Long nAllItemWidth
= (mnItemWidth
* mnCols
) + nColSpace
;
1050 tools::Long nAllItemHeight
= (mnItemHeight
* mnVisLines
) + nNoneHeight
+ nLineSpace
;
1051 nStartX
= (aWinSize
.Width() - nAllItemWidth
) / 2;
1052 nStartY
= (aWinSize
.Height() - nAllItemHeight
) / 2;
1060 // calculate and draw items
1061 maVirDev
->SetLineColor();
1062 tools::Long x
= nStartX
;
1063 tools::Long y
= nStartY
;
1065 // create NoSelection field and show it
1066 if (nStyle
& WB_NONEFIELD
)
1069 mpNoneItem
.reset(new ValueSetItem(*this));
1071 mpNoneItem
->mnId
= 0;
1072 mpNoneItem
->meType
= VALUESETITEM_NONE
;
1073 mpNoneItem
->mbVisible
= true;
1074 maNoneItemRect
.SetLeft( x
);
1075 maNoneItemRect
.SetTop( y
);
1076 maNoneItemRect
.SetRight( maNoneItemRect
.Left() + aWinSize
.Width() - x
- 1 );
1077 maNoneItemRect
.SetBottom( y
+ nNoneHeight
- 1 );
1079 ImplFormatItem(rRenderContext
, mpNoneItem
.get(), maNoneItemRect
);
1081 y
+= nNoneHeight
+ nNoneSpace
;
1085 sal_uLong nFirstItem
= static_cast<sal_uLong
>(mnFirstLine
) * mnCols
;
1086 sal_uLong nLastItem
= nFirstItem
+ (mnVisLines
* mnCols
);
1088 maItemListRect
.SetLeft( x
);
1089 maItemListRect
.SetTop( y
);
1090 maItemListRect
.SetRight( x
+ mnCols
* (mnItemWidth
+ mnSpacing
) - mnSpacing
- 1 );
1091 maItemListRect
.SetBottom( y
+ mnVisLines
* (mnItemHeight
+ mnSpacing
) - mnSpacing
- 1 );
1095 // If want also draw parts of items in the last line,
1096 // then we add one more line if parts of these line are
1098 if (y
+ (mnVisLines
* (mnItemHeight
+ mnSpacing
)) < aWinSize
.Height())
1099 nLastItem
+= mnCols
;
1100 maItemListRect
.SetBottom( aWinSize
.Height() - y
);
1102 for (size_t i
= 0; i
< nItemCount
; i
++)
1104 ValueSetItem
* pItem
= mItemList
[i
].get();
1106 if (i
>= nFirstItem
&& i
< nLastItem
)
1108 if (!pItem
->mbVisible
&& ImplHasAccessibleListeners())
1113 aNewAny
<<= pItem
->GetAccessible(false/*bIsTransientChildrenDisabled*/);
1114 ImplFireAccessibleEvent(AccessibleEventId::CHILD
, aOldAny
, aNewAny
);
1117 pItem
->mbVisible
= true;
1118 ImplFormatItem(rRenderContext
, pItem
, tools::Rectangle(Point(x
, y
), Size(mnItemWidth
, mnItemHeight
)));
1120 if (!((i
+ 1) % mnCols
))
1123 y
+= mnItemHeight
+ mnSpacing
;
1126 x
+= mnItemWidth
+ mnSpacing
;
1130 if (pItem
->mbVisible
&& ImplHasAccessibleListeners())
1135 aOldAny
<<= pItem
->GetAccessible(false/*bIsTransientChildrenDisabled*/);
1136 ImplFireAccessibleEvent(AccessibleEventId::CHILD
, aOldAny
, aNewAny
);
1139 pItem
->mbVisible
= false;
1143 // arrange ScrollBar, set values and show it
1144 if (mxScrolledWindow
&& (nStyle
& WB_VSCROLL
))
1146 bool bTurnScrollbarOn
= mxScrolledWindow
->get_vpolicy() != VclPolicyType::ALWAYS
;
1147 if (bAdjustmentOutOfDate
|| bTurnScrollbarOn
)
1149 tools::Long nPageSize
= mnVisLines
;
1152 mxScrolledWindow
->vadjustment_configure(mnFirstLine
, 0, mnLines
, 1,
1153 mnVisLines
, nPageSize
);
1156 if (bTurnScrollbarOn
)
1161 // waiting for the next since the formatting is finished
1165 void ValueSet::ImplDrawSelect(vcl::RenderContext
& rRenderContext
)
1167 if (!IsReallyVisible())
1170 const bool bFocus
= HasFocus();
1172 if (!bFocus
&& mbNoSelection
&& !mbHighlight
)
1175 tools::Rectangle aSelectedRect
, aHoverRect
;
1176 ValueSetItem
* pSelectedItem
= ImplGetDrawSelectItem(mnSelItemId
, bFocus
, aSelectedRect
);
1177 ValueSetItem
* pHighlightItem
= mnHighItemId
? ImplGetDrawSelectItem(mnHighItemId
, false, aHoverRect
) : nullptr;
1181 const bool bHover
= pSelectedItem
== pHighlightItem
;
1182 ImplDrawSelect(rRenderContext
, aSelectedRect
, pSelectedItem
, bFocus
, !mbNoSelection
, true, bHover
);
1184 if (pHighlightItem
&& (pSelectedItem
!= pHighlightItem
|| mbNoSelection
))
1186 // For the case that there isn't a selected item, but due to wanting to
1187 // show focus is in the valueset, the above block will have drawn the
1188 // first item with a focus rect. For that situation; if the valueset is
1189 // the thin WB_MENUSTYLEVALUESET case then blend this highlight border
1190 // on top of that focus rect and it will appear with a highlighted
1191 // focus rect. If it's the other case of a thicker border then redraw
1192 // the focus rect highlighted with the hover color.
1194 WinBits nStyle
= GetStyle();
1195 if (nStyle
& WB_MENUSTYLEVALUESET
)
1198 bDrawFocus
= pSelectedItem
== pHighlightItem
&& mbNoSelection
;
1200 ImplDrawSelect(rRenderContext
, aHoverRect
, pHighlightItem
, bDrawFocus
, mbHighlight
, false, true);
1204 ValueSetItem
* ValueSet::ImplGetDrawSelectItem(sal_uInt16 nItemId
, const bool bFocus
, tools::Rectangle
& rRect
)
1206 ValueSetItem
* pItem
= nullptr;
1209 const size_t nPos
= GetItemPos( nItemId
);
1210 pItem
= mItemList
[ nPos
].get();
1211 rRect
= ImplGetItemRect( nPos
);
1213 else if (mpNoneItem
)
1215 pItem
= mpNoneItem
.get();
1216 rRect
= maNoneItemRect
;
1218 else if (bFocus
&& (pItem
= ImplGetFirstItem()))
1220 rRect
= ImplGetItemRect(0);
1225 void ValueSet::ImplDrawSelect(vcl::RenderContext
& rRenderContext
,
1226 const tools::Rectangle
& rRect
, const ValueSetItem
* pItem
,
1227 const bool bFocus
, const bool bDrawSel
,
1228 const bool bSelected
, const bool bHover
)
1230 tools::Rectangle
aRect(rRect
);
1233 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
1234 rRenderContext
.SetFillColor();
1239 sal_uInt16 nTransparencePercent
= 0;
1241 if (bSelected
&& bHover
)
1243 aDoubleColor
= rStyleSettings
.GetActiveColor();
1244 aSingleColor
= rStyleSettings
.GetActiveTextColor();
1246 else if (bSelected
|| bHover
)
1248 aDoubleColor
= rStyleSettings
.GetHighlightColor();
1249 aSingleColor
= rStyleSettings
.GetHighlightTextColor();
1252 nTransparencePercent
= 55;
1256 // specify selection output
1257 WinBits nStyle
= GetStyle();
1258 if (nStyle
& WB_MENUSTYLEVALUESET
)
1261 InvertFocusRect(rRenderContext
, aRect
);
1264 rRenderContext
.SetLineColor(aDoubleColor
);
1265 tools::PolyPolygon
aPolyPoly(1);
1266 aPolyPoly
.Insert(aRect
);
1267 rRenderContext
.DrawTransparent(aPolyPoly
, nTransparencePercent
);
1272 rRenderContext
.SetLineColor(aDoubleColor
);
1273 tools::Rectangle aFocusRect
;
1277 // an outer rectangle surrounding a "focus" rectangle, surrounding
1278 // an inner rectangle. Focus rectangle is always drawn, but rendered
1279 // empty when there is no focus. e.g. as seen in color valuesets
1282 tools::PolyPolygon
aPolyPoly(1);
1283 aPolyPoly
.Insert(aRect
);
1284 rRenderContext
.DrawTransparent(aPolyPoly
, nTransparencePercent
);
1287 aRect
.AdjustLeft( 1 );
1288 aRect
.AdjustTop( 1 );
1289 aRect
.AdjustRight( -1 );
1290 aRect
.AdjustBottom( -1 );
1294 aRect
.AdjustLeft( 1 );
1295 aRect
.AdjustTop( 1 );
1296 aRect
.AdjustRight( -1 );
1297 aRect
.AdjustBottom( -1 );
1301 tools::PolyPolygon
aPolyPoly(1);
1302 aPolyPoly
.Insert(aRect
);
1303 rRenderContext
.DrawTransparent(aPolyPoly
, nTransparencePercent
);
1307 rRenderContext
.SetLineColor(aSingleColor
);
1309 rRenderContext
.SetLineColor(COL_LIGHTGRAY
);
1311 rRenderContext
.DrawRect(aFocusRect
);
1315 // a thick bordered rectangle surrounding an optional "focus"
1316 // rectangle which is only drawn when focused, as seen in format,
1317 // bullets and numbering in writer
1318 const int nAdjust
= 2;
1320 aRect
.AdjustLeft(nAdjust
);
1321 aRect
.AdjustTop(nAdjust
);
1322 aRect
.AdjustRight(-nAdjust
);
1323 aRect
.AdjustBottom(-nAdjust
);
1329 const basegfx::B2DPolygon
aRectPoly(
1330 basegfx::utils::createPolygonFromRect(
1331 vcl::unotools::b2DRectangleFromRectangle(aRect
)));
1333 const int nThickness
= nAdjust
* 2;
1335 if (!rRenderContext
.DrawPolyLineDirect(basegfx::B2DHomMatrix(),
1338 nTransparencePercent
/ 100.0,
1340 basegfx::B2DLineJoin::Miter
))
1342 SAL_WARN("svtools", "presumably impossible in practice, but fallback to see something");
1343 rRenderContext
.DrawPolyLine(aRectPoly
, nThickness
, basegfx::B2DLineJoin::Miter
);
1350 rRenderContext
.SetLineColor(aSingleColor
);
1352 rRenderContext
.SetLineColor(COL_LIGHTGRAY
);
1353 rRenderContext
.DrawRect(aFocusRect
);
1358 InvertFocusRect(rRenderContext
, aFocusRect
);
1361 ImplDrawItemText(rRenderContext
, pItem
->maText
);
1364 void ValueSet::ImplFormatItem(vcl::RenderContext
const & rRenderContext
, ValueSetItem
* pItem
, tools::Rectangle aRect
)
1366 WinBits nStyle
= GetStyle();
1367 if (nStyle
& WB_ITEMBORDER
)
1369 aRect
.AdjustLeft(1 );
1370 aRect
.AdjustTop(1 );
1371 aRect
.AdjustRight( -1 );
1372 aRect
.AdjustBottom( -1 );
1374 if (nStyle
& WB_FLATVALUESET
)
1376 sal_Int32 nBorder
= (nStyle
& WB_DOUBLEBORDER
) ? 2 : 1;
1378 aRect
.AdjustLeft(nBorder
);
1379 aRect
.AdjustTop(nBorder
);
1380 aRect
.AdjustRight( -nBorder
);
1381 aRect
.AdjustBottom( -nBorder
);
1385 DecorationView
aView(maVirDev
.get());
1386 aRect
= aView
.DrawFrame(aRect
, mnFrameStyle
);
1390 if (pItem
== mpNoneItem
.get())
1391 pItem
->maText
= GetText();
1393 if ((aRect
.GetHeight() <= 0) || (aRect
.GetWidth() <= 0))
1396 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
1398 if (pItem
== mpNoneItem
.get())
1400 maVirDev
->SetFont(rRenderContext
.GetFont());
1401 maVirDev
->SetTextColor((nStyle
& WB_MENUSTYLEVALUESET
) ? rStyleSettings
.GetMenuTextColor() : rStyleSettings
.GetWindowTextColor());
1402 maVirDev
->SetTextFillColor();
1403 maVirDev
->SetFillColor((nStyle
& WB_MENUSTYLEVALUESET
) ? rStyleSettings
.GetMenuColor() : rStyleSettings
.GetWindowColor());
1404 maVirDev
->DrawRect(aRect
);
1405 Point
aTxtPos(aRect
.Left() + 2, aRect
.Top());
1406 tools::Long nTxtWidth
= rRenderContext
.GetTextWidth(pItem
->maText
);
1407 if ((aTxtPos
.X() + nTxtWidth
) > aRect
.Right())
1409 maVirDev
->SetClipRegion(vcl::Region(aRect
));
1410 maVirDev
->DrawText(aTxtPos
, pItem
->maText
);
1411 maVirDev
->SetClipRegion();
1414 maVirDev
->DrawText(aTxtPos
, pItem
->maText
);
1416 else if (pItem
->meType
== VALUESETITEM_COLOR
)
1418 maVirDev
->SetFillColor(pItem
->maColor
);
1419 maVirDev
->DrawRect(aRect
);
1424 maVirDev
->SetFillColor(maColor
);
1425 else if (nStyle
& WB_MENUSTYLEVALUESET
)
1426 maVirDev
->SetFillColor(rStyleSettings
.GetMenuColor());
1427 else if (IsEnabled())
1428 maVirDev
->SetFillColor(rStyleSettings
.GetWindowColor());
1430 maVirDev
->SetFillColor(rStyleSettings
.GetFaceColor());
1431 maVirDev
->DrawRect(aRect
);
1433 if (pItem
->meType
== VALUESETITEM_USERDRAW
)
1435 UserDrawEvent
aUDEvt(maVirDev
.get(), aRect
, pItem
->mnId
);
1440 Size aImageSize
= pItem
->maImage
.GetSizePixel();
1441 Size aRectSize
= aRect
.GetSize();
1442 Point
aPos(aRect
.Left(), aRect
.Top());
1443 aPos
.AdjustX((aRectSize
.Width() - aImageSize
.Width()) / 2 );
1445 if (pItem
->meType
!= VALUESETITEM_IMAGE_AND_TEXT
)
1446 aPos
.AdjustY((aRectSize
.Height() - aImageSize
.Height()) / 2 );
1448 DrawImageFlags nImageStyle
= DrawImageFlags::NONE
;
1450 nImageStyle
|= DrawImageFlags::Disable
;
1452 if (aImageSize
.Width() > aRectSize
.Width() ||
1453 aImageSize
.Height() > aRectSize
.Height())
1455 maVirDev
->SetClipRegion(vcl::Region(aRect
));
1456 maVirDev
->DrawImage(aPos
, pItem
->maImage
, nImageStyle
);
1457 maVirDev
->SetClipRegion();
1460 maVirDev
->DrawImage(aPos
, pItem
->maImage
, nImageStyle
);
1462 if (pItem
->meType
== VALUESETITEM_IMAGE_AND_TEXT
)
1464 maVirDev
->SetFont(rRenderContext
.GetFont());
1465 maVirDev
->SetTextColor((nStyle
& WB_MENUSTYLEVALUESET
) ? rStyleSettings
.GetMenuTextColor() : rStyleSettings
.GetWindowTextColor());
1466 maVirDev
->SetTextFillColor();
1468 tools::Long nTxtWidth
= maVirDev
->GetTextWidth(pItem
->maText
);
1470 if (nTxtWidth
> aRect
.GetWidth())
1471 maVirDev
->SetClipRegion(vcl::Region(aRect
));
1473 maVirDev
->DrawText(Point(aRect
.Left() +
1474 (aRect
.GetWidth() - nTxtWidth
) / 2,
1475 aRect
.Bottom() - maVirDev
->GetTextHeight()),
1478 if (nTxtWidth
> aRect
.GetWidth())
1479 maVirDev
->SetClipRegion();
1484 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
1486 if (nEdgeBlendingPercent
)
1488 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
1489 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
1490 const sal_uInt8
nAlpha((nEdgeBlendingPercent
* 255) / 100);
1491 const BitmapEx
aBlendFrame(createBlendFrame(aRect
.GetSize(), nAlpha
, rTopLeft
, rBottomRight
));
1493 if (!aBlendFrame
.IsEmpty())
1495 maVirDev
->DrawBitmapEx(aRect
.TopLeft(), aBlendFrame
);
1500 void ValueSet::ImplDrawItemText(vcl::RenderContext
& rRenderContext
, const OUString
& rText
)
1502 if (!(GetStyle() & WB_NAMEFIELD
))
1505 Size
aWinSize(GetOutputSizePixel());
1506 tools::Long nTxtWidth
= rRenderContext
.GetTextWidth(rText
);
1507 tools::Long nTxtOffset
= mnTextOffset
;
1509 rRenderContext
.Push(vcl::PushFlags::TEXTCOLOR
);
1511 // delete rectangle and show text
1512 const bool bFlat(GetStyle() & WB_FLATVALUESET
);
1514 nTxtOffset
+= NAME_LINE_HEIGHT
+NAME_LINE_OFF_Y
;
1516 rRenderContext
.SetTextColor(Application::GetSettings().GetStyleSettings().GetButtonTextColor());
1517 // tdf#153787 highlighted entry text is drawn in the same Paint as the selected text, so can
1518 // overwrite already rendered text
1519 rRenderContext
.Erase(tools::Rectangle(Point(0, nTxtOffset
), Point(aWinSize
.Width(), aWinSize
.Height())));
1520 rRenderContext
.DrawText(Point((aWinSize
.Width() - nTxtWidth
) / 2, nTxtOffset
+ (NAME_OFFSET
/ 2)), rText
);
1522 rRenderContext
.Pop();
1525 void ValueSet::StyleUpdated()
1528 CustomWidgetController::StyleUpdated();
1531 void ValueSet::EnableFullItemMode( bool bFullMode
)
1533 mbFullMode
= bFullMode
;
1536 void ValueSet::SetColCount( sal_uInt16 nNewCols
)
1538 if ( mnUserCols
!= nNewCols
)
1540 mnUserCols
= nNewCols
;
1545 void ValueSet::SetItemImage( sal_uInt16 nItemId
, const Image
& rImage
)
1547 size_t nPos
= GetItemPos( nItemId
);
1549 if ( nPos
== VALUESET_ITEM_NOTFOUND
)
1552 ValueSetItem
* pItem
= mItemList
[nPos
].get();
1553 pItem
->meType
= VALUESETITEM_IMAGE
;
1554 pItem
->maImage
= rImage
;
1556 if ( !mbFormat
&& IsReallyVisible() && IsUpdateMode() )
1558 const tools::Rectangle aRect
= ImplGetItemRect(nPos
);
1565 void ValueSet::SetItemColor( sal_uInt16 nItemId
, const Color
& rColor
)
1567 size_t nPos
= GetItemPos( nItemId
);
1569 if ( nPos
== VALUESET_ITEM_NOTFOUND
)
1572 ValueSetItem
* pItem
= mItemList
[nPos
].get();
1573 pItem
->meType
= VALUESETITEM_COLOR
;
1574 pItem
->maColor
= rColor
;
1576 if ( !mbFormat
&& IsReallyVisible() && IsUpdateMode() )
1578 const tools::Rectangle aRect
= ImplGetItemRect(nPos
);
1579 Invalidate( aRect
);
1585 Color
ValueSet::GetItemColor( sal_uInt16 nItemId
) const
1587 size_t nPos
= GetItemPos( nItemId
);
1589 if ( nPos
!= VALUESET_ITEM_NOTFOUND
)
1590 return mItemList
[nPos
]->maColor
;
1595 Size
ValueSet::CalcWindowSizePixel( const Size
& rItemSize
, sal_uInt16 nDesireCols
,
1596 sal_uInt16 nDesireLines
) const
1598 size_t nCalcCols
= nDesireCols
;
1599 size_t nCalcLines
= nDesireLines
;
1604 nCalcCols
= mnUserCols
;
1611 nCalcLines
= mnVisLines
;
1615 if ( mnUserVisLines
)
1616 nCalcLines
= mnUserVisLines
;
1619 // Floor( (M+N-1)/N )==Ceiling( M/N )
1620 nCalcLines
= (mItemList
.size()+nCalcCols
-1) / nCalcCols
;
1627 Size
aSize( rItemSize
.Width() * nCalcCols
, rItemSize
.Height() * nCalcLines
);
1628 WinBits nStyle
= GetStyle();
1629 tools::Long nTxtHeight
= GetTextHeight();
1632 if ( nStyle
& WB_ITEMBORDER
)
1634 if ( nStyle
& WB_DOUBLEBORDER
)
1635 n
= ITEM_OFFSET_DOUBLE
;
1639 aSize
.AdjustWidth(n
* nCalcCols
);
1640 aSize
.AdjustHeight(n
* nCalcLines
);
1647 aSize
.AdjustWidth(mnSpacing
* (nCalcCols
- 1) );
1648 aSize
.AdjustHeight(mnSpacing
* (nCalcLines
- 1) );
1651 if ( nStyle
& WB_NAMEFIELD
)
1653 aSize
.AdjustHeight(nTxtHeight
+ NAME_OFFSET
);
1654 if ( !(nStyle
& WB_FLATVALUESET
) )
1655 aSize
.AdjustHeight(NAME_LINE_HEIGHT
+ NAME_LINE_OFF_Y
);
1658 if ( nStyle
& WB_NONEFIELD
)
1660 aSize
.AdjustHeight(nTxtHeight
+ n
+ mnSpacing
);
1666 void ValueSet::InsertItem( sal_uInt16 nItemId
, const Image
& rImage
)
1668 std::unique_ptr
<ValueSetItem
> pItem(new ValueSetItem( *this ));
1669 pItem
->mnId
= nItemId
;
1670 pItem
->meType
= VALUESETITEM_IMAGE
;
1671 pItem
->maImage
= rImage
;
1672 ImplInsertItem( std::move(pItem
), VALUESET_APPEND
);
1675 void ValueSet::InsertItem( sal_uInt16 nItemId
, const Image
& rImage
,
1676 const OUString
& rText
, size_t nPos
,
1679 std::unique_ptr
<ValueSetItem
> pItem(new ValueSetItem( *this ));
1680 pItem
->mnId
= nItemId
;
1681 pItem
->meType
= bShowLegend
? VALUESETITEM_IMAGE_AND_TEXT
: VALUESETITEM_IMAGE
;
1682 pItem
->maImage
= rImage
;
1683 pItem
->maText
= rText
;
1684 ImplInsertItem( std::move(pItem
), nPos
);
1687 void ValueSet::InsertItem( sal_uInt16 nItemId
, size_t nPos
)
1689 std::unique_ptr
<ValueSetItem
> pItem(new ValueSetItem( *this ));
1690 pItem
->mnId
= nItemId
;
1691 pItem
->meType
= VALUESETITEM_USERDRAW
;
1692 ImplInsertItem( std::move(pItem
), nPos
);
1695 void ValueSet::InsertItem( sal_uInt16 nItemId
, const Color
& rColor
,
1696 const OUString
& rText
)
1698 std::unique_ptr
<ValueSetItem
> pItem(new ValueSetItem( *this ));
1699 pItem
->mnId
= nItemId
;
1700 pItem
->meType
= VALUESETITEM_COLOR
;
1701 pItem
->maColor
= rColor
;
1702 pItem
->maText
= rText
;
1703 ImplInsertItem( std::move(pItem
), VALUESET_APPEND
);
1706 void ValueSet::ImplInsertItem( std::unique_ptr
<ValueSetItem
> pItem
, const size_t nPos
)
1708 DBG_ASSERT( pItem
->mnId
, "ValueSet::InsertItem(): ItemId == 0" );
1709 DBG_ASSERT( GetItemPos( pItem
->mnId
) == VALUESET_ITEM_NOTFOUND
,
1710 "ValueSet::InsertItem(): ItemId already exists" );
1712 if ( nPos
< mItemList
.size() ) {
1713 mItemList
.insert( mItemList
.begin() + nPos
, std::move(pItem
) );
1715 mItemList
.push_back( std::move(pItem
) );
1721 int ValueSet::GetScrollWidth() const
1723 if (mxScrolledWindow
)
1724 return mxScrolledWindow
->get_scroll_thickness();
1728 void ValueSet::SetEdgeBlending(bool bNew
)
1730 if(mbEdgeBlending
!= bNew
)
1732 mbEdgeBlending
= bNew
;
1735 if (GetDrawingArea() && IsReallyVisible() && IsUpdateMode())
1742 Size
ValueSet::CalcItemSizePixel( const Size
& rItemSize
) const
1744 Size aSize
= rItemSize
;
1746 WinBits nStyle
= GetStyle();
1747 if ( nStyle
& WB_ITEMBORDER
)
1751 if ( nStyle
& WB_DOUBLEBORDER
)
1752 n
= ITEM_OFFSET_DOUBLE
;
1756 aSize
.AdjustWidth(n
);
1757 aSize
.AdjustHeight(n
);
1763 void ValueSet::SetLineCount( sal_uInt16 nNewLines
)
1765 if ( mnUserVisLines
!= nNewLines
)
1767 mnUserVisLines
= nNewLines
;
1772 void ValueSet::SetItemWidth( tools::Long nNewItemWidth
)
1774 if ( mnUserItemWidth
!= nNewItemWidth
)
1776 mnUserItemWidth
= nNewItemWidth
;
1781 //method to set accessible when the style is user draw.
1782 void ValueSet::InsertItem( sal_uInt16 nItemId
, const OUString
& rText
, size_t nPos
)
1784 DBG_ASSERT( nItemId
, "ValueSet::InsertItem(): ItemId == 0" );
1785 DBG_ASSERT( GetItemPos( nItemId
) == VALUESET_ITEM_NOTFOUND
,
1786 "ValueSet::InsertItem(): ItemId already exists" );
1787 std::unique_ptr
<ValueSetItem
> pItem(new ValueSetItem( *this ));
1788 pItem
->mnId
= nItemId
;
1789 pItem
->meType
= VALUESETITEM_USERDRAW
;
1790 pItem
->maText
= rText
;
1791 ImplInsertItem( std::move(pItem
), nPos
);
1794 void ValueSet::SetItemHeight( tools::Long nNewItemHeight
)
1796 if ( mnUserItemHeight
!= nNewItemHeight
)
1798 mnUserItemHeight
= nNewItemHeight
;
1803 OUString
ValueSet::RequestHelp(tools::Rectangle
& rHelpRect
)
1805 Point aPos
= rHelpRect
.TopLeft();
1806 const size_t nItemPos
= ImplGetItem( aPos
);
1808 if (nItemPos
!= VALUESET_ITEM_NOTFOUND
)
1810 rHelpRect
= ImplGetItemRect(nItemPos
);
1811 sRet
= GetItemText(ImplGetItem(nItemPos
)->mnId
);
1816 OUString
ValueSet::GetItemText(sal_uInt16 nItemId
) const
1818 const size_t nPos
= GetItemPos(nItemId
);
1820 if ( nPos
!= VALUESET_ITEM_NOTFOUND
)
1821 return mItemList
[nPos
]->maText
;
1826 void ValueSet::SetExtraSpacing( sal_uInt16 nNewSpacing
)
1828 if ( GetStyle() & WB_ITEMBORDER
)
1830 mnSpacing
= nNewSpacing
;
1835 void ValueSet::SetFormat()
1840 void ValueSet::SetItemData( sal_uInt16 nItemId
, void* pData
)
1842 size_t nPos
= GetItemPos( nItemId
);
1844 if ( nPos
== VALUESET_ITEM_NOTFOUND
)
1847 ValueSetItem
* pItem
= mItemList
[nPos
].get();
1848 pItem
->mpData
= pData
;
1850 if ( pItem
->meType
== VALUESETITEM_USERDRAW
)
1852 if ( !mbFormat
&& IsReallyVisible() && IsUpdateMode() )
1854 const tools::Rectangle aRect
= ImplGetItemRect(nPos
);
1862 void* ValueSet::GetItemData( sal_uInt16 nItemId
) const
1864 size_t nPos
= GetItemPos( nItemId
);
1866 if ( nPos
!= VALUESET_ITEM_NOTFOUND
)
1867 return mItemList
[nPos
]->mpData
;
1872 void ValueSet::SetItemText(sal_uInt16 nItemId
, const OUString
& rText
)
1874 size_t nPos
= GetItemPos( nItemId
);
1876 if ( nPos
== VALUESET_ITEM_NOTFOUND
)
1879 ValueSetItem
* pItem
= mItemList
[nPos
].get();
1881 // Remember old and new name for accessibility event.
1884 OUString
sString (pItem
->maText
);
1885 aOldName
<<= sString
;
1887 aNewName
<<= sString
;
1889 pItem
->maText
= rText
;
1891 if (!mbFormat
&& IsReallyVisible() && IsUpdateMode())
1893 sal_uInt16 nTempId
= mnSelItemId
;
1896 nTempId
= mnHighItemId
;
1898 if (nTempId
== nItemId
)
1902 if (ImplHasAccessibleListeners())
1904 Reference
<XAccessible
> xAccessible(pItem
->GetAccessible( false/*bIsTransientChildrenDisabled*/));
1905 ValueItemAcc
* pValueItemAcc
= static_cast<ValueItemAcc
*>(xAccessible
.get());
1906 pValueItemAcc
->FireAccessibleEvent(AccessibleEventId::NAME_CHANGED
, aOldName
, aNewName
);
1910 Size
ValueSet::GetLargestItemSize()
1914 for (const std::unique_ptr
<ValueSetItem
>& pItem
: mItemList
)
1916 if (!pItem
->mbVisible
)
1919 if (pItem
->meType
!= VALUESETITEM_IMAGE
&&
1920 pItem
->meType
!= VALUESETITEM_IMAGE_AND_TEXT
)
1922 // handle determining an optimal size for this case
1926 Size aSize
= pItem
->maImage
.GetSizePixel();
1927 if (pItem
->meType
== VALUESETITEM_IMAGE_AND_TEXT
)
1929 aSize
.AdjustHeight(3 * NAME_LINE_HEIGHT
+
1930 maVirDev
->GetTextHeight() );
1931 aSize
.setWidth( std::max(aSize
.Width(),
1932 maVirDev
->GetTextWidth(pItem
->maText
) + NAME_OFFSET
) );
1935 aLargestItem
.setWidth( std::max(aLargestItem
.Width(), aSize
.Width()) );
1936 aLargestItem
.setHeight( std::max(aLargestItem
.Height(), aSize
.Height()) );
1939 return aLargestItem
;
1942 void ValueSet::SetOptimalSize()
1944 Size
aLargestSize(GetLargestItemSize());
1945 aLargestSize
.setWidth(std::max(aLargestSize
.Width(), mnUserItemWidth
));
1946 aLargestSize
.setHeight(std::max(aLargestSize
.Height(), mnUserItemHeight
));
1947 Size
aPrefSize(CalcWindowSizePixel(aLargestSize
));
1948 GetDrawingArea()->set_size_request(aPrefSize
.Width(), aPrefSize
.Height());
1951 Image
ValueSet::GetItemImage(sal_uInt16 nItemId
) const
1953 size_t nPos
= GetItemPos( nItemId
);
1955 if ( nPos
!= VALUESET_ITEM_NOTFOUND
)
1956 return mItemList
[nPos
]->maImage
;
1961 void ValueSet::SetColor(const Color
& rColor
)
1965 if (IsReallyVisible() && IsUpdateMode())
1969 void ValueSet::Show()
1971 if (mxScrolledWindow
)
1972 mxScrolledWindow
->show();
1973 CustomWidgetController::Show();
1976 void ValueSet::Hide()
1978 CustomWidgetController::Hide();
1979 if (mxScrolledWindow
)
1980 mxScrolledWindow
->hide();
1983 FactoryFunction
ValueSet::GetUITestFactory() const
1985 return ValueSetUIObject::create
;
1988 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */