build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / control / combobox.cxx
blobef5686fc50ef2be1f41f60b33c1642746935e060
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/combobox.hxx>
22 #include <set>
24 #include <comphelper/string.hxx>
25 #include <tools/debug.hxx>
26 #include <tools/rc.h>
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>
34 #include <svdata.hxx>
35 #include "listbox.hxx"
36 #include <controldata.hxx>
39 struct ComboBoxBounds
41 Point aSubEditPos;
42 Size aSubEditSize;
44 Point aButtonPos;
45 Size aButtonSize;
48 struct ComboBox::Impl
50 ComboBox & m_rThis;
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)
65 : m_rThis(rThis)
66 , m_nDDHeight(0)
67 , m_cMultiSep(0)
68 , m_isDDAutoSize(false)
69 , m_isSyntheticModify(false)
70 , m_isMatchCase(false)
71 , m_nMaxWidthChars(0)
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 );
110 SetWidthInChars(-1);
113 ComboBox::~ComboBox()
115 disposeOnce();
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();
128 Edit::dispose();
131 void ComboBox::Impl::ImplInitComboBoxData()
133 m_pSubEdit.disposeAndClear();
134 m_pBtn = nullptr;
135 m_pImplLB = nullptr;
136 m_pFloatWin = nullptr;
138 m_nDDHeight = 0;
139 m_isDDAutoSize = true;
140 m_isSyntheticModify = false;
141 m_isMatchCase = false;
142 m_cMultiSep = ';';
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,
159 aCtrlRegion,
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;
178 else
180 if ( !bNoBorder )
181 nStyle |= WB_BORDER;
184 Edit::ImplInit( pParent, nStyle );
185 SetBackground();
187 // DropDown ?
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;
205 else
207 if ( !bNoBorder )
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 );
237 else
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) )
250 nStyle |= WB_GROUP;
251 return nStyle;
254 void ComboBox::EnableAutocomplete( bool bEnable, bool bMatchCase )
256 m_pImpl->m_isMatchCase = bMatchCase;
258 if ( bEnable )
259 m_pImpl->m_pSubEdit->SetAutocompleteHdl( LINK(m_pImpl.get(), ComboBox::Impl, ImplAutocompleteHdl) );
260 else
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();
275 else
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();
283 if (m_pImplLB)
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 );
297 m_rThis.Select();
298 m_pImplLB->SetTravelSelect( bTravelSelect );
302 m_rThis.ImplClearLayoutData();
303 if (m_pImplLB)
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 )
320 nStart = 0;
322 sal_Int32 nPos = LISTBOX_ENTRY_NOTFOUND;
323 if (!m_isMatchCase)
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)
354 OUString aText;
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))
375 nIndex--;
376 ++nSepCount;
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 );
402 else
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 );
414 bCallSelect = true;
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();
423 m_rThis.GrabFocus();
426 if ( bCallSelect )
428 m_pSubEdit->SetModifyFlag();
429 m_isSyntheticModify = true;
430 m_rThis.Modify();
431 m_isSyntheticModify = false;
432 m_rThis.Select();
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();
467 else
469 m_pImpl->m_pSubEdit->GrabFocus();
470 if (!m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount())
471 m_pImpl->ImplUpdateFloatSelection();
472 else
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();
505 else if ( !bAuto )
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();
535 return nLines;
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()
559 Control::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);
571 else
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)
597 // dropdown mode
598 if (m_pImpl->m_pFloatWin->IsReallyVisible())
600 AppendLayoutData( *rMainWindow );
601 rMainWindow->SetLayoutDataParent( this );
604 else
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() );
618 if (m_pImpl->m_pBtn)
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() );
625 if (m_pImpl->m_pBtn)
626 m_pImpl->m_pBtn->Enable( IsEnabled() && !IsReadOnly() );
627 Invalidate();
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();
638 Resize();
640 else if ( nType == StateChangedType::ControlFont )
642 m_pImpl->m_pImplLB->SetControlFont( GetControlFont() );
643 m_pImpl->m_pSubEdit->SetControlFont( GetControlFont() );
644 ImplCalcEditHeight();
645 Resize();
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 )
664 if (m_pImpl->m_pBtn)
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() );
671 Resize();
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)) )
684 if (m_pImpl->m_pBtn)
686 m_pImpl->m_pBtn->SetSettings( GetSettings() );
687 ImplInitDropDownButton( m_pImpl->m_pBtn );
689 Resize();
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 )
699 bool bDone = false;
700 if ((rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
701 && (rNEvt.GetWindow() == m_pImpl->m_pSubEdit)
702 && !IsReadOnly())
704 KeyEvent aKeyEvt = *rNEvt.GetKeyEvent();
705 sal_uInt16 nKeyCode = aKeyEvt.GetKeyCode().GetCode();
706 switch( nKeyCode )
708 case KEY_UP:
709 case KEY_DOWN:
710 case KEY_PAGEUP:
711 case KEY_PAGEDOWN:
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 );
725 bDone = true;
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();
732 bDone = true;
734 else
736 bDone = m_pImpl->m_pImplLB->ProcessKeyInput( aKeyEvt );
739 break;
741 case KEY_RETURN:
743 if ((rNEvt.GetWindow() == m_pImpl->m_pSubEdit) && IsInDropDown())
745 m_pImpl->m_pImplLB->ProcessKeyInput( aKeyEvt );
746 bDone = true;
749 break;
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() );
772 else
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();
807 Edit::Modify();
810 void ComboBox::Impl::ImplUpdateFloatSelection()
812 if (!m_pImplLB || !m_pSubEdit)
813 return;
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;
821 bool bSelect = true;
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 );
836 bSelect = false;
839 if( nSelect != LISTBOX_ENTRY_NOTFOUND )
841 if (!m_pImplLB->IsVisible(nSelect))
842 m_pImplLB->ShowProminentEntry( nSelect );
843 m_pImplLB->SelectEntry( nSelect, bSelect );
845 else
847 nSelect = m_pImplLB->GetEntryList()->GetSelectEntryPos( 0 );
848 if( nSelect != LISTBOX_ENTRY_NOTFOUND )
849 m_pImplLB->SelectEntry( nSelect, false );
850 m_pImplLB->ResetCurrentPos();
853 else
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());
867 sal_Int32 nRealPos;
868 if (nPos == COMBOBOX_APPEND)
869 nRealPos = nPos;
870 else
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) );
880 return 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());
888 sal_Int32 nRealPos;
889 if (nPos == COMBOBOX_APPEND)
890 nRealPos = nPos;
891 else
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) );
901 return 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)
913 return;
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 );
929 return Image();
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();
937 return nPos;
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();
945 return nPos;
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)
952 return OUString();
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;
1007 Point aPoint;
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
1026 Size aSz;
1028 if (!m_pImpl->m_pImplLB)
1029 return aSz;
1031 if (!IsDropDownBox())
1033 aSz = m_pImpl->m_pImplLB->CalcSize( m_pImpl->m_pImplLB->GetEntryList()->GetEntryCount() );
1034 aSz.Height() += m_pImpl->m_nDDHeight;
1036 else
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 );
1058 return 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;
1071 if ( nLines < 1 )
1072 nLines = 1;
1073 aSz.Height() = nLines * nEntryHeight;
1074 aSz.Height() += m_pImpl->m_nDDHeight;
1076 else
1078 aSz.Height() = m_pImpl->m_nDDHeight;
1080 aSz.Height() += nTop+nBottom;
1082 aSz = CalcWindowSize( aSz );
1083 return aSz;
1086 Size ComboBox::CalcBlockSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const
1088 // show ScrollBars where appropriate
1089 Size aMinSz = CalcMinimumSize();
1090 Size aSz;
1092 // height
1093 if ( nLines )
1095 if ( !IsDropDownBox() )
1096 aSz.Height() = m_pImpl->m_pImplLB->CalcSize( nLines ).Height() + m_pImpl->m_nDDHeight;
1097 else
1098 aSz.Height() = m_pImpl->m_nDDHeight;
1100 else
1101 aSz.Height() = aMinSz.Height();
1103 // width
1104 if ( nColumns )
1105 aSz.Width() = nColumns * approximate_char_width();
1106 else
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 );
1123 return 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());
1135 else
1137 Size aOutSz = m_pImpl->m_pSubEdit->GetOutputSizePixel();
1138 rnCols = (nCharWidth > 0) ? (sal_uInt16)(aOutSz.Width()/nCharWidth) : 1;
1139 rnLines = 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();
1152 pDev->Push();
1153 pDev->SetMapMode();
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;
1166 if ( bBorder )
1168 ImplDrawFrame( pDev, aRect );
1170 if ( bBackground )
1172 pDev->SetFillColor( GetControlBackground() );
1173 pDev->DrawRect( aRect );
1177 // contents
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;
1193 else
1194 nTextStyle |= DrawTextFlags::Left;
1196 if ( ( nFlags & DrawFlags::Mono ) || ( eOutDevType == OUTDEV_PRINTER ) )
1198 pDev->SetTextColor( Color( COL_BLACK ) );
1200 else
1202 if ( !(nFlags & DrawFlags::NoDisable ) && !IsEnabled() )
1204 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1205 pDev->SetTextColor( rStyleSettings.GetDisableColor() );
1207 else
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 );
1216 if ( !nLines )
1217 nLines = 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;
1236 pDev->Pop();
1238 // Call Edit::Draw after restoring the MapMode...
1239 if ( IsDropDownBox() )
1241 m_pImpl->m_pSubEdit->Draw( pDev, rPos, rSize, nFlags );
1242 // DD-Button ?
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())
1317 nPos = 0;
1318 return nPos;
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))
1330 : Rectangle();
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();
1344 return rBack;
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());
1361 return nPos;
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() );
1388 return aRect;
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() )
1404 FillLayoutData();
1406 // check whether rPoint fits at all
1407 long nIndex = Control::GetIndexForPoint( rPoint );
1408 if( nIndex != -1 )
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 )
1423 nIndex = -1;
1424 else
1425 rPos = nEntry;
1428 // get line relative index
1429 if( nIndex != -1 )
1430 nIndex = ToRelativeLineIndex( nIndex );
1432 return nIndex;
1435 ComboBoxBounds ComboBox::Impl::calcComboBoxDropDownComponentBounds(
1436 const Size &rOutSz, const Size &rBorderOutSz) const
1438 ComboBoxBounds aBounds;
1440 long nTop = 0;
1441 long nBottom = rOutSz.Height();
1443 vcl::Window *pBorder = m_rThis.GetWindow( GetWindowType::Border );
1444 ImplControlValue aControlValue;
1445 Point aPoint;
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();
1472 else
1474 // use the themes drop down size for the button
1475 aBounds.aSubEditSize = Size(rOutSz.Width() - aContent.getWidth(), rOutSz.Height());
1478 else
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));
1486 return aBounds;
1489 void ComboBox::setMaxWidthChars(sal_Int32 nWidth)
1491 if (nWidth != m_pImpl->m_nMaxWidthChars)
1493 m_pImpl->m_nMaxWidthChars = nWidth;
1494 queue_resize();
1498 bool ComboBox::set_property(const OString &rKey, const OString &rValue)
1500 if (rKey == "max-width-chars")
1501 setMaxWidthChars(rValue.toInt32());
1502 else
1503 return Control::set_property(rKey, rValue);
1504 return true;
1507 FactoryFunction ComboBox::GetUITestFactory() const
1509 return ComboBoxUIObject::create;
1512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */