Update git submodules
[LibreOffice.git] / vcl / source / control / listbox.cxx
blob81e9eafdc33e1b0be1714ca8a7b816e27e53f9f9
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/builder.hxx>
21 #include <vcl/commandevent.hxx>
22 #include <vcl/event.hxx>
23 #include <vcl/toolkit/lstbox.hxx>
24 #include <vcl/settings.hxx>
25 #include <vcl/uitest/uiobject.hxx>
26 #include <sal/log.hxx>
28 #include <svdata.hxx>
29 #include <listbox.hxx>
30 #include <dndeventdispatcher.hxx>
31 #include <comphelper/lok.hxx>
33 #include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
34 #include <boost/property_tree/ptree.hpp>
35 #include <tools/json_writer.hxx>
37 ListBox::ListBox(WindowType nType)
38 : Control(nType)
39 , mpImplLB(nullptr)
41 ImplInitListBoxData();
44 ListBox::ListBox( vcl::Window* pParent, WinBits nStyle ) : Control( WindowType::LISTBOX )
46 ImplInitListBoxData();
47 ImplInit( pParent, nStyle );
50 ListBox::~ListBox()
52 disposeOnce();
55 void ListBox::dispose()
57 CallEventListeners( VclEventId::ObjectDying );
59 mpImplLB.disposeAndClear();
60 mpFloatWin.disposeAndClear();
61 mpImplWin.disposeAndClear();
62 mpBtn.disposeAndClear();
64 Control::dispose();
67 void ListBox::ImplInitListBoxData()
69 mpFloatWin = nullptr;
70 mpImplWin = nullptr;
71 mpBtn = nullptr;
72 mnDDHeight = 0;
73 mnLineCount = 0;
74 m_nMaxWidthChars = -1;
75 mbDDAutoSize = true;
78 void ListBox::ImplInit( vcl::Window* pParent, WinBits nStyle )
80 nStyle = ImplInitStyle( nStyle );
81 if ( !(nStyle & WB_NOBORDER) && ( nStyle & WB_DROPDOWN ) )
82 nStyle |= WB_BORDER;
84 Control::ImplInit( pParent, nStyle, nullptr );
86 css::uno::Reference< css::datatransfer::dnd::XDropTargetListener> xDrop = new DNDEventDispatcher(this);
88 if( nStyle & WB_DROPDOWN )
90 sal_Int32 nLeft, nTop, nRight, nBottom;
91 GetBorder( nLeft, nTop, nRight, nBottom );
92 mnDDHeight = static_cast<sal_uInt16>(GetTextHeight() + nTop + nBottom + 4);
94 if( IsNativeWidgetEnabled() &&
95 IsNativeControlSupported( ControlType::Listbox, ControlPart::Entire ) )
97 ImplControlValue aControlValue;
98 tools::Rectangle aCtrlRegion( Point( 0, 0 ), Size( 20, mnDDHeight ) );
99 tools::Rectangle aBoundingRgn( aCtrlRegion );
100 tools::Rectangle aContentRgn( aCtrlRegion );
101 if( GetNativeControlRegion( ControlType::Listbox, ControlPart::Entire, aCtrlRegion,
102 ControlState::ENABLED, aControlValue,
103 aBoundingRgn, aContentRgn ) )
105 sal_Int32 nHeight = aBoundingRgn.GetHeight();
106 if( nHeight > mnDDHeight )
107 mnDDHeight = static_cast<sal_uInt16>(nHeight);
111 mpFloatWin = VclPtr<ImplListBoxFloatingWindow>::Create( this );
112 if (!IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Focus))
113 mpFloatWin->RequestDoubleBuffering(true);
114 mpFloatWin->SetAutoWidth( true );
115 mpFloatWin->SetPopupModeEndHdl( LINK( this, ListBox, ImplPopupModeEndHdl ) );
116 mpFloatWin->GetDropTarget()->addDropTargetListener(xDrop);
118 mpImplWin = VclPtr<ImplWin>::Create( this, (nStyle & (WB_LEFT|WB_RIGHT|WB_CENTER))|WB_NOBORDER );
119 mpImplWin->SetMBDownHdl( LINK( this, ListBox, ImplClickBtnHdl ) );
120 mpImplWin->Show();
121 mpImplWin->GetDropTarget()->addDropTargetListener(xDrop);
122 mpImplWin->SetEdgeBlending(false);
124 mpBtn = VclPtr<ImplBtn>::Create( this, WB_NOLIGHTBORDER | WB_RECTSTYLE );
125 ImplInitDropDownButton( mpBtn );
126 mpBtn->SetMBDownHdl( LINK( this, ListBox, ImplClickBtnHdl ) );
127 mpBtn->Show();
128 mpBtn->GetDropTarget()->addDropTargetListener(xDrop);
131 vcl::Window* pLBParent = this;
132 if ( mpFloatWin )
133 pLBParent = mpFloatWin;
134 mpImplLB = VclPtr<ImplListBox>::Create( pLBParent, nStyle&(~WB_BORDER) );
135 mpImplLB->SetSelectHdl( LINK( this, ListBox, ImplSelectHdl ) );
136 mpImplLB->SetScrollHdl( LINK( this, ListBox, ImplScrollHdl ) );
137 mpImplLB->SetCancelHdl( LINK( this, ListBox, ImplCancelHdl ) );
138 mpImplLB->SetDoubleClickHdl( LINK( this, ListBox, ImplDoubleClickHdl ) );
139 mpImplLB->SetFocusHdl( LINK( this, ListBox, ImplFocusHdl ) );
140 mpImplLB->SetListItemSelectHdl( LINK( this, ListBox, ImplListItemSelectHdl ) );
141 mpImplLB->SetPosPixel( Point() );
142 mpImplLB->SetEdgeBlending(false);
143 mpImplLB->Show();
145 mpImplLB->GetDropTarget()->addDropTargetListener(xDrop);
147 if ( mpFloatWin )
149 mpFloatWin->SetImplListBox( mpImplLB );
150 mpImplLB->SetSelectionChangedHdl( LINK( this, ListBox, ImplSelectionChangedHdl ) );
152 else
153 mpImplLB->GetMainWindow()->AllowGrabFocus( true );
155 SetCompoundControl( true );
158 WinBits ListBox::ImplInitStyle( WinBits nStyle )
160 if ( !(nStyle & WB_NOTABSTOP) )
161 nStyle |= WB_TABSTOP;
162 if ( !(nStyle & WB_NOGROUP) )
163 nStyle |= WB_GROUP;
164 return nStyle;
167 IMPL_LINK_NOARG(ListBox, ImplSelectHdl, LinkParamNone*, void)
169 bool bPopup = IsInDropDown();
170 if( IsDropDownBox() )
172 if( !mpImplLB->IsTravelSelect() )
174 mpFloatWin->EndPopupMode();
175 mpImplWin->GrabFocus();
178 mpImplWin->SetItemPos( GetSelectedEntryPos() );
179 mpImplWin->SetString( GetSelectedEntry() );
180 if( mpImplLB->GetEntryList().HasImages() )
182 Image aImage = mpImplLB->GetEntryList().GetEntryImage( GetSelectedEntryPos() );
183 mpImplWin->SetImage( aImage );
185 mpImplWin->Invalidate();
188 if ( ( !IsTravelSelect() || mpImplLB->IsSelectionChanged() ) || ( bPopup && !IsMultiSelectionEnabled() ) )
189 Select();
192 IMPL_LINK( ListBox, ImplFocusHdl, sal_Int32, nPos, void )
194 CallEventListeners( VclEventId::ListboxFocus, reinterpret_cast<void*>(static_cast<sal_IntPtr>(nPos)) );
197 IMPL_LINK_NOARG( ListBox, ImplListItemSelectHdl, LinkParamNone*, void )
199 CallEventListeners( VclEventId::DropdownSelect );
202 IMPL_LINK_NOARG(ListBox, ImplScrollHdl, ImplListBox*, void)
204 CallEventListeners( VclEventId::ListboxScrolled );
207 IMPL_LINK_NOARG(ListBox, ImplCancelHdl, LinkParamNone*, void)
209 if( IsInDropDown() )
210 mpFloatWin->EndPopupMode();
213 IMPL_LINK( ListBox, ImplSelectionChangedHdl, sal_Int32, nChanged, void )
215 if ( mpImplLB->IsTrackingSelect() )
216 return;
218 const ImplEntryList& rEntryList = mpImplLB->GetEntryList();
219 if ( rEntryList.IsEntryPosSelected( nChanged ) )
221 // FIXME? This should've been turned into an ImplPaintEntry some time ago...
222 if ( nChanged < rEntryList.GetMRUCount() )
223 nChanged = rEntryList.FindEntry( rEntryList.GetEntryText( nChanged ) );
224 mpImplWin->SetItemPos( nChanged );
225 mpImplWin->SetString( rEntryList.GetEntryText( nChanged ) );
226 if( rEntryList.HasImages() )
228 Image aImage = rEntryList.GetEntryImage( nChanged );
229 mpImplWin->SetImage( aImage );
232 else
234 mpImplWin->SetItemPos( LISTBOX_ENTRY_NOTFOUND );
235 mpImplWin->SetString( OUString() );
236 Image aImage;
237 mpImplWin->SetImage( aImage );
239 mpImplWin->Invalidate();
242 IMPL_LINK_NOARG(ListBox, ImplDoubleClickHdl, ImplListBoxWindow*, void)
244 DoubleClick();
247 IMPL_LINK_NOARG(ListBox, ImplClickBtnHdl, void*, void)
249 if( mpFloatWin->IsInPopupMode() )
250 return;
252 CallEventListeners( VclEventId::DropdownPreOpen );
253 mpImplWin->GrabFocus();
254 mpBtn->SetPressed( true );
255 mpFloatWin->StartFloat( true );
256 CallEventListeners( VclEventId::DropdownOpen );
258 ImplClearLayoutData();
259 if( mpImplLB )
260 mpImplLB->GetMainWindow()->ImplClearLayoutData();
261 if( mpImplWin )
262 mpImplWin->ImplClearLayoutData();
265 IMPL_LINK_NOARG(ListBox, ImplPopupModeEndHdl, FloatingWindow*, void)
267 if( mpFloatWin->IsPopupModeCanceled() )
269 if ( ( mpFloatWin->GetPopupModeStartSaveSelection() != LISTBOX_ENTRY_NOTFOUND )
270 && !IsEntryPosSelected( mpFloatWin->GetPopupModeStartSaveSelection() ) )
272 mpImplLB->SelectEntry( mpFloatWin->GetPopupModeStartSaveSelection(), true );
273 bool bTravelSelect = mpImplLB->IsTravelSelect();
274 mpImplLB->SetTravelSelect( true );
276 VclPtr<vcl::Window> xWindow = this;
277 Select();
278 if ( xWindow->isDisposed() )
279 return;
281 mpImplLB->SetTravelSelect( bTravelSelect );
285 ImplClearLayoutData();
286 if( mpImplLB )
287 mpImplLB->GetMainWindow()->ImplClearLayoutData();
288 if( mpImplWin )
289 mpImplWin->ImplClearLayoutData();
291 mpBtn->SetPressed( false );
292 CallEventListeners( VclEventId::DropdownClose );
295 void ListBox::ToggleDropDown()
297 if( !IsDropDownBox() )
298 return;
300 if( mpFloatWin->IsInPopupMode() )
301 mpFloatWin->EndPopupMode();
302 else
304 CallEventListeners( VclEventId::DropdownPreOpen );
305 mpImplWin->GrabFocus();
306 mpBtn->SetPressed( true );
307 mpFloatWin->StartFloat( true );
308 CallEventListeners( VclEventId::DropdownOpen );
312 void ListBox::ApplySettings(vcl::RenderContext& rRenderContext)
314 rRenderContext.SetBackground();
317 void ListBox::Draw( OutputDevice* pDev, const Point& rPos, SystemTextColorFlags nFlags )
319 mpImplLB->GetMainWindow()->ApplySettings(*pDev);
321 Point aPos = pDev->LogicToPixel( rPos );
322 Size aSize = GetSizePixel();
323 vcl::Font aFont = mpImplLB->GetMainWindow()->GetDrawPixelFont( pDev );
325 pDev->Push();
326 pDev->SetMapMode();
327 pDev->SetFont( aFont );
328 pDev->SetTextFillColor();
330 // Border/Background
331 pDev->SetLineColor();
332 pDev->SetFillColor();
333 bool bBorder = (GetStyle() & WB_BORDER);
334 bool bBackground = IsControlBackground();
335 if ( bBorder || bBackground )
337 tools::Rectangle aRect( aPos, aSize );
338 if ( bBorder )
340 ImplDrawFrame( pDev, aRect );
342 if ( bBackground )
344 pDev->SetFillColor( GetControlBackground() );
345 pDev->DrawRect( aRect );
349 // Content
350 if ( nFlags & SystemTextColorFlags::Mono )
352 pDev->SetTextColor( COL_BLACK );
354 else
356 if ( !IsEnabled() )
358 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
359 pDev->SetTextColor( rStyleSettings.GetDisableColor() );
361 else
363 pDev->SetTextColor( GetTextColor() );
367 const tools::Long nOnePixel = GetDrawPixel( pDev, 1 );
368 const tools::Long nOffX = 3*nOnePixel;
369 DrawTextFlags nTextStyle = DrawTextFlags::VCenter;
370 tools::Rectangle aTextRect( aPos, aSize );
372 if ( GetStyle() & WB_CENTER )
373 nTextStyle |= DrawTextFlags::Center;
374 else if ( GetStyle() & WB_RIGHT )
375 nTextStyle |= DrawTextFlags::Right;
376 else
377 nTextStyle |= DrawTextFlags::Left;
379 aTextRect.AdjustLeft(nOffX );
380 aTextRect.AdjustRight( -nOffX );
382 if ( IsDropDownBox() )
384 OUString aText = GetSelectedEntry();
385 tools::Long nTextHeight = pDev->GetTextHeight();
386 tools::Long nTextWidth = pDev->GetTextWidth( aText );
387 tools::Long nOffY = (aSize.Height()-nTextHeight) / 2;
389 // Clipping?
390 if ( (nOffY < 0) ||
391 ((nOffY+nTextHeight) > aSize.Height()) ||
392 ((nOffX+nTextWidth) > aSize.Width()) )
394 tools::Rectangle aClip( aPos, aSize );
395 if ( nTextHeight > aSize.Height() )
396 aClip.AdjustBottom(nTextHeight-aSize.Height()+1 ); // So that HP Printers don't optimize this away
397 pDev->IntersectClipRegion( aClip );
400 pDev->DrawText( aTextRect, aText, nTextStyle );
402 else
404 tools::Long nTextHeight = pDev->GetTextHeight();
405 sal_uInt16 nLines = ( nTextHeight > 0 ) ? static_cast<sal_uInt16>(aSize.Height() / nTextHeight) : 1;
406 tools::Rectangle aClip( aPos, aSize );
408 pDev->IntersectClipRegion( aClip );
410 if ( !nLines )
411 nLines = 1;
413 for ( sal_uInt16 n = 0; n < nLines; n++ )
415 sal_Int32 nEntry = n+mpImplLB->GetTopEntry();
416 bool bSelected = mpImplLB->GetEntryList().IsEntryPosSelected( nEntry );
417 if ( bSelected )
419 pDev->SetFillColor( COL_BLACK );
420 pDev->DrawRect( tools::Rectangle( Point( aPos.X(), aPos.Y() + n*nTextHeight ),
421 Point( aPos.X() + aSize.Width(), aPos.Y() + (n+1)*nTextHeight + 2*nOnePixel ) ) );
422 pDev->SetFillColor();
423 pDev->SetTextColor( COL_WHITE );
426 aTextRect.SetTop( aPos.Y() + n*nTextHeight );
427 aTextRect.SetBottom( aTextRect.Top() + nTextHeight );
429 pDev->DrawText( aTextRect, mpImplLB->GetEntryList().GetEntryText( nEntry ), nTextStyle );
431 if ( bSelected )
432 pDev->SetTextColor( COL_BLACK );
436 pDev->Pop();
439 void ListBox::GetFocus()
441 if ( mpImplLB )
443 if( IsDropDownBox() )
444 mpImplWin->GrabFocus();
445 else
446 mpImplLB->GrabFocus();
449 Control::GetFocus();
452 void ListBox::LoseFocus()
454 if( IsDropDownBox() )
456 if (mpImplWin)
457 mpImplWin->HideFocus();
459 else
461 if (mpImplLB)
462 mpImplLB->HideFocus();
465 Control::LoseFocus();
468 void ListBox::DataChanged( const DataChangedEvent& rDCEvt )
470 Control::DataChanged( rDCEvt );
472 if ( !((rDCEvt.GetType() == DataChangedEventType::FONTS) ||
473 (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
474 ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
475 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))) )
476 return;
478 SetBackground(); // Due to a hack in Window::UpdateSettings the background must be reset
479 // otherwise it will overpaint NWF drawn listboxes
480 Resize();
481 mpImplLB->Resize(); // Is not called by ListBox::Resize() if the ImplLB does not change
483 if ( mpImplWin )
485 mpImplWin->GetOutDev()->SetSettings( GetSettings() ); // If not yet set...
486 mpImplWin->ApplySettings(*mpImplWin->GetOutDev());
488 mpBtn->GetOutDev()->SetSettings( GetSettings() );
489 ImplInitDropDownButton( mpBtn );
492 if ( IsDropDownBox() )
493 Invalidate();
496 void ListBox::EnableAutoSize( bool bAuto )
498 mbDDAutoSize = bAuto;
499 if ( mpFloatWin )
501 if ( bAuto && !mpFloatWin->GetDropDownLineCount() )
503 // use GetListBoxMaximumLineCount here; before, was on fixed number of five
504 AdaptDropDownLineCountToMaximum();
506 else if ( !bAuto )
508 mpFloatWin->SetDropDownLineCount( 0 );
513 void ListBox::SetDropDownLineCount( sal_uInt16 nLines )
515 mnLineCount = nLines;
516 if ( mpFloatWin )
517 mpFloatWin->SetDropDownLineCount( mnLineCount );
520 void ListBox::AdaptDropDownLineCountToMaximum()
522 // Adapt to maximum allowed number.
523 // Limit for LOK as we can't render outside of the dialog canvas.
524 if (comphelper::LibreOfficeKit::isActive())
525 SetDropDownLineCount(11);
526 else
527 SetDropDownLineCount(GetSettings().GetStyleSettings().GetListBoxMaximumLineCount());
530 sal_uInt16 ListBox::GetDropDownLineCount() const
532 if ( mpFloatWin )
533 return mpFloatWin->GetDropDownLineCount();
534 return mnLineCount;
537 void ListBox::setPosSizePixel( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, PosSizeFlags nFlags )
539 if( IsDropDownBox() && ( nFlags & PosSizeFlags::Size ) )
541 Size aPrefSz = mpFloatWin->GetPrefSize();
542 if ( ( nFlags & PosSizeFlags::Height ) && ( nHeight >= 2*mnDDHeight ) )
543 aPrefSz.setHeight( nHeight-mnDDHeight );
544 if ( nFlags & PosSizeFlags::Width )
545 aPrefSz.setWidth( nWidth );
546 mpFloatWin->SetPrefSize( aPrefSz );
548 if (IsAutoSizeEnabled())
549 nHeight = mnDDHeight;
552 Control::setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
555 void ListBox::Resize()
557 Size aOutSz = GetOutputSizePixel();
558 if( IsDropDownBox() )
560 // Initialize the dropdown button size with the standard scrollbar width
561 tools::Long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
562 tools::Long nBottom = aOutSz.Height();
564 // Note: in case of no border, pBorder will actually be this
565 vcl::Window *pBorder = GetWindow( GetWindowType::Border );
566 ImplControlValue aControlValue;
567 Point aPoint;
568 tools::Rectangle aContent, aBound;
570 // Use the full extent of the control
571 tools::Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
573 if ( GetNativeControlRegion( ControlType::Listbox, ControlPart::ButtonDown,
574 aArea, ControlState::NONE, aControlValue, aBound, aContent) )
576 // Convert back from border space to local coordinates
577 aPoint = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aPoint ) );
578 aContent.Move( -aPoint.X(), -aPoint.Y() );
580 // Use the themes drop down size for the button
581 aOutSz.setWidth( aContent.Left() );
582 mpBtn->setPosSizePixel( aContent.Left(), 0, aContent.GetWidth(), nBottom );
584 // Adjust the size of the edit field
585 if ( GetNativeControlRegion( ControlType::Listbox, ControlPart::SubEdit,
586 aArea, ControlState::NONE, aControlValue, aBound, aContent) )
588 // Convert back from border space to local coordinates
589 aContent.Move( -aPoint.X(), -aPoint.Y() );
591 // Use the themes drop down size
592 if( ! (GetStyle() & WB_BORDER) && ImplGetSVData()->maNWFData.mbNoFocusRects )
594 // No border but focus ring behavior -> we have a problem; the
595 // native rect relies on the border to draw the focus
596 // let's do the best we can and center vertically, so it doesn't look
597 // completely wrong.
598 Size aSz( GetOutputSizePixel() );
599 tools::Long nDiff = aContent.Top() - (aSz.Height() - aContent.GetHeight())/2;
600 aContent.AdjustTop( -nDiff );
601 aContent.AdjustBottom( -nDiff );
603 mpImplWin->SetPosSizePixel( aContent.TopLeft(), aContent.GetSize() );
605 else
606 mpImplWin->SetSizePixel( aOutSz );
608 else
610 nSBWidth = CalcZoom( nSBWidth );
611 mpImplWin->setPosSizePixel( 0, 0, aOutSz.Width() - nSBWidth, aOutSz.Height() );
612 mpBtn->setPosSizePixel( aOutSz.Width() - nSBWidth, 0, nSBWidth, aOutSz.Height() );
615 else
617 mpImplLB->SetSizePixel( aOutSz );
620 // Retain FloatingWindow size even when it's invisible, as we still process KEY_PGUP/DOWN ...
621 if ( mpFloatWin )
622 mpFloatWin->SetSizePixel( mpFloatWin->CalcFloatSize() );
624 Control::Resize();
627 void ListBox::FillLayoutData() const
629 mxLayoutData.emplace();
630 const ImplListBoxWindow* rMainWin = mpImplLB->GetMainWindow();
631 if( mpFloatWin )
633 // Dropdown mode
634 AppendLayoutData( *mpImplWin );
635 mpImplWin->SetLayoutDataParent( this );
636 if( mpFloatWin->IsReallyVisible() )
638 AppendLayoutData( *rMainWin );
639 rMainWin->SetLayoutDataParent( this );
642 else
644 AppendLayoutData( *rMainWin );
645 rMainWin->SetLayoutDataParent( this );
649 tools::Long ListBox::GetIndexForPoint( const Point& rPoint, sal_Int32& rPos ) const
651 if( !HasLayoutData() )
652 FillLayoutData();
654 // Check whether rPoint fits at all
655 tools::Long nIndex = Control::GetIndexForPoint( rPoint );
656 if( nIndex != -1 )
658 // Point must be either in main list window
659 // or in impl window (dropdown case)
660 ImplListBoxWindow* rMain = mpImplLB->GetMainWindow();
662 // Convert coordinates to ImplListBoxWindow pixel coordinate space
663 Point aConvPoint = LogicToPixel( rPoint );
664 AbsoluteScreenPixelPoint aConvPointAbs = OutputToAbsoluteScreenPixel( aConvPoint );
665 aConvPoint = rMain->AbsoluteScreenToOutputPixel( aConvPointAbs );
666 aConvPoint = rMain->PixelToLogic( aConvPoint );
668 // Try to find entry
669 sal_Int32 nEntry = rMain->GetEntryPosForPoint( aConvPoint );
670 if( nEntry == LISTBOX_ENTRY_NOTFOUND )
672 // Not found, maybe dropdown case
673 if( mpImplWin && mpImplWin->IsReallyVisible() )
675 // Convert to impl window pixel coordinates
676 aConvPoint = LogicToPixel( rPoint );
677 aConvPointAbs = OutputToAbsoluteScreenPixel( aConvPoint );
678 aConvPoint = mpImplWin->AbsoluteScreenToOutputPixel( aConvPointAbs );
680 // Check whether converted point is inside impl window
681 Size aImplWinSize = mpImplWin->GetOutputSizePixel();
682 if( aConvPoint.X() >= 0 && aConvPoint.Y() >= 0 && aConvPoint.X() < aImplWinSize.Width() && aConvPoint.Y() < aImplWinSize.Height() )
684 // Inside the impl window, the position is the current item pos
685 rPos = mpImplWin->GetItemPos();
687 else
688 nIndex = -1;
690 else
691 nIndex = -1;
693 else
694 rPos = nEntry;
696 SAL_WARN_IF( nIndex == -1, "vcl", "found index for point, but relative index failed" );
699 // Get line relative index
700 if( nIndex != -1 )
701 nIndex = ToRelativeLineIndex( nIndex );
703 return nIndex;
706 void ListBox::StateChanged( StateChangedType nType )
708 if( nType == StateChangedType::ReadOnly )
710 if( mpImplWin )
711 mpImplWin->Enable( !IsReadOnly() );
712 if( mpBtn )
713 mpBtn->Enable( !IsReadOnly() );
715 else if( nType == StateChangedType::Enable )
717 mpImplLB->Enable( IsEnabled() );
718 if( mpImplWin )
720 mpImplWin->Enable( IsEnabled() );
721 if ( IsNativeControlSupported(ControlType::Listbox, ControlPart::Entire)
722 && ! IsNativeControlSupported(ControlType::Listbox, ControlPart::ButtonDown) )
724 GetWindow( GetWindowType::Border )->Invalidate( InvalidateFlags::NoErase );
726 else
727 mpImplWin->Invalidate();
729 if( mpBtn )
730 mpBtn->Enable( IsEnabled() );
732 else if( nType == StateChangedType::UpdateMode )
734 mpImplLB->SetUpdateMode( IsUpdateMode() );
736 else if ( nType == StateChangedType::Zoom )
738 mpImplLB->SetZoom( GetZoom() );
739 if ( mpImplWin )
741 mpImplWin->SetZoom( GetZoom() );
742 mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
743 mpImplWin->Invalidate();
745 Resize();
747 else if ( nType == StateChangedType::ControlFont )
749 mpImplLB->SetControlFont( GetControlFont() );
750 if ( mpImplWin )
752 mpImplWin->SetControlFont( GetControlFont() );
753 mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
754 mpImplWin->Invalidate();
756 Resize();
758 else if ( nType == StateChangedType::ControlForeground )
760 mpImplLB->SetControlForeground( GetControlForeground() );
761 if ( mpImplWin )
763 mpImplWin->SetControlForeground( GetControlForeground() );
764 mpImplWin->SetTextColor( GetControlForeground() );
765 mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
766 mpImplWin->Invalidate();
769 else if ( nType == StateChangedType::ControlBackground )
771 mpImplLB->SetControlBackground( GetControlBackground() );
772 if ( mpImplWin )
775 mpImplWin->SetBackground( GetControlBackground() );
776 mpImplWin->SetControlBackground( GetControlBackground() );
777 mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
778 mpImplWin->Invalidate();
781 else if ( nType == StateChangedType::Style )
783 SetStyle( ImplInitStyle( GetStyle() ) );
784 mpImplLB->GetMainWindow()->EnableSort( ( GetStyle() & WB_SORT ) != 0 );
785 bool bSimpleMode = ( GetStyle() & WB_SIMPLEMODE ) != 0;
786 mpImplLB->SetMultiSelectionSimpleMode( bSimpleMode );
788 else if( nType == StateChangedType::Mirroring )
790 if( mpBtn )
792 mpBtn->EnableRTL( IsRTLEnabled() );
793 ImplInitDropDownButton( mpBtn );
795 mpImplLB->EnableRTL( IsRTLEnabled() );
796 if( mpImplWin )
797 mpImplWin->EnableRTL( IsRTLEnabled() );
798 Resize();
801 Control::StateChanged( nType );
804 bool ListBox::PreNotify( NotifyEvent& rNEvt )
806 bool bDone = false;
807 if ( mpImplLB )
809 if( ( rNEvt.GetType() == NotifyEventType::KEYINPUT ) && ( rNEvt.GetWindow() == mpImplWin ) )
811 KeyEvent aKeyEvt = *rNEvt.GetKeyEvent();
812 switch( aKeyEvt.GetKeyCode().GetCode() )
814 case KEY_DOWN:
816 if( mpFloatWin && !mpFloatWin->IsInPopupMode() &&
817 aKeyEvt.GetKeyCode().IsMod2() )
819 CallEventListeners( VclEventId::DropdownPreOpen );
820 mpBtn->SetPressed( true );
821 mpFloatWin->StartFloat( false );
822 CallEventListeners( VclEventId::DropdownOpen );
823 bDone = true;
825 else
827 bDone = mpImplLB->ProcessKeyInput( aKeyEvt );
830 break;
831 case KEY_UP:
833 if( mpFloatWin && mpFloatWin->IsInPopupMode() &&
834 aKeyEvt.GetKeyCode().IsMod2() )
836 mpFloatWin->EndPopupMode();
837 bDone = true;
839 else
841 bDone = mpImplLB->ProcessKeyInput( aKeyEvt );
844 break;
845 case KEY_RETURN:
847 if( IsInDropDown() )
849 mpImplLB->ProcessKeyInput( aKeyEvt );
850 bDone = true;
853 break;
855 default:
857 bDone = mpImplLB->ProcessKeyInput( aKeyEvt );
861 else if ( rNEvt.GetType() == NotifyEventType::LOSEFOCUS )
863 if ( IsInDropDown() && !HasChildPathFocus( true ) )
864 mpFloatWin->EndPopupMode();
866 else if ( (rNEvt.GetType() == NotifyEventType::COMMAND) &&
867 (rNEvt.GetCommandEvent()->GetCommand() == CommandEventId::Wheel) &&
868 (rNEvt.GetWindow() == mpImplWin) )
870 const Point& rMousePos = rNEvt.GetCommandEvent()->GetMousePosPixel();
871 const tools::Rectangle aWinRect(mpImplWin->GetPosPixel(), mpImplWin->GetSizePixel());
872 const bool bMousePositionedOverWin = aWinRect.Contains(rMousePos);
874 MouseWheelBehaviour nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
875 if (bMousePositionedOverWin
876 && ((nWheelBehavior == MouseWheelBehaviour::ALWAYS)
877 || ((nWheelBehavior == MouseWheelBehaviour::FocusOnly) && HasChildPathFocus())))
879 bDone = mpImplLB->HandleWheelAsCursorTravel(*rNEvt.GetCommandEvent(), *this);
881 else
883 bDone = false; // Don't consume this event, let the default handling take it (i.e. scroll the context)
888 if (rNEvt.GetType() == NotifyEventType::MOUSEMOVE)
890 const MouseEvent* pMouseEvt = rNEvt.GetMouseEvent();
891 if (pMouseEvt && (pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow()))
893 // trigger redraw as mouse over state has changed
894 if (IsNativeControlSupported(ControlType::Listbox, ControlPart::Entire)
895 && !IsNativeControlSupported(ControlType::Listbox, ControlPart::ButtonDown))
897 GetWindow(GetWindowType::Border)->Invalidate(InvalidateFlags::NoErase);
902 return bDone || Control::PreNotify( rNEvt );
905 void ListBox::Select()
907 ImplCallEventListenersAndHandler( VclEventId::ListboxSelect, [this] () { maSelectHdl.Call(*this); } );
910 void ListBox::DoubleClick()
912 ImplCallEventListenersAndHandler( VclEventId::ListboxDoubleClick, {} );
915 void ListBox::Clear()
917 if (!mpImplLB)
918 return;
919 mpImplLB->Clear();
920 if( IsDropDownBox() )
922 mpImplWin->SetItemPos( LISTBOX_ENTRY_NOTFOUND );
923 mpImplWin->SetString( OUString() );
924 Image aImage;
925 mpImplWin->SetImage( aImage );
926 mpImplWin->Invalidate();
928 CallEventListeners( VclEventId::ListboxItemRemoved, reinterpret_cast<void*>(-1) );
931 void ListBox::SetNoSelection()
933 mpImplLB->SetNoSelection();
934 if( IsDropDownBox() )
936 mpImplWin->SetItemPos( LISTBOX_ENTRY_NOTFOUND );
937 mpImplWin->SetString( OUString() );
938 Image aImage;
939 mpImplWin->SetImage( aImage );
940 mpImplWin->Invalidate();
944 sal_Int32 ListBox::InsertEntry( const OUString& rStr, sal_Int32 nPos )
946 sal_Int32 nRealPos = mpImplLB->InsertEntry( nPos + mpImplLB->GetEntryList().GetMRUCount(), rStr );
947 nRealPos = sal::static_int_cast<sal_Int32>(nRealPos - mpImplLB->GetEntryList().GetMRUCount());
948 CallEventListeners( VclEventId::ListboxItemAdded, reinterpret_cast<void*>(static_cast<sal_IntPtr>(nRealPos)) );
949 return nRealPos;
952 sal_Int32 ListBox::InsertEntry( const OUString& rStr, const Image& rImage, sal_Int32 nPos )
954 sal_Int32 nRealPos = mpImplLB->InsertEntry( nPos + mpImplLB->GetEntryList().GetMRUCount(), rStr, rImage );
955 nRealPos = sal::static_int_cast<sal_Int32>(nRealPos - mpImplLB->GetEntryList().GetMRUCount());
956 CallEventListeners( VclEventId::ListboxItemAdded, reinterpret_cast<void*>(static_cast<sal_IntPtr>(nRealPos)) );
957 return nRealPos;
960 void ListBox::RemoveEntry( sal_Int32 nPos )
962 mpImplLB->RemoveEntry( nPos + mpImplLB->GetEntryList().GetMRUCount() );
963 CallEventListeners( VclEventId::ListboxItemRemoved, reinterpret_cast<void*>(static_cast<sal_IntPtr>(nPos)) );
966 Image ListBox::GetEntryImage( sal_Int32 nPos ) const
968 if ( mpImplLB && mpImplLB->GetEntryList().HasEntryImage( nPos ) )
969 return mpImplLB->GetEntryList().GetEntryImage( nPos );
970 return Image();
973 sal_Int32 ListBox::GetEntryPos( std::u16string_view rStr ) const
975 if (!mpImplLB)
976 return LISTBOX_ENTRY_NOTFOUND;
977 sal_Int32 nPos = mpImplLB->GetEntryList().FindEntry( rStr );
978 if ( nPos != LISTBOX_ENTRY_NOTFOUND )
979 nPos = nPos - mpImplLB->GetEntryList().GetMRUCount();
980 return nPos;
983 OUString ListBox::GetEntry( sal_Int32 nPos ) const
985 if (!mpImplLB)
986 return OUString();
987 return mpImplLB->GetEntryList().GetEntryText( nPos + mpImplLB->GetEntryList().GetMRUCount() );
990 sal_Int32 ListBox::GetEntryCount() const
992 if (!mpImplLB)
993 return 0;
994 return mpImplLB->GetEntryList().GetEntryCount() - mpImplLB->GetEntryList().GetMRUCount();
997 OUString ListBox::GetSelectedEntry(sal_Int32 nIndex) const
999 return GetEntry( GetSelectedEntryPos( nIndex ) );
1002 sal_Int32 ListBox::GetSelectedEntryCount() const
1004 if (!mpImplLB)
1005 return 0;
1006 return mpImplLB->GetEntryList().GetSelectedEntryCount();
1009 sal_Int32 ListBox::GetSelectedEntryPos( sal_Int32 nIndex ) const
1011 if (!mpImplLB)
1012 return LISTBOX_ENTRY_NOTFOUND;
1014 sal_Int32 nPos = mpImplLB->GetEntryList().GetSelectedEntryPos( nIndex );
1015 if ( nPos != LISTBOX_ENTRY_NOTFOUND )
1017 if ( nPos < mpImplLB->GetEntryList().GetMRUCount() )
1018 nPos = mpImplLB->GetEntryList().FindEntry( mpImplLB->GetEntryList().GetEntryText( nPos ) );
1019 nPos = nPos - mpImplLB->GetEntryList().GetMRUCount();
1021 return nPos;
1024 bool ListBox::IsEntryPosSelected( sal_Int32 nPos ) const
1026 return mpImplLB->GetEntryList().IsEntryPosSelected( nPos + mpImplLB->GetEntryList().GetMRUCount() );
1029 void ListBox::SelectEntry( std::u16string_view rStr, bool bSelect )
1031 SelectEntryPos( GetEntryPos( rStr ), bSelect );
1034 void ListBox::SelectEntryPos( sal_Int32 nPos, bool bSelect )
1036 if (!mpImplLB)
1037 return;
1039 if ( 0 <= nPos && nPos < mpImplLB->GetEntryList().GetEntryCount() )
1041 sal_Int32 nCurrentPos = mpImplLB->GetCurrentPos();
1042 mpImplLB->SelectEntry( nPos + mpImplLB->GetEntryList().GetMRUCount(), bSelect );
1043 //Only when bSelect == true, send both Selection & Focus events
1044 if (nCurrentPos != nPos && bSelect)
1046 CallEventListeners( VclEventId::ListboxSelect, reinterpret_cast<void*>(static_cast<sal_IntPtr>(nPos)));
1047 if (HasFocus())
1048 CallEventListeners( VclEventId::ListboxFocus, reinterpret_cast<void*>(static_cast<sal_IntPtr>(nPos)));
1053 void ListBox::SelectEntriesPos( const std::vector<sal_Int32>& rPositions, bool bSelect )
1055 if (!mpImplLB)
1056 return;
1058 bool bCallListeners = false;
1060 const sal_Int32 nCurrentPos = mpImplLB->GetCurrentPos();
1061 const auto nEntryCount = mpImplLB->GetEntryList().GetEntryCount();
1062 const auto nMRUCount = mpImplLB->GetEntryList().GetMRUCount();
1064 for (auto nPos : rPositions)
1066 if (0 <= nPos && nPos < nEntryCount)
1068 mpImplLB->SelectEntry(nPos + nMRUCount, bSelect);
1069 if (nCurrentPos != nPos && bSelect)
1070 bCallListeners = true;
1074 //Only when bSelect == true, send both Selection & Focus events
1075 if (bCallListeners)
1077 CallEventListeners(VclEventId::ListboxSelect);
1078 if (HasFocus())
1079 CallEventListeners(VclEventId::ListboxFocus);
1083 void ListBox::SetEntryData( sal_Int32 nPos, void* pNewData )
1085 mpImplLB->SetEntryData( nPos + mpImplLB->GetEntryList().GetMRUCount(), pNewData );
1088 void* ListBox::GetEntryData( sal_Int32 nPos ) const
1090 return mpImplLB->GetEntryList().GetEntryData( nPos + mpImplLB->GetEntryList().GetMRUCount() );
1093 void ListBox::SetEntryFlags( sal_Int32 nPos, ListBoxEntryFlags nFlags )
1095 mpImplLB->SetEntryFlags( nPos + mpImplLB->GetEntryList().GetMRUCount(), nFlags );
1098 void ListBox::SetTopEntry( sal_Int32 nPos )
1100 mpImplLB->SetTopEntry( nPos + mpImplLB->GetEntryList().GetMRUCount() );
1103 sal_Int32 ListBox::GetTopEntry() const
1105 sal_Int32 nPos = GetEntryCount() ? mpImplLB->GetTopEntry() : LISTBOX_ENTRY_NOTFOUND;
1106 if ( nPos < mpImplLB->GetEntryList().GetMRUCount() )
1107 nPos = 0;
1108 return nPos;
1111 bool ListBox::IsTravelSelect() const
1113 return mpImplLB->IsTravelSelect();
1116 bool ListBox::IsInDropDown() const
1118 // when the dropdown is dismissed, first mbInPopupMode is set to false, and on the next event iteration then
1119 // mbPopupMode is set to false
1120 return mpFloatWin && mpFloatWin->IsInPopupMode() && mpFloatWin->ImplIsInPrivatePopupMode();
1123 tools::Rectangle ListBox::GetBoundingRectangle( sal_Int32 nItem ) const
1125 tools::Rectangle aRect = mpImplLB->GetMainWindow()->GetBoundingRectangle( nItem );
1126 tools::Rectangle aOffset = mpImplLB->GetMainWindow()->GetWindowExtentsRelative( *static_cast<vcl::Window*>(const_cast<ListBox *>(this)) );
1127 aRect.Move( aOffset.Left(), aOffset.Top() );
1128 return aRect;
1131 void ListBox::EnableMultiSelection( bool bMulti )
1133 mpImplLB->EnableMultiSelection( bMulti );
1135 // WB_SIMPLEMODE:
1136 // The MultiListBox behaves just like a normal ListBox
1137 // MultiSelection is possible via corresponding additional keys
1138 bool bSimpleMode = ( GetStyle() & WB_SIMPLEMODE ) != 0;
1139 mpImplLB->SetMultiSelectionSimpleMode( bSimpleMode );
1141 // In a MultiSelection, we can't see us travelling without focus
1142 if ( mpFloatWin )
1143 mpImplLB->GetMainWindow()->AllowGrabFocus( bMulti );
1146 bool ListBox::IsMultiSelectionEnabled() const
1148 return mpImplLB->IsMultiSelectionEnabled();
1151 void ListBox::SetHighlightColor(const Color& rColor)
1153 AllSettings aSettings(GetSettings());
1154 StyleSettings aStyle(aSettings.GetStyleSettings());
1155 aStyle.SetHighlightColor(rColor);
1156 aSettings.SetStyleSettings(aStyle);
1157 SetSettings(aSettings);
1159 mpImplLB->SetHighlightColor(rColor);
1162 void ListBox::SetHighlightTextColor(const Color& rColor)
1164 AllSettings aSettings(GetSettings());
1165 StyleSettings aStyle(aSettings.GetStyleSettings());
1166 aStyle.SetHighlightTextColor(rColor);
1167 aSettings.SetStyleSettings(aStyle);
1168 SetSettings(aSettings);
1170 mpImplLB->SetHighlightTextColor(rColor);
1173 Size ListBox::CalcMinimumSize() const
1175 Size aSz;
1177 if (!mpImplLB)
1178 return aSz;
1180 aSz = CalcSubEditSize();
1182 bool bAddScrollWidth = false;
1184 if (IsDropDownBox())
1186 aSz.AdjustHeight(4 ); // add a space between entry and border
1187 aSz.AdjustWidth(4 ); // add a little breathing space
1188 bAddScrollWidth = true;
1190 else
1191 bAddScrollWidth = (GetStyle() & WB_VSCROLL) == WB_VSCROLL;
1193 if (bAddScrollWidth)
1195 // Try native borders; scrollbar size may not be a good indicator
1196 // See how large the edit area inside is to estimate what is needed for the dropdown
1197 ImplControlValue aControlValue;
1198 tools::Rectangle aContent, aBound;
1199 Size aTestSize( 100, 20 );
1200 tools::Rectangle aArea( Point(), aTestSize );
1201 if( GetNativeControlRegion( ControlType::Listbox, ControlPart::SubEdit, aArea, ControlState::NONE,
1202 aControlValue, aBound, aContent) )
1204 // use the themes drop down size
1205 aSz.AdjustWidth(aTestSize.Width() - aContent.GetWidth() );
1207 else
1208 aSz.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
1211 aSz = CalcWindowSize( aSz );
1213 if (IsDropDownBox()) // Check minimum height of dropdown box
1215 ImplControlValue aControlValue;
1216 tools::Rectangle aRect( Point( 0, 0 ), aSz );
1217 tools::Rectangle aContent, aBound;
1218 if( GetNativeControlRegion( ControlType::Listbox, ControlPart::Entire, aRect, ControlState::NONE,
1219 aControlValue, aBound, aContent) )
1221 if( aBound.GetHeight() > aSz.Height() )
1222 aSz.setHeight( aBound.GetHeight() );
1226 return aSz;
1229 Size ListBox::CalcSubEditSize() const
1231 Size aSz;
1233 if (!mpImplLB)
1234 return aSz;
1236 if ( !IsDropDownBox() )
1237 aSz = mpImplLB->CalcSize (mnLineCount ? mnLineCount : mpImplLB->GetEntryList().GetEntryCount());
1238 else
1240 aSz.setHeight( mpImplLB->GetEntryHeight() );
1241 // Size to maximum entry width
1242 aSz.setWidth( mpImplLB->GetMaxEntryWidth() );
1244 if (m_nMaxWidthChars != -1)
1246 tools::Long nMaxWidth = m_nMaxWidthChars * approximate_char_width();
1247 aSz.setWidth( std::min(aSz.Width(), nMaxWidth) );
1250 // Do not create ultrathin ListBoxes, it doesn't look good
1251 if( aSz.Width() < GetSettings().GetStyleSettings().GetScrollBarSize() )
1252 aSz.setWidth( GetSettings().GetStyleSettings().GetScrollBarSize() );
1255 return aSz;
1258 Size ListBox::GetOptimalSize() const
1260 return CalcMinimumSize();
1263 Size ListBox::CalcAdjustedSize( const Size& rPrefSize ) const
1265 Size aSz = rPrefSize;
1266 sal_Int32 nLeft, nTop, nRight, nBottom;
1267 static_cast<vcl::Window*>(const_cast<ListBox *>(this))->GetBorder( nLeft, nTop, nRight, nBottom );
1268 aSz.AdjustHeight( -(nTop+nBottom) );
1269 if ( !IsDropDownBox() )
1271 tools::Long nEntryHeight = CalcBlockSize( 1, 1 ).Height();
1272 tools::Long nLines = aSz.Height() / nEntryHeight;
1273 if ( nLines < 1 )
1274 nLines = 1;
1275 aSz.setHeight( nLines * nEntryHeight );
1277 else
1279 aSz.setHeight( mnDDHeight );
1281 aSz.AdjustHeight(nTop+nBottom );
1283 aSz = CalcWindowSize( aSz );
1284 return aSz;
1287 Size ListBox::CalcBlockSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const
1289 // ScrollBars are shown if needed
1290 Size aMinSz = CalcMinimumSize();
1291 // aMinSz = ImplCalcOutSz( aMinSz );
1293 Size aSz;
1295 // Height
1296 if ( nLines )
1298 if ( !IsDropDownBox() )
1299 aSz.setHeight( mpImplLB->CalcSize( nLines ).Height() );
1300 else
1301 aSz.setHeight( mnDDHeight );
1303 else
1304 aSz.setHeight( aMinSz.Height() );
1306 // Width
1307 if ( nColumns )
1308 aSz.setWidth( nColumns * GetTextWidth( OUString('X') ) );
1309 else
1310 aSz.setWidth( aMinSz.Width() );
1312 if ( IsDropDownBox() )
1313 aSz.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
1315 if ( !IsDropDownBox() )
1317 if ( aSz.Width() < aMinSz.Width() )
1318 aSz.AdjustHeight(GetSettings().GetStyleSettings().GetScrollBarSize() );
1319 if ( aSz.Height() < aMinSz.Height() )
1320 aSz.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
1323 aSz = CalcWindowSize( aSz );
1324 return aSz;
1327 void ListBox::GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const
1329 float nCharWidth = approximate_char_width();
1330 if ( !IsDropDownBox() )
1332 Size aOutSz = mpImplLB->GetMainWindow()->GetOutputSizePixel();
1333 rnCols = static_cast<sal_uInt16>(aOutSz.Width()/nCharWidth);
1334 rnLines = static_cast<sal_uInt16>(aOutSz.Height()/mpImplLB->GetEntryHeightWithMargin());
1336 else
1338 Size aOutSz = mpImplWin->GetOutputSizePixel();
1339 rnCols = static_cast<sal_uInt16>(aOutSz.Width()/nCharWidth);
1340 rnLines = 1;
1344 void ListBox::SetReadOnly( bool bReadOnly )
1346 if ( mpImplLB->IsReadOnly() != bReadOnly )
1348 mpImplLB->SetReadOnly( bReadOnly );
1349 CompatStateChanged( StateChangedType::ReadOnly );
1353 bool ListBox::IsReadOnly() const
1355 return mpImplLB->IsReadOnly();
1358 void ListBox::SetSeparatorPos( sal_Int32 n )
1360 mpImplLB->SetSeparatorPos( n );
1363 sal_Int32 ListBox::GetSeparatorPos() const
1365 return mpImplLB->GetSeparatorPos();
1368 void ListBox::AddSeparator( sal_Int32 n )
1370 mpImplLB->AddSeparator( n );
1373 sal_uInt16 ListBox::GetDisplayLineCount() const
1375 return mpImplLB->GetDisplayLineCount();
1378 tools::Rectangle ListBox::GetDropDownPosSizePixel() const
1380 return mpFloatWin ? mpFloatWin->GetWindowExtentsRelative(*this) : tools::Rectangle();
1383 const Wallpaper& ListBox::GetDisplayBackground() const
1385 // !!! Recursion does not occur because the ImplListBox is initialized by default
1386 // to a non-transparent color in Window::ImplInitData
1387 return mpImplLB->GetDisplayBackground();
1390 void ListBox::setMaxWidthChars(sal_Int32 nWidth)
1392 if (nWidth != m_nMaxWidthChars)
1394 m_nMaxWidthChars = nWidth;
1395 queue_resize();
1399 bool ListBox::set_property(const OUString &rKey, const OUString &rValue)
1401 if (rKey == "active")
1402 SelectEntryPos(rValue.toInt32());
1403 else if (rKey == "max-width-chars")
1404 setMaxWidthChars(rValue.toInt32());
1405 else if (rKey == "can-focus")
1407 // as far as I can see in Gtk, setting a ComboBox as can.focus means
1408 // the focus gets stuck in it, so try here to behave like gtk does
1409 // with the settings that work, i.e. can.focus of false doesn't
1410 // set the hard WB_NOTABSTOP
1411 WinBits nBits = GetStyle();
1412 nBits &= ~(WB_TABSTOP|WB_NOTABSTOP);
1413 if (toBool(rValue))
1414 nBits |= WB_TABSTOP;
1415 SetStyle(nBits);
1417 else
1418 return Control::set_property(rKey, rValue);
1419 return true;
1422 FactoryFunction ListBox::GetUITestFactory() const
1424 return ListBoxUIObject::create;
1427 void ListBox::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
1429 Control::DumpAsPropertyTree(rJsonWriter);
1432 auto entriesNode = rJsonWriter.startArray("entries");
1433 for (int i = 0; i < GetEntryCount(); ++i)
1435 rJsonWriter.putSimpleValue(GetEntry(i));
1439 rJsonWriter.put("selectedCount", GetSelectedEntryCount());
1442 auto entriesNode = rJsonWriter.startArray("selectedEntries");
1443 for (int i = 0; i < GetSelectedEntryCount(); ++i)
1445 rJsonWriter.putSimpleValue(OUString::number(GetSelectedEntryPos(i)));
1450 MultiListBox::MultiListBox( vcl::Window* pParent, WinBits nStyle ) :
1451 ListBox( WindowType::MULTILISTBOX )
1453 ImplInit( pParent, nStyle );
1454 EnableMultiSelection( true );
1457 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */