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/combobox.hxx>
24 #include <comphelper/string.hxx>
25 #include <tools/debug.hxx>
27 #include <vcl/decoview.hxx>
28 #include <vcl/lstbox.hxx>
29 #include <vcl/button.hxx>
30 #include <vcl/event.hxx>
31 #include <vcl/settings.hxx>
32 #include <vcl/uitest/uiobject.hxx>
35 #include "listbox.hxx"
36 #include <controldata.hxx>
51 VclPtr
<Edit
> m_pSubEdit
;
52 VclPtr
<ImplListBox
> m_pImplLB
;
53 VclPtr
<ImplBtn
> m_pBtn
;
54 VclPtr
<ImplListBoxFloatingWindow
> m_pFloatWin
;
55 sal_uInt16 m_nDDHeight
;
56 sal_Unicode m_cMultiSep
;
57 bool m_isDDAutoSize
: 1;
58 bool m_isSyntheticModify
: 1;
59 bool m_isMatchCase
: 1;
60 sal_Int32 m_nMaxWidthChars
;
61 Link
<ComboBox
&,void> m_SelectHdl
;
62 Link
<ComboBox
&,void> m_DoubleClickHdl
;
64 explicit Impl(ComboBox
& rThis
)
68 , m_isDDAutoSize(false)
69 , m_isSyntheticModify(false)
70 , m_isMatchCase(false)
75 void ImplInitComboBoxData();
76 void ImplUpdateFloatSelection();
77 ComboBoxBounds
calcComboBoxDropDownComponentBounds(
78 const Size
&rOutSize
, const Size
&rBorderOutSize
) const;
80 DECL_DLLPRIVATE_LINK( ImplSelectHdl
, LinkParamNone
*, void );
81 DECL_DLLPRIVATE_LINK( ImplCancelHdl
, LinkParamNone
*, void );
82 DECL_DLLPRIVATE_LINK( ImplDoubleClickHdl
, ImplListBoxWindow
*, void );
83 DECL_DLLPRIVATE_LINK( ImplClickBtnHdl
, void*, void );
84 DECL_DLLPRIVATE_LINK( ImplPopupModeEndHdl
, FloatingWindow
*, void );
85 DECL_DLLPRIVATE_LINK( ImplSelectionChangedHdl
, sal_Int32
, void );
86 DECL_DLLPRIVATE_LINK( ImplUserDrawHdl
, UserDrawEvent
*, void );
87 DECL_DLLPRIVATE_LINK( ImplAutocompleteHdl
, Edit
&, void );
88 DECL_DLLPRIVATE_LINK( ImplListItemSelectHdl
, LinkParamNone
*, void );
92 static void lcl_GetSelectedEntries( ::std::set
< sal_Int32
>& rSelectedPos
, const OUString
& rText
, sal_Unicode cTokenSep
, const ImplEntryList
* pEntryList
)
94 for (sal_Int32 n
= comphelper::string::getTokenCount(rText
, cTokenSep
); n
;)
96 OUString aToken
= rText
.getToken( --n
, cTokenSep
);
97 aToken
= comphelper::string::strip(aToken
, ' ');
98 sal_Int32 nPos
= pEntryList
->FindEntry( aToken
);
99 if ( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
100 rSelectedPos
.insert( nPos
);
104 ComboBox::ComboBox(vcl::Window
*const pParent
, WinBits
const nStyle
)
105 : Edit( WINDOW_COMBOBOX
)
106 , m_pImpl(new Impl(*this))
108 m_pImpl
->ImplInitComboBoxData();
109 ImplInit( pParent
, nStyle
);
113 ComboBox::~ComboBox()
118 void ComboBox::dispose()
120 m_pImpl
->m_pSubEdit
.disposeAndClear();
122 VclPtr
< ImplListBox
> pImplLB
= m_pImpl
->m_pImplLB
;
123 m_pImpl
->m_pImplLB
.clear();
124 pImplLB
.disposeAndClear();
126 m_pImpl
->m_pFloatWin
.disposeAndClear();
127 m_pImpl
->m_pBtn
.disposeAndClear();
131 void ComboBox::Impl::ImplInitComboBoxData()
133 m_pSubEdit
.disposeAndClear();
136 m_pFloatWin
= nullptr;
139 m_isDDAutoSize
= true;
140 m_isSyntheticModify
= false;
141 m_isMatchCase
= false;
143 m_nMaxWidthChars
= -1;
146 void ComboBox::ImplCalcEditHeight()
148 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
149 GetBorder( nLeft
, nTop
, nRight
, nBottom
);
150 m_pImpl
->m_nDDHeight
= (sal_uInt16
)(m_pImpl
->m_pSubEdit
->GetTextHeight() + nTop
+ nBottom
+ 4);
151 if ( !IsDropDownBox() )
152 m_pImpl
->m_nDDHeight
+= 4;
154 Rectangle
aCtrlRegion( Point( 0, 0 ), Size( 10, 10 ) );
155 Rectangle aBoundRegion
, aContentRegion
;
156 ImplControlValue aControlValue
;
157 ControlType aType
= IsDropDownBox() ? ControlType::Combobox
: ControlType::Editbox
;
158 if( GetNativeControlRegion( aType
, ControlPart::Entire
,
160 ControlState::ENABLED
,
161 aControlValue
, OUString(),
162 aBoundRegion
, aContentRegion
) )
164 const long nNCHeight
= aBoundRegion
.GetHeight();
165 if (m_pImpl
->m_nDDHeight
< nNCHeight
)
166 m_pImpl
->m_nDDHeight
= sal::static_int_cast
<sal_uInt16
>(nNCHeight
);
170 void ComboBox::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
172 bool bNoBorder
= ( nStyle
& WB_NOBORDER
) != 0;
173 if ( !(nStyle
& WB_DROPDOWN
) )
175 nStyle
&= ~WB_BORDER
;
176 nStyle
|= WB_NOBORDER
;
184 Edit::ImplInit( pParent
, nStyle
);
188 WinBits nEditStyle
= nStyle
& ( WB_LEFT
| WB_RIGHT
| WB_CENTER
);
189 WinBits nListStyle
= nStyle
;
190 if( nStyle
& WB_DROPDOWN
)
192 m_pImpl
->m_pFloatWin
= VclPtr
<ImplListBoxFloatingWindow
>::Create( this );
193 m_pImpl
->m_pFloatWin
->SetAutoWidth( true );
194 m_pImpl
->m_pFloatWin
->SetPopupModeEndHdl( LINK(m_pImpl
.get(), ComboBox::Impl
, ImplPopupModeEndHdl
) );
196 m_pImpl
->m_pBtn
= VclPtr
<ImplBtn
>::Create( this, WB_NOLIGHTBORDER
| WB_RECTSTYLE
);
197 ImplInitDropDownButton( m_pImpl
->m_pBtn
);
198 m_pImpl
->m_pBtn
->SetMBDownHdl( LINK( m_pImpl
.get(), ComboBox::Impl
, ImplClickBtnHdl
) );
199 m_pImpl
->m_pBtn
->Show();
201 nEditStyle
|= WB_NOBORDER
;
202 nListStyle
&= ~WB_BORDER
;
203 nListStyle
|= WB_NOBORDER
;
209 nEditStyle
|= WB_BORDER
;
210 nListStyle
&= ~WB_NOBORDER
;
211 nListStyle
|= WB_BORDER
;
215 m_pImpl
->m_pSubEdit
.set( VclPtr
<Edit
>::Create( this, nEditStyle
) );
216 m_pImpl
->m_pSubEdit
->EnableRTL( false );
217 SetSubEdit( m_pImpl
->m_pSubEdit
);
218 m_pImpl
->m_pSubEdit
->SetPosPixel( Point() );
219 EnableAutocomplete( true );
220 m_pImpl
->m_pSubEdit
->Show();
222 vcl::Window
* pLBParent
= this;
223 if (m_pImpl
->m_pFloatWin
)
224 pLBParent
= m_pImpl
->m_pFloatWin
;
225 m_pImpl
->m_pImplLB
= VclPtr
<ImplListBox
>::Create( pLBParent
, nListStyle
|WB_SIMPLEMODE
|WB_AUTOHSCROLL
);
226 m_pImpl
->m_pImplLB
->SetPosPixel( Point() );
227 m_pImpl
->m_pImplLB
->SetSelectHdl( LINK(m_pImpl
.get(), ComboBox::Impl
, ImplSelectHdl
) );
228 m_pImpl
->m_pImplLB
->SetCancelHdl( LINK(m_pImpl
.get(), ComboBox::Impl
, ImplCancelHdl
) );
229 m_pImpl
->m_pImplLB
->SetDoubleClickHdl( LINK(m_pImpl
.get(), ComboBox::Impl
, ImplDoubleClickHdl
) );
230 m_pImpl
->m_pImplLB
->SetUserDrawHdl( LINK(m_pImpl
.get(), ComboBox::Impl
, ImplUserDrawHdl
) );
231 m_pImpl
->m_pImplLB
->SetSelectionChangedHdl( LINK(m_pImpl
.get(), ComboBox::Impl
, ImplSelectionChangedHdl
) );
232 m_pImpl
->m_pImplLB
->SetListItemSelectHdl( LINK(m_pImpl
.get(), ComboBox::Impl
, ImplListItemSelectHdl
) );
233 m_pImpl
->m_pImplLB
->Show();
235 if (m_pImpl
->m_pFloatWin
)
236 m_pImpl
->m_pFloatWin
->SetImplListBox( m_pImpl
->m_pImplLB
);
238 m_pImpl
->m_pImplLB
->GetMainWindow()->AllowGrabFocus( true );
240 ImplCalcEditHeight();
242 SetCompoundControl( true );
245 WinBits
ComboBox::ImplInitStyle( WinBits nStyle
)
247 if ( !(nStyle
& WB_NOTABSTOP
) )
248 nStyle
|= WB_TABSTOP
;
249 if ( !(nStyle
& WB_NOGROUP
) )
254 void ComboBox::EnableAutocomplete( bool bEnable
, bool bMatchCase
)
256 m_pImpl
->m_isMatchCase
= bMatchCase
;
259 m_pImpl
->m_pSubEdit
->SetAutocompleteHdl( LINK(m_pImpl
.get(), ComboBox::Impl
, ImplAutocompleteHdl
) );
261 m_pImpl
->m_pSubEdit
->SetAutocompleteHdl( Link
<Edit
&,void>() );
264 bool ComboBox::IsAutocompleteEnabled() const
266 return m_pImpl
->m_pSubEdit
->GetAutocompleteHdl().IsSet();
269 IMPL_LINK_NOARG(ComboBox::Impl
, ImplClickBtnHdl
, void*, void)
271 m_rThis
.CallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN
);
272 m_pSubEdit
->GrabFocus();
273 if (!m_pImplLB
->GetEntryList()->GetMRUCount())
274 ImplUpdateFloatSelection();
276 m_pImplLB
->SelectEntry( 0 , true );
277 m_pBtn
->SetPressed( true );
278 m_rThis
.SetSelection( Selection( 0, SELECTION_MAX
) );
279 m_pFloatWin
->StartFloat( true );
280 m_rThis
.CallEventListeners( VCLEVENT_DROPDOWN_OPEN
);
282 m_rThis
.ImplClearLayoutData();
284 m_pImplLB
->GetMainWindow()->ImplClearLayoutData();
287 IMPL_LINK_NOARG(ComboBox::Impl
, ImplPopupModeEndHdl
, FloatingWindow
*, void)
289 if (m_pFloatWin
->IsPopupModeCanceled())
291 if (!m_pImplLB
->GetEntryList()->IsEntryPosSelected(
292 m_pFloatWin
->GetPopupModeStartSaveSelection()))
294 m_pImplLB
->SelectEntry(m_pFloatWin
->GetPopupModeStartSaveSelection(), true);
295 bool bTravelSelect
= m_pImplLB
->IsTravelSelect();
296 m_pImplLB
->SetTravelSelect( true );
298 m_pImplLB
->SetTravelSelect( bTravelSelect
);
302 m_rThis
.ImplClearLayoutData();
304 m_pImplLB
->GetMainWindow()->ImplClearLayoutData();
306 m_pBtn
->SetPressed( false );
307 m_rThis
.CallEventListeners( VCLEVENT_DROPDOWN_CLOSE
);
310 IMPL_LINK(ComboBox::Impl
, ImplAutocompleteHdl
, Edit
&, rEdit
, void)
312 Selection aSel
= rEdit
.GetSelection();
315 OUString aFullText
= rEdit
.GetText();
316 OUString aStartText
= aFullText
.copy( 0, (sal_Int32
)aSel
.Max() );
317 sal_Int32 nStart
= m_pImplLB
->GetCurrentPos();
319 if ( nStart
== LISTBOX_ENTRY_NOTFOUND
)
322 sal_Int32 nPos
= LISTBOX_ENTRY_NOTFOUND
;
325 // Try match case insensitive from current position
326 nPos
= m_pImplLB
->GetEntryList()->FindMatchingEntry(aStartText
, nStart
, true);
327 if ( nPos
== LISTBOX_ENTRY_NOTFOUND
)
328 // Try match case insensitive, but from start
329 nPos
= m_pImplLB
->GetEntryList()->FindMatchingEntry(aStartText
, 0, true);
332 if ( nPos
== LISTBOX_ENTRY_NOTFOUND
)
333 // Try match full from current position
334 nPos
= m_pImplLB
->GetEntryList()->FindMatchingEntry(aStartText
, nStart
, false);
335 if ( nPos
== LISTBOX_ENTRY_NOTFOUND
)
336 // Match full, but from start
337 nPos
= m_pImplLB
->GetEntryList()->FindMatchingEntry(aStartText
, 0, false);
339 if ( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
341 OUString aText
= m_pImplLB
->GetEntryList()->GetEntryText( nPos
);
342 Selection
aSelection( aText
.getLength(), aStartText
.getLength() );
343 rEdit
.SetText( aText
, aSelection
);
348 IMPL_LINK_NOARG(ComboBox::Impl
, ImplSelectHdl
, LinkParamNone
*, void)
350 bool bPopup
= m_rThis
.IsInDropDown();
351 bool bCallSelect
= false;
352 if (m_pImplLB
->IsSelectionChanged() || bPopup
)
355 if (m_rThis
.IsMultiSelectionEnabled())
357 aText
= m_pSubEdit
->GetText();
359 // remove all entries to which there is an entry, but which is not selected
360 sal_Int32 nIndex
= 0;
361 while ( nIndex
>= 0 )
363 sal_Int32 nPrevIndex
= nIndex
;
364 OUString aToken
= aText
.getToken( 0, m_cMultiSep
, nIndex
);
365 sal_Int32 nTokenLen
= aToken
.getLength();
366 aToken
= comphelper::string::strip(aToken
, ' ');
367 sal_Int32 nP
= m_pImplLB
->GetEntryList()->FindEntry( aToken
);
368 if ((nP
!= LISTBOX_ENTRY_NOTFOUND
) && (!m_pImplLB
->GetEntryList()->IsEntryPosSelected(nP
)))
370 aText
= aText
.replaceAt( nPrevIndex
, nTokenLen
, "" );
371 nIndex
= nIndex
- nTokenLen
;
372 sal_Int32 nSepCount
=0;
373 if ((nPrevIndex
+nSepCount
< aText
.getLength()) && (aText
[nPrevIndex
+nSepCount
] == m_cMultiSep
))
378 aText
= aText
.replaceAt( nPrevIndex
, nSepCount
, "" );
380 aText
= comphelper::string::strip(aText
, ' ');
383 // attach missing entries
384 ::std::set
< sal_Int32
> aSelInText
;
385 lcl_GetSelectedEntries( aSelInText
, aText
, m_cMultiSep
, m_pImplLB
->GetEntryList() );
386 sal_Int32 nSelectedEntries
= m_pImplLB
->GetEntryList()->GetSelectEntryCount();
387 for ( sal_Int32 n
= 0; n
< nSelectedEntries
; n
++ )
389 sal_Int32 nP
= m_pImplLB
->GetEntryList()->GetSelectEntryPos( n
);
390 if ( !aSelInText
.count( nP
) )
392 if (!aText
.isEmpty() && (aText
[aText
.getLength()-1] != m_cMultiSep
))
393 aText
+= OUStringLiteral1(m_cMultiSep
);
394 if ( !aText
.isEmpty() )
395 aText
+= " "; // slightly loosen
396 aText
+= m_pImplLB
->GetEntryList()->GetEntryText( nP
);
397 aText
+= OUStringLiteral1(m_cMultiSep
);
400 aText
= comphelper::string::stripEnd( aText
, m_cMultiSep
);
404 aText
= m_pImplLB
->GetEntryList()->GetSelectEntry( 0 );
407 m_pSubEdit
->SetText( aText
);
409 Selection
aNewSelection( 0, aText
.getLength() );
410 if (m_rThis
.IsMultiSelectionEnabled())
411 aNewSelection
.Min() = aText
.getLength();
412 m_pSubEdit
->SetSelection( aNewSelection
);
417 // #84652# Call GrabFocus and EndPopupMode before calling Select/Modify, but after changing the text
419 if (bPopup
&& !m_pImplLB
->IsTravelSelect() &&
420 (!m_rThis
.IsMultiSelectionEnabled() || !m_pImplLB
->GetSelectModifier()))
422 m_pFloatWin
->EndPopupMode();
428 m_pSubEdit
->SetModifyFlag();
429 m_isSyntheticModify
= true;
431 m_isSyntheticModify
= false;
436 IMPL_LINK_NOARG( ComboBox::Impl
, ImplListItemSelectHdl
, LinkParamNone
*, void )
438 m_rThis
.CallEventListeners( VCLEVENT_DROPDOWN_SELECT
);
441 IMPL_LINK_NOARG(ComboBox::Impl
, ImplCancelHdl
, LinkParamNone
*, void)
443 if (m_rThis
.IsInDropDown())
444 m_pFloatWin
->EndPopupMode();
447 IMPL_LINK( ComboBox::Impl
, 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::Impl
, ImplDoubleClickHdl
, ImplListBoxWindow
*, void)
458 m_rThis
.DoubleClick();
461 void ComboBox::ToggleDropDown()
463 if( IsDropDownBox() )
465 if (m_pImpl
->m_pFloatWin
->IsInPopupMode())
466 m_pImpl
->m_pFloatWin
->EndPopupMode();
469 m_pImpl
->m_pSubEdit
->GrabFocus();
470 if (!m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount())
471 m_pImpl
->ImplUpdateFloatSelection();
473 m_pImpl
->m_pImplLB
->SelectEntry( 0 , true );
474 CallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN
);
475 m_pImpl
->m_pBtn
->SetPressed( true );
476 SetSelection( Selection( 0, SELECTION_MAX
) );
477 m_pImpl
->m_pFloatWin
->StartFloat( true );
478 CallEventListeners( VCLEVENT_DROPDOWN_OPEN
);
483 void ComboBox::Select()
485 ImplCallEventListenersAndHandler( VCLEVENT_COMBOBOX_SELECT
, [this] () { m_pImpl
->m_SelectHdl
.Call(*this); } );
488 void ComboBox::DoubleClick()
490 ImplCallEventListenersAndHandler( VCLEVENT_COMBOBOX_DOUBLECLICK
, [this] () { m_pImpl
->m_DoubleClickHdl
.Call(*this); } );
493 bool ComboBox::IsAutoSizeEnabled() const { return m_pImpl
->m_isDDAutoSize
; }
495 void ComboBox::EnableAutoSize( bool bAuto
)
497 m_pImpl
->m_isDDAutoSize
= bAuto
;
498 if (m_pImpl
->m_pFloatWin
)
500 if (bAuto
&& !m_pImpl
->m_pFloatWin
->GetDropDownLineCount())
502 // Adapt to GetListBoxMaximumLineCount here; was on fixed number of five before
503 AdaptDropDownLineCountToMaximum();
507 m_pImpl
->m_pFloatWin
->SetDropDownLineCount( 0 );
512 void ComboBox::EnableDDAutoWidth( bool b
)
514 if (m_pImpl
->m_pFloatWin
)
515 m_pImpl
->m_pFloatWin
->SetAutoWidth( b
);
518 void ComboBox::SetDropDownLineCount( sal_uInt16 nLines
)
520 if (m_pImpl
->m_pFloatWin
)
521 m_pImpl
->m_pFloatWin
->SetDropDownLineCount( nLines
);
524 void ComboBox::AdaptDropDownLineCountToMaximum()
526 // adapt to maximum allowed number
527 SetDropDownLineCount(GetSettings().GetStyleSettings().GetListBoxMaximumLineCount());
530 sal_uInt16
ComboBox::GetDropDownLineCount() const
532 sal_uInt16 nLines
= 0;
533 if (m_pImpl
->m_pFloatWin
)
534 nLines
= m_pImpl
->m_pFloatWin
->GetDropDownLineCount();
538 void ComboBox::setPosSizePixel( long nX
, long nY
, long nWidth
, long nHeight
,
539 PosSizeFlags nFlags
)
541 if( IsDropDownBox() && ( nFlags
& PosSizeFlags::Size
) )
543 Size aPrefSz
= m_pImpl
->m_pFloatWin
->GetPrefSize();
544 if ((nFlags
& PosSizeFlags::Height
) && (nHeight
>= 2*m_pImpl
->m_nDDHeight
))
545 aPrefSz
.Height() = nHeight
-m_pImpl
->m_nDDHeight
;
546 if ( nFlags
& PosSizeFlags::Width
)
547 aPrefSz
.Width() = nWidth
;
548 m_pImpl
->m_pFloatWin
->SetPrefSize( aPrefSz
);
550 if (IsAutoSizeEnabled())
551 nHeight
= m_pImpl
->m_nDDHeight
;
554 Edit::setPosSizePixel( nX
, nY
, nWidth
, nHeight
, nFlags
);
557 void ComboBox::Resize()
561 if (m_pImpl
->m_pSubEdit
)
563 Size aOutSz
= GetOutputSizePixel();
564 if( IsDropDownBox() )
566 ComboBoxBounds
aBounds(m_pImpl
->calcComboBoxDropDownComponentBounds(aOutSz
,
567 GetWindow(GetWindowType::Border
)->GetOutputSizePixel()));
568 m_pImpl
->m_pSubEdit
->SetPosSizePixel(aBounds
.aSubEditPos
, aBounds
.aSubEditSize
);
569 m_pImpl
->m_pBtn
->SetPosSizePixel(aBounds
.aButtonPos
, aBounds
.aButtonSize
);
573 m_pImpl
->m_pSubEdit
->SetSizePixel(Size(aOutSz
.Width(), m_pImpl
->m_nDDHeight
));
574 m_pImpl
->m_pImplLB
->setPosSizePixel(0, m_pImpl
->m_nDDHeight
,
575 aOutSz
.Width(), aOutSz
.Height() - m_pImpl
->m_nDDHeight
);
576 if ( !GetText().isEmpty() )
577 m_pImpl
->ImplUpdateFloatSelection();
581 // adjust the size of the FloatingWindow even when invisible
582 // as KEY_PGUP/DOWN is being processed...
583 if (m_pImpl
->m_pFloatWin
)
584 m_pImpl
->m_pFloatWin
->SetSizePixel(m_pImpl
->m_pFloatWin
->CalcFloatSize());
587 bool ComboBox::IsDropDownBox() const { return m_pImpl
->m_pFloatWin
!= nullptr; }
589 void ComboBox::FillLayoutData() const
591 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
592 AppendLayoutData( *m_pImpl
->m_pSubEdit
);
593 m_pImpl
->m_pSubEdit
->SetLayoutDataParent( this );
594 ImplListBoxWindow
* rMainWindow
= m_pImpl
->m_pImplLB
->GetMainWindow();
595 if (m_pImpl
->m_pFloatWin
)
598 if (m_pImpl
->m_pFloatWin
->IsReallyVisible())
600 AppendLayoutData( *rMainWindow
);
601 rMainWindow
->SetLayoutDataParent( this );
606 AppendLayoutData( *rMainWindow
);
607 rMainWindow
->SetLayoutDataParent( this );
611 void ComboBox::StateChanged( StateChangedType nType
)
613 Edit::StateChanged( nType
);
615 if ( nType
== StateChangedType::ReadOnly
)
617 m_pImpl
->m_pImplLB
->SetReadOnly( IsReadOnly() );
619 m_pImpl
->m_pBtn
->Enable( IsEnabled() && !IsReadOnly() );
621 else if ( nType
== StateChangedType::Enable
)
623 m_pImpl
->m_pSubEdit
->Enable( IsEnabled() );
624 m_pImpl
->m_pImplLB
->Enable( IsEnabled() && !IsReadOnly() );
626 m_pImpl
->m_pBtn
->Enable( IsEnabled() && !IsReadOnly() );
629 else if( nType
== StateChangedType::UpdateMode
)
631 m_pImpl
->m_pImplLB
->SetUpdateMode( IsUpdateMode() );
633 else if ( nType
== StateChangedType::Zoom
)
635 m_pImpl
->m_pImplLB
->SetZoom( GetZoom() );
636 m_pImpl
->m_pSubEdit
->SetZoom( GetZoom() );
637 ImplCalcEditHeight();
640 else if ( nType
== StateChangedType::ControlFont
)
642 m_pImpl
->m_pImplLB
->SetControlFont( GetControlFont() );
643 m_pImpl
->m_pSubEdit
->SetControlFont( GetControlFont() );
644 ImplCalcEditHeight();
647 else if ( nType
== StateChangedType::ControlForeground
)
649 m_pImpl
->m_pImplLB
->SetControlForeground( GetControlForeground() );
650 m_pImpl
->m_pSubEdit
->SetControlForeground( GetControlForeground() );
652 else if ( nType
== StateChangedType::ControlBackground
)
654 m_pImpl
->m_pImplLB
->SetControlBackground( GetControlBackground() );
655 m_pImpl
->m_pSubEdit
->SetControlBackground( GetControlBackground() );
657 else if ( nType
== StateChangedType::Style
)
659 SetStyle( ImplInitStyle( GetStyle() ) );
660 m_pImpl
->m_pImplLB
->GetMainWindow()->EnableSort( ( GetStyle() & WB_SORT
) != 0 );
662 else if( nType
== StateChangedType::Mirroring
)
666 m_pImpl
->m_pBtn
->EnableRTL( IsRTLEnabled() );
667 ImplInitDropDownButton( m_pImpl
->m_pBtn
);
669 m_pImpl
->m_pSubEdit
->CompatStateChanged( StateChangedType::Mirroring
);
670 m_pImpl
->m_pImplLB
->EnableRTL( IsRTLEnabled() );
675 void ComboBox::DataChanged( const DataChangedEvent
& rDCEvt
)
677 Control::DataChanged( rDCEvt
);
679 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
680 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
681 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
682 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
686 m_pImpl
->m_pBtn
->SetSettings( GetSettings() );
687 ImplInitDropDownButton( m_pImpl
->m_pBtn
);
690 m_pImpl
->m_pImplLB
->Resize(); // not called by ComboBox::Resize() if ImplLB is unchanged
692 SetBackground(); // due to a hack in Window::UpdateSettings the background must be reset
693 // otherwise it will overpaint NWF drawn comboboxes
697 bool ComboBox::EventNotify( NotifyEvent
& rNEvt
)
700 if ((rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
)
701 && (rNEvt
.GetWindow() == m_pImpl
->m_pSubEdit
)
704 KeyEvent aKeyEvt
= *rNEvt
.GetKeyEvent();
705 sal_uInt16 nKeyCode
= aKeyEvt
.GetKeyCode().GetCode();
713 m_pImpl
->ImplUpdateFloatSelection();
714 if ((nKeyCode
== KEY_DOWN
) && m_pImpl
->m_pFloatWin
715 && !m_pImpl
->m_pFloatWin
->IsInPopupMode()
716 && aKeyEvt
.GetKeyCode().IsMod2())
718 CallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN
);
719 m_pImpl
->m_pBtn
->SetPressed( true );
720 if (m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount())
721 m_pImpl
->m_pImplLB
->SelectEntry( 0 , true );
722 SetSelection( Selection( 0, SELECTION_MAX
) );
723 m_pImpl
->m_pFloatWin
->StartFloat( false );
724 CallEventListeners( VCLEVENT_DROPDOWN_OPEN
);
727 else if ((nKeyCode
== KEY_UP
) && m_pImpl
->m_pFloatWin
728 && m_pImpl
->m_pFloatWin
->IsInPopupMode()
729 && aKeyEvt
.GetKeyCode().IsMod2())
731 m_pImpl
->m_pFloatWin
->EndPopupMode();
736 bDone
= m_pImpl
->m_pImplLB
->ProcessKeyInput( aKeyEvt
);
743 if ((rNEvt
.GetWindow() == m_pImpl
->m_pSubEdit
) && IsInDropDown())
745 m_pImpl
->m_pImplLB
->ProcessKeyInput( aKeyEvt
);
752 else if ((rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
) && m_pImpl
->m_pFloatWin
)
754 if (m_pImpl
->m_pFloatWin
->HasChildPathFocus())
755 m_pImpl
->m_pSubEdit
->GrabFocus();
756 else if (m_pImpl
->m_pFloatWin
->IsInPopupMode() && !HasChildPathFocus(true))
757 m_pImpl
->m_pFloatWin
->EndPopupMode();
759 else if( (rNEvt
.GetType() == MouseNotifyEvent::COMMAND
) &&
760 (rNEvt
.GetCommandEvent()->GetCommand() == CommandEventId::Wheel
) &&
761 (rNEvt
.GetWindow() == m_pImpl
->m_pSubEdit
) )
763 MouseWheelBehaviour
nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
764 if ( ( nWheelBehavior
== MouseWheelBehaviour::ALWAYS
)
765 || ( ( nWheelBehavior
== MouseWheelBehaviour::FocusOnly
)
766 && HasChildPathFocus()
770 bDone
= m_pImpl
->m_pImplLB
->HandleWheelAsCursorTravel( *rNEvt
.GetCommandEvent() );
774 bDone
= false; // don't eat this event, let the default handling happen (i.e. scroll the context)
777 else if ((rNEvt
.GetType() == MouseNotifyEvent::MOUSEBUTTONDOWN
)
778 && (rNEvt
.GetWindow() == m_pImpl
->m_pImplLB
->GetMainWindow()))
780 m_pImpl
->m_pSubEdit
->GrabFocus();
783 return bDone
|| Edit::EventNotify( rNEvt
);
786 void ComboBox::SetText( const OUString
& rStr
)
788 CallEventListeners( VCLEVENT_COMBOBOX_SETTEXT
);
790 Edit::SetText( rStr
);
791 m_pImpl
->ImplUpdateFloatSelection();
794 void ComboBox::SetText( const OUString
& rStr
, const Selection
& rNewSelection
)
796 CallEventListeners( VCLEVENT_COMBOBOX_SETTEXT
);
798 Edit::SetText( rStr
, rNewSelection
);
799 m_pImpl
->ImplUpdateFloatSelection();
802 void ComboBox::Modify()
804 if (!m_pImpl
->m_isSyntheticModify
)
805 m_pImpl
->ImplUpdateFloatSelection();
810 void ComboBox::Impl::ImplUpdateFloatSelection()
812 if (!m_pImplLB
|| !m_pSubEdit
)
815 // move text in the ListBox into the visible region
816 m_pImplLB
->SetCallSelectionChangedHdl( false );
817 if (!m_rThis
.IsMultiSelectionEnabled())
819 OUString
aSearchStr( m_pSubEdit
->GetText() );
820 sal_Int32 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
823 if (m_pImplLB
->GetCurrentPos() != LISTBOX_ENTRY_NOTFOUND
)
825 OUString aCurrent
= m_pImplLB
->GetEntryList()->GetEntryText(
826 m_pImplLB
->GetCurrentPos());
827 if ( aCurrent
== aSearchStr
)
828 nSelect
= m_pImplLB
->GetCurrentPos();
831 if ( nSelect
== LISTBOX_ENTRY_NOTFOUND
)
832 nSelect
= m_pImplLB
->GetEntryList()->FindEntry( aSearchStr
);
833 if ( nSelect
== LISTBOX_ENTRY_NOTFOUND
)
835 nSelect
= m_pImplLB
->GetEntryList()->FindMatchingEntry( aSearchStr
, 0, true );
839 if( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
841 if (!m_pImplLB
->IsVisible(nSelect
))
842 m_pImplLB
->ShowProminentEntry( nSelect
);
843 m_pImplLB
->SelectEntry( nSelect
, bSelect
);
847 nSelect
= m_pImplLB
->GetEntryList()->GetSelectEntryPos( 0 );
848 if( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
849 m_pImplLB
->SelectEntry( nSelect
, false );
850 m_pImplLB
->ResetCurrentPos();
855 ::std::set
< sal_Int32
> aSelInText
;
856 lcl_GetSelectedEntries(aSelInText
, m_pSubEdit
->GetText(), m_cMultiSep
, m_pImplLB
->GetEntryList());
857 for (sal_Int32 n
= 0; n
< m_pImplLB
->GetEntryList()->GetEntryCount(); n
++)
858 m_pImplLB
->SelectEntry( n
, aSelInText
.count( n
) );
860 m_pImplLB
->SetCallSelectionChangedHdl( true );
863 sal_Int32
ComboBox::InsertEntry(const OUString
& rStr
, sal_Int32
const nPos
)
865 assert(nPos
>= 0 && COMBOBOX_MAX_ENTRIES
> m_pImpl
->m_pImplLB
->GetEntryList()->GetEntryCount());
868 if (nPos
== COMBOBOX_APPEND
)
872 const sal_Int32 nMRUCount
= m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount();
873 assert(nPos
<= COMBOBOX_MAX_ENTRIES
- nMRUCount
);
874 nRealPos
= nPos
+ nMRUCount
;
877 nRealPos
= m_pImpl
->m_pImplLB
->InsertEntry( nRealPos
, rStr
);
878 nRealPos
-= m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount();
879 CallEventListeners( VCLEVENT_COMBOBOX_ITEMADDED
, reinterpret_cast<void*>(nRealPos
) );
883 sal_Int32
ComboBox::InsertEntryWithImage(
884 const OUString
& rStr
, const Image
& rImage
, sal_Int32
const nPos
)
886 assert(nPos
>= 0 && COMBOBOX_MAX_ENTRIES
> m_pImpl
->m_pImplLB
->GetEntryList()->GetEntryCount());
889 if (nPos
== COMBOBOX_APPEND
)
893 const sal_Int32 nMRUCount
= m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount();
894 assert(nPos
<= COMBOBOX_MAX_ENTRIES
- nMRUCount
);
895 nRealPos
= nPos
+ nMRUCount
;
898 nRealPos
= m_pImpl
->m_pImplLB
->InsertEntry( nRealPos
, rStr
, rImage
);
899 nRealPos
-= m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount();
900 CallEventListeners( VCLEVENT_COMBOBOX_ITEMADDED
, reinterpret_cast<void*>(nRealPos
) );
904 void ComboBox::RemoveEntry( const OUString
& rStr
)
906 RemoveEntryAt(GetEntryPos(rStr
));
909 void ComboBox::RemoveEntryAt(sal_Int32
const nPos
)
911 const sal_Int32 nMRUCount
= m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount();
912 if (nPos
< 0 || nPos
> COMBOBOX_MAX_ENTRIES
- nMRUCount
)
915 m_pImpl
->m_pImplLB
->RemoveEntry( nPos
+ nMRUCount
);
916 CallEventListeners( VCLEVENT_COMBOBOX_ITEMREMOVED
, reinterpret_cast<void*>(nPos
) );
919 void ComboBox::Clear()
921 m_pImpl
->m_pImplLB
->Clear();
922 CallEventListeners( VCLEVENT_COMBOBOX_ITEMREMOVED
, reinterpret_cast<void*>(-1) );
925 Image
ComboBox::GetEntryImage( sal_Int32 nPos
) const
927 if (m_pImpl
->m_pImplLB
->GetEntryList()->HasEntryImage(nPos
))
928 return m_pImpl
->m_pImplLB
->GetEntryList()->GetEntryImage( nPos
);
932 sal_Int32
ComboBox::GetEntryPos( const OUString
& rStr
) const
934 sal_Int32 nPos
= m_pImpl
->m_pImplLB
->GetEntryList()->FindEntry( rStr
);
935 if ( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
936 nPos
-= m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount();
940 sal_Int32
ComboBox::GetEntryPos( const void* pData
) const
942 sal_Int32 nPos
= m_pImpl
->m_pImplLB
->GetEntryList()->FindEntry( pData
);
943 if ( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
944 nPos
= nPos
- m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount();
948 OUString
ComboBox::GetEntry( sal_Int32 nPos
) const
950 const sal_Int32 nMRUCount
= m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount();
951 if (nPos
< 0 || nPos
> COMBOBOX_MAX_ENTRIES
- nMRUCount
)
954 return m_pImpl
->m_pImplLB
->GetEntryList()->GetEntryText( nPos
+ nMRUCount
);
957 sal_Int32
ComboBox::GetEntryCount() const
959 return m_pImpl
->m_pImplLB
->GetEntryList()->GetEntryCount() - m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount();
962 bool ComboBox::IsTravelSelect() const
964 return m_pImpl
->m_pImplLB
->IsTravelSelect();
967 bool ComboBox::IsInDropDown() const
969 return m_pImpl
->m_pFloatWin
&& m_pImpl
->m_pFloatWin
->IsInPopupMode();
972 void ComboBox::EnableMultiSelection( bool bMulti
)
974 m_pImpl
->m_pImplLB
->EnableMultiSelection( bMulti
, false );
975 m_pImpl
->m_pImplLB
->SetMultiSelectionSimpleMode( true );
978 bool ComboBox::IsMultiSelectionEnabled() const
980 return m_pImpl
->m_pImplLB
->IsMultiSelectionEnabled();
983 void ComboBox::SetSelectHdl(const Link
<ComboBox
&,void>& rLink
) { m_pImpl
->m_SelectHdl
= rLink
; }
985 const Link
<ComboBox
&,void>& ComboBox::GetSelectHdl() const { return m_pImpl
->m_SelectHdl
; }
987 void ComboBox::SetDoubleClickHdl(const Link
<ComboBox
&,void>& rLink
) { m_pImpl
->m_DoubleClickHdl
= rLink
; }
989 const Link
<ComboBox
&,void>& ComboBox::GetDoubleClickHdl() const { return m_pImpl
->m_DoubleClickHdl
; }
991 long ComboBox::CalcWindowSizePixel( sal_uInt16 nLines
) const
993 return m_pImpl
->m_pImplLB
->GetEntryHeight() * nLines
;
996 Size
ComboBox::GetOptimalSize() const
998 return CalcMinimumSize();
1001 long ComboBox::getMaxWidthScrollBarAndDownButton() const
1003 long nButtonDownWidth
= 0;
1005 vcl::Window
*pBorder
= GetWindow( GetWindowType::Border
);
1006 ImplControlValue aControlValue
;
1008 Rectangle aContent
, aBound
;
1010 // use the full extent of the control
1011 Rectangle
aArea( aPoint
, pBorder
->GetOutputSizePixel() );
1013 if ( GetNativeControlRegion(ControlType::Combobox
, ControlPart::ButtonDown
,
1014 aArea
, ControlState::NONE
, aControlValue
, OUString(), aBound
, aContent
) )
1016 nButtonDownWidth
= aContent
.getWidth();
1019 long nScrollBarWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
1021 return std::max(nScrollBarWidth
, nButtonDownWidth
);
1024 Size
ComboBox::CalcMinimumSize() const
1028 if (!m_pImpl
->m_pImplLB
)
1031 if (!IsDropDownBox())
1033 aSz
= m_pImpl
->m_pImplLB
->CalcSize( m_pImpl
->m_pImplLB
->GetEntryList()->GetEntryCount() );
1034 aSz
.Height() += m_pImpl
->m_nDDHeight
;
1038 aSz
.Height() = Edit::CalcMinimumSizeForText(GetText()).Height();
1039 aSz
.Width() = m_pImpl
->m_pImplLB
->GetMaxEntryWidth();
1042 if (m_pImpl
->m_nMaxWidthChars
!= -1)
1044 long nMaxWidth
= m_pImpl
->m_nMaxWidthChars
* approximate_char_width();
1045 aSz
.Width() = std::min(aSz
.Width(), nMaxWidth
);
1048 if (IsDropDownBox())
1049 aSz
.Width() += getMaxWidthScrollBarAndDownButton();
1051 ComboBoxBounds
aBounds(m_pImpl
->calcComboBoxDropDownComponentBounds(
1052 Size(0xFFFF, 0xFFFF), Size(0xFFFF, 0xFFFF)));
1053 aSz
.Width() += aBounds
.aSubEditPos
.X()*2;
1055 aSz
.Width() += ImplGetExtraXOffset() * 2;
1057 aSz
= CalcWindowSize( aSz
);
1061 Size
ComboBox::CalcAdjustedSize( const Size
& rPrefSize
) const
1063 Size aSz
= rPrefSize
;
1064 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
1065 static_cast<vcl::Window
*>(const_cast<ComboBox
*>(this))->GetBorder( nLeft
, nTop
, nRight
, nBottom
);
1066 aSz
.Height() -= nTop
+nBottom
;
1067 if ( !IsDropDownBox() )
1069 long nEntryHeight
= CalcBlockSize( 1, 1 ).Height();
1070 long nLines
= aSz
.Height() / nEntryHeight
;
1073 aSz
.Height() = nLines
* nEntryHeight
;
1074 aSz
.Height() += m_pImpl
->m_nDDHeight
;
1078 aSz
.Height() = m_pImpl
->m_nDDHeight
;
1080 aSz
.Height() += nTop
+nBottom
;
1082 aSz
= CalcWindowSize( aSz
);
1086 Size
ComboBox::CalcBlockSize( sal_uInt16 nColumns
, sal_uInt16 nLines
) const
1088 // show ScrollBars where appropriate
1089 Size aMinSz
= CalcMinimumSize();
1095 if ( !IsDropDownBox() )
1096 aSz
.Height() = m_pImpl
->m_pImplLB
->CalcSize( nLines
).Height() + m_pImpl
->m_nDDHeight
;
1098 aSz
.Height() = m_pImpl
->m_nDDHeight
;
1101 aSz
.Height() = aMinSz
.Height();
1105 aSz
.Width() = nColumns
* approximate_char_width();
1107 aSz
.Width() = aMinSz
.Width();
1109 if ( IsDropDownBox() )
1110 aSz
.Width() += getMaxWidthScrollBarAndDownButton();
1112 if ( !IsDropDownBox() )
1114 if ( aSz
.Width() < aMinSz
.Width() )
1115 aSz
.Height() += GetSettings().GetStyleSettings().GetScrollBarSize();
1116 if ( aSz
.Height() < aMinSz
.Height() )
1117 aSz
.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
1120 aSz
.Width() += ImplGetExtraXOffset() * 2;
1122 aSz
= CalcWindowSize( aSz
);
1126 void ComboBox::GetMaxVisColumnsAndLines( sal_uInt16
& rnCols
, sal_uInt16
& rnLines
) const
1128 long nCharWidth
= GetTextWidth(OUString(static_cast<sal_Unicode
>('x')));
1129 if ( !IsDropDownBox() )
1131 Size aOutSz
= m_pImpl
->m_pImplLB
->GetMainWindow()->GetOutputSizePixel();
1132 rnCols
= (nCharWidth
> 0) ? (sal_uInt16
)(aOutSz
.Width()/nCharWidth
) : 1;
1133 rnLines
= (sal_uInt16
)(aOutSz
.Height()/m_pImpl
->m_pImplLB
->GetEntryHeight());
1137 Size aOutSz
= m_pImpl
->m_pSubEdit
->GetOutputSizePixel();
1138 rnCols
= (nCharWidth
> 0) ? (sal_uInt16
)(aOutSz
.Width()/nCharWidth
) : 1;
1143 void ComboBox::Draw( OutputDevice
* pDev
, const Point
& rPos
, const Size
& rSize
, DrawFlags nFlags
)
1145 m_pImpl
->m_pImplLB
->GetMainWindow()->ApplySettings(*pDev
);
1147 Point aPos
= pDev
->LogicToPixel( rPos
);
1148 Size aSize
= pDev
->LogicToPixel( rSize
);
1149 vcl::Font aFont
= m_pImpl
->m_pImplLB
->GetMainWindow()->GetDrawPixelFont( pDev
);
1150 OutDevType eOutDevType
= pDev
->GetOutDevType();
1154 pDev
->SetFont( aFont
);
1155 pDev
->SetTextFillColor();
1157 // Border/Background
1158 pDev
->SetLineColor();
1159 pDev
->SetFillColor();
1160 bool bBorder
= !(nFlags
& DrawFlags::NoBorder
) && (GetStyle() & WB_BORDER
);
1161 bool bBackground
= !(nFlags
& DrawFlags::NoBackground
) && IsControlBackground();
1162 if ( bBorder
|| bBackground
)
1164 Rectangle
aRect( aPos
, aSize
);
1165 // aRect.Top() += nEditHeight;
1168 ImplDrawFrame( pDev
, aRect
);
1172 pDev
->SetFillColor( GetControlBackground() );
1173 pDev
->DrawRect( aRect
);
1178 if ( !IsDropDownBox() )
1180 long nOnePixel
= GetDrawPixel( pDev
, 1 );
1181 long nTextHeight
= pDev
->GetTextHeight();
1182 long nEditHeight
= nTextHeight
+ 6*nOnePixel
;
1183 DrawTextFlags nTextStyle
= DrawTextFlags::VCenter
;
1185 // First, draw the edit part
1186 m_pImpl
->m_pSubEdit
->Draw( pDev
, aPos
, Size( aSize
.Width(), nEditHeight
), nFlags
);
1188 // Second, draw the listbox
1189 if ( GetStyle() & WB_CENTER
)
1190 nTextStyle
|= DrawTextFlags::Center
;
1191 else if ( GetStyle() & WB_RIGHT
)
1192 nTextStyle
|= DrawTextFlags::Right
;
1194 nTextStyle
|= DrawTextFlags::Left
;
1196 if ( ( nFlags
& DrawFlags::Mono
) || ( eOutDevType
== OUTDEV_PRINTER
) )
1198 pDev
->SetTextColor( Color( COL_BLACK
) );
1202 if ( !(nFlags
& DrawFlags::NoDisable
) && !IsEnabled() )
1204 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
1205 pDev
->SetTextColor( rStyleSettings
.GetDisableColor() );
1209 pDev
->SetTextColor( GetTextColor() );
1213 Rectangle
aClip( aPos
, aSize
);
1214 pDev
->IntersectClipRegion( aClip
);
1215 sal_Int32 nLines
= static_cast<sal_Int32
>( nTextHeight
> 0 ? (aSize
.Height()-nEditHeight
)/nTextHeight
: 1 );
1218 const sal_Int32 nTEntry
= IsReallyVisible() ? m_pImpl
->m_pImplLB
->GetTopEntry() : 0;
1220 Rectangle
aTextRect( aPos
, aSize
);
1222 aTextRect
.Left() += 3*nOnePixel
;
1223 aTextRect
.Right() -= 3*nOnePixel
;
1224 aTextRect
.Top() += nEditHeight
+ nOnePixel
;
1225 aTextRect
.Bottom() = aTextRect
.Top() + nTextHeight
;
1227 // the drawing starts here
1228 for ( sal_Int32 n
= 0; n
< nLines
; ++n
)
1230 pDev
->DrawText( aTextRect
, m_pImpl
->m_pImplLB
->GetEntryList()->GetEntryText( n
+nTEntry
), nTextStyle
);
1231 aTextRect
.Top() += nTextHeight
;
1232 aTextRect
.Bottom() += nTextHeight
;
1238 // Call Edit::Draw after restoring the MapMode...
1239 if ( IsDropDownBox() )
1241 m_pImpl
->m_pSubEdit
->Draw( pDev
, rPos
, rSize
, nFlags
);
1247 IMPL_LINK(ComboBox::Impl
, ImplUserDrawHdl
, UserDrawEvent
*, pEvent
, void)
1249 m_rThis
.UserDraw(*pEvent
);
1252 void ComboBox::UserDraw( const UserDrawEvent
& )
1256 void ComboBox::SetUserItemSize( const Size
& rSz
)
1258 m_pImpl
->m_pImplLB
->GetMainWindow()->SetUserItemSize( rSz
);
1261 void ComboBox::EnableUserDraw( bool bUserDraw
)
1263 m_pImpl
->m_pImplLB
->GetMainWindow()->EnableUserDraw( bUserDraw
);
1266 void ComboBox::DrawEntry(const UserDrawEvent
& rEvt
, bool bDrawImage
, bool bDrawText
, bool bDrawTextAtImagePos
)
1268 SAL_WARN_IF(rEvt
.GetWindow() != m_pImpl
->m_pImplLB
->GetMainWindow(), "vcl", "DrawEntry?!");
1269 m_pImpl
->m_pImplLB
->GetMainWindow()->DrawEntry(*rEvt
.GetRenderContext(), rEvt
.GetItemId(), bDrawImage
, bDrawText
, bDrawTextAtImagePos
);
1272 void ComboBox::SetSeparatorPos( sal_Int32 n
)
1274 m_pImpl
->m_pImplLB
->SetSeparatorPos( n
);
1277 void ComboBox::SetMRUEntries( const OUString
& rEntries
)
1279 m_pImpl
->m_pImplLB
->SetMRUEntries( rEntries
, ';' );
1282 OUString
ComboBox::GetMRUEntries() const
1284 return m_pImpl
->m_pImplLB
? m_pImpl
->m_pImplLB
->GetMRUEntries( ';' ) : OUString();
1287 void ComboBox::SetMaxMRUCount( sal_Int32 n
)
1289 m_pImpl
->m_pImplLB
->SetMaxMRUCount( n
);
1292 sal_Int32
ComboBox::GetMaxMRUCount() const
1294 return m_pImpl
->m_pImplLB
? m_pImpl
->m_pImplLB
->GetMaxMRUCount() : 0;
1297 sal_uInt16
ComboBox::GetDisplayLineCount() const
1299 return m_pImpl
->m_pImplLB
? m_pImpl
->m_pImplLB
->GetDisplayLineCount() : 0;
1302 void ComboBox::SetEntryData( sal_Int32 nPos
, void* pNewData
)
1304 m_pImpl
->m_pImplLB
->SetEntryData( nPos
+ m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount(), pNewData
);
1307 void* ComboBox::GetEntryData( sal_Int32 nPos
) const
1309 return m_pImpl
->m_pImplLB
->GetEntryList()->GetEntryData(
1310 nPos
+ m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount() );
1313 sal_Int32
ComboBox::GetTopEntry() const
1315 sal_Int32 nPos
= GetEntryCount() ? m_pImpl
->m_pImplLB
->GetTopEntry() : LISTBOX_ENTRY_NOTFOUND
;
1316 if (nPos
< m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount())
1321 void ComboBox::SetProminentEntryType( ProminentEntry eType
)
1323 m_pImpl
->m_pImplLB
->SetProminentEntryType( eType
);
1326 Rectangle
ComboBox::GetDropDownPosSizePixel() const
1328 return m_pImpl
->m_pFloatWin
1329 ? m_pImpl
->m_pFloatWin
->GetWindowExtentsRelative(const_cast<ComboBox
*>(this))
1333 const Wallpaper
& ComboBox::GetDisplayBackground() const
1335 if (!m_pImpl
->m_pSubEdit
->IsBackground())
1336 return Control::GetDisplayBackground();
1338 const Wallpaper
& rBack
= m_pImpl
->m_pSubEdit
->GetBackground();
1339 if( ! rBack
.IsBitmap() &&
1340 ! rBack
.IsGradient() &&
1341 rBack
.GetColor().GetColor() == COL_TRANSPARENT
1343 return Control::GetDisplayBackground();
1347 sal_Int32
ComboBox::GetSelectEntryCount() const
1349 return m_pImpl
->m_pImplLB
->GetEntryList()->GetSelectEntryCount();
1352 sal_Int32
ComboBox::GetSelectEntryPos( sal_Int32 nIndex
) const
1354 sal_Int32 nPos
= m_pImpl
->m_pImplLB
->GetEntryList()->GetSelectEntryPos( nIndex
);
1355 if ( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
1357 if (nPos
< m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount())
1358 nPos
= m_pImpl
->m_pImplLB
->GetEntryList()->FindEntry(m_pImpl
->m_pImplLB
->GetEntryList()->GetEntryText(nPos
));
1359 nPos
= sal::static_int_cast
<sal_Int32
>(nPos
- m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount());
1364 bool ComboBox::IsEntryPosSelected( sal_Int32 nPos
) const
1366 return m_pImpl
->m_pImplLB
->GetEntryList()->IsEntryPosSelected(
1367 nPos
+ m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount() );
1370 void ComboBox::SelectEntryPos( sal_Int32 nPos
, bool bSelect
)
1372 if (nPos
< m_pImpl
->m_pImplLB
->GetEntryList()->GetEntryCount())
1373 m_pImpl
->m_pImplLB
->SelectEntry(
1374 nPos
+ m_pImpl
->m_pImplLB
->GetEntryList()->GetMRUCount(), bSelect
);
1377 void ComboBox::SetNoSelection()
1379 m_pImpl
->m_pImplLB
->SetNoSelection();
1380 m_pImpl
->m_pSubEdit
->SetText( OUString() );
1383 Rectangle
ComboBox::GetBoundingRectangle( sal_Int32 nItem
) const
1385 Rectangle aRect
= m_pImpl
->m_pImplLB
->GetMainWindow()->GetBoundingRectangle( nItem
);
1386 Rectangle aOffset
= m_pImpl
->m_pImplLB
->GetMainWindow()->GetWindowExtentsRelative( static_cast<vcl::Window
*>(const_cast<ComboBox
*>(this)) );
1387 aRect
.Move( aOffset
.TopLeft().X(), aOffset
.TopLeft().Y() );
1391 void ComboBox::SetBorderStyle( WindowBorderStyle nBorderStyle
)
1393 Window::SetBorderStyle( nBorderStyle
);
1394 if ( !IsDropDownBox() )
1396 m_pImpl
->m_pSubEdit
->SetBorderStyle( nBorderStyle
);
1397 m_pImpl
->m_pImplLB
->SetBorderStyle( nBorderStyle
);
1401 long ComboBox::GetIndexForPoint( const Point
& rPoint
, sal_Int32
& rPos
) const
1403 if( !HasLayoutData() )
1406 // check whether rPoint fits at all
1407 long nIndex
= Control::GetIndexForPoint( rPoint
);
1410 // point must be either in main list window
1411 // or in impl window (dropdown case)
1412 ImplListBoxWindow
* rMain
= m_pImpl
->m_pImplLB
->GetMainWindow();
1414 // convert coordinates to ImplListBoxWindow pixel coordinate space
1415 Point aConvPoint
= LogicToPixel( rPoint
);
1416 aConvPoint
= OutputToAbsoluteScreenPixel( aConvPoint
);
1417 aConvPoint
= rMain
->AbsoluteScreenToOutputPixel( aConvPoint
);
1418 aConvPoint
= rMain
->PixelToLogic( aConvPoint
);
1420 // try to find entry
1421 sal_Int32 nEntry
= rMain
->GetEntryPosForPoint( aConvPoint
);
1422 if( nEntry
== LISTBOX_ENTRY_NOTFOUND
)
1428 // get line relative index
1430 nIndex
= ToRelativeLineIndex( nIndex
);
1435 ComboBoxBounds
ComboBox::Impl::calcComboBoxDropDownComponentBounds(
1436 const Size
&rOutSz
, const Size
&rBorderOutSz
) const
1438 ComboBoxBounds aBounds
;
1441 long nBottom
= rOutSz
.Height();
1443 vcl::Window
*pBorder
= m_rThis
.GetWindow( GetWindowType::Border
);
1444 ImplControlValue aControlValue
;
1446 Rectangle aContent
, aBound
;
1448 // use the full extent of the control
1449 Rectangle
aArea( aPoint
, rBorderOutSz
);
1451 if (m_rThis
.GetNativeControlRegion(ControlType::Combobox
, ControlPart::ButtonDown
,
1452 aArea
, ControlState::NONE
, aControlValue
, OUString(), aBound
, aContent
) )
1454 // convert back from border space to local coordinates
1455 aPoint
= pBorder
->ScreenToOutputPixel(m_rThis
.OutputToScreenPixel(aPoint
));
1456 aContent
.Move(-aPoint
.X(), -aPoint
.Y());
1458 aBounds
.aButtonPos
= Point(aContent
.Left(), nTop
);
1459 aBounds
.aButtonSize
= Size(aContent
.getWidth(), (nBottom
-nTop
));
1461 // adjust the size of the edit field
1462 if (m_rThis
.GetNativeControlRegion(ControlType::Combobox
, ControlPart::SubEdit
,
1463 aArea
, ControlState::NONE
, aControlValue
, OUString(), aBound
, aContent
) )
1465 // convert back from border space to local coordinates
1466 aContent
.Move(-aPoint
.X(), -aPoint
.Y());
1468 // use the themes drop down size
1469 aBounds
.aSubEditPos
= aContent
.TopLeft();
1470 aBounds
.aSubEditSize
= aContent
.GetSize();
1474 // use the themes drop down size for the button
1475 aBounds
.aSubEditSize
= Size(rOutSz
.Width() - aContent
.getWidth(), rOutSz
.Height());
1480 long nSBWidth
= m_rThis
.GetSettings().GetStyleSettings().GetScrollBarSize();
1481 nSBWidth
= m_rThis
.CalcZoom( nSBWidth
);
1482 aBounds
.aSubEditSize
= Size(rOutSz
.Width() - nSBWidth
, rOutSz
.Height());
1483 aBounds
.aButtonPos
= Point(rOutSz
.Width() - nSBWidth
, nTop
);
1484 aBounds
.aButtonSize
= Size(nSBWidth
, (nBottom
-nTop
));
1489 void ComboBox::setMaxWidthChars(sal_Int32 nWidth
)
1491 if (nWidth
!= m_pImpl
->m_nMaxWidthChars
)
1493 m_pImpl
->m_nMaxWidthChars
= nWidth
;
1498 bool ComboBox::set_property(const OString
&rKey
, const OString
&rValue
)
1500 if (rKey
== "max-width-chars")
1501 setMaxWidthChars(rValue
.toInt32());
1503 return Control::set_property(rKey
, rValue
);
1507 FactoryFunction
ComboBox::GetUITestFactory() const
1509 return ComboBoxUIObject::create
;
1512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */