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 <vcl/toolkit/combobox.hxx>
24 #include <comphelper/string.hxx>
25 #include <vcl/toolkit/lstbox.hxx>
26 #include <vcl/builder.hxx>
27 #include <vcl/commandevent.hxx>
28 #include <vcl/event.hxx>
29 #include <vcl/settings.hxx>
30 #include <vcl/vclevent.hxx>
31 #include <vcl/uitest/uiobject.hxx>
32 #include <sal/log.hxx>
34 #include <listbox.hxx>
35 #include <comphelper/lok.hxx>
36 #include <tools/json_writer.hxx>
37 #include <o3tl/string_view.hxx>
49 static void lcl_GetSelectedEntries( ::std::set
< sal_Int32
>& rSelectedPos
, std::u16string_view rText
, sal_Unicode cTokenSep
, const ImplEntryList
& rEntryList
)
56 const sal_Int32 nPos
= rEntryList
.FindEntry(comphelper::string::strip(o3tl::getToken(rText
, 0, cTokenSep
, nIdx
), ' '));
57 if ( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
58 rSelectedPos
.insert( nPos
);
62 ComboBox::ComboBox(vcl::Window
*const pParent
, WinBits
const nStyle
)
63 : Edit( WindowType::COMBOBOX
)
66 , m_isDDAutoSize(false)
67 , m_isSyntheticModify(false)
68 , m_isKeyBoardModify(false)
69 , m_isMatchCase(false)
73 ImplInitComboBoxData();
74 ImplInit( pParent
, nStyle
);
83 void ComboBox::dispose()
85 m_pSubEdit
.disposeAndClear();
87 VclPtr
< ImplListBox
> pImplLB
= m_pImplLB
;
89 pImplLB
.disposeAndClear();
91 m_pFloatWin
.disposeAndClear();
92 m_pBtn
.disposeAndClear();
96 void ComboBox::ImplInitComboBoxData()
98 m_pSubEdit
.disposeAndClear();
101 m_pFloatWin
= nullptr;
104 m_isDDAutoSize
= true;
105 m_isSyntheticModify
= false;
106 m_isKeyBoardModify
= false;
107 m_isMatchCase
= false;
109 m_nMaxWidthChars
= -1;
110 m_nWidthInChars
= -1;
113 void ComboBox::ImplCalcEditHeight()
115 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
116 GetBorder( nLeft
, nTop
, nRight
, nBottom
);
117 m_nDDHeight
= static_cast<sal_uInt16
>(m_pSubEdit
->GetTextHeight() + nTop
+ nBottom
+ 4);
118 if ( !IsDropDownBox() )
121 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), Size( 10, 10 ) );
122 tools::Rectangle aBoundRegion
, aContentRegion
;
123 ImplControlValue aControlValue
;
124 ControlType aType
= IsDropDownBox() ? ControlType::Combobox
: ControlType::Editbox
;
125 if( GetNativeControlRegion( aType
, ControlPart::Entire
,
127 ControlState::ENABLED
,
129 aBoundRegion
, aContentRegion
) )
131 const tools::Long nNCHeight
= aBoundRegion
.GetHeight();
132 if (m_nDDHeight
< nNCHeight
)
133 m_nDDHeight
= sal::static_int_cast
<sal_uInt16
>(nNCHeight
);
137 void ComboBox::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
139 bool bNoBorder
= ( nStyle
& WB_NOBORDER
) != 0;
140 if ( !(nStyle
& WB_DROPDOWN
) )
142 nStyle
&= ~WB_BORDER
;
143 nStyle
|= WB_NOBORDER
;
151 Edit::ImplInit( pParent
, nStyle
);
155 WinBits nEditStyle
= nStyle
& ( WB_LEFT
| WB_RIGHT
| WB_CENTER
);
156 WinBits nListStyle
= nStyle
;
157 if( nStyle
& WB_DROPDOWN
)
159 m_pFloatWin
= VclPtr
<ImplListBoxFloatingWindow
>::Create( this );
160 if (!IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Focus
))
161 m_pFloatWin
->RequestDoubleBuffering(true);
162 m_pFloatWin
->SetAutoWidth( true );
163 m_pFloatWin
->SetPopupModeEndHdl(LINK(this, ComboBox
, ImplPopupModeEndHdl
));
165 m_pBtn
= VclPtr
<ImplBtn
>::Create( this, WB_NOLIGHTBORDER
| WB_RECTSTYLE
);
166 ImplInitDropDownButton( m_pBtn
);
167 m_pBtn
->SetMBDownHdl(LINK(this, ComboBox
, ImplClickBtnHdl
));
170 nEditStyle
|= WB_NOBORDER
;
171 nListStyle
&= ~WB_BORDER
;
172 nListStyle
|= WB_NOBORDER
;
178 nEditStyle
|= WB_BORDER
;
179 nListStyle
&= ~WB_NOBORDER
;
180 nListStyle
|= WB_BORDER
;
184 m_pSubEdit
.set( VclPtr
<Edit
>::Create( this, nEditStyle
) );
185 m_pSubEdit
->EnableRTL( false );
186 SetSubEdit( m_pSubEdit
);
187 m_pSubEdit
->SetPosPixel( Point() );
188 EnableAutocomplete( true );
191 vcl::Window
* pLBParent
= this;
193 pLBParent
= m_pFloatWin
;
194 m_pImplLB
= VclPtr
<ImplListBox
>::Create( pLBParent
, nListStyle
|WB_SIMPLEMODE
|WB_AUTOHSCROLL
);
195 m_pImplLB
->SetPosPixel( Point() );
196 m_pImplLB
->SetSelectHdl(LINK(this, ComboBox
, ImplSelectHdl
));
197 m_pImplLB
->SetCancelHdl( LINK(this, ComboBox
, ImplCancelHdl
));
198 m_pImplLB
->SetDoubleClickHdl(LINK(this, ComboBox
, ImplDoubleClickHdl
));
199 m_pImplLB
->SetSelectionChangedHdl(LINK(this, ComboBox
, ImplSelectionChangedHdl
));
200 m_pImplLB
->SetListItemSelectHdl(LINK(this, ComboBox
, ImplListItemSelectHdl
));
204 m_pFloatWin
->SetImplListBox(m_pImplLB
);
206 GetMainWindow()->AllowGrabFocus( true );
208 ImplCalcEditHeight();
210 SetCompoundControl( true );
213 WinBits
ComboBox::ImplInitStyle( WinBits nStyle
)
215 if ( !(nStyle
& WB_NOTABSTOP
) )
216 nStyle
|= WB_TABSTOP
;
217 if ( !(nStyle
& WB_NOGROUP
) )
222 void ComboBox::EnableAutocomplete( bool bEnable
, bool bMatchCase
)
224 m_isMatchCase
= bMatchCase
;
227 m_pSubEdit
->SetAutocompleteHdl(LINK(this, ComboBox
, ImplAutocompleteHdl
));
229 m_pSubEdit
->SetAutocompleteHdl( Link
<Edit
&,void>() );
232 bool ComboBox::IsAutocompleteEnabled() const
234 return m_pSubEdit
->GetAutocompleteHdl().IsSet();
237 IMPL_LINK_NOARG(ComboBox
, ImplClickBtnHdl
, void*, void)
239 CallEventListeners( VclEventId::DropdownPreOpen
);
240 m_pSubEdit
->GrabFocus();
241 if (!m_pImplLB
->GetEntryList().GetMRUCount())
242 ImplUpdateFloatSelection();
244 m_pImplLB
->SelectEntry( 0 , true );
245 m_pBtn
->SetPressed( true );
246 SetSelection( Selection( 0, SELECTION_MAX
) );
247 m_pFloatWin
->StartFloat( true );
248 CallEventListeners( VclEventId::DropdownOpen
);
250 ImplClearLayoutData();
252 m_pImplLB
->GetMainWindow()->ImplClearLayoutData();
255 IMPL_LINK_NOARG(ComboBox
, ImplPopupModeEndHdl
, FloatingWindow
*, void)
257 if (m_pFloatWin
->IsPopupModeCanceled())
259 if (!m_pImplLB
->GetEntryList().IsEntryPosSelected(
260 m_pFloatWin
->GetPopupModeStartSaveSelection()))
262 m_pImplLB
->SelectEntry(m_pFloatWin
->GetPopupModeStartSaveSelection(), true);
263 bool bTravelSelect
= m_pImplLB
->IsTravelSelect();
264 m_pImplLB
->SetTravelSelect( true );
266 m_pImplLB
->SetTravelSelect( bTravelSelect
);
270 ImplClearLayoutData();
272 m_pImplLB
->GetMainWindow()->ImplClearLayoutData();
274 m_pBtn
->SetPressed( false );
275 CallEventListeners( VclEventId::DropdownClose
);
278 IMPL_LINK(ComboBox
, ImplAutocompleteHdl
, Edit
&, rEdit
, void)
280 Selection aSel
= rEdit
.GetSelection();
283 OUString aFullText
= rEdit
.GetText();
284 OUString aStartText
= aFullText
.copy( 0, static_cast<sal_Int32
>(aSel
.Max()) );
285 sal_Int32 nStart
= m_pImplLB
->GetCurrentPos();
287 if ( nStart
== LISTBOX_ENTRY_NOTFOUND
)
290 sal_Int32 nPos
= LISTBOX_ENTRY_NOTFOUND
;
293 // Try match case insensitive from current position
294 nPos
= m_pImplLB
->GetEntryList().FindMatchingEntry(aStartText
, nStart
, true);
295 if ( nPos
== LISTBOX_ENTRY_NOTFOUND
)
296 // Try match case insensitive, but from start
297 nPos
= m_pImplLB
->GetEntryList().FindMatchingEntry(aStartText
, 0, true);
300 if ( nPos
== LISTBOX_ENTRY_NOTFOUND
)
301 // Try match full from current position
302 nPos
= m_pImplLB
->GetEntryList().FindMatchingEntry(aStartText
, nStart
, false);
303 if ( nPos
== LISTBOX_ENTRY_NOTFOUND
)
304 // Match full, but from start
305 nPos
= m_pImplLB
->GetEntryList().FindMatchingEntry(aStartText
, 0, false);
307 if ( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
309 OUString aText
= m_pImplLB
->GetEntryList().GetEntryText( nPos
);
310 Selection
aSelection( aText
.getLength(), aStartText
.getLength() );
311 rEdit
.SetText( aText
, aSelection
);
316 IMPL_LINK_NOARG(ComboBox
, ImplSelectHdl
, LinkParamNone
*, void)
318 bool bPopup
= IsInDropDown();
319 bool bCallSelect
= false;
320 if (m_pImplLB
->IsSelectionChanged() || bPopup
)
323 if (IsMultiSelectionEnabled())
325 aText
= m_pSubEdit
->GetText();
327 // remove all entries to which there is an entry, but which is not selected
328 sal_Int32 nIndex
= 0;
329 while ( nIndex
>= 0 )
331 sal_Int32 nPrevIndex
= nIndex
;
332 std::u16string_view aToken
= o3tl::getToken(aText
, 0, m_cMultiSep
, nIndex
);
333 sal_Int32 nTokenLen
= aToken
.size();
334 aToken
= comphelper::string::strip(aToken
, ' ');
335 sal_Int32 nP
= m_pImplLB
->GetEntryList().FindEntry( aToken
);
336 if ((nP
!= LISTBOX_ENTRY_NOTFOUND
) && (!m_pImplLB
->GetEntryList().IsEntryPosSelected(nP
)))
338 aText
= aText
.replaceAt( nPrevIndex
, nTokenLen
, u
"" );
339 nIndex
= nIndex
- nTokenLen
;
340 sal_Int32 nSepCount
=0;
341 if ((nPrevIndex
+nSepCount
< aText
.getLength()) && (aText
[nPrevIndex
+nSepCount
] == m_cMultiSep
))
346 aText
= aText
.replaceAt( nPrevIndex
, nSepCount
, u
"" );
348 aText
= comphelper::string::strip(aText
, ' ');
351 // attach missing entries
352 ::std::set
< sal_Int32
> aSelInText
;
353 lcl_GetSelectedEntries( aSelInText
, aText
, m_cMultiSep
, m_pImplLB
->GetEntryList() );
354 sal_Int32 nSelectedEntries
= m_pImplLB
->GetEntryList().GetSelectedEntryCount();
355 for ( sal_Int32 n
= 0; n
< nSelectedEntries
; n
++ )
357 sal_Int32 nP
= m_pImplLB
->GetEntryList().GetSelectedEntryPos( n
);
358 if ( !aSelInText
.count( nP
) )
360 if (!aText
.isEmpty() && (aText
[aText
.getLength()-1] != m_cMultiSep
))
361 aText
+= OUStringChar(m_cMultiSep
);
362 if ( !aText
.isEmpty() )
363 aText
+= " "; // slightly loosen
364 aText
+= m_pImplLB
->GetEntryList().GetEntryText( nP
) +
365 OUStringChar(m_cMultiSep
);
368 aText
= comphelper::string::stripEnd( aText
, m_cMultiSep
);
372 aText
= m_pImplLB
->GetEntryList().GetSelectedEntry( 0 );
375 m_pSubEdit
->SetText( aText
);
377 switch (GetSettings().GetStyleSettings().GetComboBoxTextSelectionMode())
379 case ComboBoxTextSelectionMode::SelectText
:
381 Selection
aNewSelection(0, aText
.getLength());
382 if (IsMultiSelectionEnabled())
383 aNewSelection
.Min() = aText
.getLength();
384 m_pSubEdit
->SetSelection(aNewSelection
);
387 case ComboBoxTextSelectionMode::CursorToStart
:
389 Selection
aNewSelection(0, 0);
390 m_pSubEdit
->SetSelection(aNewSelection
);
393 case ComboBoxTextSelectionMode::CursorToEnd
:
395 m_pSubEdit
->SetCursorAtLast();
399 assert(false && "Unhandled ComboBoxTextSelectionMode case");
406 // #84652# Call GrabFocus and EndPopupMode before calling Select/Modify, but after changing the text
407 bool bMenuSelect
= bPopup
&& !m_pImplLB
->IsTravelSelect() && (!IsMultiSelectionEnabled() || !m_pImplLB
->GetSelectModifier());
410 m_pFloatWin
->EndPopupMode();
416 m_isKeyBoardModify
= !bMenuSelect
;
417 m_pSubEdit
->SetModifyFlag();
418 m_isSyntheticModify
= true;
420 m_isSyntheticModify
= false;
422 m_isKeyBoardModify
= false;
426 bool ComboBox::IsSyntheticModify() const
428 return m_isSyntheticModify
;
431 bool ComboBox::IsModifyByKeyboard() const
433 return m_isKeyBoardModify
;
436 IMPL_LINK_NOARG(ComboBox
, ImplListItemSelectHdl
, LinkParamNone
*, void)
438 CallEventListeners(VclEventId::DropdownSelect
);
441 IMPL_LINK_NOARG(ComboBox
, ImplCancelHdl
, LinkParamNone
*, void)
444 m_pFloatWin
->EndPopupMode();
447 IMPL_LINK( ComboBox
, ImplSelectionChangedHdl
, sal_Int32
, nChanged
, void)
449 if (!m_pImplLB
->IsTrackingSelect())
451 if (!m_pSubEdit
->IsReadOnly() && m_pImplLB
->GetEntryList().IsEntryPosSelected(nChanged
))
452 m_pSubEdit
->SetText(m_pImplLB
->GetEntryList().GetEntryText(nChanged
));
456 IMPL_LINK_NOARG(ComboBox
, ImplDoubleClickHdl
, ImplListBoxWindow
*, void)
461 void ComboBox::ToggleDropDown()
463 if( !IsDropDownBox() )
466 if (m_pFloatWin
->IsInPopupMode())
467 m_pFloatWin
->EndPopupMode();
470 m_pSubEdit
->GrabFocus();
471 if (!m_pImplLB
->GetEntryList().GetMRUCount())
472 ImplUpdateFloatSelection();
474 m_pImplLB
->SelectEntry( 0 , true );
475 CallEventListeners( VclEventId::DropdownPreOpen
);
476 m_pBtn
->SetPressed( true );
477 SetSelection( Selection( 0, SELECTION_MAX
) );
478 m_pFloatWin
->StartFloat(true);
479 CallEventListeners( VclEventId::DropdownOpen
);
483 void ComboBox::Select()
485 ImplCallEventListenersAndHandler( VclEventId::ComboboxSelect
, [this] () { m_SelectHdl
.Call(*this); } );
488 void ComboBox::DoubleClick()
490 ImplCallEventListenersAndHandler( VclEventId::ComboboxDoubleClick
, [] () {} );
493 bool ComboBox::IsAutoSizeEnabled() const { return m_isDDAutoSize
; }
495 void ComboBox::EnableAutoSize( bool bAuto
)
497 m_isDDAutoSize
= bAuto
;
500 if (bAuto
&& !m_pFloatWin
->GetDropDownLineCount())
502 // Adapt to GetListBoxMaximumLineCount here; was on fixed number of five before
503 AdaptDropDownLineCountToMaximum();
507 m_pFloatWin
->SetDropDownLineCount(0);
512 void ComboBox::SetDropDownLineCount( sal_uInt16 nLines
)
515 m_pFloatWin
->SetDropDownLineCount(nLines
);
518 void ComboBox::AdaptDropDownLineCountToMaximum()
520 // Adapt to maximum allowed number.
521 // Limit for LOK as we can't render outside of the dialog canvas.
522 if (comphelper::LibreOfficeKit::isActive())
523 SetDropDownLineCount(11);
525 SetDropDownLineCount(GetSettings().GetStyleSettings().GetListBoxMaximumLineCount());
528 sal_uInt16
ComboBox::GetDropDownLineCount() const
530 sal_uInt16 nLines
= 0;
532 nLines
= m_pFloatWin
->GetDropDownLineCount();
536 void ComboBox::setPosSizePixel( tools::Long nX
, tools::Long nY
, tools::Long nWidth
, tools::Long nHeight
,
537 PosSizeFlags nFlags
)
539 if( IsDropDownBox() && ( nFlags
& PosSizeFlags::Size
) )
541 Size aPrefSz
= m_pFloatWin
->GetPrefSize();
542 if ((nFlags
& PosSizeFlags::Height
) && (nHeight
>= 2*m_nDDHeight
))
543 aPrefSz
.setHeight( nHeight
-m_nDDHeight
);
544 if ( nFlags
& PosSizeFlags::Width
)
545 aPrefSz
.setWidth( nWidth
);
546 m_pFloatWin
->SetPrefSize(aPrefSz
);
548 if (IsAutoSizeEnabled())
549 nHeight
= m_nDDHeight
;
552 Edit::setPosSizePixel( nX
, nY
, nWidth
, nHeight
, nFlags
);
555 void ComboBox::Resize()
561 Size aOutSz
= GetOutputSizePixel();
562 if( IsDropDownBox() )
564 ComboBoxBounds
aBounds(calcComboBoxDropDownComponentBounds(aOutSz
,
565 GetWindow(GetWindowType::Border
)->GetOutputSizePixel()));
566 m_pSubEdit
->SetPosSizePixel(aBounds
.aSubEditPos
, aBounds
.aSubEditSize
);
567 m_pBtn
->SetPosSizePixel(aBounds
.aButtonPos
, aBounds
.aButtonSize
);
571 m_pSubEdit
->SetSizePixel(Size(aOutSz
.Width(), m_nDDHeight
));
572 m_pImplLB
->setPosSizePixel(0, m_nDDHeight
,
573 aOutSz
.Width(), aOutSz
.Height() - m_nDDHeight
);
574 if ( !GetText().isEmpty() )
575 ImplUpdateFloatSelection();
579 // adjust the size of the FloatingWindow even when invisible
580 // as KEY_PGUP/DOWN is being processed...
582 m_pFloatWin
->SetSizePixel(m_pFloatWin
->CalcFloatSize());
585 bool ComboBox::IsDropDownBox() const { return m_pFloatWin
!= nullptr; }
587 void ComboBox::FillLayoutData() const
589 mxLayoutData
.emplace();
590 AppendLayoutData( *m_pSubEdit
);
591 m_pSubEdit
->SetLayoutDataParent( this );
592 ImplListBoxWindow
* rMainWindow
= GetMainWindow();
596 if (m_pFloatWin
->IsReallyVisible())
598 AppendLayoutData( *rMainWindow
);
599 rMainWindow
->SetLayoutDataParent( this );
604 AppendLayoutData( *rMainWindow
);
605 rMainWindow
->SetLayoutDataParent( this );
609 void ComboBox::StateChanged( StateChangedType nType
)
611 Edit::StateChanged( nType
);
613 if ( nType
== StateChangedType::ReadOnly
)
615 m_pImplLB
->SetReadOnly( IsReadOnly() );
617 m_pBtn
->Enable( IsEnabled() && !IsReadOnly() );
619 else if ( nType
== StateChangedType::Enable
)
621 m_pSubEdit
->Enable( IsEnabled() );
622 m_pImplLB
->Enable( IsEnabled() && !IsReadOnly() );
624 m_pBtn
->Enable( IsEnabled() && !IsReadOnly() );
627 else if( nType
== StateChangedType::UpdateMode
)
629 m_pImplLB
->SetUpdateMode( IsUpdateMode() );
631 else if ( nType
== StateChangedType::Zoom
)
633 m_pImplLB
->SetZoom( GetZoom() );
634 m_pSubEdit
->SetZoom( GetZoom() );
635 ImplCalcEditHeight();
638 else if ( nType
== StateChangedType::ControlFont
)
640 m_pImplLB
->SetControlFont( GetControlFont() );
641 m_pSubEdit
->SetControlFont( GetControlFont() );
642 ImplCalcEditHeight();
645 else if ( nType
== StateChangedType::ControlForeground
)
647 m_pImplLB
->SetControlForeground( GetControlForeground() );
648 m_pSubEdit
->SetControlForeground( GetControlForeground() );
650 else if ( nType
== StateChangedType::ControlBackground
)
652 m_pImplLB
->SetControlBackground( GetControlBackground() );
653 m_pSubEdit
->SetControlBackground( GetControlBackground() );
655 else if ( nType
== StateChangedType::Style
)
657 SetStyle( ImplInitStyle( GetStyle() ) );
658 GetMainWindow()->EnableSort( ( GetStyle() & WB_SORT
) != 0 );
660 else if( nType
== StateChangedType::Mirroring
)
664 m_pBtn
->EnableRTL( IsRTLEnabled() );
665 ImplInitDropDownButton( m_pBtn
);
667 m_pSubEdit
->CompatStateChanged( StateChangedType::Mirroring
);
668 m_pImplLB
->EnableRTL( IsRTLEnabled() );
673 void ComboBox::DataChanged( const DataChangedEvent
& rDCEvt
)
675 Control::DataChanged( rDCEvt
);
677 if ( !((rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
678 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
679 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
680 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))) )
685 m_pBtn
->GetOutDev()->SetSettings( GetSettings() );
686 ImplInitDropDownButton( m_pBtn
);
689 m_pImplLB
->Resize(); // not called by ComboBox::Resize() if ImplLB is unchanged
691 SetBackground(); // due to a hack in Window::UpdateSettings the background must be reset
692 // otherwise it will overpaint NWF drawn comboboxes
695 bool ComboBox::EventNotify( NotifyEvent
& rNEvt
)
698 if ((rNEvt
.GetType() == NotifyEventType::KEYINPUT
)
699 && (rNEvt
.GetWindow() == m_pSubEdit
)
702 KeyEvent aKeyEvt
= *rNEvt
.GetKeyEvent();
703 sal_uInt16 nKeyCode
= aKeyEvt
.GetKeyCode().GetCode();
711 ImplUpdateFloatSelection();
712 if ((nKeyCode
== KEY_DOWN
) && m_pFloatWin
713 && !m_pFloatWin
->IsInPopupMode()
714 && aKeyEvt
.GetKeyCode().IsMod2())
716 CallEventListeners( VclEventId::DropdownPreOpen
);
717 m_pBtn
->SetPressed( true );
718 if (m_pImplLB
->GetEntryList().GetMRUCount())
719 m_pImplLB
->SelectEntry( 0 , true );
720 SetSelection( Selection( 0, SELECTION_MAX
) );
721 m_pFloatWin
->StartFloat(false);
722 CallEventListeners( VclEventId::DropdownOpen
);
725 else if ((nKeyCode
== KEY_UP
) && m_pFloatWin
726 && m_pFloatWin
->IsInPopupMode()
727 && aKeyEvt
.GetKeyCode().IsMod2())
729 m_pFloatWin
->EndPopupMode();
734 bDone
= m_pImplLB
->ProcessKeyInput( aKeyEvt
);
741 if ((rNEvt
.GetWindow() == m_pSubEdit
) && IsInDropDown())
743 m_pImplLB
->ProcessKeyInput( aKeyEvt
);
750 else if ((rNEvt
.GetType() == NotifyEventType::LOSEFOCUS
) && m_pFloatWin
)
752 if (m_pFloatWin
->HasChildPathFocus())
753 m_pSubEdit
->GrabFocus();
754 else if (m_pFloatWin
->IsInPopupMode() && !HasChildPathFocus(true))
755 m_pFloatWin
->EndPopupMode();
757 else if( (rNEvt
.GetType() == NotifyEventType::COMMAND
) &&
758 (rNEvt
.GetCommandEvent()->GetCommand() == CommandEventId::Wheel
) &&
759 (rNEvt
.GetWindow() == m_pSubEdit
) )
761 MouseWheelBehaviour
nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
762 if ( ( nWheelBehavior
== MouseWheelBehaviour::ALWAYS
)
763 || ( ( nWheelBehavior
== MouseWheelBehaviour::FocusOnly
)
764 && HasChildPathFocus()
768 bDone
= m_pImplLB
->HandleWheelAsCursorTravel(*rNEvt
.GetCommandEvent(), *this);
772 bDone
= false; // don't eat this event, let the default handling happen (i.e. scroll the context)
775 else if ((rNEvt
.GetType() == NotifyEventType::MOUSEBUTTONDOWN
)
776 && (rNEvt
.GetWindow() == GetMainWindow()))
778 m_pSubEdit
->GrabFocus();
781 return bDone
|| Edit::EventNotify( rNEvt
);
784 void ComboBox::SetText( const OUString
& rStr
)
786 CallEventListeners( VclEventId::ComboboxSetText
);
788 Edit::SetText( rStr
);
789 ImplUpdateFloatSelection();
792 void ComboBox::SetText( const OUString
& rStr
, const Selection
& rNewSelection
)
794 CallEventListeners( VclEventId::ComboboxSetText
);
796 Edit::SetText( rStr
, rNewSelection
);
797 ImplUpdateFloatSelection();
800 void ComboBox::Modify()
802 if (!m_isSyntheticModify
)
803 ImplUpdateFloatSelection();
808 void ComboBox::ImplUpdateFloatSelection()
810 if (!m_pImplLB
|| !m_pSubEdit
)
813 // move text in the ListBox into the visible region
814 m_pImplLB
->SetCallSelectionChangedHdl( false );
815 if (!IsMultiSelectionEnabled())
817 OUString
aSearchStr( m_pSubEdit
->GetText() );
818 sal_Int32 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
821 if (m_pImplLB
->GetCurrentPos() != LISTBOX_ENTRY_NOTFOUND
)
823 OUString aCurrent
= m_pImplLB
->GetEntryList().GetEntryText(
824 m_pImplLB
->GetCurrentPos());
825 if ( aCurrent
== aSearchStr
)
826 nSelect
= m_pImplLB
->GetCurrentPos();
829 if ( nSelect
== LISTBOX_ENTRY_NOTFOUND
)
830 nSelect
= m_pImplLB
->GetEntryList().FindEntry( aSearchStr
);
831 if ( nSelect
== LISTBOX_ENTRY_NOTFOUND
)
833 nSelect
= m_pImplLB
->GetEntryList().FindMatchingEntry( aSearchStr
, 0, true );
837 if( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
839 if (!m_pImplLB
->IsVisible(nSelect
))
840 m_pImplLB
->ShowProminentEntry( nSelect
);
841 m_pImplLB
->SelectEntry( nSelect
, bSelect
);
845 nSelect
= m_pImplLB
->GetEntryList().GetSelectedEntryPos( 0 );
846 if( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
847 m_pImplLB
->SelectEntry( nSelect
, false );
848 m_pImplLB
->ResetCurrentPos();
853 ::std::set
< sal_Int32
> aSelInText
;
854 lcl_GetSelectedEntries(aSelInText
, m_pSubEdit
->GetText(), m_cMultiSep
, m_pImplLB
->GetEntryList());
855 for (sal_Int32 n
= 0; n
< m_pImplLB
->GetEntryList().GetEntryCount(); n
++)
856 m_pImplLB
->SelectEntry( n
, aSelInText
.count( n
) != 0 );
858 m_pImplLB
->SetCallSelectionChangedHdl( true );
861 sal_Int32
ComboBox::InsertEntry(const OUString
& rStr
, sal_Int32
const nPos
)
863 assert(nPos
>= 0 && COMBOBOX_MAX_ENTRIES
> m_pImplLB
->GetEntryList().GetEntryCount());
866 if (nPos
== COMBOBOX_APPEND
)
870 const sal_Int32 nMRUCount
= m_pImplLB
->GetEntryList().GetMRUCount();
871 assert(nPos
<= COMBOBOX_MAX_ENTRIES
- nMRUCount
);
872 nRealPos
= nPos
+ nMRUCount
;
875 nRealPos
= m_pImplLB
->InsertEntry( nRealPos
, rStr
);
876 nRealPos
-= m_pImplLB
->GetEntryList().GetMRUCount();
877 CallEventListeners( VclEventId::ComboboxItemAdded
, reinterpret_cast<void*>(static_cast<sal_IntPtr
>(nRealPos
)) );
881 sal_Int32
ComboBox::InsertEntryWithImage(
882 const OUString
& rStr
, const Image
& rImage
, sal_Int32
const nPos
)
884 assert(nPos
>= 0 && COMBOBOX_MAX_ENTRIES
> m_pImplLB
->GetEntryList().GetEntryCount());
887 if (nPos
== COMBOBOX_APPEND
)
891 const sal_Int32 nMRUCount
= m_pImplLB
->GetEntryList().GetMRUCount();
892 assert(nPos
<= COMBOBOX_MAX_ENTRIES
- nMRUCount
);
893 nRealPos
= nPos
+ nMRUCount
;
896 nRealPos
= m_pImplLB
->InsertEntry( nRealPos
, rStr
, rImage
);
897 nRealPos
-= m_pImplLB
->GetEntryList().GetMRUCount();
898 CallEventListeners( VclEventId::ComboboxItemAdded
, reinterpret_cast<void*>(static_cast<sal_IntPtr
>(nRealPos
)) );
902 void ComboBox::RemoveEntryAt(sal_Int32
const nPos
)
904 const sal_Int32 nMRUCount
= m_pImplLB
->GetEntryList().GetMRUCount();
905 assert(nPos
>= 0 && nPos
<= COMBOBOX_MAX_ENTRIES
- nMRUCount
);
906 m_pImplLB
->RemoveEntry( nPos
+ nMRUCount
);
907 CallEventListeners( VclEventId::ComboboxItemRemoved
, reinterpret_cast<void*>(static_cast<sal_IntPtr
>(nPos
)) );
910 void ComboBox::Clear()
915 CallEventListeners( VclEventId::ComboboxItemRemoved
, reinterpret_cast<void*>(sal_IntPtr(-1)) );
918 Image
ComboBox::GetEntryImage( sal_Int32 nPos
) const
920 if (m_pImplLB
->GetEntryList().HasEntryImage(nPos
))
921 return m_pImplLB
->GetEntryList().GetEntryImage( nPos
);
925 sal_Int32
ComboBox::GetEntryPos( std::u16string_view rStr
) const
927 sal_Int32 nPos
= m_pImplLB
->GetEntryList().FindEntry( rStr
);
928 if ( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
929 nPos
-= m_pImplLB
->GetEntryList().GetMRUCount();
933 OUString
ComboBox::GetEntry( sal_Int32 nPos
) const
935 const sal_Int32 nMRUCount
= m_pImplLB
->GetEntryList().GetMRUCount();
936 if (nPos
< 0 || nPos
> COMBOBOX_MAX_ENTRIES
- nMRUCount
)
939 return m_pImplLB
->GetEntryList().GetEntryText( nPos
+ nMRUCount
);
942 sal_Int32
ComboBox::GetEntryCount() const
946 return m_pImplLB
->GetEntryList().GetEntryCount() - m_pImplLB
->GetEntryList().GetMRUCount();
949 bool ComboBox::IsTravelSelect() const
951 return m_pImplLB
->IsTravelSelect();
954 bool ComboBox::IsInDropDown() const
956 // when the dropdown is dismissed, first mbInPopupMode is set to false, and on the next event iteration then
957 // mbPopupMode is set to false
958 return m_pFloatWin
&& m_pFloatWin
->IsInPopupMode() && m_pFloatWin
->ImplIsInPrivatePopupMode();
961 bool ComboBox::IsMultiSelectionEnabled() const
963 return m_pImplLB
->IsMultiSelectionEnabled();
966 void ComboBox::SetSelectHdl(const Link
<ComboBox
&,void>& rLink
) { m_SelectHdl
= rLink
; }
968 void ComboBox::SetEntryActivateHdl(const Link
<Edit
&,bool>& rLink
)
972 m_pSubEdit
->SetActivateHdl(rLink
);
975 Size
ComboBox::GetOptimalSize() const
977 return CalcMinimumSize();
980 tools::Long
ComboBox::getMaxWidthScrollBarAndDownButton() const
982 tools::Long nButtonDownWidth
= 0;
984 vcl::Window
*pBorder
= GetWindow( GetWindowType::Border
);
985 ImplControlValue aControlValue
;
986 tools::Rectangle aContent
, aBound
;
988 // use the full extent of the control
989 tools::Rectangle
aArea( Point(), pBorder
->GetOutputSizePixel() );
991 if ( GetNativeControlRegion(ControlType::Combobox
, ControlPart::ButtonDown
,
992 aArea
, ControlState::NONE
, aControlValue
, aBound
, aContent
) )
994 nButtonDownWidth
= aContent
.getOpenWidth();
997 tools::Long nScrollBarWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
999 return std::max(nScrollBarWidth
, nButtonDownWidth
);
1002 Size
ComboBox::CalcMinimumSize() const
1009 if (!IsDropDownBox())
1011 aSz
= m_pImplLB
->CalcSize( m_pImplLB
->GetEntryList().GetEntryCount() );
1012 aSz
.AdjustHeight(m_nDDHeight
);
1016 aSz
.setHeight( Edit::CalcMinimumSizeForText(GetText()).Height() );
1018 if (m_nWidthInChars
!= -1)
1019 aSz
.setWidth(m_nWidthInChars
* approximate_digit_width());
1021 aSz
.setWidth(m_pImplLB
->GetMaxEntryWidth());
1024 if (m_nMaxWidthChars
!= -1)
1026 tools::Long nMaxWidth
= m_nMaxWidthChars
* approximate_char_width();
1027 aSz
.setWidth( std::min(aSz
.Width(), nMaxWidth
) );
1030 if (IsDropDownBox())
1031 aSz
.AdjustWidth(getMaxWidthScrollBarAndDownButton() );
1033 ComboBoxBounds
aBounds(calcComboBoxDropDownComponentBounds(
1034 Size(0xFFFF, 0xFFFF), Size(0xFFFF, 0xFFFF)));
1035 aSz
.AdjustWidth(aBounds
.aSubEditPos
.X()*2 );
1037 aSz
.AdjustWidth(ImplGetExtraXOffset() * 2 );
1039 aSz
= CalcWindowSize( aSz
);
1043 Size
ComboBox::CalcAdjustedSize( const Size
& rPrefSize
) const
1045 Size aSz
= rPrefSize
;
1046 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
1047 static_cast<vcl::Window
*>(const_cast<ComboBox
*>(this))->GetBorder( nLeft
, nTop
, nRight
, nBottom
);
1048 aSz
.AdjustHeight( -(nTop
+nBottom
) );
1049 if ( !IsDropDownBox() )
1051 tools::Long nEntryHeight
= CalcBlockSize( 1, 1 ).Height();
1052 tools::Long nLines
= aSz
.Height() / nEntryHeight
;
1055 aSz
.setHeight( nLines
* nEntryHeight
);
1056 aSz
.AdjustHeight(m_nDDHeight
);
1060 aSz
.setHeight( m_nDDHeight
);
1062 aSz
.AdjustHeight(nTop
+nBottom
);
1064 aSz
= CalcWindowSize( aSz
);
1068 Size
ComboBox::CalcBlockSize( sal_uInt16 nColumns
, sal_uInt16 nLines
) const
1070 // show ScrollBars where appropriate
1071 Size aMinSz
= CalcMinimumSize();
1077 if ( !IsDropDownBox() )
1078 aSz
.setHeight( m_pImplLB
->CalcSize( nLines
).Height() + m_nDDHeight
);
1080 aSz
.setHeight( m_nDDHeight
);
1083 aSz
.setHeight( aMinSz
.Height() );
1087 aSz
.setWidth( nColumns
* approximate_char_width() );
1089 aSz
.setWidth( aMinSz
.Width() );
1091 if ( IsDropDownBox() )
1092 aSz
.AdjustWidth(getMaxWidthScrollBarAndDownButton() );
1094 if ( !IsDropDownBox() )
1096 if ( aSz
.Width() < aMinSz
.Width() )
1097 aSz
.AdjustHeight(GetSettings().GetStyleSettings().GetScrollBarSize() );
1098 if ( aSz
.Height() < aMinSz
.Height() )
1099 aSz
.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
1102 aSz
.AdjustWidth(ImplGetExtraXOffset() * 2 );
1104 aSz
= CalcWindowSize( aSz
);
1108 tools::Long
ComboBox::GetDropDownEntryHeight() const
1110 return m_pImplLB
->GetEntryHeight();
1113 void ComboBox::GetMaxVisColumnsAndLines( sal_uInt16
& rnCols
, sal_uInt16
& rnLines
) const
1115 tools::Long nCharWidth
= GetTextWidth(OUString(u
'x'));
1116 if ( !IsDropDownBox() )
1118 Size aOutSz
= GetMainWindow()->GetOutputSizePixel();
1119 rnCols
= (nCharWidth
> 0) ? static_cast<sal_uInt16
>(aOutSz
.Width()/nCharWidth
) : 1;
1120 rnLines
= static_cast<sal_uInt16
>(aOutSz
.Height()/GetDropDownEntryHeight());
1124 Size aOutSz
= m_pSubEdit
->GetOutputSizePixel();
1125 rnCols
= (nCharWidth
> 0) ? static_cast<sal_uInt16
>(aOutSz
.Width()/nCharWidth
) : 1;
1130 void ComboBox::Draw( OutputDevice
* pDev
, const Point
& rPos
, SystemTextColorFlags nFlags
)
1132 GetMainWindow()->ApplySettings(*pDev
);
1134 Point aPos
= pDev
->LogicToPixel( rPos
);
1135 Size aSize
= GetSizePixel();
1136 vcl::Font aFont
= GetMainWindow()->GetDrawPixelFont( pDev
);
1140 pDev
->SetFont( aFont
);
1141 pDev
->SetTextFillColor();
1143 // Border/Background
1144 pDev
->SetLineColor();
1145 pDev
->SetFillColor();
1146 bool bBorder
= (GetStyle() & WB_BORDER
);
1147 bool bBackground
= IsControlBackground();
1148 if ( bBorder
|| bBackground
)
1150 tools::Rectangle
aRect( aPos
, aSize
);
1151 // aRect.Top() += nEditHeight;
1154 ImplDrawFrame( pDev
, aRect
);
1158 pDev
->SetFillColor( GetControlBackground() );
1159 pDev
->DrawRect( aRect
);
1164 if ( !IsDropDownBox() )
1166 tools::Long nOnePixel
= GetDrawPixel( pDev
, 1 );
1167 tools::Long nTextHeight
= pDev
->GetTextHeight();
1168 tools::Long nEditHeight
= nTextHeight
+ 6*nOnePixel
;
1169 DrawTextFlags nTextStyle
= DrawTextFlags::VCenter
;
1171 // First, draw the edit part
1172 Size
aOrigSize(m_pSubEdit
->GetSizePixel());
1173 m_pSubEdit
->SetSizePixel(Size(aSize
.Width(), nEditHeight
));
1174 m_pSubEdit
->Draw( pDev
, aPos
, nFlags
);
1175 m_pSubEdit
->SetSizePixel(aOrigSize
);
1177 // Second, draw the listbox
1178 if ( GetStyle() & WB_CENTER
)
1179 nTextStyle
|= DrawTextFlags::Center
;
1180 else if ( GetStyle() & WB_RIGHT
)
1181 nTextStyle
|= DrawTextFlags::Right
;
1183 nTextStyle
|= DrawTextFlags::Left
;
1185 if ( nFlags
& SystemTextColorFlags::Mono
)
1187 pDev
->SetTextColor( COL_BLACK
);
1193 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
1194 pDev
->SetTextColor( rStyleSettings
.GetDisableColor() );
1198 pDev
->SetTextColor( GetTextColor() );
1202 tools::Rectangle
aClip( aPos
, aSize
);
1203 pDev
->IntersectClipRegion( aClip
);
1204 sal_Int32 nLines
= static_cast<sal_Int32
>( nTextHeight
> 0 ? (aSize
.Height()-nEditHeight
)/nTextHeight
: 1 );
1207 const sal_Int32 nTEntry
= IsReallyVisible() ? m_pImplLB
->GetTopEntry() : 0;
1209 tools::Rectangle
aTextRect( aPos
, aSize
);
1211 aTextRect
.AdjustLeft(3*nOnePixel
);
1212 aTextRect
.AdjustRight( -(3*nOnePixel
) );
1213 aTextRect
.AdjustTop(nEditHeight
+ nOnePixel
);
1214 aTextRect
.SetBottom( aTextRect
.Top() + nTextHeight
);
1216 // the drawing starts here
1217 for ( sal_Int32 n
= 0; n
< nLines
; ++n
)
1219 pDev
->DrawText( aTextRect
, m_pImplLB
->GetEntryList().GetEntryText( n
+nTEntry
), nTextStyle
);
1220 aTextRect
.AdjustTop(nTextHeight
);
1221 aTextRect
.AdjustBottom(nTextHeight
);
1227 // Call Edit::Draw after restoring the MapMode...
1228 if ( IsDropDownBox() )
1230 Size
aOrigSize(m_pSubEdit
->GetSizePixel());
1231 m_pSubEdit
->SetSizePixel(GetSizePixel());
1232 m_pSubEdit
->Draw( pDev
, rPos
, nFlags
);
1233 m_pSubEdit
->SetSizePixel(aOrigSize
);
1238 void ComboBox::SetUserDrawHdl(const Link
<UserDrawEvent
*, void>& rLink
)
1240 m_pImplLB
->SetUserDrawHdl(rLink
);
1243 void ComboBox::SetUserItemSize( const Size
& rSz
)
1245 GetMainWindow()->SetUserItemSize( rSz
);
1248 void ComboBox::EnableUserDraw( bool bUserDraw
)
1250 GetMainWindow()->EnableUserDraw( bUserDraw
);
1253 bool ComboBox::IsUserDrawEnabled() const
1255 return GetMainWindow()->IsUserDrawEnabled();
1258 void ComboBox::DrawEntry(const UserDrawEvent
& rEvt
)
1260 GetMainWindow()->DrawEntry(*rEvt
.GetRenderContext(), rEvt
.GetItemId(), /*bDrawImage*/false, /*bDrawText*/false);
1263 void ComboBox::AddSeparator( sal_Int32 n
)
1265 m_pImplLB
->AddSeparator( n
);
1268 void ComboBox::SetMRUEntries( std::u16string_view rEntries
)
1270 m_pImplLB
->SetMRUEntries( rEntries
, ';' );
1273 OUString
ComboBox::GetMRUEntries() const
1275 return m_pImplLB
? m_pImplLB
->GetMRUEntries( ';' ) : OUString();
1278 void ComboBox::SetMaxMRUCount( sal_Int32 n
)
1280 m_pImplLB
->SetMaxMRUCount( n
);
1283 sal_Int32
ComboBox::GetMaxMRUCount() const
1285 return m_pImplLB
? m_pImplLB
->GetMaxMRUCount() : 0;
1288 sal_uInt16
ComboBox::GetDisplayLineCount() const
1290 return m_pImplLB
? m_pImplLB
->GetDisplayLineCount() : 0;
1293 void ComboBox::SetEntryData( sal_Int32 nPos
, void* pNewData
)
1295 m_pImplLB
->SetEntryData( nPos
+ m_pImplLB
->GetEntryList().GetMRUCount(), pNewData
);
1298 void* ComboBox::GetEntryData( sal_Int32 nPos
) const
1300 return m_pImplLB
->GetEntryList().GetEntryData(
1301 nPos
+ m_pImplLB
->GetEntryList().GetMRUCount() );
1304 sal_Int32
ComboBox::GetTopEntry() const
1306 sal_Int32 nPos
= GetEntryCount() ? m_pImplLB
->GetTopEntry() : LISTBOX_ENTRY_NOTFOUND
;
1307 if (nPos
< m_pImplLB
->GetEntryList().GetMRUCount())
1312 tools::Rectangle
ComboBox::GetDropDownPosSizePixel() const
1315 ? m_pFloatWin
->GetWindowExtentsRelative(*this)
1316 : tools::Rectangle();
1319 const Wallpaper
& ComboBox::GetDisplayBackground() const
1321 if (!m_pSubEdit
->IsBackground())
1322 return Control::GetDisplayBackground();
1324 const Wallpaper
& rBack
= m_pSubEdit
->GetBackground();
1325 if( ! rBack
.IsBitmap() &&
1326 ! rBack
.IsGradient() &&
1327 rBack
== Wallpaper(COL_TRANSPARENT
)
1329 return Control::GetDisplayBackground();
1333 sal_Int32
ComboBox::GetSelectedEntryCount() const
1335 return m_pImplLB
->GetEntryList().GetSelectedEntryCount();
1338 sal_Int32
ComboBox::GetSelectedEntryPos( sal_Int32 nIndex
) const
1340 sal_Int32 nPos
= m_pImplLB
->GetEntryList().GetSelectedEntryPos( nIndex
);
1341 if ( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
1343 if (nPos
< m_pImplLB
->GetEntryList().GetMRUCount())
1344 nPos
= m_pImplLB
->GetEntryList().FindEntry(m_pImplLB
->GetEntryList().GetEntryText(nPos
));
1345 nPos
= sal::static_int_cast
<sal_Int32
>(nPos
- m_pImplLB
->GetEntryList().GetMRUCount());
1350 bool ComboBox::IsEntryPosSelected( sal_Int32 nPos
) const
1352 return m_pImplLB
->GetEntryList().IsEntryPosSelected(
1353 nPos
+ m_pImplLB
->GetEntryList().GetMRUCount() );
1356 void ComboBox::SelectEntryPos( sal_Int32 nPos
, bool bSelect
)
1358 if (nPos
< m_pImplLB
->GetEntryList().GetEntryCount())
1359 m_pImplLB
->SelectEntry(
1360 nPos
+ m_pImplLB
->GetEntryList().GetMRUCount(), bSelect
);
1363 void ComboBox::SetNoSelection()
1365 m_pImplLB
->SetNoSelection();
1366 m_pSubEdit
->SetText(OUString());
1369 tools::Rectangle
ComboBox::GetBoundingRectangle( sal_Int32 nItem
) const
1371 tools::Rectangle aRect
= GetMainWindow()->GetBoundingRectangle( nItem
);
1372 tools::Rectangle aOffset
= GetMainWindow()->GetWindowExtentsRelative( *static_cast<vcl::Window
*>(const_cast<ComboBox
*>(this)) );
1373 aRect
.Move( aOffset
.Left(), aOffset
.Top() );
1377 void ComboBox::SetBorderStyle( WindowBorderStyle nBorderStyle
)
1379 Window::SetBorderStyle( nBorderStyle
);
1380 if ( !IsDropDownBox() )
1382 m_pSubEdit
->SetBorderStyle(nBorderStyle
);
1383 m_pImplLB
->SetBorderStyle( nBorderStyle
);
1387 void ComboBox::SetHighlightColor( const Color
& rColor
)
1389 AllSettings
aSettings(GetSettings());
1390 StyleSettings
aStyle(aSettings
.GetStyleSettings());
1391 aStyle
.SetHighlightColor(rColor
);
1392 aSettings
.SetStyleSettings(aStyle
);
1393 SetSettings(aSettings
);
1395 AllSettings
aSettingsSubEdit(m_pSubEdit
->GetSettings());
1396 StyleSettings
aStyleSubEdit(aSettingsSubEdit
.GetStyleSettings());
1397 aStyleSubEdit
.SetHighlightColor(rColor
);
1398 aSettingsSubEdit
.SetStyleSettings(aStyleSubEdit
);
1399 m_pSubEdit
->SetSettings(aSettings
);
1401 m_pImplLB
->SetHighlightColor(rColor
);
1404 void ComboBox::SetHighlightTextColor( const Color
& rColor
)
1406 AllSettings
aSettings(GetSettings());
1407 StyleSettings
aStyle(aSettings
.GetStyleSettings());
1408 aStyle
.SetHighlightTextColor(rColor
);
1409 aSettings
.SetStyleSettings(aStyle
);
1410 SetSettings(aSettings
);
1412 AllSettings
aSettingsSubEdit(m_pSubEdit
->GetSettings());
1413 StyleSettings
aStyleSubEdit(aSettingsSubEdit
.GetStyleSettings());
1414 aStyleSubEdit
.SetHighlightTextColor(rColor
);
1415 aSettingsSubEdit
.SetStyleSettings(aStyleSubEdit
);
1416 m_pSubEdit
->SetSettings(aSettings
);
1418 m_pImplLB
->SetHighlightTextColor(rColor
);
1421 ImplListBoxWindow
* ComboBox::GetMainWindow() const
1423 return m_pImplLB
->GetMainWindow();
1426 tools::Long
ComboBox::GetIndexForPoint( const Point
& rPoint
, sal_Int32
& rPos
) const
1428 if( !HasLayoutData() )
1431 // check whether rPoint fits at all
1432 tools::Long nIndex
= Control::GetIndexForPoint( rPoint
);
1435 // point must be either in main list window
1436 // or in impl window (dropdown case)
1437 ImplListBoxWindow
* rMain
= GetMainWindow();
1439 // convert coordinates to ImplListBoxWindow pixel coordinate space
1440 Point aConvPoint
= LogicToPixel( rPoint
);
1441 AbsoluteScreenPixelPoint aConvPointAbs
= OutputToAbsoluteScreenPixel( aConvPoint
);
1442 aConvPoint
= rMain
->AbsoluteScreenToOutputPixel( aConvPointAbs
);
1443 aConvPoint
= rMain
->PixelToLogic( aConvPoint
);
1445 // try to find entry
1446 sal_Int32 nEntry
= rMain
->GetEntryPosForPoint( aConvPoint
);
1447 if( nEntry
== LISTBOX_ENTRY_NOTFOUND
)
1453 // get line relative index
1455 nIndex
= ToRelativeLineIndex( nIndex
);
1460 ComboBoxBounds
ComboBox::calcComboBoxDropDownComponentBounds(
1461 const Size
&rOutSz
, const Size
&rBorderOutSz
) const
1463 ComboBoxBounds aBounds
;
1465 tools::Long nTop
= 0;
1466 tools::Long nBottom
= rOutSz
.Height();
1468 vcl::Window
*pBorder
= GetWindow(GetWindowType::Border
);
1469 ImplControlValue aControlValue
;
1471 tools::Rectangle aContent
, aBound
;
1473 // use the full extent of the control
1474 tools::Rectangle
aArea( aPoint
, rBorderOutSz
);
1476 if (GetNativeControlRegion(ControlType::Combobox
, ControlPart::ButtonDown
,
1477 aArea
, ControlState::NONE
, aControlValue
, aBound
, aContent
) )
1479 // convert back from border space to local coordinates
1480 aPoint
= pBorder
->ScreenToOutputPixel(OutputToScreenPixel(aPoint
));
1481 aContent
.Move(-aPoint
.X(), -aPoint
.Y());
1483 aBounds
.aButtonPos
= Point(aContent
.Left(), nTop
);
1484 aBounds
.aButtonSize
= Size(aContent
.getOpenWidth(), (nBottom
-nTop
));
1486 // adjust the size of the edit field
1487 if (GetNativeControlRegion(ControlType::Combobox
, ControlPart::SubEdit
,
1488 aArea
, ControlState::NONE
, aControlValue
, aBound
, aContent
) )
1490 // convert back from border space to local coordinates
1491 aContent
.Move(-aPoint
.X(), -aPoint
.Y());
1493 // use the themes drop down size
1494 aBounds
.aSubEditPos
= aContent
.TopLeft();
1495 aBounds
.aSubEditSize
= aContent
.GetSize();
1499 // use the themes drop down size for the button
1500 aBounds
.aSubEditSize
= Size(rOutSz
.Width() - aContent
.getOpenWidth(), rOutSz
.Height());
1505 tools::Long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
1506 nSBWidth
= CalcZoom( nSBWidth
);
1507 aBounds
.aSubEditSize
= Size(rOutSz
.Width() - nSBWidth
, rOutSz
.Height());
1508 aBounds
.aButtonPos
= Point(rOutSz
.Width() - nSBWidth
, nTop
);
1509 aBounds
.aButtonSize
= Size(nSBWidth
, (nBottom
-nTop
));
1514 void ComboBox::SetWidthInChars(sal_Int32 nWidthInChars
)
1516 if (nWidthInChars
!= m_nWidthInChars
)
1518 m_nWidthInChars
= nWidthInChars
;
1523 void ComboBox::setMaxWidthChars(sal_Int32 nWidth
)
1525 if (nWidth
!= m_nMaxWidthChars
)
1527 m_nMaxWidthChars
= nWidth
;
1532 bool ComboBox::set_property(const OUString
&rKey
, const OUString
&rValue
)
1534 if (rKey
== "width-chars")
1535 SetWidthInChars(rValue
.toInt32());
1536 else if (rKey
== "max-width-chars")
1537 setMaxWidthChars(rValue
.toInt32());
1538 else if (rKey
== "can-focus")
1540 // as far as I can see in Gtk, setting a ComboBox as can.focus means
1541 // the focus gets stuck in it, so try here to behave like gtk does
1542 // with the settings that work, i.e. can.focus of false doesn't
1543 // set the hard WB_NOTABSTOP
1544 WinBits nBits
= GetStyle();
1545 nBits
&= ~(WB_TABSTOP
|WB_NOTABSTOP
);
1547 nBits
|= WB_TABSTOP
;
1550 else if (rKey
== "placeholder-text")
1551 SetPlaceholderText(rValue
);
1553 return Control::set_property(rKey
, rValue
);
1557 FactoryFunction
ComboBox::GetUITestFactory() const
1559 return ComboBoxUIObject::create
;
1562 void ComboBox::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
1564 Control::DumpAsPropertyTree(rJsonWriter
);
1567 auto entriesNode
= rJsonWriter
.startArray("entries");
1568 for (int i
= 0; i
< GetEntryCount(); ++i
)
1570 rJsonWriter
.putSimpleValue(GetEntry(i
));
1575 auto selectedNode
= rJsonWriter
.startArray("selectedEntries");
1576 for (int i
= 0; i
< GetSelectedEntryCount(); ++i
)
1578 rJsonWriter
.putSimpleValue(OUString::number(GetSelectedEntryPos(i
)));
1582 rJsonWriter
.put("selectedCount", GetSelectedEntryCount());
1584 if (IsUserDrawEnabled())
1585 rJsonWriter
.put("customEntryRenderer", true);
1588 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */