Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <tools/debug.hxx>
21 :
22 : #include <vcl/svapp.hxx>
23 : #include <vcl/settings.hxx>
24 : #include <vcl/event.hxx>
25 : #include <vcl/scrbar.hxx>
26 : #include <vcl/help.hxx>
27 : #include <vcl/lstbox.h>
28 : #include <vcl/unohelp.hxx>
29 : #include <vcl/i18nhelp.hxx>
30 :
31 : #include <ilstbox.hxx>
32 : #include <controldata.hxx>
33 : #include <svdata.hxx>
34 : #include <window.h>
35 :
36 : #include <com/sun/star/i18n/XCollator.hpp>
37 : #include <com/sun/star/accessibility/XAccessible.hpp>
38 : #include <com/sun/star/accessibility/AccessibleRole.hpp>
39 :
40 : #include <rtl/instance.hxx>
41 : #include <comphelper/string.hxx>
42 : #include <comphelper/processfactory.hxx>
43 :
44 : #include <limits>
45 :
46 : #define MULTILINE_ENTRY_DRAW_FLAGS ( DrawTextFlags::WordBreak | DrawTextFlags::MultiLine | DrawTextFlags::VCenter )
47 :
48 : using namespace ::com::sun::star;
49 :
50 3793 : void ImplInitDropDownButton( PushButton* pButton )
51 : {
52 3793 : if ( pButton->GetSettings().GetStyleSettings().GetOptions() & StyleSettingsOptions::SpinUpDown )
53 0 : pButton->SetSymbol( SymbolType::SPIN_UPDOWN );
54 : else
55 3793 : pButton->SetSymbol( SymbolType::SPIN_DOWN );
56 :
57 7586 : if ( pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
58 3793 : && ! pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
59 0 : pButton->SetBackground();
60 3793 : }
61 :
62 3312 : ImplEntryList::ImplEntryList( vcl::Window* pWindow )
63 : {
64 3312 : mpWindow = pWindow;
65 3312 : mnLastSelected = LISTBOX_ENTRY_NOTFOUND;
66 3312 : mnSelectionAnchor = LISTBOX_ENTRY_NOTFOUND;
67 3312 : mnImages = 0;
68 3312 : mbCallSelectionChangedHdl = true;
69 :
70 3312 : mnMRUCount = 0;
71 3312 : mnMaxMRUCount = 0;
72 3312 : }
73 :
74 6620 : ImplEntryList::~ImplEntryList()
75 : {
76 3310 : Clear();
77 3310 : }
78 :
79 12952 : void ImplEntryList::Clear()
80 : {
81 12952 : mnImages = 0;
82 12952 : maEntries.clear();
83 12952 : }
84 :
85 2659 : void ImplEntryList::SelectEntry( sal_Int32 nPos, bool bSelect )
86 : {
87 2659 : if (0 <= nPos && static_cast<size_t>(nPos) < maEntries.size())
88 : {
89 2659 : boost::ptr_vector<ImplEntryType>::iterator iter = maEntries.begin()+nPos;
90 :
91 10636 : if ( ( iter->mbIsSelected != bSelect ) &&
92 10636 : ( (iter->mnFlags & ListBoxEntryFlags::DisableSelection) == ListBoxEntryFlags::NONE ) )
93 : {
94 2659 : iter->mbIsSelected = bSelect;
95 2659 : if ( mbCallSelectionChangedHdl )
96 254 : maSelectionChangedHdl.Call( reinterpret_cast<void*>(nPos) );
97 : }
98 : }
99 2659 : }
100 :
101 : namespace
102 : {
103 : struct theSorter
104 : : public rtl::StaticWithInit< comphelper::string::NaturalStringSorter, theSorter >
105 : {
106 7 : comphelper::string::NaturalStringSorter operator () ()
107 : {
108 : return comphelper::string::NaturalStringSorter(
109 : ::comphelper::getProcessComponentContext(),
110 7 : Application::GetSettings().GetLanguageTag().getLocale());
111 : }
112 : };
113 : }
114 :
115 172810 : sal_Int32 ImplEntryList::InsertEntry( sal_Int32 nPos, ImplEntryType* pNewEntry, bool bSort )
116 : {
117 172810 : if (nPos < 0 || LISTBOX_MAX_ENTRIES <= maEntries.size())
118 0 : return LISTBOX_ERROR;
119 :
120 172810 : if ( !!pNewEntry->maImage )
121 51 : mnImages++;
122 :
123 172810 : sal_Int32 insPos = 0;
124 :
125 172810 : if ( !bSort || maEntries.empty())
126 : {
127 172470 : if (0 <= nPos && static_cast<size_t>(nPos) < maEntries.size())
128 : {
129 5815 : insPos = nPos;
130 5815 : maEntries.insert( maEntries.begin() + nPos, pNewEntry );
131 : }
132 : else
133 : {
134 166655 : insPos = maEntries.size();
135 166655 : maEntries.push_back(pNewEntry);
136 : }
137 : }
138 : else
139 : {
140 340 : const comphelper::string::NaturalStringSorter &rSorter = theSorter::get();
141 :
142 340 : const OUString& rStr = pNewEntry->maStr;
143 : sal_uLong nLow, nHigh, nMid;
144 :
145 340 : nHigh = maEntries.size();
146 :
147 340 : ImplEntryType* pTemp = GetEntry( (sal_Int32)(nHigh-1) );
148 :
149 : try
150 : {
151 340 : sal_Int32 nComp = rSorter.compare(rStr, pTemp->maStr);
152 :
153 : // fast insert for sorted data
154 340 : if ( nComp >= 0 )
155 : {
156 305 : insPos = maEntries.size();
157 305 : maEntries.push_back(pNewEntry);
158 : }
159 : else
160 : {
161 35 : nLow = mnMRUCount;
162 35 : pTemp = GetEntry( (sal_Int32)nLow );
163 :
164 35 : nComp = rSorter.compare(rStr, pTemp->maStr);
165 35 : if ( nComp <= 0 )
166 : {
167 0 : insPos = 0;
168 0 : maEntries.insert(maEntries.begin(),pNewEntry);
169 : }
170 : else
171 : {
172 : // binary search
173 35 : nHigh--;
174 87 : do
175 : {
176 87 : nMid = (nLow + nHigh) / 2;
177 87 : pTemp = GetEntry( nMid );
178 :
179 87 : nComp = rSorter.compare(rStr, pTemp->maStr);
180 :
181 87 : if ( nComp < 0 )
182 52 : nHigh = nMid-1;
183 : else
184 : {
185 35 : if ( nComp > 0 )
186 35 : nLow = nMid + 1;
187 : else
188 0 : break;
189 : }
190 : }
191 : while ( nLow <= nHigh );
192 :
193 35 : if ( nComp >= 0 )
194 13 : nMid++;
195 :
196 35 : insPos = nMid;
197 35 : maEntries.insert(maEntries.begin()+nMid,pNewEntry);
198 : }
199 : }
200 : }
201 0 : catch (uno::RuntimeException& )
202 : {
203 : // XXX this is arguable, if the exception occurred because pNewEntry is
204 : // garbage you wouldn't insert it. If the exception occurred because the
205 : // Collator implementation is garbage then give the user a chance to see
206 : // his stuff
207 0 : insPos = 0;
208 0 : maEntries.insert(maEntries.begin(),pNewEntry);
209 : }
210 :
211 : }
212 :
213 172810 : return insPos;
214 : }
215 :
216 0 : void ImplEntryList::RemoveEntry( sal_Int32 nPos )
217 : {
218 0 : if (0 <= nPos && static_cast<size_t>(nPos) < maEntries.size())
219 : {
220 0 : boost::ptr_vector<ImplEntryType>::iterator iter = maEntries.begin()+ nPos;
221 :
222 0 : if ( !!iter->maImage )
223 0 : mnImages--;
224 :
225 0 : maEntries.erase(iter);
226 : }
227 0 : }
228 :
229 13795 : sal_Int32 ImplEntryList::FindEntry( const OUString& rString, bool bSearchMRUArea ) const
230 : {
231 13795 : sal_Int32 nEntries = maEntries.size();
232 115726 : for ( sal_Int32 n = bSearchMRUArea ? 0 : GetMRUCount(); n < nEntries; n++ )
233 : {
234 104351 : OUString aComp( vcl::I18nHelper::filterFormattingChars( maEntries[n].maStr ) );
235 104351 : if ( aComp == rString )
236 2420 : return n;
237 101931 : }
238 11375 : return LISTBOX_ENTRY_NOTFOUND;
239 : }
240 :
241 11375 : sal_Int32 ImplEntryList::FindMatchingEntry( const OUString& rStr, sal_Int32 nStart, bool bForward, bool bLazy ) const
242 : {
243 11375 : sal_Int32 nPos = LISTBOX_ENTRY_NOTFOUND;
244 11375 : sal_Int32 nEntryCount = GetEntryCount();
245 11375 : if ( !bForward )
246 0 : nStart++; // decrements right away
247 :
248 11375 : const vcl::I18nHelper& rI18nHelper = mpWindow->GetSettings().GetLocaleI18nHelper();
249 38203 : for ( sal_Int32 n = nStart; bForward ? n < nEntryCount : n != 0; )
250 : {
251 17466 : if ( !bForward )
252 0 : n--;
253 :
254 17466 : ImplEntryType* pImplEntry = GetEntry( n );
255 : bool bMatch;
256 17466 : if ( bLazy )
257 : {
258 17466 : bMatch = rI18nHelper.MatchString( rStr, pImplEntry->maStr );
259 : }
260 : else
261 : {
262 0 : bMatch = rStr.isEmpty() || (pImplEntry->maStr.startsWith(rStr));
263 : }
264 17466 : if ( bMatch )
265 : {
266 2013 : nPos = n;
267 2013 : break;
268 : }
269 :
270 15453 : if ( bForward )
271 15453 : n++;
272 : }
273 :
274 11375 : return nPos;
275 : }
276 :
277 0 : sal_Int32 ImplEntryList::FindEntry( const void* pData ) const
278 : {
279 0 : sal_Int32 nPos = LISTBOX_ENTRY_NOTFOUND;
280 0 : for ( sal_Int32 n = GetEntryCount(); n; )
281 : {
282 0 : ImplEntryType* pImplEntry = GetEntry( --n );
283 0 : if ( pImplEntry->mpUserData == pData )
284 : {
285 0 : nPos = n;
286 0 : break;
287 : }
288 : }
289 0 : return nPos;
290 : }
291 :
292 34073 : long ImplEntryList::GetAddedHeight( sal_Int32 i_nEndIndex, sal_Int32 i_nBeginIndex, long i_nBeginHeight ) const
293 : {
294 34073 : long nHeight = i_nBeginHeight;
295 34073 : sal_Int32 nStart = i_nEndIndex > i_nBeginIndex ? i_nBeginIndex : i_nEndIndex;
296 34073 : sal_Int32 nStop = i_nEndIndex > i_nBeginIndex ? i_nEndIndex : i_nBeginIndex;
297 34073 : sal_Int32 nEntryCount = GetEntryCount();
298 34073 : if( 0 <= nStop && nStop != LISTBOX_ENTRY_NOTFOUND && nEntryCount != 0 )
299 : {
300 : // sanity check
301 33761 : if( nStop > nEntryCount-1 )
302 0 : nStop = nEntryCount-1;
303 33761 : if (nStart < 0)
304 0 : nStart = 0;
305 33761 : else if( nStart > nEntryCount-1 )
306 0 : nStart = nEntryCount-1;
307 :
308 33761 : sal_Int32 nIndex = nStart;
309 576313 : while( nIndex != LISTBOX_ENTRY_NOTFOUND && nIndex < nStop )
310 : {
311 508791 : long nPosHeight = GetEntryPtr( nIndex )->mnHeight;
312 508791 : if (nHeight > ::std::numeric_limits<long>::max() - nPosHeight)
313 : {
314 : SAL_WARN( "vcl", "ImplEntryList::GetAddedHeight: truncated");
315 0 : break;
316 : }
317 508791 : nHeight += nPosHeight;
318 508791 : nIndex++;
319 33761 : }
320 : }
321 : else
322 312 : nHeight = 0;
323 34073 : return i_nEndIndex > i_nBeginIndex ? nHeight : -nHeight;
324 : }
325 :
326 6980 : long ImplEntryList::GetEntryHeight( sal_Int32 nPos ) const
327 : {
328 6980 : ImplEntryType* pImplEntry = GetEntry( nPos );
329 6980 : return pImplEntry ? pImplEntry->mnHeight : 0;
330 : }
331 :
332 87920 : OUString ImplEntryList::GetEntryText( sal_Int32 nPos ) const
333 : {
334 87920 : OUString aEntryText;
335 87920 : ImplEntryType* pImplEntry = GetEntry( nPos );
336 87920 : if ( pImplEntry )
337 87918 : aEntryText = pImplEntry->maStr;
338 87920 : return aEntryText;
339 : }
340 :
341 441 : bool ImplEntryList::HasEntryImage( sal_Int32 nPos ) const
342 : {
343 441 : bool bImage = false;
344 441 : ImplEntryType* pImplEntry = GetEntry( nPos );
345 441 : if ( pImplEntry )
346 441 : bImage = !!pImplEntry->maImage;
347 441 : return bImage;
348 : }
349 :
350 3 : Image ImplEntryList::GetEntryImage( sal_Int32 nPos ) const
351 : {
352 3 : Image aImage;
353 3 : ImplEntryType* pImplEntry = GetEntry( nPos );
354 3 : if ( pImplEntry )
355 3 : aImage = pImplEntry->maImage;
356 3 : return aImage;
357 : }
358 :
359 29580 : void ImplEntryList::SetEntryData( sal_Int32 nPos, void* pNewData )
360 : {
361 29580 : ImplEntryType* pImplEntry = GetEntry( nPos );
362 29580 : if ( pImplEntry )
363 29580 : pImplEntry->mpUserData = pNewData;
364 29580 : }
365 :
366 0 : void* ImplEntryList::GetEntryData( sal_Int32 nPos ) const
367 : {
368 0 : ImplEntryType* pImplEntry = GetEntry( nPos );
369 0 : return pImplEntry ? pImplEntry->mpUserData : NULL;
370 : }
371 :
372 0 : void ImplEntryList::SetEntryFlags( sal_Int32 nPos, ListBoxEntryFlags nFlags )
373 : {
374 0 : ImplEntryType* pImplEntry = GetEntry( nPos );
375 0 : if ( pImplEntry )
376 0 : pImplEntry->mnFlags = nFlags;
377 0 : }
378 :
379 0 : ListBoxEntryFlags ImplEntryList::GetEntryFlags( sal_Int32 nPos ) const
380 : {
381 0 : ImplEntryType* pImplEntry = GetEntry( nPos );
382 0 : return pImplEntry ? pImplEntry->mnFlags : ListBoxEntryFlags::NONE;
383 : }
384 :
385 6015 : sal_Int32 ImplEntryList::GetSelectEntryCount() const
386 : {
387 6015 : sal_Int32 nSelCount = 0;
388 297739 : for ( sal_Int32 n = GetEntryCount(); n; )
389 : {
390 285709 : ImplEntryType* pImplEntry = GetEntry( --n );
391 285709 : if ( pImplEntry->mbIsSelected )
392 4277 : nSelCount++;
393 : }
394 6015 : return nSelCount;
395 : }
396 :
397 0 : OUString ImplEntryList::GetSelectEntry( sal_Int32 nIndex ) const
398 : {
399 0 : return GetEntryText( GetSelectEntryPos( nIndex ) );
400 : }
401 :
402 19845 : sal_Int32 ImplEntryList::GetSelectEntryPos( sal_Int32 nIndex ) const
403 : {
404 19845 : sal_Int32 nSelEntryPos = LISTBOX_ENTRY_NOTFOUND;
405 19845 : sal_Int32 nSel = 0;
406 19845 : sal_Int32 nEntryCount = GetEntryCount();
407 :
408 334703 : for ( sal_Int32 n = 0; n < nEntryCount; n++ )
409 : {
410 321887 : ImplEntryType* pImplEntry = GetEntry( n );
411 321887 : if ( pImplEntry->mbIsSelected )
412 : {
413 7029 : if ( nSel == nIndex )
414 : {
415 7029 : nSelEntryPos = n;
416 7029 : break;
417 : }
418 0 : nSel++;
419 : }
420 : }
421 :
422 19845 : return nSelEntryPos;
423 : }
424 :
425 8786 : bool ImplEntryList::IsEntryPosSelected( sal_Int32 nIndex ) const
426 : {
427 8786 : ImplEntryType* pImplEntry = GetEntry( nIndex );
428 8786 : return pImplEntry && pImplEntry->mbIsSelected;
429 : }
430 :
431 2657 : bool ImplEntryList::IsEntrySelectable( sal_Int32 nPos ) const
432 : {
433 2657 : ImplEntryType* pImplEntry = GetEntry( nPos );
434 2657 : return pImplEntry == nullptr || ((pImplEntry->mnFlags & ListBoxEntryFlags::DisableSelection) == ListBoxEntryFlags::NONE);
435 : }
436 :
437 0 : sal_Int32 ImplEntryList::FindFirstSelectable( sal_Int32 nPos, bool bForward /* = true */ )
438 : {
439 0 : if( IsEntrySelectable( nPos ) )
440 0 : return nPos;
441 :
442 0 : if( bForward )
443 : {
444 0 : for( nPos = nPos + 1; nPos < GetEntryCount(); nPos++ )
445 : {
446 0 : if( IsEntrySelectable( nPos ) )
447 0 : return nPos;
448 : }
449 : }
450 : else
451 : {
452 0 : while( nPos )
453 : {
454 0 : nPos--;
455 0 : if( IsEntrySelectable( nPos ) )
456 0 : return nPos;
457 : }
458 : }
459 :
460 0 : return LISTBOX_ENTRY_NOTFOUND;
461 : }
462 :
463 3312 : ImplListBoxWindow::ImplListBoxWindow( vcl::Window* pParent, WinBits nWinStyle ) :
464 : Control( pParent, 0 ),
465 3312 : maQuickSelectionEngine( *this )
466 : {
467 3312 : mpEntryList = new ImplEntryList( this );
468 :
469 3312 : mnTop = 0;
470 3312 : mnLeft = 0;
471 3312 : mnBorder = 1;
472 3312 : mnSelectModifier = 0;
473 3312 : mnUserDrawEntry = LISTBOX_ENTRY_NOTFOUND;
474 3312 : mbTrack = false;
475 3312 : mbImgsDiffSz = false;
476 3312 : mbTravelSelect = false;
477 3312 : mbTrackingSelect = false;
478 3312 : mbSelectionChanged = false;
479 3312 : mbMouseMoveSelect = false;
480 3312 : mbMulti = false;
481 3312 : mbStackMode = false;
482 3312 : mbGrabFocus = false;
483 3312 : mbUserDrawEnabled = false;
484 3312 : mbInUserDraw = false;
485 3312 : mbReadOnly = false;
486 3312 : mbHasFocusRect = false;
487 3312 : mbRight = ( nWinStyle & WB_RIGHT );
488 3312 : mbCenter = ( nWinStyle & WB_CENTER );
489 3312 : mbSimpleMode = ( nWinStyle & WB_SIMPLEMODE );
490 3312 : mbSort = ( nWinStyle & WB_SORT );
491 3312 : mbEdgeBlending = false;
492 :
493 : // pb: #106948# explicit mirroring for calc
494 3312 : mbMirroring = false;
495 :
496 3312 : mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
497 3312 : mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
498 3312 : mnSeparatorPos = LISTBOX_ENTRY_NOTFOUND;
499 3312 : meProminentType = ProminentEntry::TOP;
500 :
501 3312 : SetLineColor();
502 3312 : SetTextFillColor();
503 3312 : SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
504 :
505 3312 : ApplySettings(*this);
506 3312 : ImplCalcMetrics();
507 3312 : }
508 :
509 9930 : ImplListBoxWindow::~ImplListBoxWindow()
510 : {
511 3310 : disposeOnce();
512 6620 : }
513 :
514 3310 : void ImplListBoxWindow::dispose()
515 : {
516 3310 : delete mpEntryList;
517 3310 : Control::dispose();
518 3310 : }
519 :
520 4413 : void ImplListBoxWindow::ApplySettings(vcl::RenderContext& rRenderContext)
521 : {
522 4413 : const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
523 :
524 4413 : vcl::Font aFont = rStyleSettings.GetFieldFont();
525 4413 : if (IsControlFont())
526 815 : aFont.Merge(GetControlFont());
527 4413 : SetZoomedPointFont(rRenderContext, aFont);
528 :
529 4413 : Color aTextColor = rStyleSettings.GetFieldTextColor();
530 4413 : if (IsControlForeground())
531 17 : aTextColor = GetControlForeground();
532 4413 : rRenderContext.SetTextColor(aTextColor);
533 :
534 4413 : if (IsControlBackground())
535 25 : rRenderContext.SetBackground(GetControlBackground());
536 : else
537 4388 : rRenderContext.SetBackground(rStyleSettings.GetFieldColor());
538 4413 : }
539 :
540 11150 : void ImplListBoxWindow::ImplCalcMetrics()
541 : {
542 11150 : mnMaxWidth = 0;
543 11150 : mnMaxTxtWidth = 0;
544 11150 : mnMaxImgWidth = 0;
545 11150 : mnMaxImgTxtWidth= 0;
546 11150 : mnMaxImgHeight = 0;
547 :
548 11150 : mnTextHeight = (sal_uInt16)GetTextHeight();
549 11150 : mnMaxTxtHeight = mnTextHeight + mnBorder;
550 11150 : mnMaxHeight = mnMaxTxtHeight;
551 :
552 11150 : if ( maUserItemSize.Height() > mnMaxHeight )
553 6187 : mnMaxHeight = (sal_uInt16) maUserItemSize.Height();
554 11150 : if ( maUserItemSize.Width() > mnMaxWidth )
555 5402 : mnMaxWidth= (sal_uInt16) maUserItemSize.Width();
556 :
557 155333 : for ( sal_Int32 n = mpEntryList->GetEntryCount(); n; )
558 : {
559 133033 : ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( --n );
560 133033 : ImplUpdateEntryMetrics( *pEntry );
561 : }
562 :
563 11150 : if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
564 : {
565 2 : Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryPtr( mnCurrentPos )->mnHeight );
566 2 : maFocusRect.SetSize( aSz );
567 : }
568 11150 : }
569 :
570 9642 : void ImplListBoxWindow::Clear()
571 : {
572 9642 : mpEntryList->Clear();
573 :
574 9642 : mnMaxHeight = mnMaxTxtHeight;
575 9642 : mnMaxWidth = 0;
576 9642 : mnMaxTxtWidth = 0;
577 9642 : mnMaxImgTxtWidth= 0;
578 9642 : mnMaxImgWidth = 0;
579 9642 : mnMaxImgHeight = 0;
580 9642 : mnTop = 0;
581 9642 : mnLeft = 0;
582 9642 : mbImgsDiffSz = false;
583 9642 : ImplClearLayoutData();
584 :
585 9642 : mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
586 9642 : maQuickSelectionEngine.Reset();
587 :
588 9642 : Invalidate();
589 9642 : }
590 :
591 7218 : void ImplListBoxWindow::SetUserItemSize( const Size& rSz )
592 : {
593 7218 : ImplClearLayoutData();
594 7218 : maUserItemSize = rSz;
595 7218 : ImplCalcMetrics();
596 7218 : }
597 :
598 : struct ImplEntryMetrics
599 : {
600 : bool bText;
601 : bool bImage;
602 : long nEntryWidth;
603 : long nEntryHeight;
604 : long nTextWidth;
605 : long nImgWidth;
606 : long nImgHeight;
607 : };
608 :
609 0 : void ImplListBoxWindow::EnableQuickSelection( const bool& b )
610 : {
611 0 : maQuickSelectionEngine.SetEnabled( b );
612 0 : }
613 :
614 305843 : void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType& rEntry )
615 : {
616 : ImplEntryMetrics aMetrics;
617 305843 : aMetrics.bText = !rEntry.maStr.isEmpty();
618 305843 : aMetrics.bImage = !!rEntry.maImage;
619 305843 : aMetrics.nEntryWidth = 0;
620 305843 : aMetrics.nEntryHeight = 0;
621 305843 : aMetrics.nTextWidth = 0;
622 305843 : aMetrics.nImgWidth = 0;
623 305843 : aMetrics.nImgHeight = 0;
624 :
625 305843 : if ( aMetrics.bText )
626 : {
627 305843 : if( (rEntry.mnFlags & ListBoxEntryFlags::MultiLine) )
628 : {
629 : // multiline case
630 0 : Size aCurSize( PixelToLogic( GetSizePixel() ) );
631 : // set the current size to a large number
632 : // GetTextRect should shrink it to the actual size
633 0 : aCurSize.Height() = 0x7fffff;
634 0 : Rectangle aTextRect( Point( 0, 0 ), aCurSize );
635 0 : aTextRect = GetTextRect( aTextRect, rEntry.maStr, DrawTextFlags::WordBreak | DrawTextFlags::MultiLine );
636 0 : aMetrics.nTextWidth = aTextRect.GetWidth();
637 0 : if( aMetrics.nTextWidth > mnMaxTxtWidth )
638 0 : mnMaxTxtWidth = aMetrics.nTextWidth;
639 0 : aMetrics.nEntryWidth = mnMaxTxtWidth;
640 0 : aMetrics.nEntryHeight = aTextRect.GetHeight() + mnBorder;
641 : }
642 : else
643 : {
644 : // normal single line case
645 305843 : aMetrics.nTextWidth = (sal_uInt16)GetTextWidth( rEntry.maStr );
646 305843 : if( aMetrics.nTextWidth > mnMaxTxtWidth )
647 43747 : mnMaxTxtWidth = aMetrics.nTextWidth;
648 305843 : aMetrics.nEntryWidth = mnMaxTxtWidth;
649 305843 : aMetrics.nEntryHeight = mnTextHeight + mnBorder;
650 : }
651 : }
652 305843 : if ( aMetrics.bImage )
653 : {
654 51 : Size aImgSz = rEntry.maImage.GetSizePixel();
655 51 : aMetrics.nImgWidth = (sal_uInt16) CalcZoom( aImgSz.Width() );
656 51 : aMetrics.nImgHeight = (sal_uInt16) CalcZoom( aImgSz.Height() );
657 :
658 51 : if( mnMaxImgWidth && ( aMetrics.nImgWidth != mnMaxImgWidth ) )
659 0 : mbImgsDiffSz = true;
660 51 : else if ( mnMaxImgHeight && ( aMetrics.nImgHeight != mnMaxImgHeight ) )
661 0 : mbImgsDiffSz = true;
662 :
663 51 : if( aMetrics.nImgWidth > mnMaxImgWidth )
664 3 : mnMaxImgWidth = aMetrics.nImgWidth;
665 51 : if( aMetrics.nImgHeight > mnMaxImgHeight )
666 3 : mnMaxImgHeight = aMetrics.nImgHeight;
667 :
668 51 : mnMaxImgTxtWidth = std::max( mnMaxImgTxtWidth, aMetrics.nTextWidth );
669 51 : aMetrics.nEntryHeight = std::max( aMetrics.nImgHeight, aMetrics.nEntryHeight );
670 :
671 : }
672 305843 : if ( IsUserDrawEnabled() || aMetrics.bImage )
673 : {
674 263093 : aMetrics.nEntryWidth = std::max( aMetrics.nImgWidth, maUserItemSize.Width() );
675 263093 : if ( aMetrics.bText )
676 263093 : aMetrics.nEntryWidth += aMetrics.nTextWidth + IMG_TXT_DISTANCE;
677 263093 : aMetrics.nEntryHeight = std::max( std::max( mnMaxImgHeight, maUserItemSize.Height() ) + 2,
678 263093 : aMetrics.nEntryHeight );
679 : }
680 :
681 305843 : if ( !aMetrics.bText && !aMetrics.bImage && !IsUserDrawEnabled() )
682 : {
683 : // entries which have no (aka an empty) text, and no image,
684 : // and are not user-drawn, should be shown nonetheless
685 0 : aMetrics.nEntryHeight = mnTextHeight + mnBorder;
686 : }
687 :
688 305843 : if ( aMetrics.nEntryWidth > mnMaxWidth )
689 43751 : mnMaxWidth = aMetrics.nEntryWidth;
690 305843 : if ( aMetrics.nEntryHeight > mnMaxHeight )
691 10389 : mnMaxHeight = aMetrics.nEntryHeight;
692 :
693 305843 : rEntry.mnHeight = aMetrics.nEntryHeight;
694 305843 : }
695 :
696 0 : void ImplListBoxWindow::ImplCallSelect()
697 : {
698 0 : if ( !IsTravelSelect() && GetEntryList()->GetMaxMRUCount() )
699 : {
700 : // Insert the selected entry as MRU, if not already first MRU
701 0 : sal_Int32 nSelected = GetEntryList()->GetSelectEntryPos( 0 );
702 0 : sal_Int32 nMRUCount = GetEntryList()->GetMRUCount();
703 0 : OUString aSelected = GetEntryList()->GetEntryText( nSelected );
704 0 : sal_Int32 nFirstMatchingEntryPos = GetEntryList()->FindEntry( aSelected, true );
705 0 : if ( nFirstMatchingEntryPos || !nMRUCount )
706 : {
707 0 : bool bSelectNewEntry = false;
708 0 : if ( nFirstMatchingEntryPos < nMRUCount )
709 : {
710 0 : RemoveEntry( nFirstMatchingEntryPos );
711 0 : nMRUCount--;
712 0 : if ( nFirstMatchingEntryPos == nSelected )
713 0 : bSelectNewEntry = true;
714 : }
715 0 : else if ( nMRUCount == GetEntryList()->GetMaxMRUCount() )
716 : {
717 0 : RemoveEntry( nMRUCount - 1 );
718 0 : nMRUCount--;
719 : }
720 :
721 0 : ImplClearLayoutData();
722 :
723 0 : ImplEntryType* pNewEntry = new ImplEntryType( aSelected );
724 0 : pNewEntry->mbIsSelected = bSelectNewEntry;
725 0 : GetEntryList()->InsertEntry( 0, pNewEntry, false );
726 0 : ImplUpdateEntryMetrics( *pNewEntry );
727 0 : GetEntryList()->SetMRUCount( ++nMRUCount );
728 0 : SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
729 0 : maMRUChangedHdl.Call( NULL );
730 0 : }
731 : }
732 :
733 0 : maSelectHdl.Call( NULL );
734 0 : mbSelectionChanged = false;
735 0 : }
736 :
737 172810 : sal_Int32 ImplListBoxWindow::InsertEntry( sal_Int32 nPos, ImplEntryType* pNewEntry )
738 : {
739 172810 : if (nPos < 0 || LISTBOX_MAX_ENTRIES <= mpEntryList->GetEntryCount())
740 0 : return LISTBOX_ERROR;
741 :
742 172810 : ImplClearLayoutData();
743 172810 : sal_Int32 nNewPos = mpEntryList->InsertEntry( nPos, pNewEntry, mbSort );
744 :
745 172810 : if( (GetStyle() & WB_WORDBREAK) )
746 0 : pNewEntry->mnFlags |= ListBoxEntryFlags::MultiLine;
747 :
748 172810 : ImplUpdateEntryMetrics( *pNewEntry );
749 172810 : return nNewPos;
750 : }
751 :
752 0 : void ImplListBoxWindow::RemoveEntry( sal_Int32 nPos )
753 : {
754 0 : ImplClearLayoutData();
755 0 : mpEntryList->RemoveEntry( nPos );
756 0 : if( mnCurrentPos >= mpEntryList->GetEntryCount() )
757 0 : mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
758 0 : ImplCalcMetrics();
759 0 : }
760 :
761 0 : void ImplListBoxWindow::SetEntryFlags( sal_Int32 nPos, ListBoxEntryFlags nFlags )
762 : {
763 0 : mpEntryList->SetEntryFlags( nPos, nFlags );
764 0 : ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( nPos );
765 0 : if( pEntry )
766 0 : ImplUpdateEntryMetrics( *pEntry );
767 0 : }
768 :
769 0 : void ImplListBoxWindow::ImplShowFocusRect()
770 : {
771 0 : if ( mbHasFocusRect )
772 0 : HideFocus();
773 0 : ShowFocus( maFocusRect );
774 0 : mbHasFocusRect = true;
775 0 : }
776 :
777 6547 : void ImplListBoxWindow::ImplHideFocusRect()
778 : {
779 6547 : if ( mbHasFocusRect )
780 : {
781 0 : HideFocus();
782 0 : mbHasFocusRect = false;
783 : }
784 6547 : }
785 :
786 0 : sal_Int32 ImplListBoxWindow::GetEntryPosForPoint( const Point& rPoint ) const
787 : {
788 0 : long nY = mnBorder;
789 :
790 0 : sal_Int32 nSelect = mnTop;
791 0 : const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nSelect );
792 0 : while( pEntry && rPoint.Y() > pEntry->mnHeight + nY )
793 : {
794 0 : nY += pEntry->mnHeight;
795 0 : pEntry = mpEntryList->GetEntryPtr( ++nSelect );
796 : }
797 0 : if( pEntry == NULL )
798 0 : nSelect = LISTBOX_ENTRY_NOTFOUND;
799 :
800 0 : return nSelect;
801 : }
802 :
803 9692 : bool ImplListBoxWindow::IsVisible( sal_Int32 i_nEntry ) const
804 : {
805 9692 : bool bRet = false;
806 :
807 9692 : if( i_nEntry >= mnTop )
808 : {
809 26133 : if( mpEntryList->GetAddedHeight( i_nEntry, mnTop ) <
810 17422 : PixelToLogic( GetSizePixel() ).Height() )
811 : {
812 3221 : bRet = true;
813 : }
814 : }
815 :
816 9692 : return bRet;
817 : }
818 :
819 1203 : sal_Int32 ImplListBoxWindow::GetLastVisibleEntry() const
820 : {
821 1203 : sal_Int32 nPos = mnTop;
822 1203 : long nWindowHeight = GetSizePixel().Height();
823 1203 : sal_Int32 nCount = mpEntryList->GetEntryCount();
824 : long nDiff;
825 1204 : for( nDiff = 0; nDiff < nWindowHeight && nPos < nCount; nDiff = mpEntryList->GetAddedHeight( nPos, mnTop ) )
826 1 : nPos++;
827 :
828 1203 : if( nDiff > nWindowHeight && nPos > mnTop )
829 0 : nPos--;
830 :
831 1203 : if( nPos >= nCount )
832 0 : nPos = nCount-1;
833 :
834 1203 : return nPos;
835 : }
836 :
837 0 : void ImplListBoxWindow::MouseButtonDown( const MouseEvent& rMEvt )
838 : {
839 0 : mbMouseMoveSelect = false; // only till the first MouseButtonDown
840 0 : maQuickSelectionEngine.Reset();
841 :
842 0 : if ( !IsReadOnly() )
843 : {
844 0 : if( rMEvt.GetClicks() == 1 )
845 : {
846 0 : sal_Int32 nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
847 0 : if( nSelect != LISTBOX_ENTRY_NOTFOUND )
848 : {
849 0 : if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
850 0 : mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
851 : else
852 0 : mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
853 :
854 0 : mnCurrentPos = nSelect;
855 0 : mbTrackingSelect = true;
856 0 : bool bCurPosChange = (mnCurrentPos != nSelect);
857 0 : (void)SelectEntries( nSelect, LET_MBDOWN, rMEvt.IsShift(), rMEvt.IsMod1() ,bCurPosChange);
858 0 : mbTrackingSelect = false;
859 0 : if ( mbGrabFocus )
860 0 : GrabFocus();
861 :
862 0 : StartTracking( StartTrackingFlags::ScrollRepeat );
863 : }
864 : }
865 0 : if( rMEvt.GetClicks() == 2 )
866 : {
867 0 : maDoubleClickHdl.Call( this );
868 : }
869 : }
870 : else // if ( mbGrabFocus )
871 : {
872 0 : GrabFocus();
873 : }
874 0 : }
875 :
876 0 : void ImplListBoxWindow::MouseMove( const MouseEvent& rMEvt )
877 : {
878 0 : if ( rMEvt.IsLeaveWindow() )
879 : {
880 0 : if ( mbStackMode && IsMouseMoveSelect() && IsReallyVisible() )
881 : {
882 0 : if ( rMEvt.GetPosPixel().Y() < 0 )
883 : {
884 0 : DeselectAll();
885 0 : mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
886 0 : SetTopEntry( 0 );
887 0 : if ( mbStackMode ) // #87072#, #92323#
888 : {
889 0 : mbTravelSelect = true;
890 0 : mnSelectModifier = rMEvt.GetModifier();
891 0 : ImplCallSelect();
892 0 : mbTravelSelect = false;
893 : }
894 :
895 : }
896 : }
897 : }
898 0 : else if ( ( ( !mbMulti && IsMouseMoveSelect() ) || mbStackMode ) && mpEntryList->GetEntryCount() )
899 : {
900 0 : Point aPoint;
901 0 : Rectangle aRect( aPoint, GetOutputSizePixel() );
902 0 : if( aRect.IsInside( rMEvt.GetPosPixel() ) )
903 : {
904 0 : if ( IsMouseMoveSelect() )
905 : {
906 0 : sal_Int32 nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
907 0 : if( nSelect == LISTBOX_ENTRY_NOTFOUND )
908 0 : nSelect = mpEntryList->GetEntryCount() - 1;
909 0 : nSelect = std::min( nSelect, GetLastVisibleEntry() );
910 0 : nSelect = std::min( nSelect, (sal_Int32) ( mpEntryList->GetEntryCount() - 1 ) );
911 : // Select only visible Entries with MouseMove, otherwise Tracking...
912 0 : if ( IsVisible( nSelect ) &&
913 0 : mpEntryList->IsEntrySelectable( nSelect ) &&
914 0 : ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() || ( nSelect != GetEntryList()->GetSelectEntryPos( 0 ) ) ) )
915 : {
916 0 : mbTrackingSelect = true;
917 0 : if ( SelectEntries( nSelect, LET_TRACKING, false, false ) )
918 : {
919 0 : if ( mbStackMode ) // #87072#
920 : {
921 0 : mbTravelSelect = true;
922 0 : mnSelectModifier = rMEvt.GetModifier();
923 0 : ImplCallSelect();
924 0 : mbTravelSelect = false;
925 : }
926 : // When list box selection change by mouse move, notity
927 : // VCLEVENT_LISTBOX_SELECT vcl event.
928 : else
929 : {
930 0 : maListItemSelectHdl.Call(NULL);
931 : }
932 : }
933 0 : mbTrackingSelect = false;
934 : }
935 : }
936 :
937 : // if the DD button was pressed and someone moved into the ListBox
938 : // with the mouse button pressed...
939 0 : if ( rMEvt.IsLeft() && !rMEvt.IsSynthetic() )
940 : {
941 0 : if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
942 0 : mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
943 : else
944 0 : mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
945 :
946 0 : if ( mbStackMode && ( mpEntryList->GetSelectionAnchor() == LISTBOX_ENTRY_NOTFOUND ) )
947 0 : mpEntryList->SetSelectionAnchor( 0 );
948 :
949 0 : StartTracking( StartTrackingFlags::ScrollRepeat );
950 : }
951 : }
952 : }
953 0 : }
954 :
955 45 : void ImplListBoxWindow::DeselectAll()
956 : {
957 101 : while ( GetEntryList()->GetSelectEntryCount() )
958 : {
959 11 : sal_Int32 nS = GetEntryList()->GetSelectEntryPos( 0 );
960 11 : SelectEntry( nS, false );
961 : }
962 45 : }
963 :
964 7775 : void ImplListBoxWindow::SelectEntry( sal_Int32 nPos, bool bSelect )
965 : {
966 7775 : if( (mpEntryList->IsEntryPosSelected( nPos ) != bSelect) && mpEntryList->IsEntrySelectable( nPos ) )
967 : {
968 2657 : ImplHideFocusRect();
969 2657 : if( bSelect )
970 : {
971 2639 : if( !mbMulti )
972 : {
973 : // deselect the selected entry
974 2639 : sal_Int32 nDeselect = GetEntryList()->GetSelectEntryPos( 0 );
975 2639 : if( nDeselect != LISTBOX_ENTRY_NOTFOUND )
976 : {
977 : //SelectEntryPos( nDeselect, false );
978 2 : GetEntryList()->SelectEntry( nDeselect, false );
979 2 : if (IsUpdateMode() && IsReallyVisible())
980 0 : Invalidate();
981 : }
982 : }
983 2639 : mpEntryList->SelectEntry( nPos, true );
984 2639 : mnCurrentPos = nPos;
985 2639 : if ( ( nPos != LISTBOX_ENTRY_NOTFOUND ) && IsUpdateMode() )
986 : {
987 2631 : Invalidate();
988 2631 : if ( !IsVisible( nPos ) )
989 : {
990 1203 : ImplClearLayoutData();
991 1203 : sal_Int32 nVisibleEntries = GetLastVisibleEntry()-mnTop;
992 1203 : if ( !nVisibleEntries || !IsReallyVisible() || ( nPos < GetTopEntry() ) )
993 : {
994 1203 : Resize();
995 1203 : ShowProminentEntry( nPos );
996 : }
997 : else
998 : {
999 0 : ShowProminentEntry( nPos );
1000 : }
1001 : }
1002 : }
1003 : }
1004 : else
1005 : {
1006 18 : mpEntryList->SelectEntry( nPos, false );
1007 18 : Invalidate();
1008 : }
1009 2657 : mbSelectionChanged = true;
1010 : }
1011 7775 : }
1012 :
1013 0 : bool ImplListBoxWindow::SelectEntries( sal_Int32 nSelect, LB_EVENT_TYPE eLET, bool bShift, bool bCtrl, bool bSelectPosChange /*=FALSE*/ )
1014 : {
1015 0 : bool bSelectionChanged = false;
1016 :
1017 0 : if( IsEnabled() && mpEntryList->IsEntrySelectable( nSelect ) )
1018 : {
1019 0 : bool bFocusChanged = false;
1020 :
1021 : // here (Single-ListBox) only one entry can be deselected
1022 0 : if( !mbMulti )
1023 : {
1024 0 : sal_Int32 nDeselect = mpEntryList->GetSelectEntryPos( 0 );
1025 0 : if( nSelect != nDeselect )
1026 : {
1027 0 : SelectEntry( nSelect, true );
1028 0 : mpEntryList->SetLastSelected( nSelect );
1029 0 : bFocusChanged = true;
1030 0 : bSelectionChanged = true;
1031 : }
1032 : }
1033 : // MultiListBox without Modifier
1034 0 : else if( mbSimpleMode && !bCtrl && !bShift )
1035 : {
1036 0 : sal_Int32 nEntryCount = mpEntryList->GetEntryCount();
1037 0 : for ( sal_Int32 nPos = 0; nPos < nEntryCount; nPos++ )
1038 : {
1039 0 : bool bSelect = nPos == nSelect;
1040 0 : if ( mpEntryList->IsEntryPosSelected( nPos ) != bSelect )
1041 : {
1042 0 : SelectEntry( nPos, bSelect );
1043 0 : bFocusChanged = true;
1044 0 : bSelectionChanged = true;
1045 : }
1046 : }
1047 0 : mpEntryList->SetLastSelected( nSelect );
1048 0 : mpEntryList->SetSelectionAnchor( nSelect );
1049 : }
1050 : // MultiListBox only with CTRL/SHIFT or not in SimpleMode
1051 0 : else if( ( !mbSimpleMode /* && !bShift */ ) || ( (mbSimpleMode && ( bCtrl || bShift )) || mbStackMode ) )
1052 : {
1053 : // Space for selection change
1054 0 : if( !bShift && ( ( eLET == LET_KEYSPACE ) || ( eLET == LET_MBDOWN ) ) )
1055 : {
1056 0 : bool bSelect = ( mbStackMode && IsMouseMoveSelect() ) || !mpEntryList->IsEntryPosSelected( nSelect );
1057 0 : if ( mbStackMode )
1058 : {
1059 : sal_Int32 n;
1060 0 : if ( bSelect )
1061 : {
1062 : // All entries before nSelect must be selected...
1063 0 : for ( n = 0; n < nSelect; n++ )
1064 0 : SelectEntry( n, true );
1065 : }
1066 0 : if ( !bSelect )
1067 : {
1068 0 : for ( n = nSelect+1; n < mpEntryList->GetEntryCount(); n++ )
1069 0 : SelectEntry( n, false );
1070 : }
1071 : }
1072 0 : SelectEntry( nSelect, bSelect );
1073 0 : mpEntryList->SetLastSelected( nSelect );
1074 0 : mpEntryList->SetSelectionAnchor( mbStackMode ? 0 : nSelect );
1075 0 : if ( !mpEntryList->IsEntryPosSelected( nSelect ) )
1076 0 : mpEntryList->SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND );
1077 0 : bFocusChanged = true;
1078 0 : bSelectionChanged = true;
1079 : }
1080 0 : else if( ( ( eLET == LET_TRACKING ) && ( nSelect != mnCurrentPos ) ) ||
1081 0 : ( (bShift||mbStackMode) && ( ( eLET == LET_KEYMOVE ) || ( eLET == LET_MBDOWN ) ) ) )
1082 : {
1083 0 : mnCurrentPos = nSelect;
1084 0 : bFocusChanged = true;
1085 :
1086 0 : sal_Int32 nAnchor = mpEntryList->GetSelectionAnchor();
1087 0 : if( ( nAnchor == LISTBOX_ENTRY_NOTFOUND ) && ( mpEntryList->GetSelectEntryCount() || mbStackMode ) )
1088 : {
1089 0 : nAnchor = mbStackMode ? 0 : mpEntryList->GetSelectEntryPos( mpEntryList->GetSelectEntryCount() - 1 );
1090 : }
1091 0 : if( nAnchor != LISTBOX_ENTRY_NOTFOUND )
1092 : {
1093 : // All entries from achor to nSelect have to be selected
1094 0 : sal_Int32 nStart = std::min( nSelect, nAnchor );
1095 0 : sal_Int32 nEnd = std::max( nSelect, nAnchor );
1096 0 : for ( sal_Int32 n = nStart; n <= nEnd; n++ )
1097 : {
1098 0 : if ( !mpEntryList->IsEntryPosSelected( n ) )
1099 : {
1100 0 : SelectEntry( n, true );
1101 0 : bSelectionChanged = true;
1102 : }
1103 : }
1104 :
1105 : // if appropriate some more has to be deselected...
1106 0 : sal_Int32 nLast = mpEntryList->GetLastSelected();
1107 0 : if ( nLast != LISTBOX_ENTRY_NOTFOUND )
1108 : {
1109 0 : if ( ( nLast > nSelect ) && ( nLast > nAnchor ) )
1110 : {
1111 0 : for ( sal_Int32 n = nSelect+1; n <= nLast; n++ )
1112 : {
1113 0 : if ( mpEntryList->IsEntryPosSelected( n ) )
1114 : {
1115 0 : SelectEntry( n, false );
1116 0 : bSelectionChanged = true;
1117 : }
1118 0 : }
1119 : }
1120 0 : else if ( ( nLast < nSelect ) && ( nLast < nAnchor ) )
1121 : {
1122 0 : for ( sal_Int32 n = nLast; n < nSelect; n++ )
1123 : {
1124 0 : if ( mpEntryList->IsEntryPosSelected( n ) )
1125 : {
1126 0 : SelectEntry( n, false );
1127 0 : bSelectionChanged = true;
1128 : }
1129 : }
1130 : }
1131 : }
1132 0 : mpEntryList->SetLastSelected( nSelect );
1133 0 : }
1134 : }
1135 0 : else if( eLET != LET_TRACKING )
1136 : {
1137 0 : ImplHideFocusRect();
1138 0 : Invalidate();
1139 0 : bFocusChanged = true;
1140 0 : }
1141 : }
1142 0 : else if( bShift )
1143 : {
1144 0 : bFocusChanged = true;
1145 : }
1146 :
1147 0 : if( bSelectionChanged )
1148 0 : mbSelectionChanged = true;
1149 :
1150 0 : if( bFocusChanged )
1151 : {
1152 0 : long nHeightDiff = mpEntryList->GetAddedHeight( nSelect, mnTop, 0 );
1153 0 : maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1154 : Size aSz( maFocusRect.GetWidth(),
1155 0 : mpEntryList->GetEntryHeight( nSelect ) );
1156 0 : maFocusRect.SetSize( aSz );
1157 0 : if( HasFocus() )
1158 0 : ImplShowFocusRect();
1159 0 : if (bSelectPosChange)
1160 : {
1161 0 : maFocusHdl.Call(reinterpret_cast<void*>(nSelect));
1162 : }
1163 : }
1164 0 : ImplClearLayoutData();
1165 : }
1166 0 : return bSelectionChanged;
1167 : }
1168 :
1169 0 : void ImplListBoxWindow::Tracking( const TrackingEvent& rTEvt )
1170 : {
1171 0 : Point aPoint;
1172 0 : Rectangle aRect( aPoint, GetOutputSizePixel() );
1173 0 : bool bInside = aRect.IsInside( rTEvt.GetMouseEvent().GetPosPixel() );
1174 :
1175 0 : if( rTEvt.IsTrackingCanceled() || rTEvt.IsTrackingEnded() ) // MouseButtonUp
1176 : {
1177 0 : if ( bInside && !rTEvt.IsTrackingCanceled() )
1178 : {
1179 0 : mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1180 0 : ImplCallSelect();
1181 : }
1182 : else
1183 : {
1184 0 : maCancelHdl.Call( NULL );
1185 0 : if ( !mbMulti )
1186 : {
1187 0 : mbTrackingSelect = true;
1188 0 : SelectEntry( mnTrackingSaveSelection, true );
1189 0 : mbTrackingSelect = false;
1190 0 : if ( mnTrackingSaveSelection != LISTBOX_ENTRY_NOTFOUND )
1191 : {
1192 0 : long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1193 0 : maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1194 : Size aSz( maFocusRect.GetWidth(),
1195 0 : mpEntryList->GetEntryHeight( mnCurrentPos ) );
1196 0 : maFocusRect.SetSize( aSz );
1197 0 : ImplShowFocusRect();
1198 : }
1199 : }
1200 : }
1201 :
1202 0 : mbTrack = false;
1203 : }
1204 : else
1205 : {
1206 0 : bool bTrackOrQuickClick = mbTrack;
1207 0 : if( !mbTrack )
1208 : {
1209 0 : if ( bInside )
1210 : {
1211 0 : mbTrack = true;
1212 : }
1213 :
1214 : // this case only happens, if the mouse button is pressed very briefly
1215 0 : if( rTEvt.IsTrackingEnded() && mbTrack )
1216 : {
1217 0 : bTrackOrQuickClick = true;
1218 0 : mbTrack = false;
1219 : }
1220 : }
1221 :
1222 0 : if( bTrackOrQuickClick )
1223 : {
1224 0 : MouseEvent aMEvt = rTEvt.GetMouseEvent();
1225 0 : Point aPt( aMEvt.GetPosPixel() );
1226 0 : bool bShift = aMEvt.IsShift();
1227 0 : bool bCtrl = aMEvt.IsMod1();
1228 :
1229 0 : sal_Int32 nSelect = LISTBOX_ENTRY_NOTFOUND;
1230 0 : if( aPt.Y() < 0 )
1231 : {
1232 0 : if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1233 : {
1234 0 : nSelect = mnCurrentPos ? ( mnCurrentPos - 1 ) : 0;
1235 0 : if( nSelect < mnTop )
1236 0 : SetTopEntry( mnTop-1 );
1237 : }
1238 : }
1239 0 : else if( aPt.Y() > GetOutputSizePixel().Height() )
1240 : {
1241 0 : if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1242 : {
1243 0 : nSelect = std::min( (sal_Int32)(mnCurrentPos+1), (sal_Int32)(mpEntryList->GetEntryCount()-1) );
1244 0 : if( nSelect >= GetLastVisibleEntry() )
1245 0 : SetTopEntry( mnTop+1 );
1246 : }
1247 : }
1248 : else
1249 : {
1250 0 : nSelect = (sal_Int32) ( ( aPt.Y() + mnBorder ) / mnMaxHeight ) + (sal_Int32) mnTop;
1251 0 : nSelect = std::min( nSelect, GetLastVisibleEntry() );
1252 0 : nSelect = std::min( nSelect, (sal_Int32) ( mpEntryList->GetEntryCount() - 1 ) );
1253 : }
1254 :
1255 0 : if ( bInside )
1256 : {
1257 0 : if ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() )
1258 : {
1259 0 : mbTrackingSelect = true;
1260 0 : if ( SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl ) )
1261 : {
1262 0 : if ( mbStackMode ) // #87734# (#87072#)
1263 : {
1264 0 : mbTravelSelect = true;
1265 0 : mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1266 0 : ImplCallSelect();
1267 0 : mbTravelSelect = false;
1268 : }
1269 : }
1270 0 : mbTrackingSelect = false;
1271 : }
1272 : }
1273 : else
1274 : {
1275 0 : if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
1276 : {
1277 0 : mbTrackingSelect = true;
1278 0 : SelectEntry( GetEntryList()->GetSelectEntryPos( 0 ), false );
1279 0 : mbTrackingSelect = false;
1280 : }
1281 0 : else if ( mbStackMode )
1282 : {
1283 0 : if ( ( rTEvt.GetMouseEvent().GetPosPixel().X() > 0 ) && ( rTEvt.GetMouseEvent().GetPosPixel().X() < aRect.Right() ) )
1284 : {
1285 0 : if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 ) || ( rTEvt.GetMouseEvent().GetPosPixel().Y() > GetOutputSizePixel().Height() ) )
1286 : {
1287 0 : bool bSelectionChanged = false;
1288 0 : if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 )
1289 0 : && !mnCurrentPos )
1290 : {
1291 0 : if ( mpEntryList->IsEntryPosSelected( 0 ) )
1292 : {
1293 0 : SelectEntry( 0, false );
1294 0 : bSelectionChanged = true;
1295 0 : nSelect = LISTBOX_ENTRY_NOTFOUND;
1296 :
1297 : }
1298 : }
1299 : else
1300 : {
1301 0 : mbTrackingSelect = true;
1302 0 : bSelectionChanged = SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl );
1303 0 : mbTrackingSelect = false;
1304 : }
1305 :
1306 0 : if ( bSelectionChanged )
1307 : {
1308 0 : mbSelectionChanged = true;
1309 0 : mbTravelSelect = true;
1310 0 : mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1311 0 : ImplCallSelect();
1312 0 : mbTravelSelect = false;
1313 : }
1314 : }
1315 : }
1316 : }
1317 : }
1318 0 : mnCurrentPos = nSelect;
1319 0 : if ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1320 : {
1321 0 : ImplHideFocusRect();
1322 : }
1323 : else
1324 : {
1325 0 : long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1326 0 : maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1327 0 : Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1328 0 : maFocusRect.SetSize( aSz );
1329 0 : ImplShowFocusRect();
1330 : }
1331 : }
1332 : }
1333 0 : }
1334 :
1335 0 : void ImplListBoxWindow::KeyInput( const KeyEvent& rKEvt )
1336 : {
1337 0 : if( !ProcessKeyInput( rKEvt ) )
1338 0 : Control::KeyInput( rKEvt );
1339 0 : }
1340 :
1341 0 : bool ImplListBoxWindow::ProcessKeyInput( const KeyEvent& rKEvt )
1342 : {
1343 : // entry to be selected
1344 0 : sal_Int32 nSelect = LISTBOX_ENTRY_NOTFOUND;
1345 0 : LB_EVENT_TYPE eLET = LET_KEYMOVE;
1346 :
1347 0 : vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
1348 :
1349 0 : bool bShift = aKeyCode.IsShift();
1350 0 : bool bCtrl = aKeyCode.IsMod1() || aKeyCode.IsMod3();
1351 0 : bool bMod2 = aKeyCode.IsMod2();
1352 0 : bool bDone = false;
1353 0 : bool bHandleKey = false;
1354 :
1355 0 : switch( aKeyCode.GetCode() )
1356 : {
1357 : case KEY_UP:
1358 : {
1359 0 : if ( IsReadOnly() )
1360 : {
1361 0 : if ( GetTopEntry() )
1362 0 : SetTopEntry( GetTopEntry()-1 );
1363 : }
1364 0 : else if ( !bMod2 )
1365 : {
1366 0 : if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1367 : {
1368 0 : nSelect = mpEntryList->FindFirstSelectable( 0, true );
1369 : }
1370 0 : else if ( mnCurrentPos )
1371 : {
1372 : // search first selectable above the current position
1373 0 : nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos - 1, false );
1374 : }
1375 :
1376 0 : if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect < mnTop ) )
1377 0 : SetTopEntry( mnTop-1 );
1378 :
1379 0 : bDone = true;
1380 : }
1381 0 : maQuickSelectionEngine.Reset();
1382 : }
1383 0 : break;
1384 :
1385 : case KEY_DOWN:
1386 : {
1387 0 : if ( IsReadOnly() )
1388 : {
1389 0 : SetTopEntry( GetTopEntry()+1 );
1390 : }
1391 0 : else if ( !bMod2 )
1392 : {
1393 0 : if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1394 : {
1395 0 : nSelect = mpEntryList->FindFirstSelectable( 0, true );
1396 : }
1397 0 : else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1398 : {
1399 : // search first selectable below the current position
1400 0 : nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos + 1, true );
1401 : }
1402 :
1403 0 : if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect >= GetLastVisibleEntry() ) )
1404 0 : SetTopEntry( mnTop+1 );
1405 :
1406 0 : bDone = true;
1407 : }
1408 0 : maQuickSelectionEngine.Reset();
1409 : }
1410 0 : break;
1411 :
1412 : case KEY_PAGEUP:
1413 : {
1414 0 : if ( IsReadOnly() )
1415 : {
1416 0 : sal_Int32 nCurVis = GetLastVisibleEntry() - mnTop +1;
1417 0 : SetTopEntry( ( mnTop > nCurVis ) ?
1418 0 : (mnTop-nCurVis) : 0 );
1419 : }
1420 0 : else if ( !bCtrl && !bMod2 )
1421 : {
1422 0 : if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1423 : {
1424 0 : nSelect = mpEntryList->FindFirstSelectable( 0, true );
1425 : }
1426 0 : else if ( mnCurrentPos )
1427 : {
1428 0 : if( mnCurrentPos == mnTop )
1429 : {
1430 0 : sal_Int32 nCurVis = GetLastVisibleEntry() - mnTop +1;
1431 0 : SetTopEntry( ( mnTop > nCurVis ) ? ( mnTop-nCurVis+1 ) : 0 );
1432 : }
1433 :
1434 : // find first selectable starting from mnTop looking forward
1435 0 : nSelect = mpEntryList->FindFirstSelectable( mnTop, true );
1436 : }
1437 0 : bDone = true;
1438 : }
1439 0 : maQuickSelectionEngine.Reset();
1440 : }
1441 0 : break;
1442 :
1443 : case KEY_PAGEDOWN:
1444 : {
1445 0 : if ( IsReadOnly() )
1446 : {
1447 0 : SetTopEntry( GetLastVisibleEntry() );
1448 : }
1449 0 : else if ( !bCtrl && !bMod2 )
1450 : {
1451 0 : if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1452 : {
1453 0 : nSelect = mpEntryList->FindFirstSelectable( 0, true );
1454 : }
1455 0 : else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1456 : {
1457 0 : sal_Int32 nCount = mpEntryList->GetEntryCount();
1458 0 : sal_Int32 nCurVis = GetLastVisibleEntry() - mnTop;
1459 0 : sal_Int32 nTmp = std::min( nCurVis, nCount );
1460 0 : nTmp += mnTop - 1;
1461 0 : if( mnCurrentPos == nTmp && mnCurrentPos != nCount - 1 )
1462 : {
1463 0 : long nTmp2 = std::min( (long)(nCount-nCurVis), (long)((long)mnTop+(long)nCurVis-1) );
1464 0 : nTmp2 = std::max( (long)0 , nTmp2 );
1465 0 : nTmp = (sal_Int32)(nTmp2+(nCurVis-1) );
1466 0 : SetTopEntry( (sal_Int32)nTmp2 );
1467 : }
1468 : // find first selectable starting from nTmp looking backwards
1469 0 : nSelect = mpEntryList->FindFirstSelectable( nTmp, false );
1470 : }
1471 0 : bDone = true;
1472 : }
1473 0 : maQuickSelectionEngine.Reset();
1474 : }
1475 0 : break;
1476 :
1477 : case KEY_HOME:
1478 : {
1479 0 : if ( IsReadOnly() )
1480 : {
1481 0 : SetTopEntry( 0 );
1482 : }
1483 0 : else if ( !bCtrl && !bMod2 )
1484 : {
1485 0 : if ( mnCurrentPos )
1486 : {
1487 0 : nSelect = mpEntryList->FindFirstSelectable( mpEntryList->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND, true );
1488 0 : if( mnTop != 0 )
1489 0 : SetTopEntry( 0 );
1490 :
1491 0 : bDone = true;
1492 : }
1493 : }
1494 0 : maQuickSelectionEngine.Reset();
1495 : }
1496 0 : break;
1497 :
1498 : case KEY_END:
1499 : {
1500 0 : if ( IsReadOnly() )
1501 : {
1502 0 : SetTopEntry( 0xFFFF );
1503 : }
1504 0 : else if ( !bCtrl && !bMod2 )
1505 : {
1506 0 : if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1507 : {
1508 0 : nSelect = mpEntryList->FindFirstSelectable( 0, true );
1509 : }
1510 0 : else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1511 : {
1512 0 : sal_Int32 nCount = mpEntryList->GetEntryCount();
1513 0 : nSelect = mpEntryList->FindFirstSelectable( nCount - 1, false );
1514 0 : sal_Int32 nCurVis = GetLastVisibleEntry() - mnTop + 1;
1515 0 : if( nCount > nCurVis )
1516 0 : SetTopEntry( nCount - nCurVis );
1517 : }
1518 0 : bDone = true;
1519 : }
1520 0 : maQuickSelectionEngine.Reset();
1521 : }
1522 0 : break;
1523 :
1524 : case KEY_LEFT:
1525 : {
1526 0 : if ( !bCtrl && !bMod2 )
1527 : {
1528 0 : ScrollHorz( -HORZ_SCROLL );
1529 0 : bDone = true;
1530 : }
1531 0 : maQuickSelectionEngine.Reset();
1532 : }
1533 0 : break;
1534 :
1535 : case KEY_RIGHT:
1536 : {
1537 0 : if ( !bCtrl && !bMod2 )
1538 : {
1539 0 : ScrollHorz( HORZ_SCROLL );
1540 0 : bDone = true;
1541 : }
1542 0 : maQuickSelectionEngine.Reset();
1543 : }
1544 0 : break;
1545 :
1546 : case KEY_RETURN:
1547 : {
1548 0 : if ( !bMod2 && !IsReadOnly() )
1549 : {
1550 0 : mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
1551 0 : ImplCallSelect();
1552 0 : bDone = false; // do not catch RETURN
1553 : }
1554 0 : maQuickSelectionEngine.Reset();
1555 : }
1556 0 : break;
1557 :
1558 : case KEY_SPACE:
1559 : {
1560 0 : if ( !bMod2 && !IsReadOnly() )
1561 : {
1562 0 : if( mbMulti && ( !mbSimpleMode || ( mbSimpleMode && bCtrl && !bShift ) || mbStackMode ) )
1563 : {
1564 0 : nSelect = mnCurrentPos;
1565 0 : eLET = LET_KEYSPACE;
1566 : }
1567 0 : bDone = true;
1568 : }
1569 0 : bHandleKey = true;
1570 : }
1571 0 : break;
1572 :
1573 : case KEY_A:
1574 : {
1575 0 : if( bCtrl && mbMulti )
1576 : {
1577 : // paint only once
1578 0 : bool bUpdates = IsUpdateMode();
1579 0 : SetUpdateMode( false );
1580 :
1581 0 : sal_Int32 nEntryCount = mpEntryList->GetEntryCount();
1582 0 : for( sal_Int32 i = 0; i < nEntryCount; i++ )
1583 0 : SelectEntry( i, true );
1584 :
1585 : // restore update mode
1586 0 : SetUpdateMode( bUpdates );
1587 0 : Invalidate();
1588 :
1589 0 : maQuickSelectionEngine.Reset();
1590 :
1591 0 : bDone = true;
1592 : }
1593 : else
1594 : {
1595 0 : bHandleKey = true;
1596 : }
1597 : }
1598 0 : break;
1599 :
1600 : default:
1601 0 : bHandleKey = true;
1602 0 : break;
1603 : }
1604 0 : if (bHandleKey && !IsReadOnly())
1605 : {
1606 0 : bDone = maQuickSelectionEngine.HandleKeyEvent( rKEvt );
1607 : }
1608 :
1609 0 : if ( ( nSelect != LISTBOX_ENTRY_NOTFOUND )
1610 0 : && ( ( !mpEntryList->IsEntryPosSelected( nSelect ) )
1611 0 : || ( eLET == LET_KEYSPACE )
1612 : )
1613 : )
1614 : {
1615 : DBG_ASSERT( !mpEntryList->IsEntryPosSelected( nSelect ) || mbMulti, "ImplListBox: Selecting same Entry" );
1616 0 : if( nSelect >= mpEntryList->GetEntryCount() )
1617 0 : nSelect = mpEntryList->GetEntryCount()-1;
1618 0 : bool bCurPosChange = (mnCurrentPos != nSelect);
1619 0 : mnCurrentPos = nSelect;
1620 0 : if(SelectEntries( nSelect, eLET, bShift, bCtrl, bCurPosChange))
1621 : {
1622 0 : mbTravelSelect = true;
1623 0 : mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
1624 0 : ImplCallSelect();
1625 0 : mbTravelSelect = false;
1626 : }
1627 : }
1628 :
1629 0 : return bDone;
1630 : }
1631 :
1632 : namespace
1633 : {
1634 0 : static vcl::StringEntryIdentifier lcl_getEntry( const ImplEntryList& _rList, sal_Int32 _nPos, OUString& _out_entryText )
1635 : {
1636 : OSL_PRECOND( ( _nPos != LISTBOX_ENTRY_NOTFOUND ), "lcl_getEntry: invalid position!" );
1637 0 : sal_Int32 nEntryCount( _rList.GetEntryCount() );
1638 0 : if ( _nPos >= nEntryCount )
1639 0 : _nPos = 0;
1640 0 : _out_entryText = _rList.GetEntryText( _nPos );
1641 :
1642 : // vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
1643 : // => normalize
1644 0 : return reinterpret_cast< vcl::StringEntryIdentifier >( _nPos + 1 );
1645 : }
1646 :
1647 0 : static sal_Int32 lcl_getEntryPos( vcl::StringEntryIdentifier _entry )
1648 : {
1649 : // our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
1650 0 : return static_cast< sal_Int32 >( reinterpret_cast< sal_Int64 >( _entry ) ) - 1;
1651 : }
1652 : }
1653 :
1654 0 : vcl::StringEntryIdentifier ImplListBoxWindow::CurrentEntry( OUString& _out_entryText ) const
1655 : {
1656 0 : return lcl_getEntry( *GetEntryList(), ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND ) ? 0 : mnCurrentPos, _out_entryText );
1657 : }
1658 :
1659 0 : vcl::StringEntryIdentifier ImplListBoxWindow::NextEntry( vcl::StringEntryIdentifier _currentEntry, OUString& _out_entryText ) const
1660 : {
1661 0 : sal_Int32 nNextPos = lcl_getEntryPos( _currentEntry ) + 1;
1662 0 : return lcl_getEntry( *GetEntryList(), nNextPos, _out_entryText );
1663 : }
1664 :
1665 0 : void ImplListBoxWindow::SelectEntry( vcl::StringEntryIdentifier _entry )
1666 : {
1667 0 : sal_Int32 nSelect = lcl_getEntryPos( _entry );
1668 0 : if ( mpEntryList->IsEntryPosSelected( nSelect ) )
1669 : {
1670 : // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
1671 : // to select the given entry by typing its starting letters. No need to act.
1672 0 : return;
1673 : }
1674 :
1675 : // normalize
1676 : OSL_ENSURE( nSelect < mpEntryList->GetEntryCount(), "ImplListBoxWindow::SelectEntry: how that?" );
1677 0 : if( nSelect >= mpEntryList->GetEntryCount() )
1678 0 : nSelect = mpEntryList->GetEntryCount()-1;
1679 :
1680 : // make visible
1681 0 : ShowProminentEntry( nSelect );
1682 :
1683 : // actually select
1684 0 : mnCurrentPos = nSelect;
1685 0 : if ( SelectEntries( nSelect, LET_KEYMOVE, false, false ) )
1686 : {
1687 0 : mbTravelSelect = true;
1688 0 : mnSelectModifier = 0;
1689 0 : ImplCallSelect();
1690 0 : mbTravelSelect = false;
1691 : }
1692 : }
1693 :
1694 467 : void ImplListBoxWindow::ImplPaint(vcl::RenderContext& rRenderContext, sal_Int32 nPos, bool bErase, bool bLayout)
1695 : {
1696 467 : const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1697 :
1698 467 : const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
1699 467 : if (!pEntry)
1700 467 : return;
1701 :
1702 467 : long nWidth = rRenderContext.GetOutputSizePixel().Width();
1703 467 : long nY = mpEntryList->GetAddedHeight(nPos, mnTop);
1704 467 : Rectangle aRect(Point(0, nY), Size(nWidth, pEntry->mnHeight));
1705 :
1706 467 : if (!bLayout)
1707 : {
1708 467 : if (mpEntryList->IsEntryPosSelected(nPos))
1709 : {
1710 7 : rRenderContext.SetTextColor(!IsEnabled() ? rStyleSettings.GetDisableColor() : rStyleSettings.GetHighlightTextColor());
1711 7 : rRenderContext.SetFillColor(rStyleSettings.GetHighlightColor());
1712 7 : rRenderContext.SetTextFillColor(rStyleSettings.GetHighlightColor());
1713 7 : rRenderContext.DrawRect(aRect);
1714 : }
1715 : else
1716 : {
1717 460 : ApplySettings(*this);
1718 460 : if (!IsEnabled())
1719 195 : rRenderContext.SetTextColor(rStyleSettings.GetDisableColor());
1720 460 : rRenderContext.SetTextFillColor();
1721 460 : if (bErase)
1722 0 : rRenderContext.Erase(aRect);
1723 : }
1724 : }
1725 :
1726 467 : if (IsUserDrawEnabled())
1727 : {
1728 26 : mbInUserDraw = true;
1729 26 : mnUserDrawEntry = nPos;
1730 26 : aRect.Left() -= mnLeft;
1731 26 : if (nPos < GetEntryList()->GetMRUCount())
1732 0 : nPos = GetEntryList()->FindEntry(GetEntryList()->GetEntryText(nPos));
1733 26 : nPos = nPos - GetEntryList()->GetMRUCount();
1734 26 : sal_Int32 nCurr = mnCurrentPos;
1735 26 : if (mnCurrentPos < GetEntryList()->GetMRUCount())
1736 0 : nCurr = GetEntryList()->FindEntry(GetEntryList()->GetEntryText(nCurr));
1737 26 : nCurr = sal::static_int_cast<sal_Int32>(nCurr - GetEntryList()->GetMRUCount());
1738 :
1739 26 : UserDrawEvent aUDEvt(&rRenderContext, aRect, nPos, nCurr);
1740 26 : userDrawSignal(&aUDEvt);
1741 26 : mbInUserDraw = false;
1742 : }
1743 : else
1744 : {
1745 441 : DrawEntry(rRenderContext, nPos, true, true, false, bLayout);
1746 : }
1747 : }
1748 :
1749 467 : void ImplListBoxWindow::DrawEntry(vcl::RenderContext& rRenderContext, sal_Int32 nPos, bool bDrawImage, bool bDrawText, bool bDrawTextAtImagePos, bool bLayout)
1750 : {
1751 467 : const ImplEntryType* pEntry = mpEntryList->GetEntryPtr(nPos);
1752 467 : if (!pEntry)
1753 467 : return;
1754 :
1755 : // when changing this function don't forget to adjust ImplWin::DrawEntry()
1756 :
1757 467 : if (mbInUserDraw)
1758 26 : nPos = mnUserDrawEntry; // real entry, not the matching entry from MRU
1759 :
1760 467 : long nY = mpEntryList->GetAddedHeight(nPos, mnTop);
1761 467 : Size aImgSz;
1762 :
1763 467 : if (bDrawImage && mpEntryList->HasImages() && !bLayout)
1764 : {
1765 0 : Image aImage = mpEntryList->GetEntryImage(nPos);
1766 0 : if (!!aImage)
1767 : {
1768 0 : aImgSz = aImage.GetSizePixel();
1769 0 : Point aPtImg(mnBorder - mnLeft, nY + ((pEntry->mnHeight - aImgSz.Height()) / 2));
1770 :
1771 : // pb: #106948# explicit mirroring for calc
1772 0 : if (mbMirroring)
1773 : // right aligned
1774 0 : aPtImg.X() = mnMaxWidth + mnBorder - aImgSz.Width() - mnLeft;
1775 :
1776 0 : if (!IsZoom())
1777 : {
1778 0 : rRenderContext.DrawImage(aPtImg, aImage);
1779 : }
1780 : else
1781 : {
1782 0 : aImgSz.Width() = CalcZoom(aImgSz.Width());
1783 0 : aImgSz.Height() = CalcZoom(aImgSz.Height());
1784 0 : rRenderContext.DrawImage(aPtImg, aImgSz, aImage);
1785 : }
1786 :
1787 0 : const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1788 0 : const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
1789 :
1790 0 : if (nEdgeBlendingPercent && aImgSz.Width() && aImgSz.Height())
1791 : {
1792 0 : const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
1793 0 : const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
1794 0 : const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
1795 0 : const BitmapEx aBlendFrame(createBlendFrame(aImgSz, nAlpha, rTopLeft, rBottomRight));
1796 :
1797 0 : if (!aBlendFrame.IsEmpty())
1798 : {
1799 0 : rRenderContext.DrawBitmapEx(aPtImg, aBlendFrame);
1800 0 : }
1801 : }
1802 0 : }
1803 : }
1804 :
1805 467 : if (bDrawText)
1806 : {
1807 441 : MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
1808 441 : OUString* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
1809 441 : OUString aStr(mpEntryList->GetEntryText(nPos));
1810 441 : if (!aStr.isEmpty())
1811 : {
1812 441 : long nMaxWidth = std::max(static_cast< long >(mnMaxWidth), rRenderContext.GetOutputSizePixel().Width() - 2 * mnBorder);
1813 : // a multiline entry should only be as wide a the window
1814 441 : if ((pEntry->mnFlags & ListBoxEntryFlags::MultiLine))
1815 0 : nMaxWidth = rRenderContext.GetOutputSizePixel().Width() - 2 * mnBorder;
1816 :
1817 : Rectangle aTextRect(Point(mnBorder - mnLeft, nY),
1818 441 : Size(nMaxWidth, pEntry->mnHeight));
1819 :
1820 441 : if (!bDrawTextAtImagePos && (mpEntryList->HasEntryImage(nPos) || IsUserDrawEnabled()))
1821 : {
1822 0 : long nImageWidth = std::max(mnMaxImgWidth, maUserItemSize.Width());
1823 0 : aTextRect.Left() += nImageWidth + IMG_TXT_DISTANCE;
1824 : }
1825 :
1826 441 : if (bLayout)
1827 0 : mpControlData->mpLayoutData->m_aLineIndices.push_back(mpControlData->mpLayoutData->m_aDisplayText.getLength());
1828 :
1829 : // pb: #106948# explicit mirroring for calc
1830 441 : if (mbMirroring)
1831 : {
1832 : // right aligned
1833 0 : aTextRect.Left() = nMaxWidth + mnBorder - rRenderContext.GetTextWidth(aStr) - mnLeft;
1834 0 : if (aImgSz.Width() > 0)
1835 0 : aTextRect.Left() -= (aImgSz.Width() + IMG_TXT_DISTANCE);
1836 : }
1837 :
1838 441 : DrawTextFlags nDrawStyle = ImplGetTextStyle();
1839 441 : if ((pEntry->mnFlags & ListBoxEntryFlags::MultiLine))
1840 0 : nDrawStyle |= MULTILINE_ENTRY_DRAW_FLAGS;
1841 441 : if ((pEntry->mnFlags & ListBoxEntryFlags::DrawDisabled))
1842 0 : nDrawStyle |= DrawTextFlags::Disable;
1843 :
1844 441 : rRenderContext.DrawText(aTextRect, aStr, nDrawStyle, pVector, pDisplayText);
1845 441 : }
1846 : }
1847 :
1848 467 : if (!bLayout)
1849 : {
1850 493 : if ((mnSeparatorPos != LISTBOX_ENTRY_NOTFOUND) &&
1851 48 : ((nPos == mnSeparatorPos) || (nPos == mnSeparatorPos + 1)))
1852 : {
1853 8 : Color aOldLineColor(rRenderContext.GetLineColor());
1854 8 : rRenderContext.SetLineColor((GetBackground().GetColor() != COL_LIGHTGRAY) ? COL_LIGHTGRAY : COL_GRAY);
1855 8 : Point aStartPos(0, nY);
1856 8 : if (nPos == mnSeparatorPos)
1857 4 : aStartPos.Y() += pEntry->mnHeight - 1;
1858 8 : Point aEndPos(aStartPos);
1859 8 : aEndPos.X() = GetOutputSizePixel().Width();
1860 8 : rRenderContext.DrawLine(aStartPos, aEndPos);
1861 8 : rRenderContext.SetLineColor(aOldLineColor);
1862 : }
1863 : }
1864 : }
1865 :
1866 0 : void ImplListBoxWindow::FillLayoutData() const
1867 : {
1868 0 : mpControlData->mpLayoutData = new vcl::ControlLayoutData();
1869 0 : const_cast<ImplListBoxWindow*>(this)->Invalidate(Rectangle(Point(0, 0), GetOutputSize()));
1870 0 : }
1871 :
1872 319 : void ImplListBoxWindow::ImplDoPaint(vcl::RenderContext& rRenderContext, const Rectangle& rRect, bool bLayout)
1873 : {
1874 319 : sal_Int32 nCount = mpEntryList->GetEntryCount();
1875 :
1876 319 : bool bShowFocusRect = mbHasFocusRect;
1877 319 : if (mbHasFocusRect && !bLayout)
1878 0 : ImplHideFocusRect();
1879 :
1880 319 : long nY = 0; // + mnBorder;
1881 319 : long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1882 :
1883 800 : for (sal_Int32 i = (sal_Int32)mnTop; i < nCount && nY < nHeight + mnMaxHeight; i++)
1884 : {
1885 481 : const ImplEntryType* pEntry = mpEntryList->GetEntryPtr(i);
1886 962 : if (nY + pEntry->mnHeight >= rRect.Top() &&
1887 481 : nY <= rRect.Bottom() + mnMaxHeight)
1888 : {
1889 467 : ImplPaint(rRenderContext, i, false, bLayout);
1890 : }
1891 481 : nY += pEntry->mnHeight;
1892 : }
1893 :
1894 319 : long nHeightDiff = mpEntryList->GetAddedHeight(mnCurrentPos, mnTop, 0);
1895 319 : maFocusRect.SetPos(Point(0, nHeightDiff));
1896 319 : Size aSz(maFocusRect.GetWidth(), mpEntryList->GetEntryHeight(mnCurrentPos));
1897 319 : maFocusRect.SetSize(aSz);
1898 319 : if (HasFocus() && bShowFocusRect && !bLayout)
1899 0 : ImplShowFocusRect();
1900 319 : }
1901 :
1902 319 : void ImplListBoxWindow::Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect)
1903 : {
1904 319 : ImplDoPaint(rRenderContext, rRect);
1905 319 : }
1906 :
1907 166 : sal_uInt16 ImplListBoxWindow::GetDisplayLineCount() const
1908 : {
1909 : // FIXME: ListBoxEntryFlags::MultiLine
1910 :
1911 166 : sal_Int32 nCount = mpEntryList->GetEntryCount();
1912 166 : long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1913 166 : sal_uInt16 nEntries = static_cast< sal_uInt16 >( ( nHeight + mnMaxHeight - 1 ) / mnMaxHeight );
1914 166 : if( nEntries > nCount-mnTop )
1915 0 : nEntries = nCount-mnTop;
1916 :
1917 166 : return nEntries;
1918 : }
1919 :
1920 15939 : void ImplListBoxWindow::Resize()
1921 : {
1922 15939 : Control::Resize();
1923 :
1924 15939 : bool bShowFocusRect = mbHasFocusRect;
1925 15939 : if ( bShowFocusRect )
1926 0 : ImplHideFocusRect();
1927 :
1928 15939 : if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1929 : {
1930 6661 : Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1931 6661 : maFocusRect.SetSize( aSz );
1932 : }
1933 :
1934 15939 : if ( bShowFocusRect )
1935 0 : ImplShowFocusRect();
1936 :
1937 15939 : ImplClearLayoutData();
1938 15939 : }
1939 :
1940 0 : void ImplListBoxWindow::GetFocus()
1941 : {
1942 0 : sal_Int32 nPos = mnCurrentPos;
1943 0 : if ( nPos == LISTBOX_ENTRY_NOTFOUND )
1944 0 : nPos = 0;
1945 0 : long nHeightDiff = mpEntryList->GetAddedHeight( nPos, mnTop, 0 );
1946 0 : maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1947 0 : Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( nPos ) );
1948 0 : maFocusRect.SetSize( aSz );
1949 0 : ImplShowFocusRect();
1950 0 : Control::GetFocus();
1951 0 : }
1952 :
1953 0 : void ImplListBoxWindow::LoseFocus()
1954 : {
1955 0 : ImplHideFocusRect();
1956 0 : Control::LoseFocus();
1957 0 : }
1958 :
1959 31554 : void ImplListBoxWindow::SetTopEntry( sal_Int32 nTop )
1960 : {
1961 31554 : if( mpEntryList->GetEntryCount() == 0 )
1962 45352 : return;
1963 :
1964 17756 : long nWHeight = PixelToLogic( GetSizePixel() ).Height();
1965 :
1966 17756 : sal_Int32 nLastEntry = mpEntryList->GetEntryCount()-1;
1967 17756 : if( nTop > nLastEntry )
1968 0 : nTop = nLastEntry;
1969 17756 : const ImplEntryType* pLast = mpEntryList->GetEntryPtr( nLastEntry );
1970 35569 : while( nTop > 0 && mpEntryList->GetAddedHeight( nLastEntry, nTop-1 ) + pLast->mnHeight <= nWHeight )
1971 57 : nTop--;
1972 :
1973 17756 : if ( nTop != mnTop )
1974 : {
1975 3890 : ImplClearLayoutData();
1976 3890 : long nDiff = mpEntryList->GetAddedHeight( mnTop, nTop, 0 );
1977 3890 : Update();
1978 3890 : ImplHideFocusRect();
1979 3890 : mnTop = nTop;
1980 3890 : Scroll( 0, nDiff );
1981 3890 : Update();
1982 3890 : if( HasFocus() )
1983 0 : ImplShowFocusRect();
1984 3890 : maScrollHdl.Call( this );
1985 : }
1986 : }
1987 :
1988 9957 : void ImplListBoxWindow::ShowProminentEntry( sal_Int32 nEntryPos )
1989 : {
1990 9957 : if( meProminentType == ProminentEntry::MIDDLE )
1991 : {
1992 4915 : sal_Int32 nPos = nEntryPos;
1993 4915 : long nWHeight = PixelToLogic( GetSizePixel() ).Height();
1994 15734 : while( nEntryPos > 0 && mpEntryList->GetAddedHeight( nPos+1, nEntryPos ) < nWHeight/2 )
1995 5904 : nEntryPos--;
1996 : }
1997 9957 : SetTopEntry( nEntryPos );
1998 9957 : }
1999 :
2000 28274 : void ImplListBoxWindow::SetLeftIndent( long n )
2001 : {
2002 28274 : ScrollHorz( n - mnLeft );
2003 28274 : }
2004 :
2005 28274 : void ImplListBoxWindow::ScrollHorz( long n )
2006 : {
2007 28274 : long nDiff = 0;
2008 28274 : if ( n > 0 )
2009 : {
2010 0 : long nWidth = GetOutputSizePixel().Width();
2011 0 : if( ( mnMaxWidth - mnLeft + n ) > nWidth )
2012 0 : nDiff = n;
2013 : }
2014 28274 : else if ( n < 0 )
2015 : {
2016 0 : if( mnLeft )
2017 : {
2018 0 : long nAbs = -n;
2019 0 : nDiff = - ( ( mnLeft > nAbs ) ? nAbs : mnLeft );
2020 : }
2021 : }
2022 :
2023 28274 : if ( nDiff )
2024 : {
2025 0 : ImplClearLayoutData();
2026 0 : mnLeft = sal::static_int_cast<sal_uInt16>(mnLeft + nDiff);
2027 0 : Update();
2028 0 : ImplHideFocusRect();
2029 0 : Scroll( -nDiff, 0 );
2030 0 : Update();
2031 0 : if( HasFocus() )
2032 0 : ImplShowFocusRect();
2033 0 : maScrollHdl.Call( this );
2034 : }
2035 28274 : }
2036 :
2037 6351 : Size ImplListBoxWindow::CalcSize(sal_Int32 nMaxLines) const
2038 : {
2039 : // FIXME: ListBoxEntryFlags::MultiLine
2040 :
2041 6351 : Size aSz;
2042 6351 : aSz.Height() = nMaxLines * mnMaxHeight;
2043 6351 : aSz.Width() = mnMaxWidth + 2*mnBorder;
2044 6351 : return aSz;
2045 : }
2046 :
2047 0 : Rectangle ImplListBoxWindow::GetBoundingRectangle( sal_Int32 nItem ) const
2048 : {
2049 0 : const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nItem );
2050 0 : Size aSz( GetSizePixel().Width(), pEntry ? pEntry->mnHeight : GetEntryHeight() );
2051 0 : long nY = mpEntryList->GetAddedHeight( nItem, GetTopEntry() ) + GetEntryList()->GetMRUCount()*GetEntryHeight();
2052 0 : Rectangle aRect( Point( 0, nY ), aSz );
2053 0 : return aRect;
2054 : }
2055 :
2056 204385 : void ImplListBoxWindow::StateChanged( StateChangedType nType )
2057 : {
2058 204385 : Control::StateChanged( nType );
2059 :
2060 204385 : if ( nType == StateChangedType::Zoom )
2061 : {
2062 3 : ApplySettings(*this);
2063 3 : ImplCalcMetrics();
2064 3 : Invalidate();
2065 : }
2066 204382 : else if ( nType == StateChangedType::UpdateMode )
2067 : {
2068 200482 : if ( IsUpdateMode() && IsReallyVisible() )
2069 10 : Invalidate();
2070 : }
2071 3900 : else if ( nType == StateChangedType::ControlFont )
2072 : {
2073 319 : ApplySettings(*this);
2074 319 : ImplCalcMetrics();
2075 319 : Invalidate();
2076 : }
2077 3581 : else if ( nType == StateChangedType::ControlForeground )
2078 : {
2079 4 : ApplySettings(*this);
2080 4 : Invalidate();
2081 : }
2082 3577 : else if ( nType == StateChangedType::ControlBackground )
2083 : {
2084 4 : ApplySettings(*this);
2085 4 : Invalidate();
2086 : }
2087 3573 : else if( nType == StateChangedType::Enable )
2088 : {
2089 139 : Invalidate();
2090 : }
2091 :
2092 204385 : ImplClearLayoutData();
2093 204385 : }
2094 :
2095 298 : void ImplListBoxWindow::DataChanged( const DataChangedEvent& rDCEvt )
2096 : {
2097 298 : Control::DataChanged( rDCEvt );
2098 :
2099 1192 : if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
2100 1192 : (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
2101 894 : ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
2102 1192 : (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
2103 : {
2104 298 : ImplClearLayoutData();
2105 298 : ApplySettings(*this);
2106 298 : ImplCalcMetrics();
2107 298 : Invalidate();
2108 : }
2109 298 : }
2110 :
2111 441 : DrawTextFlags ImplListBoxWindow::ImplGetTextStyle() const
2112 : {
2113 441 : DrawTextFlags nTextStyle = DrawTextFlags::VCenter;
2114 :
2115 441 : if (mpEntryList->HasImages())
2116 0 : nTextStyle |= DrawTextFlags::Left;
2117 441 : else if (mbCenter)
2118 63 : nTextStyle |= DrawTextFlags::Center;
2119 378 : else if (mbRight)
2120 0 : nTextStyle |= DrawTextFlags::Right;
2121 : else
2122 378 : nTextStyle |= DrawTextFlags::Left;
2123 :
2124 441 : return nTextStyle;
2125 : }
2126 :
2127 3312 : ImplListBox::ImplListBox( vcl::Window* pParent, WinBits nWinStyle ) :
2128 : Control( pParent, nWinStyle ),
2129 3312 : maLBWindow(VclPtr<ImplListBoxWindow>::Create( this, nWinStyle&(~WB_BORDER) ))
2130 : {
2131 3312 : maLBWindow->userDrawSignal.connect( userDrawSignal );
2132 :
2133 : // for native widget rendering we must be able to detect this window type
2134 3312 : SetType( WINDOW_LISTBOXWINDOW );
2135 :
2136 3312 : mpVScrollBar = VclPtr<ScrollBar>::Create( this, WB_VSCROLL | WB_DRAG );
2137 3312 : mpHScrollBar = VclPtr<ScrollBar>::Create( this, WB_HSCROLL | WB_DRAG );
2138 3312 : mpScrollBarBox = VclPtr<ScrollBarBox>::Create( this );
2139 :
2140 3312 : Link<> aLink( LINK( this, ImplListBox, ScrollBarHdl ) );
2141 3312 : mpVScrollBar->SetScrollHdl( aLink );
2142 3312 : mpHScrollBar->SetScrollHdl( aLink );
2143 :
2144 3312 : mbVScroll = false;
2145 3312 : mbHScroll = false;
2146 3312 : mbAutoHScroll = ( nWinStyle & WB_AUTOHSCROLL );
2147 3312 : mbEdgeBlending = false;
2148 :
2149 3312 : maLBWindow->SetScrollHdl( LINK( this, ImplListBox, LBWindowScrolled ) );
2150 3312 : maLBWindow->SetMRUChangedHdl( LINK( this, ImplListBox, MRUChanged ) );
2151 3312 : maLBWindow->SetEdgeBlending(GetEdgeBlending());
2152 3312 : maLBWindow->Show();
2153 3312 : }
2154 :
2155 9930 : ImplListBox::~ImplListBox()
2156 : {
2157 3310 : disposeOnce();
2158 6620 : }
2159 :
2160 3310 : void ImplListBox::dispose()
2161 : {
2162 3310 : mpHScrollBar.disposeAndClear();
2163 3310 : mpVScrollBar.disposeAndClear();
2164 3310 : mpScrollBarBox.disposeAndClear();
2165 3310 : maLBWindow.disposeAndClear();
2166 3310 : Control::dispose();
2167 3310 : }
2168 :
2169 9642 : void ImplListBox::Clear()
2170 : {
2171 9642 : maLBWindow->Clear();
2172 9642 : if ( GetEntryList()->GetMRUCount() )
2173 : {
2174 0 : maLBWindow->GetEntryList()->SetMRUCount( 0 );
2175 0 : maLBWindow->SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND );
2176 : }
2177 9642 : mpVScrollBar->SetThumbPos( 0 );
2178 9642 : mpHScrollBar->SetThumbPos( 0 );
2179 9642 : CompatStateChanged( StateChangedType::Data );
2180 9642 : }
2181 :
2182 172610 : sal_Int32 ImplListBox::InsertEntry( sal_Int32 nPos, const OUString& rStr )
2183 : {
2184 172610 : ImplEntryType* pNewEntry = new ImplEntryType( rStr );
2185 172610 : sal_Int32 nNewPos = maLBWindow->InsertEntry( nPos, pNewEntry );
2186 172610 : if (nNewPos == LISTBOX_ERROR)
2187 : {
2188 0 : delete pNewEntry;
2189 0 : return nNewPos;
2190 : }
2191 172610 : CompatStateChanged( StateChangedType::Data );
2192 172610 : return nNewPos;
2193 : }
2194 :
2195 200 : sal_Int32 ImplListBox::InsertEntry( sal_Int32 nPos, const OUString& rStr, const Image& rImage )
2196 : {
2197 200 : ImplEntryType* pNewEntry = new ImplEntryType( rStr, rImage );
2198 200 : sal_Int32 nNewPos = maLBWindow->InsertEntry( nPos, pNewEntry );
2199 200 : if (nNewPos == LISTBOX_ERROR)
2200 : {
2201 0 : delete pNewEntry;
2202 0 : return nNewPos;
2203 : }
2204 200 : CompatStateChanged( StateChangedType::Data );
2205 200 : return nNewPos;
2206 : }
2207 :
2208 0 : void ImplListBox::RemoveEntry( sal_Int32 nPos )
2209 : {
2210 0 : maLBWindow->RemoveEntry( nPos );
2211 0 : CompatStateChanged( StateChangedType::Data );
2212 0 : }
2213 :
2214 0 : void ImplListBox::SetEntryFlags( sal_Int32 nPos, ListBoxEntryFlags nFlags )
2215 : {
2216 0 : maLBWindow->SetEntryFlags( nPos, nFlags );
2217 0 : }
2218 :
2219 7764 : void ImplListBox::SelectEntry( sal_Int32 nPos, bool bSelect )
2220 : {
2221 7764 : maLBWindow->SelectEntry( nPos, bSelect );
2222 7764 : }
2223 :
2224 45 : void ImplListBox::SetNoSelection()
2225 : {
2226 45 : maLBWindow->DeselectAll();
2227 45 : }
2228 :
2229 0 : void ImplListBox::GetFocus()
2230 : {
2231 0 : if (maLBWindow)
2232 0 : maLBWindow->GrabFocus();
2233 : else
2234 0 : Control::GetFocus();
2235 0 : }
2236 :
2237 0 : vcl::Window* ImplListBox::GetPreferredKeyInputWindow()
2238 : {
2239 0 : return maLBWindow.get();
2240 : }
2241 :
2242 14013 : void ImplListBox::Resize()
2243 : {
2244 14013 : Control::Resize();
2245 14013 : ImplResizeControls();
2246 14013 : ImplCheckScrollBars();
2247 14013 : }
2248 :
2249 0 : IMPL_LINK_NOARG(ImplListBox, MRUChanged)
2250 : {
2251 0 : CompatStateChanged( StateChangedType::Data );
2252 0 : return 1;
2253 : }
2254 :
2255 7780 : IMPL_LINK_NOARG(ImplListBox, LBWindowScrolled)
2256 : {
2257 3890 : long nSet = GetTopEntry();
2258 3890 : if( nSet > mpVScrollBar->GetRangeMax() )
2259 0 : mpVScrollBar->SetRangeMax( GetEntryList()->GetEntryCount() );
2260 3890 : mpVScrollBar->SetThumbPos( GetTopEntry() );
2261 :
2262 3890 : mpHScrollBar->SetThumbPos( GetLeftIndent() );
2263 :
2264 3890 : maScrollHdl.Call( this );
2265 :
2266 3890 : return 1;
2267 : }
2268 :
2269 0 : IMPL_LINK( ImplListBox, ScrollBarHdl, ScrollBar*, pSB )
2270 : {
2271 0 : sal_uInt16 nPos = (sal_uInt16) pSB->GetThumbPos();
2272 0 : if( pSB == mpVScrollBar )
2273 0 : SetTopEntry( nPos );
2274 0 : else if( pSB == mpHScrollBar )
2275 0 : SetLeftIndent( nPos );
2276 :
2277 0 : return 1;
2278 : }
2279 :
2280 14031 : void ImplListBox::ImplCheckScrollBars()
2281 : {
2282 14031 : bool bArrange = false;
2283 :
2284 14031 : Size aOutSz = GetOutputSizePixel();
2285 14031 : sal_Int32 nEntries = GetEntryList()->GetEntryCount();
2286 14031 : sal_uInt16 nMaxVisEntries = (sal_uInt16) (aOutSz.Height() / GetEntryHeight());
2287 :
2288 : // vertical ScrollBar
2289 14031 : if( nEntries > nMaxVisEntries )
2290 : {
2291 4644 : if( !mbVScroll )
2292 1483 : bArrange = true;
2293 4644 : mbVScroll = true;
2294 :
2295 : // check of the scrolled-out region
2296 8126 : if( GetEntryList()->GetSelectEntryCount() == 1 &&
2297 3482 : GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND )
2298 3482 : ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2299 : else
2300 1162 : SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2301 : }
2302 : else
2303 : {
2304 9387 : if( mbVScroll )
2305 2 : bArrange = true;
2306 9387 : mbVScroll = false;
2307 9387 : SetTopEntry( 0 );
2308 : }
2309 :
2310 : // horizontal ScrollBar
2311 14031 : if( mbAutoHScroll )
2312 : {
2313 12662 : long nWidth = (sal_uInt16) aOutSz.Width();
2314 12662 : if ( mbVScroll )
2315 4644 : nWidth -= mpVScrollBar->GetSizePixel().Width();
2316 :
2317 12662 : long nMaxWidth = GetMaxEntryWidth();
2318 12662 : if( nWidth < nMaxWidth )
2319 : {
2320 0 : if( !mbHScroll )
2321 0 : bArrange = true;
2322 0 : mbHScroll = true;
2323 :
2324 0 : if ( !mbVScroll ) // maybe we do need one now
2325 : {
2326 0 : nMaxVisEntries = (sal_uInt16) ( ( aOutSz.Height() - mpHScrollBar->GetSizePixel().Height() ) / GetEntryHeight() );
2327 0 : if( nEntries > nMaxVisEntries )
2328 : {
2329 0 : bArrange = true;
2330 0 : mbVScroll = true;
2331 :
2332 : // check of the scrolled-out region
2333 0 : if( GetEntryList()->GetSelectEntryCount() == 1 &&
2334 0 : GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND )
2335 0 : ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2336 : else
2337 0 : SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2338 : }
2339 : }
2340 :
2341 : // check of the scrolled-out region
2342 0 : sal_uInt16 nMaxLI = (sal_uInt16) (nMaxWidth - nWidth);
2343 0 : if ( nMaxLI < GetLeftIndent() )
2344 0 : SetLeftIndent( nMaxLI );
2345 : }
2346 : else
2347 : {
2348 12662 : if( mbHScroll )
2349 0 : bArrange = true;
2350 12662 : mbHScroll = false;
2351 12662 : SetLeftIndent( 0 );
2352 : }
2353 : }
2354 :
2355 14031 : if( bArrange )
2356 1485 : ImplResizeControls();
2357 :
2358 14031 : ImplInitScrollBars();
2359 14031 : }
2360 :
2361 14031 : void ImplListBox::ImplInitScrollBars()
2362 : {
2363 14031 : Size aOutSz = maLBWindow->GetOutputSizePixel();
2364 :
2365 14031 : if ( mbVScroll )
2366 : {
2367 4644 : sal_Int32 nEntries = GetEntryList()->GetEntryCount();
2368 4644 : sal_uInt16 nVisEntries = (sal_uInt16) (aOutSz.Height() / GetEntryHeight());
2369 4644 : mpVScrollBar->SetRangeMax( nEntries );
2370 4644 : mpVScrollBar->SetVisibleSize( nVisEntries );
2371 4644 : mpVScrollBar->SetPageSize( nVisEntries - 1 );
2372 : }
2373 :
2374 14031 : if ( mbHScroll )
2375 : {
2376 0 : mpHScrollBar->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL );
2377 0 : mpHScrollBar->SetVisibleSize( (sal_uInt16)aOutSz.Width() );
2378 0 : mpHScrollBar->SetLineSize( HORZ_SCROLL );
2379 0 : mpHScrollBar->SetPageSize( aOutSz.Width() - HORZ_SCROLL );
2380 : }
2381 14031 : }
2382 :
2383 15612 : void ImplListBox::ImplResizeControls()
2384 : {
2385 : // Here we only position the Controls; if the Scrollbars are to be
2386 : // visible is already determined in ImplCheckScrollBars
2387 :
2388 15612 : Size aOutSz = GetOutputSizePixel();
2389 15612 : long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
2390 15612 : nSBWidth = CalcZoom( nSBWidth );
2391 :
2392 15612 : Size aInnerSz( aOutSz );
2393 15612 : if ( mbVScroll )
2394 4648 : aInnerSz.Width() -= nSBWidth;
2395 15612 : if ( mbHScroll )
2396 0 : aInnerSz.Height() -= nSBWidth;
2397 :
2398 : // pb: #106948# explicit mirroring for calc
2399 : // Scrollbar on left or right side?
2400 15612 : bool bMirroring = maLBWindow->IsMirroring();
2401 15612 : Point aWinPos( bMirroring && mbVScroll ? nSBWidth : 0, 0 );
2402 15612 : maLBWindow->SetPosSizePixel( aWinPos, aInnerSz );
2403 :
2404 : // ScrollBarBox
2405 15612 : if( mbVScroll && mbHScroll )
2406 : {
2407 0 : Point aBoxPos( bMirroring ? 0 : aInnerSz.Width(), aInnerSz.Height() );
2408 0 : mpScrollBarBox->SetPosSizePixel( aBoxPos, Size( nSBWidth, nSBWidth ) );
2409 0 : mpScrollBarBox->Show();
2410 : }
2411 : else
2412 : {
2413 15612 : mpScrollBarBox->Hide();
2414 : }
2415 :
2416 : // vertical ScrollBar
2417 15612 : if( mbVScroll )
2418 : {
2419 : // Scrollbar on left or right side?
2420 4648 : Point aVPos( bMirroring ? 0 : aOutSz.Width() - nSBWidth, 0 );
2421 4648 : mpVScrollBar->SetPosSizePixel( aVPos, Size( nSBWidth, aInnerSz.Height() ) );
2422 4648 : mpVScrollBar->Show();
2423 : }
2424 : else
2425 : {
2426 10964 : mpVScrollBar->Hide();
2427 : // #107254# Don't reset top entry after resize, but check for max top entry
2428 10964 : SetTopEntry( GetTopEntry() );
2429 : }
2430 :
2431 : // horizontal ScrollBar
2432 15612 : if( mbHScroll )
2433 : {
2434 0 : Point aHPos( ( bMirroring && mbVScroll ) ? nSBWidth : 0, aOutSz.Height() - nSBWidth );
2435 0 : mpHScrollBar->SetPosSizePixel( aHPos, Size( aInnerSz.Width(), nSBWidth ) );
2436 0 : mpHScrollBar->Show();
2437 : }
2438 : else
2439 : {
2440 15612 : mpHScrollBar->Hide();
2441 15612 : SetLeftIndent( 0 );
2442 : }
2443 15612 : }
2444 :
2445 204385 : void ImplListBox::StateChanged( StateChangedType nType )
2446 : {
2447 204385 : if ( nType == StateChangedType::InitShow )
2448 : {
2449 8 : ImplCheckScrollBars();
2450 : }
2451 204377 : else if ( ( nType == StateChangedType::UpdateMode ) || ( nType == StateChangedType::Data ) )
2452 : {
2453 200482 : bool bUpdate = IsUpdateMode();
2454 200482 : maLBWindow->SetUpdateMode( bUpdate );
2455 200482 : if ( bUpdate && IsReallyVisible() )
2456 10 : ImplCheckScrollBars();
2457 : }
2458 3895 : else if( nType == StateChangedType::Enable )
2459 : {
2460 139 : mpHScrollBar->Enable( IsEnabled() );
2461 139 : mpVScrollBar->Enable( IsEnabled() );
2462 139 : mpScrollBarBox->Enable( IsEnabled() );
2463 139 : maLBWindow->Enable( IsEnabled() );
2464 :
2465 139 : Invalidate();
2466 : }
2467 3756 : else if ( nType == StateChangedType::Zoom )
2468 : {
2469 3 : maLBWindow->SetZoom( GetZoom() );
2470 3 : Resize();
2471 : }
2472 3753 : else if ( nType == StateChangedType::ControlFont )
2473 : {
2474 319 : maLBWindow->SetControlFont( GetControlFont() );
2475 : }
2476 3434 : else if ( nType == StateChangedType::ControlForeground )
2477 : {
2478 4 : maLBWindow->SetControlForeground( GetControlForeground() );
2479 : }
2480 3430 : else if ( nType == StateChangedType::ControlBackground )
2481 : {
2482 4 : maLBWindow->SetControlBackground( GetControlBackground() );
2483 : }
2484 3426 : else if( nType == StateChangedType::Mirroring )
2485 : {
2486 114 : maLBWindow->EnableRTL( IsRTLEnabled() );
2487 114 : mpHScrollBar->EnableRTL( IsRTLEnabled() );
2488 114 : mpVScrollBar->EnableRTL( IsRTLEnabled() );
2489 114 : ImplResizeControls();
2490 : }
2491 :
2492 204385 : Control::StateChanged( nType );
2493 204385 : }
2494 :
2495 298 : void ImplListBox::DataChanged( const DataChangedEvent& rDCEvt )
2496 : {
2497 298 : Control::DataChanged( rDCEvt );
2498 298 : }
2499 :
2500 13356 : bool ImplListBox::Notify( NotifyEvent& rNEvt )
2501 : {
2502 13356 : bool nDone = false;
2503 13356 : if ( rNEvt.GetType() == MouseNotifyEvent::COMMAND )
2504 : {
2505 0 : const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
2506 0 : if ( rCEvt.GetCommand() == CommandEventId::Wheel )
2507 : {
2508 0 : const CommandWheelData* pData = rCEvt.GetWheelData();
2509 0 : if( !pData->GetModifier() && ( pData->GetMode() == CommandWheelMode::SCROLL ) )
2510 : {
2511 0 : nDone = HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar );
2512 : }
2513 : }
2514 : }
2515 :
2516 13356 : return nDone || Window::Notify( rNEvt );
2517 : }
2518 :
2519 0 : const Wallpaper& ImplListBox::GetDisplayBackground() const
2520 : {
2521 0 : return maLBWindow->GetDisplayBackground();
2522 : }
2523 :
2524 0 : bool ImplListBox::HandleWheelAsCursorTravel( const CommandEvent& rCEvt )
2525 : {
2526 0 : bool bDone = false;
2527 0 : if ( rCEvt.GetCommand() == CommandEventId::Wheel )
2528 : {
2529 0 : const CommandWheelData* pData = rCEvt.GetWheelData();
2530 0 : if( !pData->GetModifier() && ( pData->GetMode() == CommandWheelMode::SCROLL ) )
2531 : {
2532 0 : sal_uInt16 nKey = ( pData->GetDelta() < 0 ) ? KEY_DOWN : KEY_UP;
2533 0 : KeyEvent aKeyEvent( 0, vcl::KeyCode( nKey ) );
2534 0 : bDone = ProcessKeyInput( aKeyEvent );
2535 : }
2536 : }
2537 0 : return bDone;
2538 : }
2539 :
2540 0 : void ImplListBox::SetMRUEntries( const OUString& rEntries, sal_Unicode cSep )
2541 : {
2542 0 : bool bChanges = GetEntryList()->GetMRUCount() != 0;
2543 :
2544 : // Remove old MRU entries
2545 0 : for ( sal_Int32 n = GetEntryList()->GetMRUCount();n; )
2546 0 : maLBWindow->RemoveEntry( --n );
2547 :
2548 0 : sal_Int32 nMRUCount = 0;
2549 0 : sal_Int32 nIndex = 0;
2550 0 : do
2551 : {
2552 0 : OUString aEntry = rEntries.getToken( 0, cSep, nIndex );
2553 : // Accept only existing entries
2554 0 : if ( GetEntryList()->FindEntry( aEntry ) != LISTBOX_ENTRY_NOTFOUND )
2555 : {
2556 0 : ImplEntryType* pNewEntry = new ImplEntryType( aEntry );
2557 0 : maLBWindow->GetEntryList()->InsertEntry( nMRUCount++, pNewEntry, false );
2558 0 : bChanges = true;
2559 0 : }
2560 : }
2561 0 : while ( nIndex >= 0 );
2562 :
2563 0 : if ( bChanges )
2564 : {
2565 0 : maLBWindow->GetEntryList()->SetMRUCount( nMRUCount );
2566 0 : SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
2567 0 : CompatStateChanged( StateChangedType::Data );
2568 : }
2569 0 : }
2570 :
2571 1962 : OUString ImplListBox::GetMRUEntries( sal_Unicode cSep ) const
2572 : {
2573 1962 : OUStringBuffer aEntries;
2574 1962 : for ( sal_Int32 n = 0; n < GetEntryList()->GetMRUCount(); n++ )
2575 : {
2576 0 : aEntries.append(GetEntryList()->GetEntryText( n ));
2577 0 : if( n < ( GetEntryList()->GetMRUCount() - 1 ) )
2578 0 : aEntries.append(cSep);
2579 : }
2580 1962 : return aEntries.makeStringAndClear();
2581 : }
2582 :
2583 374 : void ImplListBox::SetEdgeBlending(bool bNew)
2584 : {
2585 374 : if(mbEdgeBlending != bNew)
2586 : {
2587 51 : mbEdgeBlending = bNew;
2588 51 : maLBWindow->SetEdgeBlending(GetEdgeBlending());
2589 : }
2590 374 : }
2591 :
2592 309 : ImplWin::ImplWin( vcl::Window* pParent, WinBits nWinStyle ) :
2593 309 : Control ( pParent, nWinStyle )
2594 : {
2595 618 : if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2596 309 : && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
2597 0 : SetBackground();
2598 : else
2599 309 : SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2600 :
2601 309 : ImplGetWindowImpl()->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
2602 :
2603 309 : mbInUserDraw = false;
2604 309 : mbUserDrawEnabled = false;
2605 309 : mbEdgeBlending = false;
2606 309 : mnItemPos = LISTBOX_ENTRY_NOTFOUND;
2607 309 : }
2608 :
2609 0 : void ImplWin::MBDown()
2610 : {
2611 0 : if( IsEnabled() )
2612 0 : buttonDownSignal( this );
2613 0 : }
2614 :
2615 0 : void ImplWin::MouseButtonDown( const MouseEvent& )
2616 : {
2617 0 : if( IsEnabled() )
2618 : {
2619 0 : MBDown();
2620 : }
2621 0 : }
2622 :
2623 0 : void ImplWin::FillLayoutData() const
2624 : {
2625 0 : mpControlData->mpLayoutData = new vcl::ControlLayoutData();
2626 0 : ImplWin* pThis = const_cast<ImplWin*>(this);
2627 0 : pThis->ImplDraw(*pThis, true);
2628 0 : }
2629 :
2630 1 : bool ImplWin::PreNotify( NotifyEvent& rNEvt )
2631 : {
2632 1 : const MouseEvent* pMouseEvt = NULL;
2633 :
2634 1 : if( (rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
2635 : {
2636 0 : if( pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow() )
2637 : {
2638 : // trigger redraw as mouse over state has changed
2639 0 : if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2640 0 : && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
2641 : {
2642 0 : GetParent()->GetWindow( GetWindowType::Border )->Invalidate( InvalidateFlags::NoErase );
2643 0 : GetParent()->GetWindow( GetWindowType::Border )->Update();
2644 : }
2645 : }
2646 : }
2647 :
2648 1 : return Control::PreNotify(rNEvt);
2649 : }
2650 :
2651 1056 : void ImplWin::ImplDraw(vcl::RenderContext& rRenderContext, bool bLayout)
2652 : {
2653 1056 : const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
2654 :
2655 1056 : if (!bLayout)
2656 : {
2657 1056 : bool bNativeOK = false;
2658 :
2659 1056 : ControlState nState = ControlState::ENABLED;
2660 2112 : if (rRenderContext.IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2661 1056 : && rRenderContext.IsNativeControlSupported(CTRL_LISTBOX, HAS_BACKGROUND_TEXTURE) )
2662 : {
2663 : // Repaint the (focused) area similarly to
2664 : // ImplSmallBorderWindowView::DrawWindow() in
2665 : // vcl/source/window/brdwin.cxx
2666 0 : vcl::Window *pWin = GetParent();
2667 :
2668 0 : ImplControlValue aControlValue;
2669 0 : if ( !pWin->IsEnabled() )
2670 0 : nState &= ~ControlState::ENABLED;
2671 0 : if ( pWin->HasFocus() )
2672 0 : nState |= ControlState::FOCUSED;
2673 :
2674 : // The listbox is painted over the entire control including the
2675 : // border, but ImplWin does not contain the border => correction
2676 : // needed.
2677 : sal_Int32 nLeft, nTop, nRight, nBottom;
2678 0 : pWin->GetBorder( nLeft, nTop, nRight, nBottom );
2679 0 : Point aPoint( -nLeft, -nTop );
2680 0 : Rectangle aCtrlRegion( aPoint - GetPosPixel(), pWin->GetSizePixel() );
2681 :
2682 0 : bool bMouseOver = false;
2683 0 : if( GetParent() )
2684 : {
2685 0 : vcl::Window *pChild = GetParent()->GetWindow( GetWindowType::FirstChild );
2686 0 : while( pChild && !(bMouseOver = pChild->IsMouseOver()) )
2687 0 : pChild = pChild->GetWindow( GetWindowType::Next );
2688 : }
2689 :
2690 0 : if( bMouseOver )
2691 0 : nState |= ControlState::ROLLOVER;
2692 :
2693 : // if parent has no border, then nobody has drawn the background
2694 : // since no border window exists. so draw it here.
2695 0 : WinBits nParentStyle = pWin->GetStyle();
2696 0 : if( ! (nParentStyle & WB_BORDER) || (nParentStyle & WB_NOBORDER) )
2697 : {
2698 0 : Rectangle aParentRect( Point( 0, 0 ), pWin->GetSizePixel() );
2699 : pWin->DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aParentRect,
2700 0 : nState, aControlValue, OUString() );
2701 : }
2702 :
2703 : bNativeOK = rRenderContext.DrawNativeControl(CTRL_LISTBOX, PART_ENTIRE_CONTROL, aCtrlRegion,
2704 0 : nState, aControlValue, OUString());
2705 : }
2706 :
2707 1056 : if (IsEnabled())
2708 : {
2709 871 : if (HasFocus() && !ImplGetSVData()->maNWFData.mbDDListBoxNoTextArea)
2710 : {
2711 2 : rRenderContext.SetTextColor( rStyleSettings.GetHighlightTextColor() );
2712 2 : rRenderContext.SetFillColor( rStyleSettings.GetHighlightColor() );
2713 2 : rRenderContext.DrawRect( maFocusRect );
2714 : }
2715 : else
2716 : {
2717 869 : Color aColor;
2718 869 : if( ImplGetSVData()->maNWFData.mbDDListBoxNoTextArea )
2719 : {
2720 0 : if( bNativeOK && (nState & ControlState::ROLLOVER) )
2721 0 : aColor = rStyleSettings.GetButtonRolloverTextColor();
2722 : else
2723 0 : aColor = rStyleSettings.GetButtonTextColor();
2724 : }
2725 : else
2726 : {
2727 869 : if( bNativeOK && (nState & ControlState::ROLLOVER) )
2728 0 : aColor = rStyleSettings.GetFieldRolloverTextColor();
2729 : else
2730 869 : aColor = rStyleSettings.GetFieldTextColor();
2731 : }
2732 869 : if (IsControlForeground())
2733 0 : aColor = GetControlForeground();
2734 869 : rRenderContext.SetTextColor(aColor);
2735 869 : if (!bNativeOK)
2736 869 : rRenderContext.Erase(maFocusRect);
2737 : }
2738 : }
2739 : else // Disabled
2740 : {
2741 185 : rRenderContext.SetTextColor(rStyleSettings.GetDisableColor());
2742 185 : if (!bNativeOK)
2743 185 : rRenderContext.Erase(maFocusRect);
2744 : }
2745 : }
2746 :
2747 1056 : if ( IsUserDrawEnabled() )
2748 : {
2749 1 : mbInUserDraw = true;
2750 1 : UserDrawEvent aUDEvt(&rRenderContext, maFocusRect, mnItemPos, 0);
2751 1 : userDrawSignal( &aUDEvt );
2752 1 : mbInUserDraw = false;
2753 : }
2754 : else
2755 : {
2756 1055 : DrawEntry(rRenderContext, true, true, false, bLayout);
2757 : }
2758 1056 : }
2759 :
2760 1084 : void ImplWin::ApplySettings(vcl::RenderContext& rRenderContext)
2761 : {
2762 1084 : const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
2763 :
2764 1084 : vcl::Font aFont = rStyleSettings.GetFieldFont();
2765 1084 : if (IsControlFont())
2766 152 : aFont.Merge(GetControlFont());
2767 1084 : SetZoomedPointFont(rRenderContext, aFont);
2768 :
2769 1084 : Color aTextColor = rStyleSettings.GetFieldTextColor();
2770 1084 : if (IsControlForeground())
2771 0 : aTextColor = GetControlForeground();
2772 1084 : rRenderContext.SetTextColor(aTextColor);
2773 :
2774 1084 : if (IsControlBackground())
2775 0 : rRenderContext.SetBackground(GetControlBackground());
2776 : else
2777 1084 : rRenderContext.SetBackground(rStyleSettings.GetFieldColor());
2778 1084 : }
2779 :
2780 1056 : void ImplWin::Paint( vcl::RenderContext& rRenderContext, const Rectangle& )
2781 : {
2782 1056 : ImplDraw(rRenderContext);
2783 1056 : }
2784 :
2785 1056 : void ImplWin::DrawEntry(vcl::RenderContext& rRenderContext, bool bDrawImage, bool bDrawText, bool bDrawTextAtImagePos, bool bLayout)
2786 : {
2787 1056 : long nBorder = 1;
2788 1056 : Size aOutSz = rRenderContext.GetOutputSizePixel();
2789 :
2790 1056 : bool bImage = !!maImage;
2791 1056 : if (bDrawImage && bImage && !bLayout)
2792 : {
2793 0 : DrawImageFlags nStyle = DrawImageFlags::NONE;
2794 0 : Size aImgSz = maImage.GetSizePixel();
2795 0 : Point aPtImg( nBorder, ( ( aOutSz.Height() - aImgSz.Height() ) / 2 ) );
2796 0 : const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2797 :
2798 : // check for HC mode
2799 0 : Image *pImage = &maImage;
2800 :
2801 0 : if ( !IsZoom() )
2802 : {
2803 0 : rRenderContext.DrawImage( aPtImg, *pImage, nStyle );
2804 : }
2805 : else
2806 : {
2807 0 : aImgSz.Width() = CalcZoom( aImgSz.Width() );
2808 0 : aImgSz.Height() = CalcZoom( aImgSz.Height() );
2809 0 : rRenderContext.DrawImage( aPtImg, aImgSz, *pImage, nStyle );
2810 : }
2811 :
2812 0 : const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
2813 :
2814 0 : if(nEdgeBlendingPercent)
2815 : {
2816 0 : const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
2817 0 : const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
2818 0 : const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
2819 0 : const BitmapEx aBlendFrame(createBlendFrame(aImgSz, nAlpha, rTopLeft, rBottomRight));
2820 :
2821 0 : if(!aBlendFrame.IsEmpty())
2822 : {
2823 0 : rRenderContext.DrawBitmapEx(aPtImg, aBlendFrame);
2824 0 : }
2825 : }
2826 : }
2827 :
2828 1056 : if( bDrawText && !maString.isEmpty() )
2829 : {
2830 41 : DrawTextFlags nTextStyle = DrawTextFlags::VCenter;
2831 :
2832 41 : if ( bDrawImage && bImage && !bLayout )
2833 0 : nTextStyle |= DrawTextFlags::Left;
2834 41 : else if ( GetStyle() & WB_CENTER )
2835 0 : nTextStyle |= DrawTextFlags::Center;
2836 41 : else if ( GetStyle() & WB_RIGHT )
2837 0 : nTextStyle |= DrawTextFlags::Right;
2838 : else
2839 41 : nTextStyle |= DrawTextFlags::Left;
2840 :
2841 41 : Rectangle aTextRect( Point( nBorder, 0 ), Size( aOutSz.Width()-2*nBorder, aOutSz.Height() ) );
2842 :
2843 41 : if ( !bDrawTextAtImagePos && ( bImage || IsUserDrawEnabled() ) )
2844 : {
2845 0 : long nMaxWidth = std::max( maImage.GetSizePixel().Width(), maUserItemSize.Width() );
2846 0 : aTextRect.Left() += nMaxWidth + IMG_TXT_DISTANCE;
2847 : }
2848 :
2849 41 : MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
2850 41 : OUString* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
2851 41 : rRenderContext.DrawText( aTextRect, maString, nTextStyle, pVector, pDisplayText );
2852 : }
2853 :
2854 1056 : if( HasFocus() && !bLayout )
2855 2 : ShowFocus( maFocusRect );
2856 1056 : }
2857 :
2858 956 : void ImplWin::Resize()
2859 : {
2860 956 : Control::Resize();
2861 956 : maFocusRect.SetSize( GetOutputSizePixel() );
2862 956 : Invalidate();
2863 956 : }
2864 :
2865 1 : void ImplWin::GetFocus()
2866 : {
2867 1 : ShowFocus( maFocusRect );
2868 2 : if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2869 1 : IsNativeWidgetEnabled() &&
2870 0 : IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
2871 : {
2872 0 : vcl::Window* pWin = GetParent()->GetWindow( GetWindowType::Border );
2873 0 : if( ! pWin )
2874 0 : pWin = GetParent();
2875 0 : pWin->Invalidate();
2876 : }
2877 : else
2878 1 : Invalidate();
2879 1 : Control::GetFocus();
2880 1 : }
2881 :
2882 0 : void ImplWin::LoseFocus()
2883 : {
2884 0 : HideFocus();
2885 0 : if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2886 0 : IsNativeWidgetEnabled() &&
2887 0 : IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
2888 : {
2889 0 : vcl::Window* pWin = GetParent()->GetWindow( GetWindowType::Border );
2890 0 : if( ! pWin )
2891 0 : pWin = GetParent();
2892 0 : pWin->Invalidate();
2893 : }
2894 : else
2895 0 : Invalidate();
2896 0 : Control::LoseFocus();
2897 0 : }
2898 :
2899 3 : void ImplWin::ShowFocus(const Rectangle& rRect)
2900 : {
2901 3 : if (IsNativeControlSupported(CTRL_LISTBOX, PART_FOCUS))
2902 : {
2903 0 : ImplControlValue aControlValue;
2904 :
2905 0 : vcl::Window *pWin = GetParent();
2906 0 : Rectangle aParentRect(Point(0, 0), pWin->GetSizePixel());
2907 : pWin->DrawNativeControl(CTRL_LISTBOX, PART_FOCUS, aParentRect,
2908 0 : ControlState::FOCUSED, aControlValue, OUString());
2909 : }
2910 3 : Control::ShowFocus(rRect);
2911 3 : }
2912 :
2913 3282 : ImplBtn::ImplBtn( vcl::Window* pParent, WinBits nWinStyle ) :
2914 : PushButton( pParent, nWinStyle ),
2915 3282 : mbDown ( false )
2916 : {
2917 3282 : }
2918 :
2919 0 : void ImplBtn::MBDown()
2920 : {
2921 0 : if( IsEnabled() )
2922 0 : buttonDownSignal( this );
2923 0 : }
2924 :
2925 0 : void ImplBtn::MouseButtonDown( const MouseEvent& )
2926 : {
2927 : //PushButton::MouseButtonDown( rMEvt );
2928 0 : if( IsEnabled() )
2929 : {
2930 0 : MBDown();
2931 0 : mbDown = true;
2932 : }
2933 0 : }
2934 :
2935 3282 : ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( vcl::Window* pParent ) :
2936 3282 : FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW ) // no drop shadow for list boxes
2937 : {
2938 3282 : mpImplLB = NULL;
2939 3282 : mnDDLineCount = 0;
2940 3282 : mbAutoWidth = false;
2941 :
2942 3282 : mnPopupModeStartSaveSelection = LISTBOX_ENTRY_NOTFOUND;
2943 :
2944 3282 : EnableSaveBackground();
2945 :
2946 3282 : vcl::Window * pBorderWindow = ImplGetBorderWindow();
2947 3282 : if( pBorderWindow )
2948 : {
2949 3282 : SetAccessibleRole(accessibility::AccessibleRole::PANEL);
2950 3282 : pBorderWindow->SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
2951 : }
2952 : else
2953 : {
2954 0 : SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
2955 : }
2956 :
2957 3282 : }
2958 :
2959 9840 : ImplListBoxFloatingWindow::~ImplListBoxFloatingWindow()
2960 : {
2961 3280 : disposeOnce();
2962 6560 : }
2963 :
2964 3280 : void ImplListBoxFloatingWindow::dispose()
2965 : {
2966 3280 : mpImplLB.clear();
2967 3280 : FloatingWindow::dispose();
2968 3280 : }
2969 :
2970 :
2971 0 : bool ImplListBoxFloatingWindow::PreNotify( NotifyEvent& rNEvt )
2972 : {
2973 0 : if( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
2974 : {
2975 0 : if( !GetParent()->HasChildPathFocus( true ) )
2976 0 : EndPopupMode();
2977 : }
2978 :
2979 0 : return FloatingWindow::PreNotify( rNEvt );
2980 : }
2981 :
2982 6069 : void ImplListBoxFloatingWindow::setPosSizePixel( long nX, long nY, long nWidth, long nHeight, PosSizeFlags nFlags )
2983 : {
2984 6069 : FloatingWindow::setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
2985 :
2986 : // Fix #60890# ( MBA ): to be able to resize the Listbox even in its open state
2987 : // after a call to Resize(), we adjust its position if necessary
2988 6069 : if ( IsReallyVisible() && ( nFlags & PosSizeFlags::Height ) )
2989 : {
2990 0 : Point aPos = GetParent()->GetPosPixel();
2991 0 : aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
2992 :
2993 0 : if ( nFlags & PosSizeFlags::X )
2994 0 : aPos.X() = nX;
2995 :
2996 0 : if ( nFlags & PosSizeFlags::Y )
2997 0 : aPos.Y() = nY;
2998 :
2999 : sal_uInt16 nIndex;
3000 0 : SetPosPixel( ImplCalcPos( this, Rectangle( aPos, GetParent()->GetSizePixel() ), FloatWinPopupFlags::Down, nIndex ) );
3001 : }
3002 :
3003 : // if( !IsReallyVisible() )
3004 : {
3005 : // The ImplListBox does not get a Resize() as not visible.
3006 : // But the windows must get a Resize(), so that the number of
3007 : // visible entries is correct for PgUp/PgDown.
3008 : // The number also cannot be calculated by List/Combobox, as for
3009 : // this the presence of the vertical Scrollbar has to be known.
3010 6069 : mpImplLB->SetSizePixel( GetOutputSizePixel() );
3011 6069 : static_cast<vcl::Window*>(mpImplLB)->Resize();
3012 6069 : static_cast<vcl::Window*>(mpImplLB->GetMainWindow())->Resize();
3013 : }
3014 6069 : }
3015 :
3016 2 : void ImplListBoxFloatingWindow::Resize()
3017 : {
3018 2 : mpImplLB->GetMainWindow()->ImplClearLayoutData();
3019 2 : FloatingWindow::Resize();
3020 2 : }
3021 :
3022 6065 : Size ImplListBoxFloatingWindow::CalcFloatSize()
3023 : {
3024 6065 : Size aFloatSz( maPrefSz );
3025 :
3026 : sal_Int32 nLeft, nTop, nRight, nBottom;
3027 6065 : GetBorder( nLeft, nTop, nRight, nBottom );
3028 :
3029 6065 : sal_Int32 nLines = mpImplLB->GetEntryList()->GetEntryCount();
3030 6065 : if ( mnDDLineCount && ( nLines > mnDDLineCount ) )
3031 3 : nLines = mnDDLineCount;
3032 :
3033 6065 : Size aSz = mpImplLB->CalcSize( nLines );
3034 6065 : long nMaxHeight = aSz.Height() + nTop + nBottom;
3035 :
3036 6065 : if ( mnDDLineCount )
3037 1709 : aFloatSz.Height() = nMaxHeight;
3038 :
3039 6065 : if( mbAutoWidth )
3040 : {
3041 : // AutoSize first only for width...
3042 :
3043 6065 : aFloatSz.Width() = aSz.Width() + nLeft + nRight;
3044 6065 : aFloatSz.Width() += nRight; // adding some space looks better...
3045 :
3046 6065 : if ( ( aFloatSz.Height() < nMaxHeight ) || ( mnDDLineCount && ( mnDDLineCount < mpImplLB->GetEntryList()->GetEntryCount() ) ) )
3047 : {
3048 : // then we also need the vertical Scrollbar
3049 3036 : long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
3050 3036 : aFloatSz.Width() += nSBWidth;
3051 : }
3052 :
3053 6065 : long nDesktopWidth = GetDesktopRectPixel().getWidth();
3054 6065 : if (aFloatSz.Width() > nDesktopWidth)
3055 : // Don't exceed the desktop width.
3056 0 : aFloatSz.Width() = nDesktopWidth;
3057 : }
3058 :
3059 6065 : if ( aFloatSz.Height() > nMaxHeight )
3060 1323 : aFloatSz.Height() = nMaxHeight;
3061 :
3062 : // Minimal height, in case height is not set to Float height.
3063 : // The parent of FloatWin must be DropDown-Combo/Listbox.
3064 6065 : Size aParentSz = GetParent()->GetSizePixel();
3065 6065 : if( (!mnDDLineCount || !nLines) && ( aFloatSz.Height() < aParentSz.Height() ) )
3066 1429 : aFloatSz.Height() = aParentSz.Height();
3067 :
3068 : // do not get narrower than the parent...
3069 6065 : if( aFloatSz.Width() < aParentSz.Width() )
3070 2684 : aFloatSz.Width() = aParentSz.Width();
3071 :
3072 : // align height to entries...
3073 6065 : long nInnerHeight = aFloatSz.Height() - nTop - nBottom;
3074 6065 : long nEntryHeight = mpImplLB->GetEntryHeight();
3075 6065 : if ( nInnerHeight % nEntryHeight )
3076 : {
3077 4436 : nInnerHeight /= nEntryHeight;
3078 4436 : nInnerHeight++;
3079 4436 : nInnerHeight *= nEntryHeight;
3080 4436 : aFloatSz.Height() = nInnerHeight + nTop + nBottom;
3081 : }
3082 :
3083 6065 : if (aFloatSz.Width() < aSz.Width())
3084 : {
3085 : // The max width of list box entries exceeds the window width.
3086 : // Account for the scroll bar height.
3087 0 : long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
3088 0 : aFloatSz.Height() += nSBWidth;
3089 : }
3090 :
3091 6065 : return aFloatSz;
3092 : }
3093 :
3094 4 : void ImplListBoxFloatingWindow::StartFloat( bool bStartTracking )
3095 : {
3096 4 : if( !IsInPopupMode() )
3097 : {
3098 4 : Size aFloatSz = CalcFloatSize();
3099 :
3100 4 : SetSizePixel( aFloatSz );
3101 4 : mpImplLB->SetSizePixel( GetOutputSizePixel() );
3102 :
3103 4 : sal_Int32 nPos = mpImplLB->GetEntryList()->GetSelectEntryPos( 0 );
3104 4 : mnPopupModeStartSaveSelection = nPos;
3105 :
3106 4 : Size aSz = GetParent()->GetSizePixel();
3107 4 : Point aPos = GetParent()->GetPosPixel();
3108 4 : aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
3109 : // FIXME: this ugly hack is for Mac/Aqua
3110 : // should be replaced by a real mechanism to place the float rectangle
3111 4 : if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3112 0 : GetParent()->IsNativeWidgetEnabled() )
3113 : {
3114 0 : sal_Int32 nLeft = 4, nTop = 4, nRight = 4, nBottom = 4;
3115 0 : aPos.X() += nLeft;
3116 0 : aPos.Y() += nTop;
3117 0 : aSz.Width() -= nLeft + nRight;
3118 0 : aSz.Height() -= nTop + nBottom;
3119 : }
3120 4 : Rectangle aRect( aPos, aSz );
3121 :
3122 : // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
3123 : // where the document is unmirrored
3124 : // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
3125 4 : vcl::Window *pGrandparent = GetParent()->GetParent();
3126 4 : const OutputDevice *pGrandparentOutDev = pGrandparent->GetOutDev();
3127 :
3128 4 : if( pGrandparent->ImplIsAntiparallel() )
3129 0 : pGrandparentOutDev->ReMirror( aRect );
3130 :
3131 : // mouse-button right: close the List-Box-Float-win and don't stop the handling fdo#84795
3132 4 : StartPopupMode( aRect, FloatWinPopupFlags::Down | FloatWinPopupFlags::AllMouseButtonClose );
3133 :
3134 4 : if( nPos != LISTBOX_ENTRY_NOTFOUND )
3135 4 : mpImplLB->ShowProminentEntry( nPos );
3136 :
3137 4 : if( bStartTracking )
3138 4 : mpImplLB->GetMainWindow()->EnableMouseMoveSelect( true );
3139 :
3140 4 : if ( mpImplLB->GetMainWindow()->IsGrabFocusAllowed() )
3141 0 : mpImplLB->GetMainWindow()->GrabFocus();
3142 :
3143 4 : mpImplLB->GetMainWindow()->ImplClearLayoutData();
3144 : }
3145 805 : }
3146 :
3147 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|