/src/libreoffice/svtools/source/control/valueset.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <sal/config.h> |
21 | | |
22 | | #include <o3tl/safeint.hxx> |
23 | | #include <basegfx/matrix/b2dhommatrix.hxx> |
24 | | #include <basegfx/polygon/b2dpolygontools.hxx> |
25 | | #include <tools/debug.hxx> |
26 | | #include <vcl/bitmap.hxx> |
27 | | #include <vcl/canvastools.hxx> |
28 | | #include <vcl/decoview.hxx> |
29 | | #include <vcl/event.hxx> |
30 | | #include <vcl/svapp.hxx> |
31 | | #include <vcl/settings.hxx> |
32 | | #include <vcl/virdev.hxx> |
33 | | #include <vcl/lineinfo.hxx> |
34 | | #include <vcl/weld/ScrolledWindow.hxx> |
35 | | |
36 | | #include <com/sun/star/accessibility/AccessibleEventId.hpp> |
37 | | #include <com/sun/star/accessibility/AccessibleStateType.hpp> |
38 | | #include <com/sun/star/lang/XComponent.hpp> |
39 | | #include <rtl/ustring.hxx> |
40 | | #include <sal/log.hxx> |
41 | | #include "valueimp.hxx" |
42 | | |
43 | | #include <svtools/valueset.hxx> |
44 | | |
45 | | #include <uiobject.hxx> |
46 | | #include <vcl/uitest/logger.hxx> |
47 | | #include <vcl/uitest/eventdescription.hxx> |
48 | | |
49 | | using namespace css::uno; |
50 | | using namespace css::accessibility; |
51 | | |
52 | | namespace |
53 | | { |
54 | | void collectUIInformation( const OUString& aID , const OUString& aParentID , const OUString& aPos ) |
55 | 0 | { |
56 | 0 | EventDescription aDescription; |
57 | 0 | aDescription.aID = aID ; |
58 | 0 | aDescription.aParameters = {{"POS", aPos }}; |
59 | 0 | aDescription.aAction = "SELECT"; |
60 | 0 | aDescription.aKeyWord = "ValueSet"; |
61 | 0 | aDescription.aParent = aParentID; |
62 | 0 | UITestLogger::getInstance().logEvent(aDescription); |
63 | 0 | } |
64 | | |
65 | | enum |
66 | | { |
67 | | ITEM_OFFSET = 4, |
68 | | ITEM_OFFSET_DOUBLE = 6, |
69 | | NAME_LINE_OFF_X = 2, |
70 | | NAME_LINE_OFF_Y = 2, |
71 | | NAME_LINE_HEIGHT = 2, |
72 | | NAME_OFFSET = 2, |
73 | | }; |
74 | | |
75 | | } |
76 | | |
77 | | ValueSet::ValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow) |
78 | 0 | : maVirDev( VclPtr<VirtualDevice>::Create(DeviceFormat::WITH_ALPHA)) |
79 | 0 | , mxScrolledWindow(std::move(pScrolledWindow)) |
80 | 0 | , mnHighItemId(0) |
81 | 0 | , maColor(COL_TRANSPARENT) |
82 | 0 | , mnStyle(0) |
83 | 0 | , mbFormat(true) |
84 | 0 | , mbHighlight(false) |
85 | 0 | { |
86 | 0 | mnItemWidth = 0; |
87 | 0 | mnItemHeight = 0; |
88 | 0 | mnTextOffset = 0; |
89 | 0 | mnVisLines = 0; |
90 | 0 | mnLines = 0; |
91 | 0 | mnUserItemWidth = 0; |
92 | 0 | mnUserItemHeight = 0; |
93 | 0 | mnFirstLine = 0; |
94 | 0 | mnSelItemId = 0; |
95 | 0 | mnSavedItemId = -1; |
96 | 0 | mnCols = 0; |
97 | 0 | mnCurCol = 0; |
98 | 0 | mnUserCols = 0; |
99 | 0 | mnUserVisLines = 0; |
100 | 0 | mnSpacing = 0; |
101 | 0 | mnMargin = 0; |
102 | 0 | mnFrameStyle = DrawFrameStyle::NONE; |
103 | 0 | mbNoSelection = true; |
104 | 0 | mbDoubleSel = false; |
105 | 0 | mbFullMode = true; |
106 | 0 | mbEdgeBlending = false; |
107 | 0 | mbHasVisibleItems = false; |
108 | |
|
109 | 0 | if (mxScrolledWindow) |
110 | 0 | mxScrolledWindow->connect_vadjustment_value_changed(LINK(this, ValueSet, ImplScrollHdl)); |
111 | 0 | } |
112 | | |
113 | | void ValueSet::SetDrawingArea(weld::DrawingArea* pDrawingArea) |
114 | 0 | { |
115 | 0 | CustomWidgetController::SetDrawingArea(pDrawingArea); |
116 | | // #106446#, #106601# force mirroring of virtual device |
117 | 0 | maVirDev->EnableRTL(pDrawingArea->get_direction()); |
118 | 0 | } |
119 | | |
120 | | rtl::Reference<comphelper::OAccessible> ValueSet::CreateAccessible() |
121 | 0 | { |
122 | 0 | if (!mxAccessible) |
123 | 0 | mxAccessible.set(new ValueSetAcc(this)); |
124 | 0 | return mxAccessible; |
125 | 0 | } |
126 | | |
127 | | ValueSet::~ValueSet() |
128 | 0 | { |
129 | 0 | ImplDeleteItems(); |
130 | |
|
131 | 0 | if (mxAccessible) |
132 | 0 | mxAccessible->Invalidate(); |
133 | 0 | } |
134 | | |
135 | | void ValueSet::ImplDeleteItems() |
136 | 0 | { |
137 | 0 | const size_t n = mItemList.size(); |
138 | |
|
139 | 0 | for ( size_t i = 0; i < n; ++i ) |
140 | 0 | { |
141 | 0 | if (ValueSetItem* pItem = mItemList[i].get()) |
142 | 0 | { |
143 | 0 | rtl::Reference<ValueItemAcc> xItemAcc = pItem->GetAccessible(false); |
144 | 0 | if (xItemAcc.is()) |
145 | 0 | { |
146 | 0 | Any aOldAny; |
147 | 0 | Any aNewAny; |
148 | 0 | aOldAny <<= Reference<XAccessible>(xItemAcc); |
149 | 0 | ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny); |
150 | |
|
151 | 0 | xItemAcc->dispose(); |
152 | 0 | } |
153 | 0 | } |
154 | |
|
155 | 0 | mItemList[i].reset(); |
156 | 0 | } |
157 | |
|
158 | 0 | mItemList.clear(); |
159 | 0 | } |
160 | | |
161 | | void ValueSet::Select() |
162 | 0 | { |
163 | 0 | collectUIInformation(GetDrawingArea()->get_buildable_name() , GetDrawingArea()->get_help_id() , OUString::number(GetSelectedItemId())); |
164 | 0 | maSelectHdl.Call( this ); |
165 | 0 | } |
166 | | |
167 | | void ValueSet::UserDraw( const UserDrawEvent& ) |
168 | 0 | { |
169 | 0 | } |
170 | | |
171 | | size_t ValueSet::ImplGetItem( const Point& rPos ) const |
172 | 0 | { |
173 | 0 | if (!mbHasVisibleItems) |
174 | 0 | { |
175 | 0 | return VALUESET_ITEM_NOTFOUND; |
176 | 0 | } |
177 | | |
178 | 0 | if (maItemListRect.Contains(rPos)) |
179 | 0 | { |
180 | 0 | const int xc = rPos.X() - maItemListRect.Left(); |
181 | 0 | const int yc = rPos.Y() - maItemListRect.Top(); |
182 | | // The point is inside the area of item list, |
183 | | // let's find the containing item. |
184 | 0 | const int col = xc / (mnItemWidth + mnSpacing); |
185 | 0 | const int x = xc % (mnItemWidth + mnSpacing); |
186 | 0 | const int row = yc / (mnItemHeight + mnSpacing); |
187 | 0 | const int y = yc % (mnItemHeight + mnSpacing); |
188 | |
|
189 | 0 | if (x < mnItemWidth && y < mnItemHeight) |
190 | 0 | { |
191 | | // the point is inside item rect and not inside spacing |
192 | 0 | const size_t item = (mnFirstLine + row) * static_cast<size_t>(mnCols) + col; |
193 | 0 | if (item < mItemList.size()) |
194 | 0 | { |
195 | 0 | return item; |
196 | 0 | } |
197 | 0 | } |
198 | 0 | } |
199 | | |
200 | 0 | return VALUESET_ITEM_NOTFOUND; |
201 | 0 | } |
202 | | |
203 | | ValueSetItem* ValueSet::ImplGetItem( size_t nPos ) |
204 | 0 | { |
205 | 0 | return (nPos < mItemList.size()) ? mItemList[nPos].get() : nullptr; |
206 | 0 | } |
207 | | |
208 | | ValueSetItem* ValueSet::ImplGetFirstItem() |
209 | 0 | { |
210 | 0 | return !mItemList.empty() ? mItemList[0].get() : nullptr; |
211 | 0 | } |
212 | | |
213 | | sal_uInt16 ValueSet::ImplGetVisibleItemCount() const |
214 | 0 | { |
215 | 0 | sal_uInt16 nRet = 0; |
216 | 0 | const size_t nItemCount = mItemList.size(); |
217 | |
|
218 | 0 | for ( size_t n = 0; n < nItemCount; ++n ) |
219 | 0 | { |
220 | 0 | if ( mItemList[n]->mbVisible ) |
221 | 0 | ++nRet; |
222 | 0 | } |
223 | |
|
224 | 0 | return nRet; |
225 | 0 | } |
226 | | |
227 | | void ValueSet::ImplFireAccessibleEvent( short nEventId, const Any& rOldValue, const Any& rNewValue ) |
228 | 0 | { |
229 | 0 | if( mxAccessible ) |
230 | 0 | mxAccessible->FireAccessibleEvent( nEventId, rOldValue, rNewValue ); |
231 | 0 | } |
232 | | |
233 | | bool ValueSet::ImplHasAccessibleListeners() const |
234 | 0 | { |
235 | 0 | return mxAccessible && mxAccessible->HasAccessibleListeners(); |
236 | 0 | } |
237 | | |
238 | | IMPL_LINK(ValueSet, ImplScrollHdl, weld::ScrolledWindow&, rScrollWin, void) |
239 | 0 | { |
240 | 0 | auto nNewFirstLine = rScrollWin.vadjustment_get_value(); |
241 | 0 | if ( nNewFirstLine != mnFirstLine ) |
242 | 0 | { |
243 | 0 | mnFirstLine = nNewFirstLine; |
244 | 0 | mbFormat = true; |
245 | 0 | Invalidate(); |
246 | 0 | } |
247 | 0 | } |
248 | | |
249 | | void ValueSet::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) |
250 | 0 | { |
251 | 0 | rRenderContext.SetBackground(Application::GetSettings().GetStyleSettings().GetFaceColor()); |
252 | 0 | rRenderContext.Erase(); |
253 | 0 | ImplDraw(rRenderContext); |
254 | 0 | } |
255 | | |
256 | | void ValueSet::GetFocus() |
257 | 0 | { |
258 | 0 | SAL_INFO("svtools", "value set getting focus"); |
259 | 0 | Invalidate(); |
260 | 0 | CustomWidgetController::GetFocus(); |
261 | | |
262 | | // Tell the accessible object that we got the focus. |
263 | 0 | if (mxAccessible) |
264 | 0 | mxAccessible->GetFocus(); |
265 | 0 | } |
266 | | |
267 | | void ValueSet::LoseFocus() |
268 | 0 | { |
269 | 0 | SAL_INFO("svtools", "value set losing focus"); |
270 | 0 | Invalidate(); |
271 | 0 | CustomWidgetController::LoseFocus(); |
272 | | |
273 | | // Tell the accessible object that we lost the focus. |
274 | 0 | if( mxAccessible ) |
275 | 0 | mxAccessible->LoseFocus(); |
276 | 0 | } |
277 | | |
278 | | void ValueSet::Resize() |
279 | 0 | { |
280 | 0 | mbFormat = true; |
281 | 0 | if (IsReallyVisible()) |
282 | 0 | Invalidate(); |
283 | 0 | CustomWidgetController::Resize(); |
284 | 0 | } |
285 | | |
286 | | bool ValueSet::KeyInput( const KeyEvent& rKeyEvent ) |
287 | 0 | { |
288 | 0 | size_t nLastItem = mItemList.size(); |
289 | |
|
290 | 0 | if ( !nLastItem || !ImplGetFirstItem() ) |
291 | 0 | return CustomWidgetController::KeyInput(rKeyEvent); |
292 | | |
293 | 0 | if (mbFormat) |
294 | 0 | Invalidate(); |
295 | |
|
296 | 0 | --nLastItem; |
297 | |
|
298 | 0 | const size_t nCurPos |
299 | 0 | = mnSelItemId ? GetItemPos(mnSelItemId) : 0; |
300 | 0 | size_t nItemPos = VALUESET_ITEM_NOTFOUND; |
301 | 0 | size_t nVStep = mnCols; |
302 | |
|
303 | 0 | switch (rKeyEvent.GetKeyCode().GetCode()) |
304 | 0 | { |
305 | 0 | case KEY_HOME: |
306 | 0 | nItemPos = 0; |
307 | 0 | break; |
308 | | |
309 | 0 | case KEY_END: |
310 | 0 | nItemPos = nLastItem; |
311 | 0 | break; |
312 | | |
313 | 0 | case KEY_LEFT: |
314 | 0 | if (nCurPos) |
315 | 0 | nItemPos = nCurPos - 1; |
316 | 0 | break; |
317 | | |
318 | 0 | case KEY_RIGHT: |
319 | 0 | if (nCurPos < nLastItem) |
320 | 0 | nItemPos = nCurPos + 1; |
321 | 0 | break; |
322 | | |
323 | 0 | case KEY_PAGEUP: |
324 | 0 | if (rKeyEvent.GetKeyCode().IsShift() || rKeyEvent.GetKeyCode().IsMod1() || rKeyEvent.GetKeyCode().IsMod2()) |
325 | 0 | { |
326 | 0 | return CustomWidgetController::KeyInput(rKeyEvent); |
327 | 0 | } |
328 | 0 | nVStep *= mnVisLines; |
329 | 0 | [[fallthrough]]; |
330 | 0 | case KEY_UP: |
331 | 0 | if (nCurPos == nLastItem) |
332 | 0 | { |
333 | 0 | const size_t nCol = mnCols ? nLastItem % mnCols : 0; |
334 | 0 | if (nCol < mnCurCol) |
335 | 0 | { |
336 | | // Move to previous row/page, keeping the old column |
337 | 0 | nVStep -= mnCurCol - nCol; |
338 | 0 | } |
339 | 0 | } |
340 | 0 | if (nCurPos >= nVStep) |
341 | 0 | { |
342 | | // Go up of a whole page |
343 | 0 | nItemPos = nCurPos - nVStep; |
344 | 0 | } |
345 | 0 | else if (nCurPos > mnCols) |
346 | 0 | { |
347 | | // Go to same column in first row |
348 | 0 | nItemPos = nCurPos % mnCols; |
349 | 0 | } |
350 | 0 | break; |
351 | | |
352 | 0 | case KEY_PAGEDOWN: |
353 | 0 | if (rKeyEvent.GetKeyCode().IsShift() || rKeyEvent.GetKeyCode().IsMod1() || rKeyEvent.GetKeyCode().IsMod2()) |
354 | 0 | { |
355 | 0 | return CustomWidgetController::KeyInput(rKeyEvent); |
356 | 0 | } |
357 | 0 | nVStep *= mnVisLines; |
358 | 0 | [[fallthrough]]; |
359 | 0 | case KEY_DOWN: |
360 | 0 | if (nCurPos != nLastItem) |
361 | 0 | { |
362 | 0 | nItemPos = nCurPos + nVStep; |
363 | 0 | if (nItemPos > nLastItem) |
364 | 0 | { |
365 | 0 | nItemPos = nLastItem; |
366 | 0 | } |
367 | 0 | } |
368 | 0 | break; |
369 | | |
370 | 0 | case KEY_RETURN: |
371 | 0 | if (GetStyle() & WB_NO_DIRECTSELECT) |
372 | 0 | { |
373 | | // tdf#142479 on return select the entry the cursor is in |
374 | | // before calling Select |
375 | 0 | const sal_uInt16 nItemId = GetItemId(nCurPos); |
376 | 0 | if (nItemId != mnSelItemId) |
377 | 0 | SelectItem(nItemId); |
378 | 0 | Select(); |
379 | 0 | break; |
380 | 0 | } |
381 | 0 | [[fallthrough]]; |
382 | 0 | default: |
383 | 0 | return CustomWidgetController::KeyInput(rKeyEvent); |
384 | 0 | } |
385 | | |
386 | 0 | if ( nItemPos == VALUESET_ITEM_NOTFOUND ) |
387 | 0 | return true; |
388 | | |
389 | 0 | if (nItemPos < nLastItem) |
390 | 0 | { |
391 | | // update current column only in case of a new position |
392 | | // which is also not a "specially" handled one. |
393 | 0 | mnCurCol = mnCols ? nItemPos % mnCols : 0; |
394 | 0 | } |
395 | 0 | const sal_uInt16 nItemId = GetItemId(nItemPos); |
396 | 0 | if ( nItemId != mnSelItemId ) |
397 | 0 | { |
398 | 0 | SelectItem( nItemId ); |
399 | 0 | if (!(GetStyle() & WB_NO_DIRECTSELECT)) |
400 | 0 | { |
401 | | // select only if WB_NO_DIRECTSELECT is not set |
402 | 0 | Select(); |
403 | 0 | } |
404 | 0 | } |
405 | |
|
406 | 0 | return true; |
407 | 0 | } |
408 | | |
409 | | void ValueSet::ImplTracking(bool bLeaveWindow, const Point& rPos) |
410 | 0 | { |
411 | 0 | if (GetStyle() & WB_MENUSTYLEVALUESET || GetStyle() & WB_FLATVALUESET) |
412 | 0 | mbHighlight = true; |
413 | |
|
414 | 0 | if (ValueSetItem* pItem = bLeaveWindow ? nullptr : ImplGetItem(ImplGetItem(rPos))) |
415 | 0 | ImplHighlightItem(pItem->mnId); |
416 | 0 | else |
417 | 0 | ImplHighlightItem(0); |
418 | 0 | } |
419 | | |
420 | | bool ValueSet::MouseButtonDown( const MouseEvent& rMouseEvent ) |
421 | 0 | { |
422 | 0 | if (rMouseEvent.IsLeft() && !rMouseEvent.IsMod2()) |
423 | 0 | { |
424 | 0 | bool bConsumed = false; |
425 | 0 | ValueSetItem* pItem = ImplGetItem( ImplGetItem( rMouseEvent.GetPosPixel() ) ); |
426 | 0 | if (rMouseEvent.GetClicks() == 1) |
427 | 0 | { |
428 | 0 | if (pItem) |
429 | 0 | SelectItem(pItem->mnId); |
430 | 0 | GrabFocus(); |
431 | 0 | bConsumed = true; |
432 | 0 | } |
433 | 0 | else if (pItem && rMouseEvent.GetClicks() == 2) |
434 | 0 | { |
435 | 0 | maDoubleClickHdl.Call(this); |
436 | 0 | bConsumed = true; |
437 | 0 | } |
438 | 0 | return bConsumed; |
439 | 0 | } |
440 | | |
441 | 0 | return CustomWidgetController::MouseButtonDown( rMouseEvent ); |
442 | 0 | } |
443 | | |
444 | | bool ValueSet::MouseButtonUp( const MouseEvent& rMouseEvent ) |
445 | 0 | { |
446 | 0 | if (rMouseEvent.IsLeft() && !rMouseEvent.IsMod2()) |
447 | 0 | { |
448 | | // tdf#165881 MouseUp may be seen without previous MouseDown. Select |
449 | | // what's under the mouse on mouse release when in menu-alike modes. |
450 | 0 | const bool bMenuAlike = GetStyle() & WB_MENUSTYLEVALUESET || GetStyle() & WB_FLATVALUESET; |
451 | 0 | if (bMenuAlike) |
452 | 0 | { |
453 | 0 | if (ValueSetItem* pItem = ImplGetItem(ImplGetItem(rMouseEvent.GetPosPixel()))) |
454 | 0 | SelectItem(pItem->mnId); |
455 | 0 | } |
456 | | |
457 | | // tdf#142150 MouseUp seen without previous MouseDown |
458 | 0 | if (mnSelItemId) |
459 | 0 | Select(); |
460 | 0 | return true; |
461 | 0 | } |
462 | | |
463 | 0 | return CustomWidgetController::MouseButtonUp( rMouseEvent ); |
464 | 0 | } |
465 | | |
466 | | bool ValueSet::MouseMove(const MouseEvent& rMouseEvent) |
467 | 0 | { |
468 | | // because of SelectionMode |
469 | 0 | if ((GetStyle() & WB_MENUSTYLEVALUESET) || (GetStyle() & WB_FLATVALUESET)) |
470 | 0 | ImplTracking(rMouseEvent.IsLeaveWindow(), rMouseEvent.GetPosPixel()); |
471 | 0 | return CustomWidgetController::MouseMove(rMouseEvent); |
472 | 0 | } |
473 | | |
474 | | void ValueSet::QueueReformat() |
475 | 0 | { |
476 | 0 | queue_resize(); |
477 | 0 | RecalcScrollBar(); |
478 | 0 | mbFormat = true; |
479 | 0 | if (IsReallyVisible()) |
480 | 0 | Invalidate(); |
481 | 0 | } |
482 | | |
483 | | void ValueSet::RemoveItem( sal_uInt16 nItemId ) |
484 | 0 | { |
485 | 0 | size_t nPos = GetItemPos( nItemId ); |
486 | |
|
487 | 0 | if ( nPos == VALUESET_ITEM_NOTFOUND ) |
488 | 0 | return; |
489 | | |
490 | 0 | mItemList.erase( mItemList.begin() + nPos ); |
491 | | |
492 | | // reset variables |
493 | 0 | if (mnHighItemId == nItemId || mnSelItemId == nItemId) |
494 | 0 | { |
495 | 0 | mnCurCol = 0; |
496 | 0 | mnHighItemId = 0; |
497 | 0 | mnSelItemId = 0; |
498 | 0 | mbNoSelection = true; |
499 | 0 | } |
500 | |
|
501 | 0 | QueueReformat(); |
502 | 0 | } |
503 | | |
504 | | bool ValueSet::TurnOffScrollBar() |
505 | 0 | { |
506 | 0 | if (mxScrolledWindow->get_vpolicy() == VclPolicyType::NEVER) |
507 | 0 | return false; |
508 | 0 | mxScrolledWindow->set_vpolicy(VclPolicyType::NEVER); |
509 | 0 | weld::DrawingArea* pDrawingArea = GetDrawingArea(); |
510 | 0 | Size aPrefSize(pDrawingArea->get_preferred_size()); |
511 | 0 | pDrawingArea->set_size_request(aPrefSize.Width() + GetScrollWidth(), aPrefSize.Height()); |
512 | 0 | return true; |
513 | 0 | } |
514 | | |
515 | | void ValueSet::TurnOnScrollBar() |
516 | 0 | { |
517 | 0 | if (mxScrolledWindow->get_vpolicy() == VclPolicyType::ALWAYS) |
518 | 0 | return; |
519 | 0 | mxScrolledWindow->set_vpolicy(VclPolicyType::ALWAYS); |
520 | 0 | weld::DrawingArea* pDrawingArea = GetDrawingArea(); |
521 | 0 | Size aPrefSize(pDrawingArea->get_preferred_size()); |
522 | 0 | pDrawingArea->set_size_request(aPrefSize.Width() - GetScrollWidth(), aPrefSize.Height()); |
523 | 0 | } |
524 | | |
525 | | void ValueSet::RecalcScrollBar() |
526 | 0 | { |
527 | 0 | if (!mxScrolledWindow) |
528 | 0 | return; |
529 | 0 | const bool bScrollAllowed = GetStyle() & WB_VSCROLL; |
530 | 0 | if (!bScrollAllowed) |
531 | 0 | return; |
532 | | // reset scrolled window state to initial value so it will get configured |
533 | | // to the right adjustment on the next format which we toggle on to happen |
534 | | // if the scrolledwindow wasn't in its initial state already |
535 | 0 | if (TurnOffScrollBar()) |
536 | 0 | mbFormat = true; |
537 | 0 | } |
538 | | |
539 | | void ValueSet::Clear() |
540 | 0 | { |
541 | 0 | ImplDeleteItems(); |
542 | | |
543 | | // reset variables |
544 | 0 | mnFirstLine = 0; |
545 | 0 | mnCurCol = 0; |
546 | 0 | mnHighItemId = 0; |
547 | 0 | mnSelItemId = 0; |
548 | 0 | mbNoSelection = true; |
549 | |
|
550 | 0 | RecalcScrollBar(); |
551 | |
|
552 | 0 | mbFormat = true; |
553 | 0 | if (IsReallyVisible()) |
554 | 0 | Invalidate(); |
555 | 0 | } |
556 | | |
557 | | size_t ValueSet::GetItemCount() const |
558 | 0 | { |
559 | 0 | return mItemList.size(); |
560 | 0 | } |
561 | | |
562 | | size_t ValueSet::GetItemPos( sal_uInt16 nItemId ) const |
563 | 0 | { |
564 | 0 | for ( size_t i = 0, n = mItemList.size(); i < n; ++i ) { |
565 | 0 | if ( mItemList[i]->mnId == nItemId ) { |
566 | 0 | return i; |
567 | 0 | } |
568 | 0 | } |
569 | 0 | return VALUESET_ITEM_NOTFOUND; |
570 | 0 | } |
571 | | |
572 | | sal_uInt16 ValueSet::GetItemId( size_t nPos ) const |
573 | 0 | { |
574 | 0 | return ( nPos < mItemList.size() ) ? mItemList[nPos]->mnId : 0 ; |
575 | 0 | } |
576 | | |
577 | | sal_uInt16 ValueSet::GetItemId( const Point& rPos ) const |
578 | 0 | { |
579 | 0 | size_t nItemPos = ImplGetItem( rPos ); |
580 | 0 | if ( nItemPos != VALUESET_ITEM_NOTFOUND ) |
581 | 0 | return GetItemId( nItemPos ); |
582 | | |
583 | 0 | return 0; |
584 | 0 | } |
585 | | |
586 | | tools::Rectangle ValueSet::GetItemRect( sal_uInt16 nItemId ) const |
587 | 0 | { |
588 | 0 | const size_t nPos = GetItemPos( nItemId ); |
589 | |
|
590 | 0 | if ( nPos!=VALUESET_ITEM_NOTFOUND && mItemList[nPos]->mbVisible ) |
591 | 0 | return ImplGetItemRect( nPos ); |
592 | | |
593 | 0 | return tools::Rectangle(); |
594 | 0 | } |
595 | | |
596 | | tools::Rectangle ValueSet::ImplGetItemRect( size_t nPos ) const |
597 | 0 | { |
598 | 0 | const size_t nVisibleBegin = static_cast<size_t>(mnFirstLine)*mnCols; |
599 | 0 | const size_t nVisibleEnd = nVisibleBegin + static_cast<size_t>(mnVisLines)*mnCols; |
600 | | |
601 | | // Check if the item is inside the range of the displayed ones, |
602 | | // taking into account that last row could be incomplete |
603 | 0 | if ( nPos<nVisibleBegin || nPos>=nVisibleEnd || nPos>=mItemList.size() ) |
604 | 0 | return tools::Rectangle(); |
605 | | |
606 | 0 | nPos -= nVisibleBegin; |
607 | |
|
608 | 0 | const size_t row = mnCols ? nPos/mnCols : 0; |
609 | 0 | const size_t col = mnCols ? nPos%mnCols : 0; |
610 | 0 | const tools::Long x = maItemListRect.Left()+col*(mnItemWidth+mnSpacing); |
611 | 0 | const tools::Long y = maItemListRect.Top()+row*(mnItemHeight+mnSpacing); |
612 | |
|
613 | 0 | return tools::Rectangle( Point(x, y), Size(mnItemWidth, mnItemHeight) ); |
614 | 0 | } |
615 | | |
616 | | void ValueSet::ImplHighlightItem(sal_uInt16 nItemId) |
617 | 0 | { |
618 | 0 | if ( mnHighItemId == nItemId ) |
619 | 0 | return; |
620 | | |
621 | | // remember the old item to delete the previous selection |
622 | 0 | mnHighItemId = nItemId; |
623 | | |
624 | | // remove the old selection and draw the new one |
625 | 0 | Invalidate(); |
626 | 0 | } |
627 | | |
628 | | void ValueSet::ImplDraw(vcl::RenderContext& rRenderContext) |
629 | 0 | { |
630 | 0 | if (mbFormat) |
631 | 0 | Format(rRenderContext); |
632 | |
|
633 | 0 | Point aDefPos; |
634 | 0 | Size aSize = maVirDev->GetOutputSizePixel(); |
635 | |
|
636 | 0 | rRenderContext.DrawOutDev(aDefPos, aSize, aDefPos, aSize, *maVirDev); |
637 | | |
638 | | // draw parting line to the Namefield |
639 | 0 | if (GetStyle() & WB_NAMEFIELD) |
640 | 0 | { |
641 | 0 | if (!(GetStyle() & WB_FLATVALUESET)) |
642 | 0 | { |
643 | 0 | const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); |
644 | 0 | Size aWinSize(GetOutputSizePixel()); |
645 | 0 | Point aPos1(NAME_LINE_OFF_X, mnTextOffset + NAME_LINE_OFF_Y); |
646 | 0 | Point aPos2(aWinSize.Width() - (NAME_LINE_OFF_X * 2), mnTextOffset + NAME_LINE_OFF_Y); |
647 | 0 | if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono)) |
648 | 0 | { |
649 | 0 | rRenderContext.SetLineColor(rStyleSettings.GetShadowColor()); |
650 | 0 | rRenderContext.DrawLine(aPos1, aPos2); |
651 | 0 | aPos1.AdjustY( 1 ); |
652 | 0 | aPos2.AdjustY( 1 ); |
653 | 0 | rRenderContext.SetLineColor(rStyleSettings.GetLightColor()); |
654 | 0 | } |
655 | 0 | else |
656 | 0 | rRenderContext.SetLineColor(rStyleSettings.GetWindowTextColor()); |
657 | 0 | rRenderContext.DrawLine(aPos1, aPos2); |
658 | 0 | } |
659 | 0 | } |
660 | |
|
661 | 0 | ImplDrawSelect(rRenderContext); |
662 | 0 | } |
663 | | |
664 | | void ValueSet::SetFirstLine(sal_uInt16 nNewFirstLine) |
665 | 0 | { |
666 | 0 | if (nNewFirstLine != mnFirstLine) |
667 | 0 | { |
668 | 0 | mnFirstLine = nNewFirstLine; |
669 | 0 | if (mxScrolledWindow) |
670 | 0 | mxScrolledWindow->vadjustment_set_value(mnFirstLine); |
671 | 0 | } |
672 | 0 | } |
673 | | |
674 | | void ValueSet::SelectItem( sal_uInt16 nItemId ) |
675 | 0 | { |
676 | 0 | size_t nItemPos = 0; |
677 | |
|
678 | 0 | if ( nItemId ) |
679 | 0 | { |
680 | 0 | nItemPos = GetItemPos( nItemId ); |
681 | 0 | if ( nItemPos == VALUESET_ITEM_NOTFOUND ) |
682 | 0 | return; |
683 | 0 | } |
684 | | |
685 | 0 | if ( !((mnSelItemId != nItemId) || mbNoSelection) ) |
686 | 0 | return; |
687 | | |
688 | 0 | const sal_uInt16 nOldItem = mnSelItemId; |
689 | 0 | mnSelItemId = nItemId; |
690 | 0 | mbNoSelection = false; |
691 | |
|
692 | 0 | bool bNewOut = !mbFormat && IsReallyVisible(); |
693 | 0 | bool bNewLine = false; |
694 | |
|
695 | 0 | if (weld::DrawingArea* pNeedsFormatToScroll = !mnCols ? GetDrawingArea() : nullptr) |
696 | 0 | { |
697 | 0 | Format(pNeedsFormatToScroll->get_ref_device()); |
698 | | // reset scrollbar so it's set to the later calculated mnFirstLine on |
699 | | // the next Format |
700 | 0 | RecalcScrollBar(); |
701 | 0 | } |
702 | | |
703 | | // if necessary scroll to the visible area |
704 | 0 | if (nItemId && mnCols) |
705 | 0 | { |
706 | 0 | sal_uInt16 nNewLine = static_cast<sal_uInt16>(nItemPos / mnCols); |
707 | 0 | if ( nNewLine < mnFirstLine ) |
708 | 0 | { |
709 | 0 | SetFirstLine(nNewLine); |
710 | 0 | bNewLine = true; |
711 | 0 | } |
712 | 0 | else if (mnFirstLine + mnVisLines - 1 >= 0 |
713 | 0 | && nNewLine > o3tl::make_unsigned(mnFirstLine + mnVisLines - 1)) |
714 | 0 | { |
715 | 0 | SetFirstLine(static_cast<sal_uInt16>(nNewLine-mnVisLines+1)); |
716 | 0 | bNewLine = true; |
717 | 0 | } |
718 | 0 | } |
719 | |
|
720 | 0 | if ( bNewOut ) |
721 | 0 | { |
722 | 0 | if ( bNewLine ) |
723 | 0 | { |
724 | | // redraw everything if the visible area has changed |
725 | 0 | mbFormat = true; |
726 | 0 | } |
727 | 0 | Invalidate(); |
728 | 0 | } |
729 | |
|
730 | 0 | if( !ImplHasAccessibleListeners() ) |
731 | 0 | return; |
732 | | |
733 | | // focus event (deselect) |
734 | 0 | if( nOldItem ) |
735 | 0 | { |
736 | 0 | const size_t nPos = GetItemPos( nItemId ); |
737 | |
|
738 | 0 | if( nPos != VALUESET_ITEM_NOTFOUND ) |
739 | 0 | { |
740 | 0 | rtl::Reference<ValueItemAcc> pItemAcc = |
741 | 0 | mItemList[nPos]->GetAccessible(); |
742 | |
|
743 | 0 | if( pItemAcc ) |
744 | 0 | { |
745 | 0 | Any aOldAny; |
746 | 0 | Any aNewAny; |
747 | 0 | aOldAny <<= Reference(getXWeak(pItemAcc.get())); |
748 | 0 | ImplFireAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny ); |
749 | 0 | } |
750 | 0 | } |
751 | 0 | } |
752 | |
|
753 | 0 | if (mxAccessible->getAccessibleStateSet() & css::accessibility::AccessibleStateType::FOCUSED) |
754 | 0 | { |
755 | | // focus event (select) |
756 | 0 | const size_t nPos = GetItemPos(mnSelItemId); |
757 | |
|
758 | 0 | ValueSetItem* pItem = nullptr; |
759 | 0 | if (nPos != VALUESET_ITEM_NOTFOUND) |
760 | 0 | pItem = mItemList[nPos].get(); |
761 | |
|
762 | 0 | ValueItemAcc* pItemAcc = nullptr; |
763 | 0 | if (pItem != nullptr) |
764 | 0 | pItemAcc = |
765 | 0 | pItem->GetAccessible().get(); |
766 | |
|
767 | 0 | if (pItemAcc) |
768 | 0 | { |
769 | 0 | Any aOldAny; |
770 | 0 | Any aNewAny; |
771 | 0 | aNewAny <<= Reference(getXWeak(pItemAcc)); |
772 | 0 | ImplFireAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny); |
773 | 0 | } |
774 | 0 | } |
775 | | |
776 | | // selection event |
777 | 0 | Any aOldAny; |
778 | 0 | Any aNewAny; |
779 | 0 | ImplFireAccessibleEvent(AccessibleEventId::SELECTION_CHANGED, aOldAny, aNewAny); |
780 | 0 | } |
781 | | |
782 | | void ValueSet::SetNoSelection() |
783 | 0 | { |
784 | 0 | mbNoSelection = true; |
785 | 0 | mbHighlight = false; |
786 | |
|
787 | 0 | if (IsReallyVisible()) |
788 | 0 | Invalidate(); |
789 | 0 | } |
790 | | |
791 | | void ValueSet::SetStyle(WinBits nStyle) |
792 | 0 | { |
793 | 0 | if (nStyle != mnStyle) |
794 | 0 | { |
795 | 0 | mnStyle = nStyle; |
796 | 0 | mbFormat = true; |
797 | 0 | Invalidate(); |
798 | 0 | } |
799 | 0 | } |
800 | | |
801 | | void ValueSet::Format(vcl::RenderContext const & rRenderContext) |
802 | 0 | { |
803 | 0 | Size aWinSize(GetOutputSizePixel()); |
804 | 0 | size_t nItemCount = mItemList.size(); |
805 | 0 | WinBits nStyle = GetStyle(); |
806 | 0 | tools::Long nTxtHeight = rRenderContext.GetTextHeight(); |
807 | |
|
808 | 0 | if (mxScrolledWindow && !(nStyle & WB_VSCROLL) && mxScrolledWindow->get_vpolicy() != VclPolicyType::NEVER) |
809 | 0 | TurnOffScrollBar(); |
810 | |
|
811 | 0 | if ( mnMargin ) |
812 | 0 | { |
813 | 0 | aWinSize.AdjustWidth(-mnMargin * 2); |
814 | 0 | aWinSize.AdjustHeight(-mnMargin * 2); |
815 | 0 | } |
816 | | |
817 | | // consider size, if NameField does exist |
818 | 0 | if (nStyle & WB_NAMEFIELD) |
819 | 0 | { |
820 | 0 | mnTextOffset = aWinSize.Height() - nTxtHeight - NAME_OFFSET; |
821 | 0 | aWinSize.AdjustHeight( -(nTxtHeight + NAME_OFFSET) ); |
822 | |
|
823 | 0 | if (!(nStyle & WB_FLATVALUESET)) |
824 | 0 | { |
825 | 0 | mnTextOffset -= NAME_LINE_HEIGHT + NAME_LINE_OFF_Y; |
826 | 0 | aWinSize.AdjustHeight( -(NAME_LINE_HEIGHT + NAME_LINE_OFF_Y) ); |
827 | 0 | } |
828 | 0 | } |
829 | 0 | else |
830 | 0 | mnTextOffset = 0; |
831 | |
|
832 | 0 | mnTextOffset += mnMargin; |
833 | | |
834 | | // calculate number of columns |
835 | 0 | if (!mnUserCols) |
836 | 0 | { |
837 | 0 | if (mnUserItemWidth) |
838 | 0 | { |
839 | 0 | mnCols = static_cast<sal_uInt16>((aWinSize.Width() - mnSpacing) / (mnUserItemWidth + mnSpacing)); |
840 | 0 | if (mnCols <= 0) |
841 | 0 | mnCols = 1; |
842 | 0 | } |
843 | 0 | else |
844 | 0 | { |
845 | 0 | mnCols = 1; |
846 | 0 | } |
847 | 0 | } |
848 | 0 | else |
849 | 0 | { |
850 | 0 | mnCols = mnUserCols; |
851 | 0 | } |
852 | | |
853 | | // calculate number of rows |
854 | 0 | auto nOldLines = mnLines; |
855 | | // Floor( (M+N-1)/N )==Ceiling( M/N ) |
856 | 0 | mnLines = (static_cast<tools::Long>(nItemCount) + mnCols - 1) / mnCols; |
857 | 0 | if (mnLines <= 0) |
858 | 0 | mnLines = 1; |
859 | |
|
860 | 0 | bool bAdjustmentOutOfDate = nOldLines != mnLines; |
861 | |
|
862 | 0 | auto nOldVisLines = mnVisLines; |
863 | |
|
864 | 0 | tools::Long nCalcHeight = aWinSize.Height(); |
865 | 0 | if (mnUserVisLines) |
866 | 0 | { |
867 | 0 | mnVisLines = mnUserVisLines; |
868 | 0 | } |
869 | 0 | else if (mnUserItemHeight) |
870 | 0 | { |
871 | 0 | mnVisLines = (nCalcHeight + mnSpacing) / (mnUserItemHeight + mnSpacing); |
872 | 0 | if (!mnVisLines) |
873 | 0 | mnVisLines = 1; |
874 | 0 | } |
875 | 0 | else |
876 | 0 | { |
877 | 0 | mnVisLines = mnLines; |
878 | 0 | } |
879 | |
|
880 | 0 | bAdjustmentOutOfDate |= nOldVisLines != mnVisLines; |
881 | |
|
882 | 0 | if (mnLines <= mnVisLines) |
883 | 0 | { |
884 | 0 | SetFirstLine(0); |
885 | 0 | } |
886 | 0 | else |
887 | 0 | { |
888 | 0 | if (mnFirstLine > o3tl::make_unsigned(mnLines - mnVisLines)) |
889 | 0 | SetFirstLine(static_cast<sal_uInt16>(mnLines - mnVisLines)); |
890 | 0 | } |
891 | | |
892 | | // calculate item size |
893 | 0 | const tools::Long nColSpace = (mnCols - 1) * static_cast<tools::Long>(mnSpacing); |
894 | 0 | const tools::Long nLineSpace = (mnVisLines - 1) * mnSpacing; |
895 | 0 | if (mnUserItemWidth && !mnUserCols) |
896 | 0 | { |
897 | 0 | mnItemWidth = mnUserItemWidth; |
898 | 0 | if (mnItemWidth > aWinSize.Width() - nColSpace) |
899 | 0 | mnItemWidth = aWinSize.Width() - nColSpace; |
900 | 0 | } |
901 | 0 | else |
902 | 0 | mnItemWidth = (aWinSize.Width() - nColSpace) / mnCols; |
903 | 0 | if (mnUserItemHeight && !mnUserVisLines) |
904 | 0 | { |
905 | 0 | mnItemHeight = mnUserItemHeight; |
906 | 0 | if (mnItemHeight > nCalcHeight) |
907 | 0 | mnItemHeight = nCalcHeight; |
908 | 0 | } |
909 | 0 | else |
910 | 0 | { |
911 | 0 | nCalcHeight -= nLineSpace; |
912 | 0 | mnItemHeight = nCalcHeight / mnVisLines; |
913 | 0 | } |
914 | | |
915 | | // Init VirDev |
916 | 0 | maVirDev->SetBackground(Application::GetSettings().GetStyleSettings().GetFaceColor()); |
917 | 0 | Size aDevSize(aWinSize); |
918 | 0 | aDevSize.AdjustWidth(mnMargin * 2); |
919 | 0 | aDevSize.AdjustHeight(mnMargin * 2); |
920 | 0 | maVirDev->SetOutputSizePixel(aDevSize); |
921 | 0 | maVirDev->Erase(); |
922 | | |
923 | | // nothing is changed in case of too small items |
924 | 0 | if ((mnItemWidth <= 0) || |
925 | 0 | (mnItemHeight <= ((nStyle & WB_ITEMBORDER) ? 4 : 2)) || |
926 | 0 | !nItemCount) |
927 | 0 | { |
928 | 0 | mbHasVisibleItems = false; |
929 | |
|
930 | 0 | for (size_t i = 0; i < nItemCount; i++) |
931 | 0 | { |
932 | 0 | mItemList[i]->mbVisible = false; |
933 | 0 | } |
934 | |
|
935 | 0 | if (mxScrolledWindow && mxScrolledWindow->get_vpolicy() != VclPolicyType::NEVER) |
936 | 0 | TurnOffScrollBar(); |
937 | 0 | } |
938 | 0 | else |
939 | 0 | { |
940 | 0 | mbHasVisibleItems = true; |
941 | | |
942 | | // determine Frame-Style |
943 | 0 | if (nStyle & WB_DOUBLEBORDER) |
944 | 0 | mnFrameStyle = DrawFrameStyle::DoubleIn; |
945 | 0 | else |
946 | 0 | mnFrameStyle = DrawFrameStyle::In; |
947 | | |
948 | | // draw the selection with double width if the items are bigger |
949 | 0 | if ((nStyle & WB_DOUBLEBORDER) && |
950 | 0 | ((mnItemWidth >= 25) && (mnItemHeight >= 20))) |
951 | 0 | { |
952 | 0 | mbDoubleSel = true; |
953 | 0 | } |
954 | 0 | else |
955 | 0 | { |
956 | 0 | mbDoubleSel = false; |
957 | 0 | } |
958 | | |
959 | | // calculate offsets |
960 | 0 | tools::Long nStartX; |
961 | 0 | tools::Long nStartY; |
962 | 0 | if (mbFullMode) |
963 | 0 | { |
964 | 0 | tools::Long nAllItemWidth = (mnItemWidth * mnCols) + nColSpace; |
965 | 0 | tools::Long nAllItemHeight = (mnItemHeight * mnVisLines) + nLineSpace; |
966 | 0 | nStartX = (aWinSize.Width() - nAllItemWidth) / 2; |
967 | 0 | nStartY = (aWinSize.Height() - nAllItemHeight) / 2; |
968 | 0 | } |
969 | 0 | else |
970 | 0 | { |
971 | 0 | nStartX = 0; |
972 | 0 | nStartY = 0; |
973 | 0 | } |
974 | |
|
975 | 0 | nStartX += mnMargin; |
976 | 0 | nStartY += mnMargin; |
977 | | |
978 | | // calculate and draw items |
979 | 0 | maVirDev->SetLineColor(); |
980 | 0 | tools::Long x = nStartX; |
981 | 0 | tools::Long y = nStartY; |
982 | | |
983 | | // draw items |
984 | 0 | size_t nFirstItem = static_cast<size_t>(mnFirstLine) * mnCols; |
985 | 0 | size_t nLastItem = nFirstItem + (mnVisLines * mnCols); |
986 | |
|
987 | 0 | maItemListRect.SetLeft( x ); |
988 | 0 | maItemListRect.SetTop( y ); |
989 | 0 | maItemListRect.SetRight( x + mnCols * (mnItemWidth + mnSpacing) - mnSpacing - 1 ); |
990 | 0 | maItemListRect.SetBottom( y + mnVisLines * (mnItemHeight + mnSpacing) - mnSpacing - 1 ); |
991 | |
|
992 | 0 | if (!mbFullMode) |
993 | 0 | { |
994 | | // If want also draw parts of items in the last line, |
995 | | // then we add one more line if parts of these line are |
996 | | // visible |
997 | 0 | if (y + (mnVisLines * (mnItemHeight + mnSpacing)) < aWinSize.Height()) |
998 | 0 | nLastItem += mnCols; |
999 | 0 | maItemListRect.SetBottom( aWinSize.Height() - y ); |
1000 | 0 | } |
1001 | 0 | for (size_t i = 0; i < nItemCount; i++) |
1002 | 0 | { |
1003 | 0 | ValueSetItem* pItem = mItemList[i].get(); |
1004 | |
|
1005 | 0 | if (i >= nFirstItem && i < nLastItem) |
1006 | 0 | { |
1007 | 0 | if (!pItem->mbVisible && ImplHasAccessibleListeners()) |
1008 | 0 | { |
1009 | 0 | Any aOldAny; |
1010 | 0 | Any aNewAny; |
1011 | |
|
1012 | 0 | aNewAny <<= Reference<XAccessible>(pItem->GetAccessible()); |
1013 | 0 | ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny); |
1014 | 0 | } |
1015 | |
|
1016 | 0 | pItem->mbVisible = true; |
1017 | 0 | ImplFormatItem(rRenderContext, *pItem, |
1018 | 0 | tools::Rectangle(Point(x, y), Size(mnItemWidth, mnItemHeight))); |
1019 | |
|
1020 | 0 | if (!((i + 1) % mnCols)) |
1021 | 0 | { |
1022 | 0 | x = nStartX; |
1023 | 0 | y += mnItemHeight + mnSpacing; |
1024 | 0 | } |
1025 | 0 | else |
1026 | 0 | x += mnItemWidth + mnSpacing; |
1027 | 0 | } |
1028 | 0 | else |
1029 | 0 | { |
1030 | 0 | if (pItem->mbVisible && ImplHasAccessibleListeners()) |
1031 | 0 | { |
1032 | 0 | Any aOldAny; |
1033 | 0 | Any aNewAny; |
1034 | |
|
1035 | 0 | aOldAny <<= Reference<XAccessible>(pItem->GetAccessible()); |
1036 | 0 | ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny); |
1037 | 0 | } |
1038 | |
|
1039 | 0 | pItem->mbVisible = false; |
1040 | 0 | } |
1041 | 0 | } |
1042 | | |
1043 | | // arrange ScrollBar, set values and show it |
1044 | 0 | if (mxScrolledWindow && (nStyle & WB_VSCROLL)) |
1045 | 0 | { |
1046 | 0 | bool bTurnScrollbarOn = mxScrolledWindow->get_vpolicy() != VclPolicyType::ALWAYS; |
1047 | 0 | if (bAdjustmentOutOfDate || bTurnScrollbarOn) |
1048 | 0 | { |
1049 | 0 | tools::Long nPageSize = mnVisLines; |
1050 | 0 | if (nPageSize < 1) |
1051 | 0 | nPageSize = 1; |
1052 | 0 | mxScrolledWindow->vadjustment_configure(mnFirstLine, mnLines, 1, mnVisLines, |
1053 | 0 | nPageSize); |
1054 | 0 | } |
1055 | |
|
1056 | 0 | if (bTurnScrollbarOn) |
1057 | 0 | TurnOnScrollBar(); |
1058 | 0 | } |
1059 | 0 | } |
1060 | | |
1061 | | // waiting for the next since the formatting is finished |
1062 | 0 | mbFormat = false; |
1063 | 0 | } |
1064 | | |
1065 | | void ValueSet::ImplDrawSelect(vcl::RenderContext& rRenderContext) |
1066 | 0 | { |
1067 | 0 | if (!IsReallyVisible()) |
1068 | 0 | return; |
1069 | | |
1070 | 0 | const bool bFocus = HasFocus(); |
1071 | |
|
1072 | 0 | if (!bFocus && mbNoSelection && !mbHighlight) |
1073 | 0 | return; |
1074 | | |
1075 | 0 | tools::Rectangle aSelectedRect, aHoverRect; |
1076 | 0 | ValueSetItem* pSelectedItem = ImplGetDrawSelectItem(mnSelItemId, bFocus, aSelectedRect); |
1077 | 0 | ValueSetItem* pHighlightItem = mnHighItemId ? ImplGetDrawSelectItem(mnHighItemId, false, aHoverRect) : nullptr; |
1078 | |
|
1079 | 0 | if (pSelectedItem) |
1080 | 0 | { |
1081 | 0 | const bool bHover = pSelectedItem == pHighlightItem; |
1082 | 0 | ImplDrawSelect(rRenderContext, aSelectedRect, pSelectedItem, bFocus, !mbNoSelection, true, bHover); |
1083 | 0 | } |
1084 | 0 | if (pHighlightItem && (pSelectedItem != pHighlightItem || mbNoSelection)) |
1085 | 0 | { |
1086 | | // For the case that there isn't a selected item, but due to wanting to |
1087 | | // show focus is in the valueset, the above block will have drawn the |
1088 | | // first item with a focus rect. For that situation; if the valueset is |
1089 | | // the thin WB_MENUSTYLEVALUESET case then blend this highlight border |
1090 | | // on top of that focus rect and it will appear with a highlighted |
1091 | | // focus rect. If it's the other case of a thicker border then redraw |
1092 | | // the focus rect highlighted with the hover color. |
1093 | 0 | bool bDrawFocus; |
1094 | 0 | WinBits nStyle = GetStyle(); |
1095 | 0 | if (nStyle & WB_MENUSTYLEVALUESET) |
1096 | 0 | bDrawFocus = false; |
1097 | 0 | else |
1098 | 0 | bDrawFocus = pSelectedItem == pHighlightItem && mbNoSelection; |
1099 | |
|
1100 | 0 | ImplDrawSelect(rRenderContext, aHoverRect, pHighlightItem, bDrawFocus, mbHighlight, false, true); |
1101 | 0 | } |
1102 | 0 | } |
1103 | | |
1104 | | ValueSetItem* ValueSet::ImplGetDrawSelectItem(sal_uInt16 nItemId, const bool bFocus, tools::Rectangle& rRect) |
1105 | 0 | { |
1106 | 0 | ValueSetItem* pItem = nullptr; |
1107 | 0 | if (nItemId) |
1108 | 0 | { |
1109 | 0 | const size_t nPos = GetItemPos( nItemId ); |
1110 | 0 | pItem = mItemList[ nPos ].get(); |
1111 | 0 | rRect = ImplGetItemRect( nPos ); |
1112 | 0 | } |
1113 | 0 | else if (bFocus && (pItem = ImplGetFirstItem())) |
1114 | 0 | { |
1115 | 0 | rRect = ImplGetItemRect(0); |
1116 | 0 | } |
1117 | 0 | return pItem; |
1118 | 0 | } |
1119 | | |
1120 | | void ValueSet::ImplDrawSelect(vcl::RenderContext& rRenderContext, |
1121 | | const tools::Rectangle& rRect, const ValueSetItem* pItem, |
1122 | | const bool bFocus, const bool bDrawSel, |
1123 | | const bool bSelected, const bool bHover) |
1124 | 0 | { |
1125 | 0 | tools::Rectangle aRect(rRect); |
1126 | | |
1127 | | // draw selection |
1128 | 0 | const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); |
1129 | 0 | rRenderContext.SetFillColor(); |
1130 | |
|
1131 | 0 | Color aDoubleColor; |
1132 | 0 | Color aSingleColor; |
1133 | |
|
1134 | 0 | sal_uInt16 nTransparencePercent = 0; |
1135 | |
|
1136 | 0 | if (bSelected && bHover) |
1137 | 0 | { |
1138 | 0 | aDoubleColor = rStyleSettings.GetActiveColor(); |
1139 | 0 | aSingleColor = rStyleSettings.GetActiveTextColor(); |
1140 | 0 | } |
1141 | 0 | else if (bSelected || bHover) |
1142 | 0 | { |
1143 | 0 | aDoubleColor = rStyleSettings.GetHighlightColor(); |
1144 | 0 | aSingleColor = rStyleSettings.GetHighlightTextColor(); |
1145 | 0 | if (bHover) |
1146 | 0 | { |
1147 | 0 | nTransparencePercent = 55; |
1148 | 0 | } |
1149 | 0 | } |
1150 | | |
1151 | | // specify selection output |
1152 | 0 | WinBits nStyle = GetStyle(); |
1153 | 0 | if (nStyle & WB_MENUSTYLEVALUESET) |
1154 | 0 | { |
1155 | 0 | if (bFocus) |
1156 | 0 | InvertFocusRect(rRenderContext, aRect); |
1157 | 0 | if (bDrawSel) |
1158 | 0 | { |
1159 | 0 | rRenderContext.SetLineColor(aDoubleColor); |
1160 | 0 | aRect.AdjustLeft( -1 ); |
1161 | 0 | aRect.AdjustTop( -1 ); |
1162 | 0 | aRect.AdjustRight( -2 ); |
1163 | 0 | aRect.AdjustBottom( -2 ); |
1164 | |
|
1165 | 0 | const tools::Polygon aPoly(aRect); |
1166 | 0 | LineInfo aLineInfo; |
1167 | 0 | aLineInfo.SetWidth(3); |
1168 | 0 | rRenderContext.DrawPolyLine(aPoly, aLineInfo); // tdf#136917 |
1169 | 0 | } |
1170 | 0 | } |
1171 | 0 | else |
1172 | 0 | { |
1173 | 0 | rRenderContext.SetLineColor(aDoubleColor); |
1174 | 0 | tools::Rectangle aFocusRect; |
1175 | |
|
1176 | 0 | if (!mbDoubleSel) |
1177 | 0 | { |
1178 | | // an outer rectangle surrounding a "focus" rectangle, surrounding |
1179 | | // an inner rectangle. Focus rectangle is always drawn, but rendered |
1180 | | // empty when there is no focus. e.g. as seen in color valuesets |
1181 | 0 | if (bDrawSel) |
1182 | 0 | { |
1183 | 0 | tools::PolyPolygon aPolyPoly(1); |
1184 | 0 | aPolyPoly.Insert(tools::Polygon(aRect)); |
1185 | 0 | rRenderContext.DrawTransparent(aPolyPoly, nTransparencePercent); |
1186 | 0 | } |
1187 | |
|
1188 | 0 | aRect.AdjustLeft( 1 ); |
1189 | 0 | aRect.AdjustTop( 1 ); |
1190 | 0 | aRect.AdjustRight( -1 ); |
1191 | 0 | aRect.AdjustBottom( -1 ); |
1192 | |
|
1193 | 0 | aFocusRect = aRect; |
1194 | |
|
1195 | 0 | aRect.AdjustLeft( 1 ); |
1196 | 0 | aRect.AdjustTop( 1 ); |
1197 | 0 | aRect.AdjustRight( -1 ); |
1198 | 0 | aRect.AdjustBottom( -1 ); |
1199 | |
|
1200 | 0 | if (bDrawSel) |
1201 | 0 | { |
1202 | 0 | tools::PolyPolygon aPolyPoly(1); |
1203 | 0 | aPolyPoly.Insert(tools::Polygon(aRect)); |
1204 | 0 | rRenderContext.DrawTransparent(aPolyPoly, nTransparencePercent); |
1205 | 0 | } |
1206 | |
|
1207 | 0 | if (bDrawSel) |
1208 | 0 | rRenderContext.SetLineColor(aSingleColor); |
1209 | 0 | else |
1210 | 0 | rRenderContext.SetLineColor(COL_LIGHTGRAY); |
1211 | |
|
1212 | 0 | rRenderContext.DrawRect(aFocusRect); |
1213 | 0 | } |
1214 | 0 | else |
1215 | 0 | { |
1216 | | // a thick bordered rectangle surrounding an optional "focus" |
1217 | | // rectangle which is only drawn when focused, as seen in format, |
1218 | | // bullets and numbering in writer |
1219 | 0 | const int nAdjust = 2; |
1220 | |
|
1221 | 0 | aRect.AdjustLeft(nAdjust); |
1222 | 0 | aRect.AdjustTop(nAdjust); |
1223 | 0 | aRect.AdjustRight(-nAdjust); |
1224 | 0 | aRect.AdjustBottom(-nAdjust); |
1225 | |
|
1226 | 0 | aFocusRect = aRect; |
1227 | |
|
1228 | 0 | if (bDrawSel) |
1229 | 0 | { |
1230 | 0 | const basegfx::B2DPolygon aRectPoly( |
1231 | 0 | basegfx::utils::createPolygonFromRect( |
1232 | 0 | vcl::unotools::b2DRectangleFromRectangle(aRect))); |
1233 | |
|
1234 | 0 | const int nThickness = nAdjust * 2; |
1235 | |
|
1236 | 0 | if (!rRenderContext.DrawPolyLineDirect(basegfx::B2DHomMatrix(), |
1237 | 0 | aRectPoly, |
1238 | 0 | nThickness, |
1239 | 0 | nTransparencePercent / 100.0, |
1240 | 0 | nullptr, |
1241 | 0 | basegfx::B2DLineJoin::Miter)) |
1242 | 0 | { |
1243 | 0 | SAL_WARN("svtools", "presumably impossible in practice, but fallback to see something"); |
1244 | 0 | rRenderContext.DrawPolyLine(aRectPoly, nThickness, basegfx::B2DLineJoin::Miter); |
1245 | 0 | } |
1246 | 0 | } |
1247 | | |
1248 | 0 | if (bFocus) |
1249 | 0 | { |
1250 | 0 | if (bDrawSel) |
1251 | 0 | rRenderContext.SetLineColor(aSingleColor); |
1252 | 0 | else |
1253 | 0 | rRenderContext.SetLineColor(COL_LIGHTGRAY); |
1254 | |
|
1255 | 0 | rRenderContext.DrawRect(aFocusRect); |
1256 | 0 | } |
1257 | 0 | } |
1258 | | |
1259 | 0 | if (bFocus) |
1260 | 0 | InvertFocusRect(rRenderContext, aFocusRect); |
1261 | 0 | } |
1262 | | |
1263 | 0 | ImplDrawItemText(rRenderContext, pItem->maText); |
1264 | 0 | } |
1265 | | |
1266 | | void ValueSet::ImplFormatItem(vcl::RenderContext const& rRenderContext, ValueSetItem& rItem, |
1267 | | tools::Rectangle aRect) |
1268 | 0 | { |
1269 | 0 | WinBits nStyle = GetStyle(); |
1270 | 0 | if (nStyle & WB_ITEMBORDER) |
1271 | 0 | { |
1272 | 0 | aRect.AdjustLeft(1 ); |
1273 | 0 | aRect.AdjustTop(1 ); |
1274 | 0 | aRect.AdjustRight( -1 ); |
1275 | 0 | aRect.AdjustBottom( -1 ); |
1276 | |
|
1277 | 0 | if (nStyle & WB_FLATVALUESET) |
1278 | 0 | { |
1279 | 0 | sal_Int32 nBorder = (nStyle & WB_DOUBLEBORDER) ? 2 : 1; |
1280 | |
|
1281 | 0 | aRect.AdjustLeft(nBorder ); |
1282 | 0 | aRect.AdjustTop(nBorder ); |
1283 | 0 | aRect.AdjustRight( -nBorder ); |
1284 | 0 | aRect.AdjustBottom( -nBorder ); |
1285 | 0 | } |
1286 | 0 | else |
1287 | 0 | { |
1288 | 0 | DecorationView aView(maVirDev.get()); |
1289 | 0 | aRect = aView.DrawFrame(aRect, mnFrameStyle); |
1290 | 0 | } |
1291 | 0 | } |
1292 | |
|
1293 | 0 | if ((aRect.GetHeight() <= 0) || (aRect.GetWidth() <= 0)) |
1294 | 0 | return; |
1295 | | |
1296 | 0 | const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); |
1297 | |
|
1298 | 0 | if (rItem.meType == ValueSetItemType::Color) |
1299 | 0 | { |
1300 | 0 | maVirDev->SetFillColor(rItem.maColor); |
1301 | 0 | maVirDev->DrawRect(aRect); |
1302 | 0 | } |
1303 | 0 | else |
1304 | 0 | { |
1305 | 0 | if (IsColor()) |
1306 | 0 | maVirDev->SetFillColor(maColor); |
1307 | 0 | else if (nStyle & WB_MENUSTYLEVALUESET) |
1308 | 0 | maVirDev->SetFillColor(rStyleSettings.GetMenuColor()); |
1309 | 0 | else if (IsEnabled()) |
1310 | 0 | maVirDev->SetFillColor(rStyleSettings.GetWindowColor()); |
1311 | 0 | else |
1312 | 0 | maVirDev->SetFillColor(rStyleSettings.GetFaceColor()); |
1313 | 0 | maVirDev->DrawRect(aRect); |
1314 | |
|
1315 | 0 | if (rItem.meType == ValueSetItemType::UserDraw) |
1316 | 0 | { |
1317 | 0 | UserDrawEvent aUDEvt(maVirDev.get(), aRect, rItem.mnId); |
1318 | 0 | UserDraw(aUDEvt); |
1319 | 0 | } |
1320 | 0 | else |
1321 | 0 | { |
1322 | 0 | Size aImageSize = rItem.maImage.GetSizePixel(); |
1323 | 0 | Size aRectSize = aRect.GetSize(); |
1324 | 0 | Point aPos(aRect.Left(), aRect.Top()); |
1325 | 0 | aPos.AdjustX((aRectSize.Width() - aImageSize.Width()) / 2 ); |
1326 | |
|
1327 | 0 | if (rItem.meType != ValueSetItemType::ImageAndText) |
1328 | 0 | aPos.AdjustY((aRectSize.Height() - aImageSize.Height()) / 2 ); |
1329 | |
|
1330 | 0 | DrawImageFlags nImageStyle = DrawImageFlags::NONE; |
1331 | 0 | if (!IsEnabled()) |
1332 | 0 | nImageStyle |= DrawImageFlags::Disable; |
1333 | |
|
1334 | 0 | if (aImageSize.Width() > aRectSize.Width() || |
1335 | 0 | aImageSize.Height() > aRectSize.Height()) |
1336 | 0 | { |
1337 | 0 | maVirDev->SetClipRegion(vcl::Region(aRect)); |
1338 | 0 | maVirDev->DrawImage(aPos, rItem.maImage, nImageStyle); |
1339 | 0 | maVirDev->SetClipRegion(); |
1340 | 0 | } |
1341 | 0 | else |
1342 | 0 | maVirDev->DrawImage(aPos, rItem.maImage, nImageStyle); |
1343 | |
|
1344 | 0 | if (rItem.meType == ValueSetItemType::ImageAndText) |
1345 | 0 | { |
1346 | 0 | maVirDev->SetFont(rRenderContext.GetFont()); |
1347 | 0 | maVirDev->SetTextColor((nStyle & WB_MENUSTYLEVALUESET) ? rStyleSettings.GetMenuTextColor() : rStyleSettings.GetWindowTextColor()); |
1348 | 0 | maVirDev->SetTextFillColor(); |
1349 | |
|
1350 | 0 | tools::Long nTxtWidth = maVirDev->GetTextWidth(rItem.maText); |
1351 | |
|
1352 | 0 | if (nTxtWidth > aRect.GetWidth()) |
1353 | 0 | maVirDev->SetClipRegion(vcl::Region(aRect)); |
1354 | |
|
1355 | 0 | maVirDev->DrawText(Point(aRect.Left() + (aRect.GetWidth() - nTxtWidth) / 2, |
1356 | 0 | aRect.Bottom() - maVirDev->GetTextHeight()), |
1357 | 0 | rItem.maText); |
1358 | |
|
1359 | 0 | if (nTxtWidth > aRect.GetWidth()) |
1360 | 0 | maVirDev->SetClipRegion(); |
1361 | 0 | } |
1362 | 0 | } |
1363 | 0 | } |
1364 | |
|
1365 | 0 | const sal_uInt16 nEdgeBlendingPercent = mbEdgeBlending ? rStyleSettings.GetEdgeBlending() : 0; |
1366 | |
|
1367 | 0 | if (nEdgeBlendingPercent) |
1368 | 0 | { |
1369 | 0 | const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor()); |
1370 | 0 | const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor()); |
1371 | 0 | const sal_uInt8 nAlpha(255 - ((nEdgeBlendingPercent * 255) / 100)); |
1372 | 0 | const Bitmap aBlendFrame(createAlphaBlendFrame(aRect.GetSize(), nAlpha, rTopLeft, rBottomRight)); |
1373 | |
|
1374 | 0 | if (!aBlendFrame.IsEmpty()) |
1375 | 0 | { |
1376 | 0 | maVirDev->DrawBitmap(aRect.TopLeft(), aBlendFrame); |
1377 | 0 | } |
1378 | 0 | } |
1379 | 0 | } |
1380 | | |
1381 | | void ValueSet::ImplDrawItemText(vcl::RenderContext& rRenderContext, const OUString& rText) |
1382 | 0 | { |
1383 | 0 | if (!(GetStyle() & WB_NAMEFIELD)) |
1384 | 0 | return; |
1385 | | |
1386 | 0 | Size aWinSize(GetOutputSizePixel()); |
1387 | 0 | tools::Long nTxtWidth = rRenderContext.GetTextWidth(rText); |
1388 | 0 | tools::Long nTxtOffset = mnTextOffset; |
1389 | |
|
1390 | 0 | auto popIt = rRenderContext.ScopedPush(vcl::PushFlags::TEXTCOLOR); |
1391 | | |
1392 | | // delete rectangle and show text |
1393 | 0 | const bool bFlat(GetStyle() & WB_FLATVALUESET); |
1394 | 0 | if (!bFlat) |
1395 | 0 | nTxtOffset += NAME_LINE_HEIGHT+NAME_LINE_OFF_Y; |
1396 | |
|
1397 | 0 | rRenderContext.SetTextColor(Application::GetSettings().GetStyleSettings().GetButtonTextColor()); |
1398 | | // tdf#153787 highlighted entry text is drawn in the same Paint as the selected text, so can |
1399 | | // overwrite already rendered text |
1400 | 0 | rRenderContext.Erase(tools::Rectangle(Point(0, nTxtOffset), Point(aWinSize.Width(), aWinSize.Height()))); |
1401 | 0 | rRenderContext.DrawText(Point((aWinSize.Width() - nTxtWidth) / 2, nTxtOffset + (NAME_OFFSET / 2)), rText); |
1402 | 0 | } |
1403 | | |
1404 | | void ValueSet::StyleUpdated() |
1405 | 0 | { |
1406 | 0 | mbFormat = true; |
1407 | 0 | CustomWidgetController::StyleUpdated(); |
1408 | 0 | } |
1409 | | |
1410 | | void ValueSet::EnableFullItemMode( bool bFullMode ) |
1411 | 0 | { |
1412 | 0 | mbFullMode = bFullMode; |
1413 | 0 | } |
1414 | | |
1415 | | void ValueSet::SetColCount( sal_uInt16 nNewCols ) |
1416 | 0 | { |
1417 | 0 | if ( mnUserCols != nNewCols ) |
1418 | 0 | { |
1419 | 0 | mnUserCols = nNewCols; |
1420 | 0 | QueueReformat(); |
1421 | 0 | } |
1422 | 0 | } |
1423 | | |
1424 | | void ValueSet::SetItemImage( sal_uInt16 nItemId, const Image& rImage ) |
1425 | 0 | { |
1426 | 0 | size_t nPos = GetItemPos( nItemId ); |
1427 | |
|
1428 | 0 | if ( nPos == VALUESET_ITEM_NOTFOUND ) |
1429 | 0 | return; |
1430 | | |
1431 | 0 | ValueSetItem* pItem = mItemList[nPos].get(); |
1432 | 0 | pItem->meType = ValueSetItemType::Image; |
1433 | 0 | pItem->maImage = rImage; |
1434 | |
|
1435 | 0 | if (!mbFormat && IsReallyVisible()) |
1436 | 0 | { |
1437 | 0 | const tools::Rectangle aRect = ImplGetItemRect(nPos); |
1438 | 0 | Invalidate(aRect); |
1439 | 0 | } |
1440 | 0 | else |
1441 | 0 | mbFormat = true; |
1442 | 0 | } |
1443 | | |
1444 | | void ValueSet::SetItemColor( sal_uInt16 nItemId, const Color& rColor ) |
1445 | 0 | { |
1446 | 0 | size_t nPos = GetItemPos( nItemId ); |
1447 | |
|
1448 | 0 | if ( nPos == VALUESET_ITEM_NOTFOUND ) |
1449 | 0 | return; |
1450 | | |
1451 | 0 | ValueSetItem* pItem = mItemList[nPos].get(); |
1452 | 0 | pItem->meType = ValueSetItemType::Color; |
1453 | 0 | pItem->maColor = rColor; |
1454 | |
|
1455 | 0 | if (!mbFormat && IsReallyVisible()) |
1456 | 0 | { |
1457 | 0 | const tools::Rectangle aRect = ImplGetItemRect(nPos); |
1458 | 0 | Invalidate( aRect ); |
1459 | 0 | } |
1460 | 0 | else |
1461 | 0 | mbFormat = true; |
1462 | 0 | } |
1463 | | |
1464 | | Color ValueSet::GetItemColor( sal_uInt16 nItemId ) const |
1465 | 0 | { |
1466 | 0 | size_t nPos = GetItemPos( nItemId ); |
1467 | |
|
1468 | 0 | if ( nPos != VALUESET_ITEM_NOTFOUND ) |
1469 | 0 | return mItemList[nPos]->maColor; |
1470 | 0 | else |
1471 | 0 | return Color(); |
1472 | 0 | } |
1473 | | |
1474 | | Size ValueSet::CalcWindowSizePixel( const Size& rItemSize, sal_uInt16 nDesireCols, |
1475 | | sal_uInt16 nDesireLines ) const |
1476 | 0 | { |
1477 | 0 | size_t nCalcCols = nDesireCols; |
1478 | 0 | size_t nCalcLines = nDesireLines; |
1479 | |
|
1480 | 0 | if ( !nCalcCols ) |
1481 | 0 | { |
1482 | 0 | if ( mnUserCols ) |
1483 | 0 | nCalcCols = mnUserCols; |
1484 | 0 | else |
1485 | 0 | nCalcCols = 1; |
1486 | 0 | } |
1487 | |
|
1488 | 0 | if ( !nCalcLines ) |
1489 | 0 | { |
1490 | 0 | nCalcLines = mnVisLines; |
1491 | |
|
1492 | 0 | if ( mbFormat ) |
1493 | 0 | { |
1494 | 0 | if ( mnUserVisLines ) |
1495 | 0 | nCalcLines = mnUserVisLines; |
1496 | 0 | else |
1497 | 0 | { |
1498 | | // Floor( (M+N-1)/N )==Ceiling( M/N ) |
1499 | 0 | nCalcLines = (mItemList.size()+nCalcCols-1) / nCalcCols; |
1500 | 0 | if ( !nCalcLines ) |
1501 | 0 | nCalcLines = 1; |
1502 | 0 | } |
1503 | 0 | } |
1504 | 0 | } |
1505 | |
|
1506 | 0 | Size aSize( rItemSize.Width() * nCalcCols, rItemSize.Height() * nCalcLines ); |
1507 | 0 | WinBits nStyle = GetStyle(); |
1508 | 0 | tools::Long nTxtHeight = GetTextHeight(); |
1509 | 0 | tools::Long n; |
1510 | |
|
1511 | 0 | if ( nStyle & WB_ITEMBORDER ) |
1512 | 0 | { |
1513 | 0 | if ( nStyle & WB_DOUBLEBORDER ) |
1514 | 0 | n = ITEM_OFFSET_DOUBLE; |
1515 | 0 | else |
1516 | 0 | n = ITEM_OFFSET; |
1517 | |
|
1518 | 0 | aSize.AdjustWidth(n * nCalcCols ); |
1519 | 0 | aSize.AdjustHeight(n * nCalcLines ); |
1520 | 0 | } |
1521 | 0 | else |
1522 | 0 | n = 0; |
1523 | |
|
1524 | 0 | if ( mnSpacing ) |
1525 | 0 | { |
1526 | 0 | aSize.AdjustWidth(mnSpacing * (nCalcCols - 1) ); |
1527 | 0 | aSize.AdjustHeight(mnSpacing * (nCalcLines - 1) ); |
1528 | 0 | } |
1529 | |
|
1530 | 0 | if ( nStyle & WB_NAMEFIELD ) |
1531 | 0 | { |
1532 | 0 | aSize.AdjustHeight(nTxtHeight + NAME_OFFSET ); |
1533 | 0 | if ( !(nStyle & WB_FLATVALUESET) ) |
1534 | 0 | aSize.AdjustHeight(NAME_LINE_HEIGHT + NAME_LINE_OFF_Y ); |
1535 | 0 | } |
1536 | |
|
1537 | 0 | if ( mnMargin ) |
1538 | 0 | { |
1539 | 0 | aSize.AdjustWidth(mnMargin * 2); |
1540 | 0 | aSize.AdjustHeight(mnMargin * 2); |
1541 | 0 | } |
1542 | |
|
1543 | 0 | return aSize; |
1544 | 0 | } |
1545 | | |
1546 | | void ValueSet::InsertItem( sal_uInt16 nItemId, const Image& rImage ) |
1547 | 0 | { |
1548 | 0 | std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this )); |
1549 | 0 | pItem->mnId = nItemId; |
1550 | 0 | pItem->meType = ValueSetItemType::Image; |
1551 | 0 | pItem->maImage = rImage; |
1552 | 0 | ImplInsertItem( std::move(pItem), VALUESET_APPEND ); |
1553 | 0 | } |
1554 | | |
1555 | | void ValueSet::InsertItem( sal_uInt16 nItemId, const Image& rImage, |
1556 | | const OUString& rText, size_t nPos, |
1557 | | bool bShowLegend ) |
1558 | 0 | { |
1559 | 0 | std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this )); |
1560 | 0 | pItem->mnId = nItemId; |
1561 | 0 | pItem->meType = bShowLegend ? ValueSetItemType::ImageAndText : ValueSetItemType::Image; |
1562 | 0 | pItem->maImage = rImage; |
1563 | 0 | pItem->maText = rText; |
1564 | 0 | ImplInsertItem( std::move(pItem), nPos ); |
1565 | 0 | } |
1566 | | |
1567 | | void ValueSet::InsertItem( sal_uInt16 nItemId, size_t nPos ) |
1568 | 0 | { |
1569 | 0 | std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this )); |
1570 | 0 | pItem->mnId = nItemId; |
1571 | 0 | pItem->meType = ValueSetItemType::UserDraw; |
1572 | 0 | ImplInsertItem( std::move(pItem), nPos ); |
1573 | 0 | } |
1574 | | |
1575 | | void ValueSet::InsertItem( sal_uInt16 nItemId, const Color& rColor, |
1576 | | const OUString& rText ) |
1577 | 0 | { |
1578 | 0 | std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this )); |
1579 | 0 | pItem->mnId = nItemId; |
1580 | 0 | pItem->meType = ValueSetItemType::Color; |
1581 | 0 | pItem->maColor = rColor; |
1582 | 0 | pItem->maText = rText; |
1583 | 0 | ImplInsertItem( std::move(pItem), VALUESET_APPEND ); |
1584 | 0 | } |
1585 | | |
1586 | | void ValueSet::ImplInsertItem( std::unique_ptr<ValueSetItem> pItem, const size_t nPos ) |
1587 | 0 | { |
1588 | 0 | DBG_ASSERT( pItem->mnId, "ValueSet::InsertItem(): ItemId == 0" ); |
1589 | 0 | DBG_ASSERT( GetItemPos( pItem->mnId ) == VALUESET_ITEM_NOTFOUND, |
1590 | 0 | "ValueSet::InsertItem(): ItemId already exists" ); |
1591 | |
|
1592 | 0 | if ( nPos < mItemList.size() ) { |
1593 | 0 | mItemList.insert( mItemList.begin() + nPos, std::move(pItem) ); |
1594 | 0 | } else { |
1595 | 0 | mItemList.push_back( std::move(pItem) ); |
1596 | 0 | } |
1597 | |
|
1598 | 0 | QueueReformat(); |
1599 | 0 | } |
1600 | | |
1601 | | int ValueSet::GetScrollWidth() const |
1602 | 0 | { |
1603 | 0 | if (mxScrolledWindow) |
1604 | 0 | return mxScrolledWindow->get_scroll_thickness(); |
1605 | 0 | return 0; |
1606 | 0 | } |
1607 | | |
1608 | | void ValueSet::SetEdgeBlending(bool bNew) |
1609 | 0 | { |
1610 | 0 | if(mbEdgeBlending != bNew) |
1611 | 0 | { |
1612 | 0 | mbEdgeBlending = bNew; |
1613 | 0 | mbFormat = true; |
1614 | |
|
1615 | 0 | if (GetDrawingArea() && IsReallyVisible()) |
1616 | 0 | { |
1617 | 0 | Invalidate(); |
1618 | 0 | } |
1619 | 0 | } |
1620 | 0 | } |
1621 | | |
1622 | | Size ValueSet::CalcItemSizePixel( const Size& rItemSize) const |
1623 | 0 | { |
1624 | 0 | Size aSize = rItemSize; |
1625 | |
|
1626 | 0 | WinBits nStyle = GetStyle(); |
1627 | 0 | if ( nStyle & WB_ITEMBORDER ) |
1628 | 0 | { |
1629 | 0 | tools::Long n; |
1630 | |
|
1631 | 0 | if ( nStyle & WB_DOUBLEBORDER ) |
1632 | 0 | n = ITEM_OFFSET_DOUBLE; |
1633 | 0 | else |
1634 | 0 | n = ITEM_OFFSET; |
1635 | |
|
1636 | 0 | aSize.AdjustWidth(n ); |
1637 | 0 | aSize.AdjustHeight(n ); |
1638 | 0 | } |
1639 | |
|
1640 | 0 | return aSize; |
1641 | 0 | } |
1642 | | |
1643 | | void ValueSet::SetLineCount( sal_uInt16 nNewLines ) |
1644 | 0 | { |
1645 | 0 | if ( mnUserVisLines != nNewLines ) |
1646 | 0 | { |
1647 | 0 | mnUserVisLines = nNewLines; |
1648 | 0 | QueueReformat(); |
1649 | 0 | } |
1650 | 0 | } |
1651 | | |
1652 | | void ValueSet::SetItemWidth( tools::Long nNewItemWidth ) |
1653 | 0 | { |
1654 | 0 | if ( mnUserItemWidth != nNewItemWidth ) |
1655 | 0 | { |
1656 | 0 | mnUserItemWidth = nNewItemWidth; |
1657 | 0 | QueueReformat(); |
1658 | 0 | } |
1659 | 0 | } |
1660 | | |
1661 | | //method to set accessible when the style is user draw. |
1662 | | void ValueSet::InsertItem( sal_uInt16 nItemId, const OUString& rText, size_t nPos ) |
1663 | 0 | { |
1664 | 0 | DBG_ASSERT( nItemId, "ValueSet::InsertItem(): ItemId == 0" ); |
1665 | 0 | DBG_ASSERT( GetItemPos( nItemId ) == VALUESET_ITEM_NOTFOUND, |
1666 | 0 | "ValueSet::InsertItem(): ItemId already exists" ); |
1667 | 0 | std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this )); |
1668 | 0 | pItem->mnId = nItemId; |
1669 | 0 | pItem->meType = ValueSetItemType::UserDraw; |
1670 | 0 | pItem->maText = rText; |
1671 | 0 | ImplInsertItem( std::move(pItem), nPos ); |
1672 | 0 | } |
1673 | | |
1674 | | void ValueSet::SetItemHeight( tools::Long nNewItemHeight ) |
1675 | 0 | { |
1676 | 0 | if ( mnUserItemHeight != nNewItemHeight ) |
1677 | 0 | { |
1678 | 0 | mnUserItemHeight = nNewItemHeight; |
1679 | 0 | QueueReformat(); |
1680 | 0 | } |
1681 | 0 | } |
1682 | | |
1683 | | OUString ValueSet::RequestHelp(tools::Rectangle& rHelpRect) |
1684 | 0 | { |
1685 | 0 | Point aPos = rHelpRect.TopLeft(); |
1686 | 0 | const size_t nItemPos = ImplGetItem( aPos ); |
1687 | 0 | OUString sRet; |
1688 | 0 | if (nItemPos != VALUESET_ITEM_NOTFOUND) |
1689 | 0 | { |
1690 | 0 | rHelpRect = ImplGetItemRect(nItemPos); |
1691 | 0 | sRet = GetItemText(ImplGetItem(nItemPos)->mnId); |
1692 | 0 | } |
1693 | 0 | return sRet; |
1694 | 0 | } |
1695 | | |
1696 | | const OUString & ValueSet::GetItemText(sal_uInt16 nItemId) const |
1697 | 0 | { |
1698 | 0 | const size_t nPos = GetItemPos(nItemId); |
1699 | |
|
1700 | 0 | if ( nPos != VALUESET_ITEM_NOTFOUND ) |
1701 | 0 | return mItemList[nPos]->maText; |
1702 | | |
1703 | 0 | return EMPTY_OUSTRING; |
1704 | 0 | } |
1705 | | |
1706 | | void ValueSet::SetExtraSpacing( sal_uInt16 nNewSpacing ) |
1707 | 0 | { |
1708 | 0 | if ( GetStyle() & WB_ITEMBORDER ) |
1709 | 0 | { |
1710 | 0 | mnSpacing = nNewSpacing; |
1711 | 0 | QueueReformat(); |
1712 | 0 | } |
1713 | 0 | } |
1714 | | |
1715 | | void ValueSet::SetMargin( sal_uInt16 nNewMargin ) |
1716 | 0 | { |
1717 | 0 | mnMargin = nNewMargin; |
1718 | 0 | QueueReformat(); |
1719 | 0 | } |
1720 | | |
1721 | | void ValueSet::SetFormat() |
1722 | 0 | { |
1723 | 0 | mbFormat = true; |
1724 | 0 | } |
1725 | | |
1726 | | void ValueSet::SetItemData( sal_uInt16 nItemId, void* pData ) |
1727 | 0 | { |
1728 | 0 | size_t nPos = GetItemPos( nItemId ); |
1729 | |
|
1730 | 0 | if ( nPos == VALUESET_ITEM_NOTFOUND ) |
1731 | 0 | return; |
1732 | | |
1733 | 0 | ValueSetItem* pItem = mItemList[nPos].get(); |
1734 | 0 | pItem->mpData = pData; |
1735 | |
|
1736 | 0 | if (pItem->meType == ValueSetItemType::UserDraw) |
1737 | 0 | { |
1738 | 0 | if (!mbFormat && IsReallyVisible()) |
1739 | 0 | { |
1740 | 0 | const tools::Rectangle aRect = ImplGetItemRect(nPos); |
1741 | 0 | Invalidate(aRect); |
1742 | 0 | } |
1743 | 0 | else |
1744 | 0 | mbFormat = true; |
1745 | 0 | } |
1746 | 0 | } |
1747 | | |
1748 | | void* ValueSet::GetItemData( sal_uInt16 nItemId ) const |
1749 | 0 | { |
1750 | 0 | size_t nPos = GetItemPos( nItemId ); |
1751 | |
|
1752 | 0 | if ( nPos != VALUESET_ITEM_NOTFOUND ) |
1753 | 0 | return mItemList[nPos]->mpData; |
1754 | 0 | else |
1755 | 0 | return nullptr; |
1756 | 0 | } |
1757 | | |
1758 | | void ValueSet::SetItemText(sal_uInt16 nItemId, const OUString& rText) |
1759 | 0 | { |
1760 | 0 | size_t nPos = GetItemPos( nItemId ); |
1761 | |
|
1762 | 0 | if ( nPos == VALUESET_ITEM_NOTFOUND ) |
1763 | 0 | return; |
1764 | | |
1765 | 0 | ValueSetItem* pItem = mItemList[nPos].get(); |
1766 | | |
1767 | | // Remember old and new name for accessibility event. |
1768 | 0 | Any aOldName; |
1769 | 0 | Any aNewName; |
1770 | 0 | OUString sString (pItem->maText); |
1771 | 0 | aOldName <<= sString; |
1772 | 0 | sString = rText; |
1773 | 0 | aNewName <<= sString; |
1774 | |
|
1775 | 0 | pItem->maText = rText; |
1776 | |
|
1777 | 0 | if (!mbFormat && IsReallyVisible()) |
1778 | 0 | { |
1779 | 0 | sal_uInt16 nTempId = mnSelItemId; |
1780 | |
|
1781 | 0 | if (mbHighlight) |
1782 | 0 | nTempId = mnHighItemId; |
1783 | |
|
1784 | 0 | if (nTempId == nItemId) |
1785 | 0 | Invalidate(); |
1786 | 0 | } |
1787 | |
|
1788 | 0 | if (ImplHasAccessibleListeners()) |
1789 | 0 | { |
1790 | 0 | rtl::Reference<ValueItemAcc> xAccessible(pItem->GetAccessible()); |
1791 | 0 | xAccessible->FireAccessibleEvent(AccessibleEventId::NAME_CHANGED, aOldName, aNewName); |
1792 | 0 | } |
1793 | 0 | } |
1794 | | |
1795 | | Size ValueSet::GetLargestItemSize() |
1796 | 0 | { |
1797 | 0 | Size aLargestItem; |
1798 | |
|
1799 | 0 | for (const std::unique_ptr<ValueSetItem>& pItem : mItemList) |
1800 | 0 | { |
1801 | 0 | if (!pItem->mbVisible) |
1802 | 0 | continue; |
1803 | | |
1804 | 0 | if (pItem->meType != ValueSetItemType::Image && |
1805 | 0 | pItem->meType != ValueSetItemType::ImageAndText) |
1806 | 0 | { |
1807 | | // handle determining an optimal size for this case |
1808 | 0 | continue; |
1809 | 0 | } |
1810 | | |
1811 | 0 | Size aSize = pItem->maImage.GetSizePixel(); |
1812 | 0 | if (pItem->meType == ValueSetItemType::ImageAndText) |
1813 | 0 | { |
1814 | 0 | aSize.AdjustHeight(3 * NAME_LINE_HEIGHT + |
1815 | 0 | maVirDev->GetTextHeight() ); |
1816 | 0 | aSize.setWidth( std::max(aSize.Width(), |
1817 | 0 | maVirDev->GetTextWidth(pItem->maText) + NAME_OFFSET) ); |
1818 | 0 | } |
1819 | |
|
1820 | 0 | aLargestItem.setWidth( std::max(aLargestItem.Width(), aSize.Width()) ); |
1821 | 0 | aLargestItem.setHeight( std::max(aLargestItem.Height(), aSize.Height()) ); |
1822 | 0 | } |
1823 | |
|
1824 | 0 | return aLargestItem; |
1825 | 0 | } |
1826 | | |
1827 | | void ValueSet::SetOptimalSize() |
1828 | 0 | { |
1829 | 0 | Size aLargestSize(GetLargestItemSize()); |
1830 | 0 | aLargestSize.setWidth(std::max(aLargestSize.Width(), mnUserItemWidth)); |
1831 | 0 | aLargestSize.setHeight(std::max(aLargestSize.Height(), mnUserItemHeight)); |
1832 | 0 | Size aPrefSize(CalcWindowSizePixel(aLargestSize)); |
1833 | 0 | GetDrawingArea()->set_size_request(aPrefSize.Width(), aPrefSize.Height()); |
1834 | 0 | } |
1835 | | |
1836 | | Image ValueSet::GetItemImage(sal_uInt16 nItemId) const |
1837 | 0 | { |
1838 | 0 | size_t nPos = GetItemPos( nItemId ); |
1839 | |
|
1840 | 0 | if ( nPos != VALUESET_ITEM_NOTFOUND ) |
1841 | 0 | return mItemList[nPos]->maImage; |
1842 | 0 | else |
1843 | 0 | return Image(); |
1844 | 0 | } |
1845 | | |
1846 | | void ValueSet::SetColor(const Color& rColor) |
1847 | 0 | { |
1848 | 0 | maColor = rColor; |
1849 | 0 | mbFormat = true; |
1850 | 0 | if (IsReallyVisible()) |
1851 | 0 | Invalidate(); |
1852 | 0 | } |
1853 | | |
1854 | | void ValueSet::Show() |
1855 | 0 | { |
1856 | 0 | if (mxScrolledWindow) |
1857 | 0 | mxScrolledWindow->show(); |
1858 | 0 | CustomWidgetController::Show(); |
1859 | 0 | } |
1860 | | |
1861 | | void ValueSet::Hide() |
1862 | 0 | { |
1863 | 0 | CustomWidgetController::Hide(); |
1864 | 0 | if (mxScrolledWindow) |
1865 | 0 | mxScrolledWindow->hide(); |
1866 | 0 | } |
1867 | | |
1868 | | FactoryFunction ValueSet::GetUITestFactory() const |
1869 | 0 | { |
1870 | 0 | return ValueSetUIObject::create; |
1871 | 0 | } |
1872 | | |
1873 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |