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