Bump version to 5.0-14
[LibreOffice.git] / svtools / source / control / valueset.cxx
blob4af4a38b83cc9338daece0a60da44408ddcc9c52
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <tools/debug.hxx>
21 #include <vcl/builderfactory.hxx>
22 #include <vcl/decoview.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/scrbar.hxx>
25 #include <vcl/help.hxx>
26 #include <vcl/settings.hxx>
28 #include <com/sun/star/accessibility/AccessibleEventObject.hpp>
29 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
30 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
31 #include <com/sun/star/lang/XComponent.hpp>
32 #include <rtl/ustring.hxx>
33 #include "valueimp.hxx"
35 #include <svtools/valueset.hxx>
37 using namespace css::uno;
38 using namespace css::lang;
39 using namespace css::accessibility;
41 namespace
44 enum
46 ITEM_OFFSET = 4,
47 ITEM_OFFSET_DOUBLE = 6,
48 NAME_LINE_OFF_X = 2,
49 NAME_LINE_OFF_Y = 2,
50 NAME_LINE_HEIGHT = 2,
51 NAME_OFFSET = 2,
52 SCRBAR_OFFSET = 1,
53 SCROLL_OFFSET = 4
58 void ValueSet::ImplInit()
60 mpNoneItem.reset(NULL);
61 mxScrollBar.reset(NULL);
63 mnItemWidth = 0;
64 mnItemHeight = 0;
65 mnTextOffset = 0;
66 mnVisLines = 0;
67 mnLines = 0;
68 mnUserItemWidth = 0;
69 mnUserItemHeight = 0;
70 mnFirstLine = 0;
71 mnSelItemId = 0;
72 mnHighItemId = 0;
73 mnCols = 0;
74 mnCurCol = 0;
75 mnUserCols = 0;
76 mnUserVisLines = 0;
77 mnSpacing = 0;
78 mnFrameStyle = DrawFrameStyle::NONE;
79 mbFormat = true;
80 mbHighlight = false;
81 mbSelection = false;
82 mbNoSelection = true;
83 mbDrawSelection = true;
84 mbBlackSel = false;
85 mbDoubleSel = false;
86 mbScroll = false;
87 mbFullMode = true;
88 mbEdgeBlending = false;
89 mbHasVisibleItems = false;
91 // #106446#, #106601# force mirroring of virtual device
92 maVirDev->EnableRTL( GetParent()->IsRTLEnabled() );
94 ImplInitSettings( true, true, true );
97 ValueSet::ValueSet( vcl::Window* pParent, WinBits nWinStyle, bool bDisableTransientChildren ) :
98 Control( pParent, nWinStyle ),
99 maVirDev( VclPtr<VirtualDevice>::Create(*this) ),
100 maColor( COL_TRANSPARENT )
102 ImplInit();
103 mbIsTransientChildrenDisabled = bDisableTransientChildren;
106 VCL_BUILDER_DECL_FACTORY(ValueSet)
108 WinBits nWinBits = WB_TABSTOP;
110 OString sBorder = VclBuilder::extractCustomProperty(rMap);
111 if (!sBorder.isEmpty())
112 nWinBits |= WB_BORDER;
114 rRet = VclPtr<ValueSet>::Create(pParent, nWinBits);
117 ValueSet::ValueSet( vcl::Window* pParent, const ResId& rResId, bool bDisableTransientChildren ) :
118 Control( pParent, rResId ),
119 maVirDev( VclPtr<VirtualDevice>::Create(*this) ),
120 maColor( COL_TRANSPARENT )
122 ImplInit();
123 mbIsTransientChildrenDisabled = bDisableTransientChildren;
126 ValueSet::~ValueSet()
128 disposeOnce();
131 void ValueSet::dispose()
133 Reference<XComponent> xComponent(GetAccessible(false), UNO_QUERY);
134 if (xComponent.is())
135 xComponent->dispose();
137 ImplDeleteItems();
138 mxScrollBar.disposeAndClear();
139 Control::dispose();
142 void ValueSet::ImplDeleteItems()
144 const size_t n = mItemList.size();
146 for ( size_t i = 0; i < n; ++i )
148 ValueSetItem* pItem = mItemList[i];
149 if ( pItem->mbVisible && ImplHasAccessibleListeners() )
151 Any aOldAny;
152 Any aNewAny;
154 aOldAny <<= pItem->GetAccessible( mbIsTransientChildrenDisabled );
155 ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny);
158 delete pItem;
161 mItemList.clear();
164 void ValueSet::ApplySettings(vcl::RenderContext& rRenderContext)
166 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
168 ApplyControlFont(rRenderContext, rStyleSettings.GetAppFont());
169 ApplyControlForeground(rRenderContext, rStyleSettings.GetButtonTextColor());
170 SetTextFillColor();
171 Color aColor;
172 if (GetStyle() & WB_MENUSTYLEVALUESET)
173 aColor = rStyleSettings.GetMenuColor();
174 else if (IsEnabled() && (GetStyle() & WB_FLATVALUESET))
175 aColor = rStyleSettings.GetWindowColor();
176 else
177 aColor = rStyleSettings.GetFaceColor();
178 ApplyControlBackground(rRenderContext, aColor);
181 void ValueSet::ImplInitSettings(bool bFont, bool bForeground, bool bBackground)
183 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
185 if (bFont)
187 ApplyControlFont(*this, rStyleSettings.GetAppFont());
190 if (bForeground || bFont)
192 ApplyControlForeground(*this, rStyleSettings.GetButtonTextColor());
193 SetTextFillColor();
196 if (bBackground)
198 Color aColor;
199 if (GetStyle() & WB_MENUSTYLEVALUESET)
200 aColor = rStyleSettings.GetMenuColor();
201 else if (IsEnabled() && (GetStyle() & WB_FLATVALUESET))
202 aColor = rStyleSettings.GetWindowColor();
203 else
204 aColor = rStyleSettings.GetFaceColor();
205 ApplyControlBackground(*this, aColor);
209 void ValueSet::ImplInitScrollBar()
211 if (GetStyle() & WB_VSCROLL)
213 if (!mxScrollBar.get())
215 mxScrollBar.reset(VclPtr<ScrollBar>::Create(this, WB_VSCROLL | WB_DRAG));
216 mxScrollBar->SetScrollHdl(LINK(this, ValueSet, ImplScrollHdl));
218 else
220 // adapt the width because of the changed settings
221 long nScrBarWidth = Application::GetSettings().GetStyleSettings().GetScrollBarSize();
222 mxScrollBar->setPosSizePixel(0, 0, nScrBarWidth, 0, PosSizeFlags::Width);
227 void ValueSet::ImplFormatItem(vcl::RenderContext& rRenderContext, ValueSetItem* pItem, Rectangle aRect)
229 WinBits nStyle = GetStyle();
230 if (nStyle & WB_ITEMBORDER)
232 aRect.Left() += 1;
233 aRect.Top() += 1;
234 aRect.Right() -= 1;
235 aRect.Bottom() -= 1;
237 if (nStyle & WB_FLATVALUESET)
239 sal_Int32 nBorder = (nStyle & WB_DOUBLEBORDER) ? 2 : 1;
241 aRect.Left() += nBorder;
242 aRect.Top() += nBorder;
243 aRect.Right() -= nBorder;
244 aRect.Bottom() -= nBorder;
246 else
248 DecorationView aView(maVirDev.get());
249 aRect = aView.DrawFrame(aRect, mnFrameStyle);
253 if (pItem == mpNoneItem.get())
254 pItem->maText = GetText();
256 if ((aRect.GetHeight() > 0) && (aRect.GetWidth() > 0))
258 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
260 if (pItem == mpNoneItem.get())
262 maVirDev->SetFont(rRenderContext.GetFont());
263 maVirDev->SetTextColor((nStyle & WB_MENUSTYLEVALUESET) ? rStyleSettings.GetMenuTextColor() : rStyleSettings.GetWindowTextColor());
264 maVirDev->SetTextFillColor();
265 maVirDev->SetFillColor((nStyle & WB_MENUSTYLEVALUESET) ? rStyleSettings.GetMenuColor() : rStyleSettings.GetWindowColor());
266 maVirDev->DrawRect(aRect);
267 Point aTxtPos(aRect.Left() + 2, aRect.Top());
268 long nTxtWidth = rRenderContext.GetTextWidth(pItem->maText);
269 if (nStyle & WB_RADIOSEL)
271 aTxtPos.X() += 4;
272 aTxtPos.Y() += 4;
274 if ((aTxtPos.X() + nTxtWidth) > aRect.Right())
276 maVirDev->SetClipRegion(vcl::Region(aRect));
277 maVirDev->DrawText(aTxtPos, pItem->maText);
278 maVirDev->SetClipRegion();
280 else
281 maVirDev->DrawText(aTxtPos, pItem->maText);
283 else if (pItem->meType == VALUESETITEM_COLOR)
285 maVirDev->SetFillColor(pItem->maColor);
286 maVirDev->DrawRect(aRect);
288 else
290 if (IsColor())
291 maVirDev->SetFillColor(maColor);
292 else if (nStyle & WB_MENUSTYLEVALUESET)
293 maVirDev->SetFillColor(rStyleSettings.GetMenuColor());
294 else if (IsEnabled())
295 maVirDev->SetFillColor(rStyleSettings.GetWindowColor());
296 else
297 maVirDev->SetFillColor(rStyleSettings.GetFaceColor());
298 maVirDev->DrawRect(aRect);
300 if (pItem->meType == VALUESETITEM_USERDRAW)
302 UserDrawEvent aUDEvt(this, maVirDev.get(), aRect, pItem->mnId);
303 UserDraw(aUDEvt);
305 else
307 Size aImageSize = pItem->maImage.GetSizePixel();
308 Size aRectSize = aRect.GetSize();
309 Point aPos(aRect.Left(), aRect.Top());
310 aPos.X() += (aRectSize.Width() - aImageSize.Width()) / 2;
311 aPos.Y() += (aRectSize.Height() - aImageSize.Height()) / 2;
313 DrawImageFlags nImageStyle = DrawImageFlags::NONE;
314 if (!IsEnabled())
315 nImageStyle |= DrawImageFlags::Disable;
317 if (aImageSize.Width() > aRectSize.Width() ||
318 aImageSize.Height() > aRectSize.Height())
320 maVirDev->SetClipRegion(vcl::Region(aRect));
321 maVirDev->DrawImage(aPos, pItem->maImage, nImageStyle);
322 maVirDev->SetClipRegion();
324 else
325 maVirDev->DrawImage(aPos, pItem->maImage, nImageStyle);
329 const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
331 if (nEdgeBlendingPercent)
333 const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
334 const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
335 const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
336 const BitmapEx aBlendFrame(createBlendFrame(aRect.GetSize(), nAlpha, rTopLeft, rBottomRight));
338 if (!aBlendFrame.IsEmpty())
340 maVirDev->DrawBitmapEx(aRect.TopLeft(), aBlendFrame);
346 Reference<XAccessible> ValueSet::CreateAccessible()
348 return new ValueSetAcc( this, mbIsTransientChildrenDisabled );
351 void ValueSet::Format(vcl::RenderContext& rRenderContext)
353 Size aWinSize(GetOutputSizePixel());
354 size_t nItemCount = mItemList.size();
355 WinBits nStyle = GetStyle();
356 long nTxtHeight = rRenderContext.GetTextHeight();
357 long nOff;
358 long nNoneHeight;
359 long nNoneSpace;
360 VclPtr<ScrollBar> xDeletedScrollBar;
362 // consider the scrolling
363 if (nStyle & WB_VSCROLL)
364 ImplInitScrollBar();
365 else
367 xDeletedScrollBar = mxScrollBar;
368 mxScrollBar.clear();
371 // calculate item offset
372 if (nStyle & WB_ITEMBORDER)
374 if (nStyle & WB_DOUBLEBORDER)
375 nOff = ITEM_OFFSET_DOUBLE;
376 else
377 nOff = ITEM_OFFSET;
379 else
380 nOff = 0;
382 // consider size, if NameField does exist
383 if (nStyle & WB_NAMEFIELD)
385 mnTextOffset = aWinSize.Height() - nTxtHeight - NAME_OFFSET;
386 aWinSize.Height() -= nTxtHeight + NAME_OFFSET;
388 if (!(nStyle & WB_FLATVALUESET))
390 mnTextOffset -= NAME_LINE_HEIGHT + NAME_LINE_OFF_Y;
391 aWinSize.Height() -= NAME_LINE_HEIGHT + NAME_LINE_OFF_Y;
394 else
395 mnTextOffset = 0;
397 // consider offset and size, if NoneField does exist
398 if (nStyle & WB_NONEFIELD)
400 nNoneHeight = nTxtHeight + nOff;
401 nNoneSpace = mnSpacing;
402 if (nStyle & WB_RADIOSEL)
403 nNoneHeight += 8;
405 else
407 nNoneHeight = 0;
408 nNoneSpace = 0;
410 if (mpNoneItem.get())
411 mpNoneItem.reset(NULL);
414 // calculate ScrollBar width
415 long nScrBarWidth = 0;
416 if (mxScrollBar.get())
417 nScrBarWidth = mxScrollBar->GetSizePixel().Width() + SCRBAR_OFFSET;
419 // calculate number of columns
420 if (!mnUserCols)
422 if (mnUserItemWidth)
424 mnCols = static_cast<sal_uInt16>((aWinSize.Width() - nScrBarWidth + mnSpacing) / (mnUserItemWidth + mnSpacing));
425 if (mnCols <= 0)
426 mnCols = 1;
428 else
430 mnCols = 1;
433 else
435 mnCols = mnUserCols;
438 // calculate number of rows
439 mbScroll = false;
441 // Floor( (M+N-1)/N )==Ceiling( M/N )
442 mnLines = (static_cast<long>(nItemCount) + mnCols - 1) / mnCols;
443 if (mnLines <= 0)
444 mnLines = 1;
446 long nCalcHeight = aWinSize.Height() - nNoneHeight;
447 if (mnUserVisLines)
449 mnVisLines = mnUserVisLines;
451 else if (mnUserItemHeight)
453 mnVisLines = (nCalcHeight - nNoneSpace + mnSpacing) / (mnUserItemHeight + mnSpacing);
454 if (!mnVisLines)
455 mnVisLines = 1;
457 else
459 mnVisLines = mnLines;
462 if (mnLines > mnVisLines)
463 mbScroll = true;
465 if (mnLines <= mnVisLines)
467 mnFirstLine = 0;
469 else
471 if (mnFirstLine > static_cast<sal_uInt16>(mnLines - mnVisLines))
472 mnFirstLine = static_cast<sal_uInt16>(mnLines - mnVisLines);
475 // calculate item size
476 const long nColSpace = (mnCols - 1) * static_cast<long>(mnSpacing);
477 const long nLineSpace = ((mnVisLines - 1) * mnSpacing) + nNoneSpace;
478 if (mnUserItemWidth && !mnUserCols)
480 mnItemWidth = mnUserItemWidth;
481 if (mnItemWidth > aWinSize.Width() - nScrBarWidth - nColSpace)
482 mnItemWidth = aWinSize.Width() - nScrBarWidth - nColSpace;
484 else
485 mnItemWidth = (aWinSize.Width() - nScrBarWidth-nColSpace) / mnCols;
486 if (mnUserItemHeight && !mnUserVisLines)
488 mnItemHeight = mnUserItemHeight;
489 if (mnItemHeight > nCalcHeight - nNoneSpace)
490 mnItemHeight = nCalcHeight - nNoneSpace;
492 else
494 nCalcHeight -= nLineSpace;
495 mnItemHeight = nCalcHeight / mnVisLines;
498 // Init VirDev
499 maVirDev->SetSettings(rRenderContext.GetSettings());
500 maVirDev->SetBackground(rRenderContext.GetBackground());
501 maVirDev->SetOutputSizePixel(aWinSize, true);
503 // nothing is changed in case of too small items
504 if ((mnItemWidth <= 0) ||
505 (mnItemHeight <= ((nStyle & WB_ITEMBORDER) ? 4 : 2)) ||
506 !nItemCount)
508 mbHasVisibleItems = false;
510 if (nStyle & WB_NONEFIELD)
512 if (mpNoneItem.get())
514 mpNoneItem->mbVisible = false;
515 mpNoneItem->maText = GetText();
519 for (size_t i = 0; i < nItemCount; i++)
521 mItemList[i]->mbVisible = false;
524 if (mxScrollBar.get())
525 mxScrollBar->Hide();
527 else
529 mbHasVisibleItems = true;
531 // determine Frame-Style
532 if (nStyle & WB_DOUBLEBORDER)
533 mnFrameStyle = DrawFrameStyle::DoubleIn;
534 else
535 mnFrameStyle = DrawFrameStyle::In;
537 // determine selected color and width
538 // if necessary change the colors, to make the selection
539 // better detectable
540 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
541 Color aHighColor(rStyleSettings.GetHighlightColor());
542 if (((aHighColor.GetRed() > 0x80) || (aHighColor.GetGreen() > 0x80) ||
543 (aHighColor.GetBlue() > 0x80)) ||
544 ((aHighColor.GetRed() == 0x80) && (aHighColor.GetGreen() == 0x80) &&
545 (aHighColor.GetBlue() == 0x80)))
547 mbBlackSel = true;
549 else
551 mbBlackSel = false;
553 // draw the selection with double width if the items are bigger
554 if ((nStyle & WB_DOUBLEBORDER) &&
555 ((mnItemWidth >= 25) && (mnItemHeight >= 20)))
557 mbDoubleSel = true;
559 else
561 mbDoubleSel = false;
564 // calculate offsets
565 long nStartX;
566 long nStartY;
567 if (mbFullMode)
569 long nAllItemWidth = (mnItemWidth * mnCols) + nColSpace;
570 long nAllItemHeight = (mnItemHeight * mnVisLines) + nNoneHeight + nLineSpace;
571 nStartX = (aWinSize.Width() - nScrBarWidth - nAllItemWidth) / 2;
572 nStartY = (aWinSize.Height() - nAllItemHeight) / 2;
574 else
576 nStartX = 0;
577 nStartY = 0;
580 // calculate and draw items
581 maVirDev->SetLineColor();
582 long x = nStartX;
583 long y = nStartY;
585 // create NoSelection field and show it
586 if (nStyle & WB_NONEFIELD)
588 if (mpNoneItem.get() == NULL)
589 mpNoneItem.reset(new ValueSetItem(*this));
591 mpNoneItem->mnId = 0;
592 mpNoneItem->meType = VALUESETITEM_NONE;
593 mpNoneItem->mbVisible = true;
594 maNoneItemRect.Left() = x;
595 maNoneItemRect.Top() = y;
596 maNoneItemRect.Right() = maNoneItemRect.Left() + aWinSize.Width() - x - 1;
597 maNoneItemRect.Bottom() = y + nNoneHeight - 1;
599 ImplFormatItem(rRenderContext, mpNoneItem.get(), maNoneItemRect);
601 y += nNoneHeight + nNoneSpace;
604 // draw items
605 sal_uLong nFirstItem = static_cast<sal_uLong>(mnFirstLine) * mnCols;
606 sal_uLong nLastItem = nFirstItem + (mnVisLines * mnCols);
608 maItemListRect.Left() = x;
609 maItemListRect.Top() = y;
610 maItemListRect.Right() = x + mnCols * (mnItemWidth + mnSpacing) - mnSpacing - 1;
611 maItemListRect.Bottom() = y + mnVisLines * (mnItemHeight + mnSpacing) - mnSpacing - 1;
613 if (!mbFullMode)
615 // If want also draw parts of items in the last line,
616 // then we add one more line if parts of these line are
617 // visible
618 if (y + (mnVisLines * (mnItemHeight + mnSpacing)) < aWinSize.Height())
619 nLastItem += mnCols;
620 maItemListRect.Bottom() = aWinSize.Height() - y;
622 for (size_t i = 0; i < nItemCount; i++)
624 ValueSetItem* pItem = mItemList[i];
626 if (i >= nFirstItem && i < nLastItem)
628 if (!pItem->mbVisible && ImplHasAccessibleListeners())
630 Any aOldAny;
631 Any aNewAny;
633 aNewAny <<= pItem->GetAccessible(mbIsTransientChildrenDisabled);
634 ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny);
637 pItem->mbVisible = true;
638 ImplFormatItem(rRenderContext, pItem, Rectangle(Point(x, y), Size(mnItemWidth, mnItemHeight)));
640 if (!((i + 1) % mnCols))
642 x = nStartX;
643 y += mnItemHeight + mnSpacing;
645 else
646 x += mnItemWidth + mnSpacing;
648 else
650 if (pItem->mbVisible && ImplHasAccessibleListeners())
652 Any aOldAny;
653 Any aNewAny;
655 aOldAny <<= pItem->GetAccessible(mbIsTransientChildrenDisabled);
656 ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny);
659 pItem->mbVisible = false;
663 // arrange ScrollBar, set values and show it
664 if (mxScrollBar.get())
666 Point aPos(aWinSize.Width() - nScrBarWidth + SCRBAR_OFFSET, 0);
667 Size aSize(nScrBarWidth - SCRBAR_OFFSET, aWinSize.Height());
668 // If a none field is visible, then we center the scrollbar
669 if (nStyle & WB_NONEFIELD)
671 aPos.Y() = nStartY + nNoneHeight + 1;
672 aSize.Height() = ((mnItemHeight + mnSpacing) * mnVisLines) - 2 - mnSpacing;
674 mxScrollBar->SetPosSizePixel(aPos, aSize);
675 mxScrollBar->SetRangeMax(mnLines);
676 mxScrollBar->SetVisibleSize(mnVisLines);
677 mxScrollBar->SetThumbPos((long)mnFirstLine);
678 long nPageSize = mnVisLines;
679 if (nPageSize < 1)
680 nPageSize = 1;
681 mxScrollBar->SetPageSize(nPageSize);
682 mxScrollBar->Show();
686 // waiting for the next since the formatting is finished
687 mbFormat = false;
689 xDeletedScrollBar.disposeAndClear();
692 void ValueSet::ImplDrawItemText(vcl::RenderContext& rRenderContext, const OUString& rText)
694 if (!(GetStyle() & WB_NAMEFIELD))
695 return;
697 Size aWinSize(GetOutputSizePixel());
698 long nTxtWidth = rRenderContext.GetTextWidth(rText);
699 long nTxtOffset = mnTextOffset;
701 // delete rectangle and show text
702 if (GetStyle() & WB_FLATVALUESET)
704 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
705 rRenderContext.SetLineColor();
706 rRenderContext.SetFillColor(rStyleSettings.GetFaceColor());
707 rRenderContext.DrawRect(Rectangle(Point(0, nTxtOffset), Point(aWinSize.Width(), aWinSize.Height())));
708 rRenderContext.SetTextColor(rStyleSettings.GetButtonTextColor());
710 else
712 nTxtOffset += NAME_LINE_HEIGHT+NAME_LINE_OFF_Y;
713 rRenderContext.Erase(Rectangle(Point(0, nTxtOffset), Point(aWinSize.Width(), aWinSize.Height())));
715 rRenderContext.DrawText(Point((aWinSize.Width() - nTxtWidth) / 2, nTxtOffset + (NAME_OFFSET / 2)), rText);
718 void ValueSet::ImplDrawSelect(vcl::RenderContext& rRenderContext)
720 if (!IsReallyVisible())
721 return;
723 const bool bFocus = HasFocus();
724 const bool bDrawSel = !((mbNoSelection && !mbHighlight) || (!mbDrawSelection && mbHighlight));
726 if (!bFocus && !bDrawSel)
728 ImplDrawItemText(rRenderContext, OUString());
729 return;
732 ImplDrawSelect(rRenderContext, mnSelItemId, bFocus, bDrawSel);
733 if (mbHighlight)
735 ImplDrawSelect(rRenderContext, mnHighItemId, bFocus, bDrawSel);
739 void ValueSet::ImplDrawSelect(vcl::RenderContext& rRenderContext, sal_uInt16 nItemId, const bool bFocus, const bool bDrawSel )
741 ValueSetItem* pItem;
742 Rectangle aRect;
743 if (nItemId)
745 const size_t nPos = GetItemPos( nItemId );
746 pItem = mItemList[ nPos ];
747 aRect = ImplGetItemRect( nPos );
749 else if (mpNoneItem.get())
751 pItem = mpNoneItem.get();
752 aRect = maNoneItemRect;
754 else if (bFocus && (pItem = ImplGetFirstItem()))
756 aRect = ImplGetItemRect(0);
758 else
760 return;
763 if (pItem->mbVisible)
765 // draw selection
766 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
767 rRenderContext.SetFillColor();
769 Color aDoubleColor(rStyleSettings.GetHighlightColor());
770 Color aSingleColor(rStyleSettings.GetHighlightTextColor());
771 if (!mbDoubleSel)
774 * #99777# contrast enhancement for thin mode
776 const Wallpaper& rWall = GetDisplayBackground();
777 if (!rWall.IsBitmap() && ! rWall.IsGradient())
779 const Color& rBack = rWall.GetColor();
780 if (rBack.IsDark() && ! aDoubleColor.IsBright())
782 aDoubleColor = Color(COL_WHITE);
783 aSingleColor = Color(COL_BLACK);
785 else if (rBack.IsBright() && ! aDoubleColor.IsDark())
787 aDoubleColor = Color(COL_BLACK);
788 aSingleColor = Color(COL_WHITE);
793 // specify selection output
794 WinBits nStyle = GetStyle();
795 if (nStyle & WB_MENUSTYLEVALUESET)
797 if (bFocus)
798 ShowFocus(aRect);
800 if (bDrawSel)
802 rRenderContext.SetLineColor(mbBlackSel ? Color(COL_BLACK) : aDoubleColor);
803 rRenderContext.DrawRect(aRect);
806 else if (nStyle & WB_RADIOSEL)
808 aRect.Left() += 3;
809 aRect.Top() += 3;
810 aRect.Right() -= 3;
811 aRect.Bottom() -= 3;
812 if (nStyle & WB_DOUBLEBORDER)
814 aRect.Left()++;
815 aRect.Top()++;
816 aRect.Right()--;
817 aRect.Bottom()--;
820 if (bFocus)
821 ShowFocus(aRect);
823 aRect.Left()++;
824 aRect.Top()++;
825 aRect.Right()--;
826 aRect.Bottom()--;
828 if (bDrawSel)
830 rRenderContext.SetLineColor(aDoubleColor);
831 aRect.Left()++;
832 aRect.Top()++;
833 aRect.Right()--;
834 aRect.Bottom()--;
835 rRenderContext.DrawRect(aRect);
836 aRect.Left()++;
837 aRect.Top()++;
838 aRect.Right()--;
839 aRect.Bottom()--;
840 rRenderContext.DrawRect(aRect);
843 else
845 if (bDrawSel)
847 rRenderContext.SetLineColor(mbBlackSel ? Color(COL_BLACK) : aDoubleColor);
848 rRenderContext.DrawRect(aRect);
850 if (mbDoubleSel)
852 aRect.Left()++;
853 aRect.Top()++;
854 aRect.Right()--;
855 aRect.Bottom()--;
856 if (bDrawSel)
857 rRenderContext.DrawRect(aRect);
859 aRect.Left()++;
860 aRect.Top()++;
861 aRect.Right()--;
862 aRect.Bottom()--;
863 Rectangle aRect2 = aRect;
864 aRect.Left()++;
865 aRect.Top()++;
866 aRect.Right()--;
867 aRect.Bottom()--;
868 if (bDrawSel)
869 rRenderContext.DrawRect(aRect);
870 if (mbDoubleSel)
872 aRect.Left()++;
873 aRect.Top()++;
874 aRect.Right()--;
875 aRect.Bottom()--;
876 if (bDrawSel)
877 rRenderContext.DrawRect(aRect);
880 if (bDrawSel)
882 rRenderContext.SetLineColor(mbBlackSel ? Color(COL_WHITE) : aSingleColor);
884 else
886 rRenderContext.SetLineColor(Color(COL_LIGHTGRAY));
888 rRenderContext.DrawRect(aRect2);
890 if (bFocus)
891 ShowFocus(aRect2);
894 ImplDrawItemText(rRenderContext, pItem->maText);
898 void ValueSet::ImplHideSelect( sal_uInt16 nItemId )
900 Rectangle aRect;
902 const size_t nItemPos = GetItemPos( nItemId );
903 if ( nItemPos != VALUESET_ITEM_NOTFOUND )
905 if ( !mItemList[nItemPos]->mbVisible )
907 return;
909 aRect = ImplGetItemRect(nItemPos);
911 else
913 if (mpNoneItem.get() == NULL)
915 return;
917 aRect = maNoneItemRect;
920 HideFocus();
921 const Point aPos = aRect.TopLeft();
922 const Size aSize = aRect.GetSize();
923 DrawOutDev( aPos, aSize, aPos, aSize, *maVirDev.get() );
926 void ValueSet::ImplHighlightItem( sal_uInt16 nItemId, bool bIsSelection )
928 if ( mnHighItemId != nItemId )
930 // remember the old item to delete the previous selection
931 sal_uInt16 nOldItem = mnHighItemId;
932 mnHighItemId = nItemId;
934 // don't draw the selection if nothing is selected
935 if ( !bIsSelection && mbNoSelection )
936 mbDrawSelection = false;
938 // remove the old selection and draw the new one
939 ImplHideSelect( nOldItem );
940 Invalidate();
941 mbDrawSelection = true;
945 void ValueSet::ImplDraw(vcl::RenderContext& rRenderContext)
947 if (mbFormat)
948 Format(rRenderContext);
950 HideFocus();
952 Point aDefPos;
953 Size aSize = maVirDev->GetOutputSizePixel();
955 if (mxScrollBar.get() && mxScrollBar->IsVisible())
957 Point aScrPos = mxScrollBar->GetPosPixel();
958 Size aScrSize = mxScrollBar->GetSizePixel();
959 Point aTempPos(0, aScrPos.Y());
960 Size aTempSize(aSize.Width(), aScrPos.Y());
962 rRenderContext.DrawOutDev(aDefPos, aTempSize, aDefPos, aTempSize, *maVirDev.get());
963 aTempSize.Width() = aScrPos.X() - 1;
964 aTempSize.Height() = aScrSize.Height();
965 rRenderContext.DrawOutDev(aTempPos, aTempSize, aTempPos, aTempSize, *maVirDev.get());
966 aTempPos.Y() = aScrPos.Y() + aScrSize.Height();
967 aTempSize.Width() = aSize.Width();
968 aTempSize.Height() = aSize.Height() - aTempPos.Y();
969 rRenderContext.DrawOutDev(aTempPos, aTempSize, aTempPos, aTempSize, *maVirDev.get());
971 else
972 rRenderContext.DrawOutDev(aDefPos, aSize, aDefPos, aSize, *maVirDev.get());
974 // draw parting line to the Namefield
975 if (GetStyle() & WB_NAMEFIELD)
977 if (!(GetStyle() & WB_FLATVALUESET))
979 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
980 Size aWinSize(GetOutputSizePixel());
981 Point aPos1(NAME_LINE_OFF_X, mnTextOffset + NAME_LINE_OFF_Y);
982 Point aPos2(aWinSize.Width() - (NAME_LINE_OFF_X * 2), mnTextOffset + NAME_LINE_OFF_Y);
983 if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
985 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
986 rRenderContext.DrawLine(aPos1, aPos2);
987 aPos1.Y()++;
988 aPos2.Y()++;
989 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
991 else
992 rRenderContext.SetLineColor(rStyleSettings.GetWindowTextColor());
993 rRenderContext.DrawLine(aPos1, aPos2);
997 ImplDrawSelect(rRenderContext);
1000 bool ValueSet::ImplScroll(const Point& rPos)
1002 if (!mbScroll || !maItemListRect.IsInside(rPos))
1003 return false;
1005 const long nScrollOffset = (mnItemHeight <= 16) ? SCROLL_OFFSET / 2 : SCROLL_OFFSET;
1006 bool bScroll = false;
1008 if (rPos.Y() <= maItemListRect.Top() + nScrollOffset)
1010 if (mnFirstLine > 0)
1012 --mnFirstLine;
1013 bScroll = true;
1016 else if (rPos.Y() >= maItemListRect.Bottom() - nScrollOffset)
1018 if (mnFirstLine < static_cast<sal_uInt16>(mnLines - mnVisLines))
1020 ++mnFirstLine;
1021 bScroll = true;
1025 if (!bScroll)
1026 return false;
1028 mbFormat = true;
1029 Invalidate();
1030 return true;
1033 size_t ValueSet::ImplGetItem( const Point& rPos, bool bMove ) const
1035 if (!mbHasVisibleItems)
1037 return VALUESET_ITEM_NOTFOUND;
1040 if (mpNoneItem.get() && maNoneItemRect.IsInside(rPos))
1042 return VALUESET_ITEM_NONEITEM;
1045 if (maItemListRect.IsInside(rPos))
1047 const int xc = rPos.X() - maItemListRect.Left();
1048 const int yc = rPos.Y() - maItemListRect.Top();
1049 // The point is inside the area of item list,
1050 // let's find the containing item.
1051 const int col = xc / (mnItemWidth + mnSpacing);
1052 const int x = xc % (mnItemWidth + mnSpacing);
1053 const int row = yc / (mnItemHeight + mnSpacing);
1054 const int y = yc % (mnItemHeight + mnSpacing);
1056 if (x < mnItemWidth && y < mnItemHeight)
1058 // the point is inside item rect and not inside spacing
1059 const size_t item = (mnFirstLine + row) * static_cast<size_t>(mnCols) + col;
1060 if (item < mItemList.size())
1062 return item;
1066 // return the previously selected item if spacing is set and
1067 // the mouse hasn't left the window yet
1068 if (bMove && mnSpacing && mnHighItemId)
1070 return GetItemPos( mnHighItemId );
1074 return VALUESET_ITEM_NOTFOUND;
1077 ValueSetItem* ValueSet::ImplGetItem( size_t nPos )
1079 if (nPos == VALUESET_ITEM_NONEITEM)
1080 return mpNoneItem.get();
1081 else
1082 return (nPos < mItemList.size()) ? mItemList[nPos] : NULL;
1085 ValueSetItem* ValueSet::ImplGetFirstItem()
1087 return mItemList.size() ? mItemList[0] : NULL;
1090 sal_uInt16 ValueSet::ImplGetVisibleItemCount() const
1092 sal_uInt16 nRet = 0;
1093 const size_t nItemCount = mItemList.size();
1095 for ( size_t n = 0; n < nItemCount; ++n )
1097 if ( mItemList[n]->mbVisible )
1098 ++nRet;
1101 return nRet;
1104 void ValueSet::ImplFireAccessibleEvent( short nEventId, const Any& rOldValue, const Any& rNewValue )
1106 ValueSetAcc* pAcc = ValueSetAcc::getImplementation( GetAccessible( false ) );
1108 if( pAcc )
1109 pAcc->FireAccessibleEvent( nEventId, rOldValue, rNewValue );
1112 bool ValueSet::ImplHasAccessibleListeners()
1114 ValueSetAcc* pAcc = ValueSetAcc::getImplementation( GetAccessible( false ) );
1115 return( pAcc && pAcc->HasAccessibleListeners() );
1118 IMPL_LINK( ValueSet,ImplScrollHdl, ScrollBar*, pScrollBar )
1120 sal_uInt16 nNewFirstLine = (sal_uInt16)pScrollBar->GetThumbPos();
1121 if ( nNewFirstLine != mnFirstLine )
1123 mnFirstLine = nNewFirstLine;
1124 mbFormat = true;
1125 Invalidate();
1127 return 0;
1130 IMPL_LINK_NOARG_TYPED(ValueSet, ImplTimerHdl, Timer *, void)
1132 ImplTracking( GetPointerPosPixel(), true );
1135 void ValueSet::ImplTracking( const Point& rPos, bool bRepeat )
1137 if ( bRepeat || mbSelection )
1139 if ( ImplScroll( rPos ) )
1141 if ( mbSelection )
1143 maTimer.SetTimeoutHdl( LINK( this, ValueSet, ImplTimerHdl ) );
1144 maTimer.SetTimeout( GetSettings().GetMouseSettings().GetScrollRepeat() );
1145 maTimer.Start();
1150 ValueSetItem* pItem = ImplGetItem( ImplGetItem( rPos ) );
1151 if ( pItem )
1153 if( GetStyle() & WB_MENUSTYLEVALUESET )
1154 mbHighlight = true;
1156 ImplHighlightItem( pItem->mnId );
1158 else
1160 if( GetStyle() & WB_MENUSTYLEVALUESET )
1161 mbHighlight = true;
1163 ImplHighlightItem( mnSelItemId, false );
1167 void ValueSet::ImplEndTracking( const Point& rPos, bool bCancel )
1169 ValueSetItem* pItem;
1171 // restore the old status in case of termination
1172 if ( bCancel )
1173 pItem = NULL;
1174 else
1175 pItem = ImplGetItem( ImplGetItem( rPos ) );
1177 if ( pItem )
1179 SelectItem( pItem->mnId );
1180 if ( !mbSelection && !(GetStyle() & WB_NOPOINTERFOCUS) )
1181 GrabFocus();
1182 mbHighlight = false;
1183 mbSelection = false;
1184 Select();
1186 else
1188 ImplHighlightItem( mnSelItemId, false );
1189 mbHighlight = false;
1190 mbSelection = false;
1194 void ValueSet::MouseButtonDown( const MouseEvent& rMouseEvent )
1196 if ( rMouseEvent.IsLeft() )
1198 ValueSetItem* pItem = ImplGetItem( ImplGetItem( rMouseEvent.GetPosPixel() ) );
1199 if ( mbSelection )
1201 mbHighlight = true;
1202 if ( pItem )
1204 mnHighItemId = mnSelItemId;
1205 ImplHighlightItem( pItem->mnId );
1208 return;
1210 else
1212 if ( pItem && !rMouseEvent.IsMod2() )
1214 if ( rMouseEvent.GetClicks() == 1 )
1216 mbHighlight = true;
1217 mnHighItemId = mnSelItemId;
1218 ImplHighlightItem( pItem->mnId );
1219 StartTracking( STARTTRACK_SCROLLREPEAT );
1221 else if ( rMouseEvent.GetClicks() == 2 )
1222 DoubleClick();
1224 return;
1229 Control::MouseButtonDown( rMouseEvent );
1232 void ValueSet::MouseButtonUp( const MouseEvent& rMouseEvent )
1234 // because of SelectionMode
1235 if ( rMouseEvent.IsLeft() && mbSelection )
1236 ImplEndTracking( rMouseEvent.GetPosPixel(), false );
1237 else
1238 Control::MouseButtonUp( rMouseEvent );
1241 void ValueSet::MouseMove( const MouseEvent& rMouseEvent )
1243 // because of SelectionMode
1244 if ( mbSelection || (GetStyle() & WB_MENUSTYLEVALUESET) )
1245 ImplTracking( rMouseEvent.GetPosPixel(), false );
1246 Control::MouseMove( rMouseEvent );
1249 void ValueSet::Tracking( const TrackingEvent& rTrackingEvent )
1251 Point aMousePos = rTrackingEvent.GetMouseEvent().GetPosPixel();
1253 if ( rTrackingEvent.IsTrackingEnded() )
1254 ImplEndTracking( aMousePos, rTrackingEvent.IsTrackingCanceled() );
1255 else
1256 ImplTracking( aMousePos, rTrackingEvent.IsTrackingRepeat() );
1259 void ValueSet::KeyInput( const KeyEvent& rKeyEvent )
1261 size_t nLastItem = mItemList.size();
1263 if ( !nLastItem || !ImplGetFirstItem() )
1265 Control::KeyInput( rKeyEvent );
1266 return;
1269 if (mbFormat)
1270 Invalidate();
1272 --nLastItem;
1274 const size_t nCurPos = mnSelItemId ? GetItemPos(mnSelItemId)
1275 : (mpNoneItem.get() ? VALUESET_ITEM_NONEITEM : 0);
1276 size_t nItemPos = VALUESET_ITEM_NOTFOUND;
1277 size_t nVStep = mnCols;
1279 switch (rKeyEvent.GetKeyCode().GetCode())
1281 case KEY_HOME:
1282 nItemPos = mpNoneItem.get() ? VALUESET_ITEM_NONEITEM : 0;
1283 break;
1285 case KEY_END:
1286 nItemPos = nLastItem;
1287 break;
1289 case KEY_LEFT:
1290 if (nCurPos != VALUESET_ITEM_NONEITEM)
1292 if (nCurPos)
1294 nItemPos = nCurPos-1;
1296 else if (mpNoneItem.get())
1298 nItemPos = VALUESET_ITEM_NONEITEM;
1301 break;
1303 case KEY_RIGHT:
1304 if (nCurPos < nLastItem)
1306 if (nCurPos == VALUESET_ITEM_NONEITEM)
1308 nItemPos = 0;
1310 else
1312 nItemPos = nCurPos+1;
1315 break;
1317 case KEY_PAGEUP:
1318 if (rKeyEvent.GetKeyCode().IsShift() || rKeyEvent.GetKeyCode().IsMod1() || rKeyEvent.GetKeyCode().IsMod2())
1320 Control::KeyInput( rKeyEvent );
1321 return;
1323 nVStep *= mnVisLines;
1324 // intentional fall-through
1325 case KEY_UP:
1326 if (nCurPos != VALUESET_ITEM_NONEITEM)
1328 if (nCurPos == nLastItem)
1330 const size_t nCol = mnCols ? nLastItem % mnCols : 0;
1331 if (nCol < mnCurCol)
1333 // Move to previous row/page, keeping the old column
1334 nVStep -= mnCurCol - nCol;
1337 if (nCurPos >= nVStep)
1339 // Go up of a whole page
1340 nItemPos = nCurPos-nVStep;
1342 else if (mpNoneItem.get())
1344 nItemPos = VALUESET_ITEM_NONEITEM;
1346 else if (nCurPos > mnCols)
1348 // Go to same column in first row
1349 nItemPos = nCurPos % mnCols;
1352 break;
1354 case KEY_PAGEDOWN:
1355 if (rKeyEvent.GetKeyCode().IsShift() || rKeyEvent.GetKeyCode().IsMod1() || rKeyEvent.GetKeyCode().IsMod2())
1357 Control::KeyInput( rKeyEvent );
1358 return;
1360 nVStep *= mnVisLines;
1361 // intentional fall-through
1362 case KEY_DOWN:
1363 if (nCurPos != nLastItem)
1365 if (nCurPos == VALUESET_ITEM_NONEITEM)
1367 nItemPos = nVStep-mnCols+mnCurCol;
1369 else
1371 nItemPos = nCurPos+nVStep;
1373 if (nItemPos > nLastItem)
1375 nItemPos = nLastItem;
1378 break;
1380 case KEY_RETURN:
1381 if (GetStyle() & WB_NO_DIRECTSELECT)
1383 Select();
1384 break;
1386 // intentional fall-through
1387 default:
1388 Control::KeyInput( rKeyEvent );
1389 return;
1392 // This point is reached only if key travelling was used,
1393 // in which case selection mode should be switched off
1394 EndSelection();
1396 if ( nItemPos != VALUESET_ITEM_NOTFOUND )
1398 if ( nItemPos!=VALUESET_ITEM_NONEITEM && nItemPos<nLastItem )
1400 // update current column only in case of a new position
1401 // which is also not a "specially" handled one.
1402 mnCurCol = mnCols ? nItemPos % mnCols : 0;
1404 const sal_uInt16 nItemId = (nItemPos != VALUESET_ITEM_NONEITEM) ? GetItemId( nItemPos ) : 0;
1405 if ( nItemId != mnSelItemId )
1407 SelectItem( nItemId );
1408 if (!(GetStyle() & WB_NO_DIRECTSELECT))
1410 // select only if WB_NO_DIRECTSELECT is not set
1411 Select();
1417 void ValueSet::Command( const CommandEvent& rCommandEvent )
1419 if ( rCommandEvent.GetCommand() == CommandEventId::Wheel ||
1420 rCommandEvent.GetCommand() == CommandEventId::StartAutoScroll ||
1421 rCommandEvent.GetCommand() == CommandEventId::AutoScroll )
1423 if ( HandleScrollCommand( rCommandEvent, NULL, mxScrollBar.get() ) )
1424 return;
1427 Control::Command( rCommandEvent );
1430 void ValueSet::Paint(vcl::RenderContext& rRenderContext, const Rectangle&)
1432 if (GetStyle() & WB_FLATVALUESET)
1434 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1435 rRenderContext.SetLineColor();
1436 rRenderContext.SetFillColor(rStyleSettings.GetFaceColor());
1437 long nOffY = maVirDev->GetOutputSizePixel().Height();
1438 Size aWinSize(GetOutputSizePixel());
1439 rRenderContext.DrawRect(Rectangle(Point(0, nOffY ), Point( aWinSize.Width(), aWinSize.Height())));
1442 ImplDraw(rRenderContext);
1445 void ValueSet::GetFocus()
1447 OSL_TRACE ("value set getting focus");
1448 Invalidate();
1449 Control::GetFocus();
1451 // Tell the accessible object that we got the focus.
1452 ValueSetAcc* pAcc = ValueSetAcc::getImplementation(GetAccessible(false));
1453 if (pAcc)
1454 pAcc->GetFocus();
1457 void ValueSet::LoseFocus()
1459 OSL_TRACE ("value set losing focus");
1460 if ( mbNoSelection && mnSelItemId )
1461 ImplHideSelect( mnSelItemId );
1462 else
1463 HideFocus();
1464 Control::LoseFocus();
1466 // Tell the accessible object that we lost the focus.
1467 ValueSetAcc* pAcc = ValueSetAcc::getImplementation( GetAccessible( false ) );
1468 if( pAcc )
1469 pAcc->LoseFocus();
1472 void ValueSet::Resize()
1474 mbFormat = true;
1475 if ( IsReallyVisible() && IsUpdateMode() )
1476 Invalidate();
1477 Control::Resize();
1480 void ValueSet::RequestHelp( const HelpEvent& rHelpEvent )
1482 if ( (rHelpEvent.GetMode() & (HelpEventMode::QUICK | HelpEventMode::BALLOON)) == HelpEventMode::QUICK )
1484 Point aPos = ScreenToOutputPixel( rHelpEvent.GetMousePosPixel() );
1485 size_t nItemPos = ImplGetItem( aPos );
1486 if ( nItemPos != VALUESET_ITEM_NOTFOUND )
1488 Rectangle aItemRect = ImplGetItemRect( nItemPos );
1489 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1490 aItemRect.Left() = aPt.X();
1491 aItemRect.Top() = aPt.Y();
1492 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1493 aItemRect.Right() = aPt.X();
1494 aItemRect.Bottom() = aPt.Y();
1495 Help::ShowQuickHelp( this, aItemRect, GetItemText( ImplGetItem( nItemPos )->mnId ) );
1496 return;
1500 Control::RequestHelp( rHelpEvent );
1503 void ValueSet::StateChanged(StateChangedType nType)
1505 Control::StateChanged(nType);
1507 if (nType == StateChangedType::InitShow)
1509 if (mbFormat)
1510 Invalidate();
1512 else if (nType == StateChangedType::UpdateMode)
1514 if (IsReallyVisible() && IsUpdateMode())
1515 Invalidate();
1517 else if (nType == StateChangedType::Text)
1519 if (mpNoneItem.get() && !mbFormat && IsReallyVisible() && IsUpdateMode())
1521 Invalidate(maNoneItemRect);
1524 else if ((nType == StateChangedType::Zoom) ||
1525 (nType == StateChangedType::ControlFont))
1527 ImplInitSettings(true, false, false);
1528 Invalidate();
1530 else if (nType == StateChangedType::ControlForeground)
1532 ImplInitSettings(false, true, false);
1533 Invalidate();
1535 else if (nType == StateChangedType::ControlBackground)
1537 ImplInitSettings(false, false, true);
1538 Invalidate();
1540 else if ((nType == StateChangedType::Style) || (nType == StateChangedType::Enable))
1542 mbFormat = true;
1543 ImplInitSettings(false, false, true);
1544 Invalidate();
1548 void ValueSet::DataChanged( const DataChangedEvent& rDataChangedEvent )
1550 Control::DataChanged( rDataChangedEvent );
1552 if ( rDataChangedEvent.GetType() == DataChangedEventType::FONTS ||
1553 rDataChangedEvent.GetType() == DataChangedEventType::DISPLAY ||
1554 rDataChangedEvent.GetType() == DataChangedEventType::FONTSUBSTITUTION ||
1555 (rDataChangedEvent.GetType() == DataChangedEventType::SETTINGS &&
1556 rDataChangedEvent.GetFlags() & AllSettingsFlags::STYLE) )
1558 mbFormat = true;
1559 ImplInitSettings( true, true, true );
1560 Invalidate();
1564 void ValueSet::Select()
1566 maSelectHdl.Call( this );
1569 void ValueSet::DoubleClick()
1571 maDoubleClickHdl.Call( this );
1574 void ValueSet::UserDraw( const UserDrawEvent& )
1578 void ValueSet::InsertItem( sal_uInt16 nItemId, const Image& rImage, size_t nPos )
1580 ValueSetItem* pItem = new ValueSetItem( *this );
1581 pItem->mnId = nItemId;
1582 pItem->meType = VALUESETITEM_IMAGE;
1583 pItem->maImage = rImage;
1584 ImplInsertItem( pItem, nPos );
1587 void ValueSet::InsertItem( sal_uInt16 nItemId, const Image& rImage,
1588 const OUString& rText, size_t nPos )
1590 ValueSetItem* pItem = new ValueSetItem( *this );
1591 pItem->mnId = nItemId;
1592 pItem->meType = VALUESETITEM_IMAGE;
1593 pItem->maImage = rImage;
1594 pItem->maText = rText;
1595 ImplInsertItem( pItem, nPos );
1598 void ValueSet::InsertItem( sal_uInt16 nItemId, const Color& rColor,
1599 const OUString& rText, size_t nPos )
1601 ValueSetItem* pItem = new ValueSetItem( *this );
1602 pItem->mnId = nItemId;
1603 pItem->meType = VALUESETITEM_COLOR;
1604 pItem->maColor = rColor;
1605 pItem->maText = rText;
1606 ImplInsertItem( pItem, nPos );
1609 void ValueSet::InsertItem( sal_uInt16 nItemId, size_t nPos )
1611 ValueSetItem* pItem = new ValueSetItem( *this );
1612 pItem->mnId = nItemId;
1613 pItem->meType = VALUESETITEM_USERDRAW;
1614 ImplInsertItem( pItem, nPos );
1617 void ValueSet::ImplInsertItem( ValueSetItem *const pItem, const size_t nPos )
1619 DBG_ASSERT( pItem->mnId, "ValueSet::InsertItem(): ItemId == 0" );
1620 DBG_ASSERT( GetItemPos( pItem->mnId ) == VALUESET_ITEM_NOTFOUND,
1621 "ValueSet::InsertItem(): ItemId already exists" );
1623 if ( nPos < mItemList.size() ) {
1624 ValueItemList::iterator it = mItemList.begin();
1625 ::std::advance( it, nPos );
1626 mItemList.insert( it, pItem );
1627 } else {
1628 mItemList.push_back( pItem );
1631 queue_resize();
1633 mbFormat = true;
1634 if ( IsReallyVisible() && IsUpdateMode() )
1635 Invalidate();
1638 Rectangle ValueSet::ImplGetItemRect( size_t nPos ) const
1640 const size_t nVisibleBegin = static_cast<size_t>(mnFirstLine)*mnCols;
1641 const size_t nVisibleEnd = nVisibleBegin + static_cast<size_t>(mnVisLines)*mnCols;
1643 // Check if the item is inside the range of the displayed ones,
1644 // taking into account that last row could be incomplete
1645 if ( nPos<nVisibleBegin || nPos>=nVisibleEnd || nPos>=mItemList.size() )
1646 return Rectangle();
1648 nPos -= nVisibleBegin;
1650 const size_t row = mnCols ? nPos/mnCols : 0;
1651 const size_t col = mnCols ? nPos%mnCols : 0;
1652 const long x = maItemListRect.Left()+col*(mnItemWidth+mnSpacing);
1653 const long y = maItemListRect.Top()+row*(mnItemHeight+mnSpacing);
1655 return Rectangle( Point(x, y), Size(mnItemWidth, mnItemHeight) );
1658 void ValueSet::RemoveItem( sal_uInt16 nItemId )
1660 size_t nPos = GetItemPos( nItemId );
1662 if ( nPos == VALUESET_ITEM_NOTFOUND )
1663 return;
1665 if ( nPos < mItemList.size() ) {
1666 ValueItemList::iterator it = mItemList.begin();
1667 ::std::advance( it, nPos );
1668 delete *it;
1669 mItemList.erase( it );
1672 // reset variables
1673 if ( (mnHighItemId == nItemId) || (mnSelItemId == nItemId) )
1675 mnCurCol = 0;
1676 mnHighItemId = 0;
1677 mnSelItemId = 0;
1678 mbNoSelection = true;
1681 queue_resize();
1683 mbFormat = true;
1684 if ( IsReallyVisible() && IsUpdateMode() )
1685 Invalidate();
1688 void ValueSet::Clear()
1690 ImplDeleteItems();
1692 // reset variables
1693 mnFirstLine = 0;
1694 mnCurCol = 0;
1695 mnHighItemId = 0;
1696 mnSelItemId = 0;
1697 mbNoSelection = true;
1699 mbFormat = true;
1700 if ( IsReallyVisible() && IsUpdateMode() )
1701 Invalidate();
1704 size_t ValueSet::GetItemCount() const
1706 return mItemList.size();
1709 size_t ValueSet::GetItemPos( sal_uInt16 nItemId ) const
1711 for ( size_t i = 0, n = mItemList.size(); i < n; ++i ) {
1712 if ( mItemList[i]->mnId == nItemId ) {
1713 return i;
1716 return VALUESET_ITEM_NOTFOUND;
1719 sal_uInt16 ValueSet::GetItemId( size_t nPos ) const
1721 return ( nPos < mItemList.size() ) ? mItemList[nPos]->mnId : 0 ;
1724 sal_uInt16 ValueSet::GetItemId( const Point& rPos ) const
1726 size_t nItemPos = ImplGetItem( rPos );
1727 if ( nItemPos != VALUESET_ITEM_NOTFOUND )
1728 return GetItemId( nItemPos );
1730 return 0;
1733 Rectangle ValueSet::GetItemRect( sal_uInt16 nItemId ) const
1735 const size_t nPos = GetItemPos( nItemId );
1737 if ( nPos!=VALUESET_ITEM_NOTFOUND && mItemList[nPos]->mbVisible )
1738 return ImplGetItemRect( nPos );
1740 return Rectangle();
1743 void ValueSet::EnableFullItemMode( bool bFullMode )
1745 mbFullMode = bFullMode;
1748 void ValueSet::SetColCount( sal_uInt16 nNewCols )
1750 if ( mnUserCols != nNewCols )
1752 mnUserCols = nNewCols;
1753 mbFormat = true;
1754 queue_resize();
1755 if ( IsReallyVisible() && IsUpdateMode() )
1756 Invalidate();
1760 void ValueSet::SetLineCount( sal_uInt16 nNewLines )
1762 if ( mnUserVisLines != nNewLines )
1764 mnUserVisLines = nNewLines;
1765 mbFormat = true;
1766 queue_resize();
1767 if ( IsReallyVisible() && IsUpdateMode() )
1768 Invalidate();
1772 void ValueSet::SetItemWidth( long nNewItemWidth )
1774 if ( mnUserItemWidth != nNewItemWidth )
1776 mnUserItemWidth = nNewItemWidth;
1777 mbFormat = true;
1778 queue_resize();
1779 if ( IsReallyVisible() && IsUpdateMode() )
1780 Invalidate();
1784 //method to set accessible when the style is user draw.
1785 void ValueSet::InsertItem( sal_uInt16 nItemId, const OUString& rText, size_t nPos )
1787 DBG_ASSERT( nItemId, "ValueSet::InsertItem(): ItemId == 0" );
1788 DBG_ASSERT( GetItemPos( nItemId ) == VALUESET_ITEM_NOTFOUND,
1789 "ValueSet::InsertItem(): ItemId already exists" );
1790 ValueSetItem* pItem = new ValueSetItem( *this );
1791 pItem->mnId = nItemId;
1792 pItem->meType = VALUESETITEM_USERDRAW;
1793 pItem->maText = rText;
1794 ImplInsertItem( pItem, nPos );
1797 void ValueSet::SetItemHeight( long nNewItemHeight )
1799 if ( mnUserItemHeight != nNewItemHeight )
1801 mnUserItemHeight = nNewItemHeight;
1802 mbFormat = true;
1803 queue_resize();
1804 if ( IsReallyVisible() && IsUpdateMode() )
1805 Invalidate();
1809 void ValueSet::SelectItem( sal_uInt16 nItemId )
1811 size_t nItemPos = 0;
1813 if ( nItemId )
1815 nItemPos = GetItemPos( nItemId );
1816 if ( nItemPos == VALUESET_ITEM_NOTFOUND )
1817 return;
1820 if ( (mnSelItemId != nItemId) || mbNoSelection )
1822 sal_uInt16 nOldItem = mnSelItemId ? mnSelItemId : 1;
1823 mnSelItemId = nItemId;
1824 mbNoSelection = false;
1826 bool bNewOut = !mbFormat && IsReallyVisible() && IsUpdateMode();
1827 bool bNewLine = false;
1829 // if necessary scroll to the visible area
1830 if (mbScroll && nItemId && mnCols)
1832 sal_uInt16 nNewLine = (sal_uInt16)(nItemPos / mnCols);
1833 if ( nNewLine < mnFirstLine )
1835 mnFirstLine = nNewLine;
1836 bNewLine = true;
1838 else if ( nNewLine > (sal_uInt16)(mnFirstLine+mnVisLines-1) )
1840 mnFirstLine = (sal_uInt16)(nNewLine-mnVisLines+1);
1841 bNewLine = true;
1845 if ( bNewOut )
1847 if ( bNewLine )
1849 // redraw everything if the visible area has changed
1850 mbFormat = true;
1851 Invalidate();
1853 else
1855 // remove old selection and draw the new one
1856 ImplHideSelect( nOldItem );
1857 Invalidate();
1861 if( ImplHasAccessibleListeners() )
1863 // focus event (deselect)
1864 if( nOldItem )
1866 const size_t nPos = GetItemPos( nItemId );
1868 if( nPos != VALUESET_ITEM_NOTFOUND )
1870 ValueItemAcc* pItemAcc = ValueItemAcc::getImplementation(
1871 mItemList[nPos]->GetAccessible( mbIsTransientChildrenDisabled ) );
1873 if( pItemAcc )
1875 Any aOldAny;
1876 Any aNewAny;
1877 if( !mbIsTransientChildrenDisabled )
1879 aOldAny <<= Reference<XInterface>(static_cast<cppu::OWeakObject*>(pItemAcc));
1880 ImplFireAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny );
1882 else
1884 aOldAny <<= AccessibleStateType::FOCUSED;
1885 pItemAcc->FireAccessibleEvent(AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny);
1891 // focus event (select)
1892 const size_t nPos = GetItemPos( mnSelItemId );
1894 ValueSetItem* pItem;
1895 if( nPos != VALUESET_ITEM_NOTFOUND )
1896 pItem = mItemList[nPos];
1897 else
1898 pItem = mpNoneItem.get();
1900 ValueItemAcc* pItemAcc = NULL;
1901 if (pItem != NULL)
1902 pItemAcc = ValueItemAcc::getImplementation( pItem->GetAccessible( mbIsTransientChildrenDisabled ) );
1904 if( pItemAcc )
1906 Any aOldAny;
1907 Any aNewAny;
1908 if( !mbIsTransientChildrenDisabled )
1910 aNewAny <<= Reference<XInterface>(static_cast<cppu::OWeakObject*>(pItemAcc));
1911 ImplFireAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny);
1913 else
1915 aNewAny <<= AccessibleStateType::FOCUSED;
1916 pItemAcc->FireAccessibleEvent(AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny);
1920 // selection event
1921 Any aOldAny;
1922 Any aNewAny;
1923 ImplFireAccessibleEvent(AccessibleEventId::SELECTION_CHANGED, aOldAny, aNewAny);
1925 maHighlightHdl.Call(this);
1929 void ValueSet::SetNoSelection()
1931 mbNoSelection = true;
1932 mbHighlight = false;
1933 mbSelection = false;
1935 if (IsReallyVisible() && IsUpdateMode())
1936 Invalidate();
1939 void ValueSet::SetItemImage( sal_uInt16 nItemId, const Image& rImage )
1941 size_t nPos = GetItemPos( nItemId );
1943 if ( nPos == VALUESET_ITEM_NOTFOUND )
1944 return;
1946 ValueSetItem* pItem = mItemList[nPos];
1947 pItem->meType = VALUESETITEM_IMAGE;
1948 pItem->maImage = rImage;
1950 if ( !mbFormat && IsReallyVisible() && IsUpdateMode() )
1952 const Rectangle aRect = ImplGetItemRect(nPos);
1953 Invalidate(aRect);
1955 else
1956 mbFormat = true;
1959 Image ValueSet::GetItemImage( sal_uInt16 nItemId ) const
1961 size_t nPos = GetItemPos( nItemId );
1963 if ( nPos != VALUESET_ITEM_NOTFOUND )
1964 return mItemList[nPos]->maImage;
1965 else
1966 return Image();
1969 void ValueSet::SetItemColor( sal_uInt16 nItemId, const Color& rColor )
1971 size_t nPos = GetItemPos( nItemId );
1973 if ( nPos == VALUESET_ITEM_NOTFOUND )
1974 return;
1976 ValueSetItem* pItem = mItemList[nPos];
1977 pItem->meType = VALUESETITEM_COLOR;
1978 pItem->maColor = rColor;
1980 if ( !mbFormat && IsReallyVisible() && IsUpdateMode() )
1982 const Rectangle aRect = ImplGetItemRect(nPos);
1983 Invalidate( aRect );
1985 else
1986 mbFormat = true;
1989 Color ValueSet::GetItemColor( sal_uInt16 nItemId ) const
1991 size_t nPos = GetItemPos( nItemId );
1993 if ( nPos != VALUESET_ITEM_NOTFOUND )
1994 return mItemList[nPos]->maColor;
1995 else
1996 return Color();
1999 void ValueSet::SetItemData( sal_uInt16 nItemId, void* pData )
2001 size_t nPos = GetItemPos( nItemId );
2003 if ( nPos == VALUESET_ITEM_NOTFOUND )
2004 return;
2006 ValueSetItem* pItem = mItemList[nPos];
2007 pItem->mpData = pData;
2009 if ( pItem->meType == VALUESETITEM_USERDRAW )
2011 if ( !mbFormat && IsReallyVisible() && IsUpdateMode() )
2013 const Rectangle aRect = ImplGetItemRect(nPos);
2014 Invalidate(aRect);
2016 else
2017 mbFormat = true;
2021 void* ValueSet::GetItemData( sal_uInt16 nItemId ) const
2023 size_t nPos = GetItemPos( nItemId );
2025 if ( nPos != VALUESET_ITEM_NOTFOUND )
2026 return mItemList[nPos]->mpData;
2027 else
2028 return NULL;
2031 void ValueSet::SetItemText(sal_uInt16 nItemId, const OUString& rText)
2033 size_t nPos = GetItemPos( nItemId );
2035 if ( nPos == VALUESET_ITEM_NOTFOUND )
2036 return;
2039 ValueSetItem* pItem = mItemList[nPos];
2041 // Remember old and new name for accessibility event.
2042 Any aOldName;
2043 Any aNewName;
2044 OUString sString (pItem->maText);
2045 aOldName <<= sString;
2046 sString = rText;
2047 aNewName <<= sString;
2049 pItem->maText = rText;
2051 if (!mbFormat && IsReallyVisible() && IsUpdateMode())
2053 sal_uInt16 nTempId = mnSelItemId;
2055 if (mbHighlight)
2056 nTempId = mnHighItemId;
2058 if (nTempId == nItemId)
2059 Invalidate();
2062 if (ImplHasAccessibleListeners())
2064 Reference<XAccessible> xAccessible(pItem->GetAccessible( mbIsTransientChildrenDisabled));
2065 ValueItemAcc* pValueItemAcc = static_cast<ValueItemAcc*>(xAccessible.get());
2066 pValueItemAcc->FireAccessibleEvent(AccessibleEventId::NAME_CHANGED, aOldName, aNewName);
2070 OUString ValueSet::GetItemText( sal_uInt16 nItemId ) const
2072 size_t nPos = GetItemPos( nItemId );
2074 if ( nPos != VALUESET_ITEM_NOTFOUND )
2075 return mItemList[nPos]->maText;
2077 return OUString();
2080 void ValueSet::SetColor( const Color& rColor )
2082 maColor = rColor;
2083 mbFormat = true;
2084 if (IsReallyVisible() && IsUpdateMode())
2085 Invalidate();
2088 void ValueSet::SetExtraSpacing( sal_uInt16 nNewSpacing )
2090 if ( GetStyle() & WB_ITEMBORDER )
2092 mnSpacing = nNewSpacing;
2094 mbFormat = true;
2095 queue_resize();
2096 if ( IsReallyVisible() && IsUpdateMode() )
2097 Invalidate();
2101 void ValueSet::StartSelection()
2103 mbHighlight = true;
2104 mbSelection = true;
2105 mnHighItemId = mnSelItemId;
2108 void ValueSet::EndSelection()
2110 if ( mbHighlight )
2112 if ( IsTracking() )
2113 EndTracking( TrackingEventFlags::Cancel );
2115 ImplHighlightItem( mnSelItemId );
2116 mbHighlight = false;
2118 mbSelection = false;
2121 void ValueSet::SetFormat(bool bFormat)
2123 mbFormat = bFormat;
2126 bool ValueSet::StartDrag( const CommandEvent& rEvent, vcl::Region& rRegion )
2128 if ( rEvent.GetCommand() != CommandEventId::StartDrag )
2129 return false;
2131 // if necessary abort an existing action
2132 EndSelection();
2134 // Check out if the clicked on page is selected. If this is not the
2135 // case set it as the current item. We only check mouse actions since
2136 // drag-and-drop can also be triggered by the keyboard
2137 sal_uInt16 nSelId;
2138 if ( rEvent.IsMouseEvent() )
2139 nSelId = GetItemId( rEvent.GetMousePosPixel() );
2140 else
2141 nSelId = mnSelItemId;
2143 // don't activate dragging if no item was clicked on
2144 if ( !nSelId )
2145 return false;
2147 // Check out if the page was selected. If not set as current page and
2148 // call select.
2149 if ( nSelId != mnSelItemId )
2151 SelectItem( nSelId );
2152 Update();
2153 Select();
2156 vcl::Region aRegion;
2158 // assign region
2159 rRegion = aRegion;
2161 return true;
2164 Size ValueSet::CalcWindowSizePixel( const Size& rItemSize, sal_uInt16 nDesireCols,
2165 sal_uInt16 nDesireLines ) const
2167 size_t nCalcCols = nDesireCols;
2168 size_t nCalcLines = nDesireLines;
2170 if ( !nCalcCols )
2172 if ( mnUserCols )
2173 nCalcCols = mnUserCols;
2174 else
2175 nCalcCols = 1;
2178 if ( !nCalcLines )
2180 nCalcLines = mnVisLines;
2182 if ( mbFormat )
2184 if ( mnUserVisLines )
2185 nCalcLines = mnUserVisLines;
2186 else
2188 // Floor( (M+N-1)/N )==Ceiling( M/N )
2189 nCalcLines = (mItemList.size()+nCalcCols-1) / nCalcCols;
2190 if ( !nCalcLines )
2191 nCalcLines = 1;
2196 Size aSize( rItemSize.Width() * nCalcCols, rItemSize.Height() * nCalcLines );
2197 WinBits nStyle = GetStyle();
2198 long nTxtHeight = GetTextHeight();
2199 long n;
2201 if ( nStyle & WB_ITEMBORDER )
2203 if ( nStyle & WB_DOUBLEBORDER )
2204 n = ITEM_OFFSET_DOUBLE;
2205 else
2206 n = ITEM_OFFSET;
2208 aSize.Width() += n * nCalcCols;
2209 aSize.Height() += n * nCalcLines;
2211 else
2212 n = 0;
2214 if ( mnSpacing )
2216 aSize.Width() += mnSpacing * (nCalcCols - 1);
2217 aSize.Height() += mnSpacing * (nCalcLines - 1);
2220 if ( nStyle & WB_NAMEFIELD )
2222 aSize.Height() += nTxtHeight + NAME_OFFSET;
2223 if ( !(nStyle & WB_FLATVALUESET) )
2224 aSize.Height() += NAME_LINE_HEIGHT + NAME_LINE_OFF_Y;
2227 if ( nStyle & WB_NONEFIELD )
2229 aSize.Height() += nTxtHeight + n + mnSpacing;
2230 if ( nStyle & WB_RADIOSEL )
2231 aSize.Height() += 8;
2234 // sum possible ScrollBar width
2235 aSize.Width() += GetScrollWidth();
2237 return aSize;
2240 Size ValueSet::CalcItemSizePixel( const Size& rItemSize, bool bOut ) const
2242 Size aSize = rItemSize;
2244 WinBits nStyle = GetStyle();
2245 if ( nStyle & WB_ITEMBORDER )
2247 long n;
2249 if ( nStyle & WB_DOUBLEBORDER )
2250 n = ITEM_OFFSET_DOUBLE;
2251 else
2252 n = ITEM_OFFSET;
2254 if ( bOut )
2256 aSize.Width() += n;
2257 aSize.Height() += n;
2259 else
2261 aSize.Width() -= n;
2262 aSize.Height() -= n;
2266 return aSize;
2269 long ValueSet::GetScrollWidth() const
2271 if (GetStyle() & WB_VSCROLL)
2273 ValueSet* pValueSet = const_cast<ValueSet*>(this);
2274 if (!mxScrollBar)
2276 pValueSet->ImplInitScrollBar();
2278 pValueSet->Invalidate();
2279 return mxScrollBar->GetSizePixel().Width() + SCRBAR_OFFSET;
2281 else
2282 return 0;
2285 void ValueSet::SetHighlightHdl( const Link<>& rLink )
2287 maHighlightHdl = rLink;
2290 Size ValueSet::GetOptimalSize() const
2292 Size aLargestItemSize;
2294 for (size_t i = 0, n = mItemList.size(); i < n; ++i)
2296 const ValueSetItem* pItem = mItemList[i];
2297 if (!pItem->mbVisible)
2298 continue;
2300 if (pItem->meType != VALUESETITEM_IMAGE)
2302 //handle determining an optimal size for this case
2303 continue;
2306 Size aImageSize = pItem->maImage.GetSizePixel();
2307 aLargestItemSize.Width() = std::max(aLargestItemSize.Width(), aImageSize.Width());
2308 aLargestItemSize.Height() = std::max(aLargestItemSize.Height(), aImageSize.Height());
2311 return CalcWindowSizePixel(aLargestItemSize);
2314 void ValueSet::SetEdgeBlending(bool bNew)
2316 if(mbEdgeBlending != bNew)
2318 mbEdgeBlending = bNew;
2319 mbFormat = true;
2321 if(IsReallyVisible() && IsUpdateMode())
2323 Invalidate();
2328 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */