/src/libreoffice/vcl/source/window/layout.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 | | |
10 | | #include <sal/config.h> |
11 | | |
12 | | // Needed since LLVM 15 libc++ (hence the ignored -Wunused-macros for older libc++) when |
13 | | // #include <boost/multi_array.hpp> below includes Boost 1.79.0 |
14 | | // workdir/UnpackedTarball/boost/boost/functional.hpp using std::unary_function, but must |
15 | | // come very early here in case <functional> is already (indirectly) included earlier: |
16 | | #include <config_libcxx.h> |
17 | | #if HAVE_LIBCPP |
18 | | #if defined __clang__ |
19 | | #pragma clang diagnostic push |
20 | | #pragma clang diagnostic ignored "-Wunused-macros" |
21 | | #endif |
22 | | // [-loplugin:reservedid]: |
23 | | #define _LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION |
24 | | #if defined __clang__ |
25 | | #pragma clang diagnostic pop |
26 | | #endif |
27 | | #endif |
28 | | |
29 | | #include <string_view> |
30 | | |
31 | | #include <config_features.h> |
32 | | #include <com/sun/star/accessibility/AccessibleRole.hpp> |
33 | | #include <comphelper/base64.hxx> |
34 | | #include <comphelper/lok.hxx> |
35 | | #include <o3tl/enumarray.hxx> |
36 | | #include <o3tl/enumrange.hxx> |
37 | | #include <o3tl/string_view.hxx> |
38 | | #include <tools/stream.hxx> |
39 | | #include <utility> |
40 | | #include <vcl/builder.hxx> |
41 | | #include <vcl/toolkit/button.hxx> |
42 | | #include <vcl/cvtgrf.hxx> |
43 | | #include <vcl/decoview.hxx> |
44 | | #include <vcl/help.hxx> |
45 | | #include <vcl/toolkit/dialog.hxx> |
46 | | #include <vcl/layout.hxx> |
47 | | #include <vcl/toolkit/scrbar.hxx> |
48 | | #include <vcl/salnativewidgets.hxx> |
49 | | #include <vcl/stdtext.hxx> |
50 | | #include <vcl/split.hxx> |
51 | | #include <vcl/svapp.hxx> |
52 | | #include <vcl/settings.hxx> |
53 | | #include <vcl/virdev.hxx> |
54 | | #include <bitmaps.hlst> |
55 | | #include <messagedialog.hxx> |
56 | | #include <svdata.hxx> |
57 | | #include <window.h> |
58 | | #include <boost/multi_array.hpp> |
59 | | #include <vcl/toolkit/vclmedit.hxx> |
60 | | #include <vcl/uitest/uiobject.hxx> |
61 | | #include <sal/log.hxx> |
62 | | #include <tools/json_writer.hxx> |
63 | | |
64 | | VclContainer::VclContainer(vcl::Window *pParent, WinBits nStyle) |
65 | 0 | : Window(WindowType::CONTAINER) |
66 | 0 | , m_bLayoutDirty(true) |
67 | 0 | { |
68 | 0 | ImplInit(pParent, nStyle, nullptr); |
69 | 0 | EnableChildTransparentMode(); |
70 | 0 | SetPaintTransparent(true); |
71 | 0 | SetBackground(); |
72 | 0 | } |
73 | | |
74 | | sal_uInt16 VclContainer::getDefaultAccessibleRole() const |
75 | 0 | { |
76 | 0 | return css::accessibility::AccessibleRole::PANEL; |
77 | 0 | } |
78 | | |
79 | | Size VclContainer::GetOptimalSize() const |
80 | 0 | { |
81 | 0 | return calculateRequisition(); |
82 | 0 | } |
83 | | |
84 | | void VclContainer::setLayoutPosSize(vcl::Window &rWindow, const Point &rPos, const Size &rSize) |
85 | 0 | { |
86 | 0 | sal_Int32 nBorderWidth = rWindow.get_border_width(); |
87 | 0 | sal_Int32 nLeft = rWindow.get_margin_start() + nBorderWidth; |
88 | 0 | sal_Int32 nTop = rWindow.get_margin_top() + nBorderWidth; |
89 | 0 | sal_Int32 nRight = rWindow.get_margin_end() + nBorderWidth; |
90 | 0 | sal_Int32 nBottom = rWindow.get_margin_bottom() + nBorderWidth; |
91 | 0 | Point aPos(rPos.X() + nLeft, rPos.Y() + nTop); |
92 | 0 | Size aSize(rSize.Width() - nLeft - nRight, rSize.Height() - nTop - nBottom); |
93 | 0 | rWindow.SetPosSizePixel(aPos, aSize); |
94 | 0 | } |
95 | | |
96 | | void VclContainer::setLayoutAllocation(vcl::Window &rChild, const Point &rAllocPos, const Size &rChildAlloc) |
97 | 0 | { |
98 | 0 | VclAlign eHalign = rChild.get_halign(); |
99 | 0 | VclAlign eValign = rChild.get_valign(); |
100 | | |
101 | | //typical case |
102 | 0 | if (eHalign == VclAlign::Fill && eValign == VclAlign::Fill) |
103 | 0 | { |
104 | 0 | setLayoutPosSize(rChild, rAllocPos, rChildAlloc); |
105 | 0 | return; |
106 | 0 | } |
107 | | |
108 | 0 | Point aChildPos(rAllocPos); |
109 | 0 | Size aChildSize(rChildAlloc); |
110 | 0 | Size aChildPreferredSize(getLayoutRequisition(rChild)); |
111 | |
|
112 | 0 | switch (eHalign) |
113 | 0 | { |
114 | 0 | case VclAlign::Fill: |
115 | 0 | break; |
116 | 0 | case VclAlign::Start: |
117 | 0 | if (aChildPreferredSize.Width() < rChildAlloc.Width()) |
118 | 0 | aChildSize.setWidth( aChildPreferredSize.Width() ); |
119 | 0 | break; |
120 | 0 | case VclAlign::End: |
121 | 0 | if (aChildPreferredSize.Width() < rChildAlloc.Width()) |
122 | 0 | aChildSize.setWidth( aChildPreferredSize.Width() ); |
123 | 0 | aChildPos.AdjustX(rChildAlloc.Width() ); |
124 | 0 | aChildPos.AdjustX( -(aChildSize.Width()) ); |
125 | 0 | break; |
126 | 0 | case VclAlign::Center: |
127 | 0 | if (aChildPreferredSize.Width() < aChildSize.Width()) |
128 | 0 | aChildSize.setWidth( aChildPreferredSize.Width() ); |
129 | 0 | aChildPos.AdjustX((rChildAlloc.Width() - aChildSize.Width()) / 2 ); |
130 | 0 | break; |
131 | 0 | } |
132 | | |
133 | 0 | switch (eValign) |
134 | 0 | { |
135 | 0 | case VclAlign::Fill: |
136 | 0 | break; |
137 | 0 | case VclAlign::Start: |
138 | 0 | if (aChildPreferredSize.Height() < rChildAlloc.Height()) |
139 | 0 | aChildSize.setHeight( aChildPreferredSize.Height() ); |
140 | 0 | break; |
141 | 0 | case VclAlign::End: |
142 | 0 | if (aChildPreferredSize.Height() < rChildAlloc.Height()) |
143 | 0 | aChildSize.setHeight( aChildPreferredSize.Height() ); |
144 | 0 | aChildPos.AdjustY(rChildAlloc.Height() ); |
145 | 0 | aChildPos.AdjustY( -(aChildSize.Height()) ); |
146 | 0 | break; |
147 | 0 | case VclAlign::Center: |
148 | 0 | if (aChildPreferredSize.Height() < aChildSize.Height()) |
149 | 0 | aChildSize.setHeight( aChildPreferredSize.Height() ); |
150 | 0 | aChildPos.AdjustY((rChildAlloc.Height() - aChildSize.Height()) / 2 ); |
151 | 0 | break; |
152 | 0 | } |
153 | | |
154 | 0 | setLayoutPosSize(rChild, aChildPos, aChildSize); |
155 | 0 | } |
156 | | |
157 | | namespace |
158 | | { |
159 | | Size subtractBorder(const vcl::Window &rWindow, const Size& rSize) |
160 | 0 | { |
161 | 0 | sal_Int32 nBorderWidth = rWindow.get_border_width(); |
162 | 0 | sal_Int32 nLeft = rWindow.get_margin_start() + nBorderWidth; |
163 | 0 | sal_Int32 nTop = rWindow.get_margin_top() + nBorderWidth; |
164 | 0 | sal_Int32 nRight = rWindow.get_margin_end() + nBorderWidth; |
165 | 0 | sal_Int32 nBottom = rWindow.get_margin_bottom() + nBorderWidth; |
166 | 0 | Size aSize(rSize); |
167 | 0 | return Size(aSize.Width() + nLeft + nRight, aSize.Height() + nTop + nBottom); |
168 | 0 | } |
169 | | } |
170 | | |
171 | | Size VclContainer::getLayoutRequisition(const vcl::Window &rWindow) |
172 | 0 | { |
173 | 0 | return subtractBorder(rWindow, rWindow.get_preferred_size()); |
174 | 0 | } |
175 | | |
176 | | void VclContainer::SetPosSizePixel(const Point& rAllocPos, const Size& rAllocation) |
177 | 0 | { |
178 | 0 | bool bSizeChanged = rAllocation != GetOutputSizePixel(); |
179 | 0 | Window::SetPosSizePixel(rAllocPos, rAllocation); |
180 | 0 | if (m_bLayoutDirty || bSizeChanged) |
181 | 0 | { |
182 | 0 | m_bLayoutDirty = false; |
183 | 0 | setAllocation(rAllocation); |
184 | 0 | } |
185 | 0 | } |
186 | | |
187 | | void VclContainer::SetPosPixel(const Point& rAllocPos) |
188 | 0 | { |
189 | 0 | Point aAllocPos = rAllocPos; |
190 | 0 | sal_Int32 nBorderWidth = get_border_width(); |
191 | 0 | aAllocPos.AdjustX(nBorderWidth + get_margin_start() ); |
192 | 0 | aAllocPos.AdjustY(nBorderWidth + get_margin_top() ); |
193 | |
|
194 | 0 | if (aAllocPos != GetPosPixel()) |
195 | 0 | Window::SetPosPixel(aAllocPos); |
196 | 0 | } |
197 | | |
198 | | void VclContainer::SetSizePixel(const Size& rAllocation) |
199 | 0 | { |
200 | 0 | Size aAllocation = rAllocation; |
201 | 0 | sal_Int32 nBorderWidth = get_border_width(); |
202 | 0 | aAllocation.AdjustWidth( -(nBorderWidth*2 + get_margin_start() + get_margin_end()) ); |
203 | 0 | aAllocation.AdjustHeight( -(nBorderWidth*2 + get_margin_top() + get_margin_bottom()) ); |
204 | 0 | bool bSizeChanged = aAllocation != GetSizePixel(); |
205 | 0 | if (bSizeChanged) |
206 | 0 | Window::SetSizePixel(aAllocation); |
207 | 0 | if (m_bLayoutDirty || bSizeChanged) |
208 | 0 | { |
209 | 0 | m_bLayoutDirty = false; |
210 | 0 | setAllocation(aAllocation); |
211 | 0 | } |
212 | 0 | } |
213 | | |
214 | | void VclContainer::queue_resize(StateChangedType eReason) |
215 | 0 | { |
216 | 0 | m_bLayoutDirty = true; |
217 | 0 | Window::queue_resize(eReason); |
218 | 0 | } |
219 | | |
220 | | // support for screenshot context menu |
221 | | void VclContainer::Command(const CommandEvent& rCEvt) |
222 | 0 | { |
223 | 0 | if (CommandEventId::ContextMenu == rCEvt.GetCommand()) |
224 | 0 | { |
225 | 0 | auto pParent = GetParent(); |
226 | 0 | if (pParent) |
227 | 0 | { |
228 | 0 | CommandEvent aCEvt(rCEvt.GetMousePosPixel() + GetPosPixel(), rCEvt.GetCommand(), rCEvt.IsMouseEvent(), rCEvt.GetEventData()); |
229 | 0 | pParent->Command(aCEvt); |
230 | 0 | return; |
231 | 0 | } |
232 | 0 | } |
233 | | |
234 | | // call parent (do not consume) |
235 | 0 | Window::Command(rCEvt); |
236 | 0 | } |
237 | | |
238 | | void VclBox::accumulateMaxes(const Size &rChildSize, Size &rSize) const |
239 | 0 | { |
240 | 0 | tools::Long nSecondaryChildDimension = getSecondaryDimension(rChildSize); |
241 | 0 | tools::Long nSecondaryBoxDimension = getSecondaryDimension(rSize); |
242 | 0 | setSecondaryDimension(rSize, std::max(nSecondaryChildDimension, nSecondaryBoxDimension)); |
243 | |
|
244 | 0 | tools::Long nPrimaryChildDimension = getPrimaryDimension(rChildSize); |
245 | 0 | tools::Long nPrimaryBoxDimension = getPrimaryDimension(rSize); |
246 | 0 | if (m_bHomogeneous) |
247 | 0 | setPrimaryDimension(rSize, std::max(nPrimaryBoxDimension, nPrimaryChildDimension)); |
248 | 0 | else |
249 | 0 | setPrimaryDimension(rSize, nPrimaryBoxDimension + nPrimaryChildDimension); |
250 | 0 | } |
251 | | |
252 | | Size VclBox::calculateRequisition() const |
253 | 0 | { |
254 | 0 | sal_uInt16 nVisibleChildren = 0; |
255 | |
|
256 | 0 | Size aSize; |
257 | 0 | for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next)) |
258 | 0 | { |
259 | 0 | if (!pChild->IsVisible()) |
260 | 0 | continue; |
261 | 0 | ++nVisibleChildren; |
262 | 0 | Size aChildSize = getLayoutRequisition(*pChild); |
263 | |
|
264 | 0 | tools::Long nPrimaryDimension = getPrimaryDimension(aChildSize); |
265 | 0 | nPrimaryDimension += pChild->get_padding() * 2; |
266 | 0 | setPrimaryDimension(aChildSize, nPrimaryDimension); |
267 | |
|
268 | 0 | accumulateMaxes(aChildSize, aSize); |
269 | 0 | } |
270 | |
|
271 | 0 | return finalizeMaxes(aSize, nVisibleChildren); |
272 | 0 | } |
273 | | |
274 | | void VclBox::setAllocation(const Size &rAllocation) |
275 | 0 | { |
276 | 0 | sal_uInt16 nVisibleChildren = 0, nExpandChildren = 0; |
277 | 0 | for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next)) |
278 | 0 | { |
279 | 0 | if (!pChild->IsVisible()) |
280 | 0 | continue; |
281 | 0 | ++nVisibleChildren; |
282 | 0 | bool bExpand = getPrimaryDimensionChildExpand(*pChild); |
283 | 0 | if (bExpand) |
284 | 0 | ++nExpandChildren; |
285 | 0 | } |
286 | |
|
287 | 0 | if (!nVisibleChildren) |
288 | 0 | return; |
289 | | |
290 | 0 | tools::Long nAllocPrimaryDimension = getPrimaryDimension(rAllocation); |
291 | |
|
292 | 0 | tools::Long nHomogeneousDimension = 0, nExtraSpace = 0; |
293 | 0 | if (m_bHomogeneous) |
294 | 0 | { |
295 | 0 | nHomogeneousDimension = (nAllocPrimaryDimension - |
296 | 0 | (nVisibleChildren - 1) * m_nSpacing) / nVisibleChildren; |
297 | 0 | } |
298 | 0 | else if (nExpandChildren) |
299 | 0 | { |
300 | 0 | Size aRequisition = calculateRequisition(); |
301 | 0 | tools::Long nPrimaryDimension = getPrimaryDimension(rAllocation); |
302 | 0 | nExtraSpace = (nPrimaryDimension - getPrimaryDimension(aRequisition)) / nExpandChildren; |
303 | 0 | } |
304 | | |
305 | | //Split into those we pack from the start onwards, and those we pack from the end backwards |
306 | 0 | o3tl::enumarray<VclPackType,std::vector<vcl::Window*>> aWindows; |
307 | 0 | for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next)) |
308 | 0 | { |
309 | 0 | if (!pChild->IsVisible()) |
310 | 0 | continue; |
311 | | |
312 | 0 | VclPackType ePacking = pChild->get_pack_type(); |
313 | 0 | aWindows[ePacking].push_back(pChild); |
314 | 0 | } |
315 | | |
316 | | //See VclBuilder::sortIntoBestTabTraversalOrder for why they are in visual |
317 | | //order under the parent which requires us to reverse them here to |
318 | | //pack from the end back |
319 | 0 | std::reverse(aWindows[VclPackType::End].begin(),aWindows[VclPackType::End].end()); |
320 | |
|
321 | 0 | for (VclPackType ePackType : o3tl::enumrange<VclPackType>()) |
322 | 0 | { |
323 | 0 | Point aPos(0, 0); |
324 | 0 | if (ePackType == VclPackType::End) |
325 | 0 | { |
326 | 0 | tools::Long nPrimaryCoordinate = getPrimaryCoordinate(aPos); |
327 | 0 | setPrimaryCoordinate(aPos, nPrimaryCoordinate + nAllocPrimaryDimension); |
328 | 0 | } |
329 | |
|
330 | 0 | for (auto const& window : aWindows[ePackType]) |
331 | 0 | { |
332 | 0 | vcl::Window *pChild = window; |
333 | |
|
334 | 0 | tools::Long nPadding = pChild->get_padding(); |
335 | |
|
336 | 0 | Size aBoxSize; |
337 | 0 | if (m_bHomogeneous) |
338 | 0 | setPrimaryDimension(aBoxSize, nHomogeneousDimension); |
339 | 0 | else |
340 | 0 | { |
341 | 0 | aBoxSize = getLayoutRequisition(*pChild); |
342 | 0 | tools::Long nPrimaryDimension = getPrimaryDimension(aBoxSize); |
343 | 0 | nPrimaryDimension += nPadding * 2; |
344 | 0 | if (getPrimaryDimensionChildExpand(*pChild)) |
345 | 0 | nPrimaryDimension += nExtraSpace; |
346 | 0 | setPrimaryDimension(aBoxSize, nPrimaryDimension); |
347 | 0 | } |
348 | 0 | setSecondaryDimension(aBoxSize, getSecondaryDimension(rAllocation)); |
349 | |
|
350 | 0 | Point aChildPos(aPos); |
351 | 0 | Size aChildSize(aBoxSize); |
352 | 0 | tools::Long nPrimaryCoordinate = getPrimaryCoordinate(aPos); |
353 | |
|
354 | 0 | bool bFill = pChild->get_fill(); |
355 | 0 | if (bFill) |
356 | 0 | { |
357 | 0 | setPrimaryDimension(aChildSize, std::max(static_cast<tools::Long>(1), |
358 | 0 | std::min(getPrimaryDimension(rAllocation), getPrimaryDimension(aBoxSize) - nPadding * 2))); |
359 | |
|
360 | 0 | setPrimaryCoordinate(aChildPos, nPrimaryCoordinate + nPadding); |
361 | 0 | } |
362 | 0 | else |
363 | 0 | { |
364 | 0 | setPrimaryDimension(aChildSize, |
365 | 0 | getPrimaryDimension(getLayoutRequisition(*pChild))); |
366 | |
|
367 | 0 | setPrimaryCoordinate(aChildPos, nPrimaryCoordinate + |
368 | 0 | (getPrimaryDimension(aBoxSize) - getPrimaryDimension(aChildSize)) / 2); |
369 | 0 | } |
370 | |
|
371 | 0 | tools::Long nDiff = getPrimaryDimension(aBoxSize) + m_nSpacing; |
372 | 0 | if (ePackType == VclPackType::Start) |
373 | 0 | setPrimaryCoordinate(aPos, nPrimaryCoordinate + nDiff); |
374 | 0 | else |
375 | 0 | { |
376 | 0 | setPrimaryCoordinate(aPos, nPrimaryCoordinate - nDiff); |
377 | 0 | setPrimaryCoordinate(aChildPos, getPrimaryCoordinate(aChildPos) - |
378 | 0 | getPrimaryDimension(aBoxSize)); |
379 | 0 | } |
380 | |
|
381 | 0 | setLayoutAllocation(*pChild, aChildPos, aChildSize); |
382 | 0 | } |
383 | 0 | } |
384 | 0 | } |
385 | | |
386 | | bool VclBox::set_property(const OUString &rKey, const OUString &rValue) |
387 | 0 | { |
388 | 0 | if (rKey == "spacing") |
389 | 0 | set_spacing(rValue.toInt32()); |
390 | 0 | else if (rKey == "homogeneous") |
391 | 0 | set_homogeneous(toBool(rValue)); |
392 | 0 | else |
393 | 0 | return VclContainer::set_property(rKey, rValue); |
394 | 0 | return true; |
395 | 0 | } |
396 | | |
397 | | void VclBox::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) |
398 | 0 | { |
399 | 0 | VclContainer::DumpAsPropertyTree(rJsonWriter); |
400 | 0 | rJsonWriter.put("vertical", m_bVerticalContainer); |
401 | 0 | } |
402 | | |
403 | | sal_uInt16 VclBox::getDefaultAccessibleRole() const |
404 | 0 | { |
405 | | // fdo#74284 call Boxes Panels, keep them as "Filler" under |
406 | | // at least Linux seeing as that's what Gtk3 did for GtkBoxes. |
407 | | // Though now with Gtk4 that uses GTK_ACCESSIBLE_ROLE_GROUP |
408 | | // which maps to ATSPI_ROLE_PANEL |
409 | | #if defined(_WIN32) |
410 | | return css::accessibility::AccessibleRole::PANEL; |
411 | | #else |
412 | 0 | static sal_uInt16 eRole = Application::GetToolkitName() == "gtk4" ? |
413 | 0 | css::accessibility::AccessibleRole::PANEL : |
414 | 0 | css::accessibility::AccessibleRole::FILLER; |
415 | 0 | return eRole; |
416 | 0 | #endif |
417 | 0 | } |
418 | | |
419 | 0 | #define DEFAULT_CHILD_MIN_WIDTH 85 |
420 | 0 | #define DEFAULT_CHILD_MIN_HEIGHT 27 |
421 | | |
422 | | Size VclBox::finalizeMaxes(const Size &rSize, sal_uInt16 nVisibleChildren) const |
423 | 0 | { |
424 | 0 | Size aRet; |
425 | |
|
426 | 0 | if (nVisibleChildren) |
427 | 0 | { |
428 | 0 | tools::Long nPrimaryDimension = getPrimaryDimension(rSize); |
429 | 0 | if (m_bHomogeneous) |
430 | 0 | nPrimaryDimension *= nVisibleChildren; |
431 | 0 | setPrimaryDimension(aRet, nPrimaryDimension + m_nSpacing * (nVisibleChildren-1)); |
432 | 0 | setSecondaryDimension(aRet, getSecondaryDimension(rSize)); |
433 | 0 | } |
434 | |
|
435 | 0 | return aRet; |
436 | 0 | } |
437 | | |
438 | | Size VclButtonBox::addReqGroups(const VclButtonBox::Requisition &rReq) const |
439 | 0 | { |
440 | 0 | Size aRet; |
441 | |
|
442 | 0 | tools::Long nMainGroupDimension = getPrimaryDimension(rReq.m_aMainGroupSize); |
443 | 0 | tools::Long nSubGroupDimension = getPrimaryDimension(rReq.m_aSubGroupSize); |
444 | |
|
445 | 0 | setPrimaryDimension(aRet, nMainGroupDimension + nSubGroupDimension); |
446 | |
|
447 | 0 | setSecondaryDimension(aRet, |
448 | 0 | std::max(getSecondaryDimension(rReq.m_aMainGroupSize), |
449 | 0 | getSecondaryDimension(rReq.m_aSubGroupSize))); |
450 | |
|
451 | 0 | return aRet; |
452 | 0 | } |
453 | | |
454 | | static tools::Long getMaxNonOutlier(const std::vector<tools::Long> &rG, tools::Long nAvgDimension) |
455 | 0 | { |
456 | 0 | tools::Long nMaxDimensionNonOutlier = 0; |
457 | 0 | for (auto const& nPrimaryChildDimension : rG) |
458 | 0 | { |
459 | 0 | if (nPrimaryChildDimension < nAvgDimension * 1.5) |
460 | 0 | { |
461 | 0 | nMaxDimensionNonOutlier = std::max(nPrimaryChildDimension, |
462 | 0 | nMaxDimensionNonOutlier); |
463 | 0 | } |
464 | 0 | } |
465 | 0 | return nMaxDimensionNonOutlier; |
466 | 0 | } |
467 | | |
468 | | static std::vector<tools::Long> setButtonSizes(const std::vector<tools::Long> &rG, |
469 | | const std::vector<bool> &rNonHomogeneous, |
470 | | tools::Long nAvgDimension, tools::Long nMaxNonOutlier, tools::Long nMinWidth) |
471 | 0 | { |
472 | 0 | std::vector<tools::Long> aVec; |
473 | | //set everything < 1.5 times the average to the same width, leave the |
474 | | //outliers un-touched |
475 | 0 | std::vector<bool>::const_iterator aJ = rNonHomogeneous.begin(); |
476 | 0 | auto nNonOutlierWidth = std::max(nMaxNonOutlier, nMinWidth); |
477 | 0 | for (auto const& nPrimaryChildDimension : rG) |
478 | 0 | { |
479 | 0 | bool bNonHomogeneous = *aJ; |
480 | 0 | if (!bNonHomogeneous && nPrimaryChildDimension < nAvgDimension * 1.5) |
481 | 0 | { |
482 | 0 | aVec.push_back(nNonOutlierWidth); |
483 | 0 | } |
484 | 0 | else |
485 | 0 | { |
486 | 0 | aVec.push_back(std::max(nPrimaryChildDimension, nMinWidth)); |
487 | 0 | } |
488 | 0 | ++aJ; |
489 | 0 | } |
490 | 0 | return aVec; |
491 | 0 | } |
492 | | |
493 | | VclButtonBox::Requisition VclButtonBox::calculatePrimarySecondaryRequisitions() const |
494 | 0 | { |
495 | 0 | Requisition aReq; |
496 | |
|
497 | 0 | Size aMainGroupSize(DEFAULT_CHILD_MIN_WIDTH, DEFAULT_CHILD_MIN_HEIGHT); //to-do, pull from theme |
498 | 0 | Size aSubGroupSize(DEFAULT_CHILD_MIN_WIDTH, DEFAULT_CHILD_MIN_HEIGHT); //to-do, pull from theme |
499 | |
|
500 | 0 | tools::Long nMinMainGroupPrimary = getPrimaryDimension(aMainGroupSize); |
501 | 0 | tools::Long nMinSubGroupPrimary = getPrimaryDimension(aSubGroupSize); |
502 | 0 | tools::Long nMainGroupSecondary = getSecondaryDimension(aMainGroupSize); |
503 | 0 | tools::Long nSubGroupSecondary = getSecondaryDimension(aSubGroupSize); |
504 | |
|
505 | 0 | bool bIgnoreSecondaryPacking = (m_eLayoutStyle == VclButtonBoxStyle::Spread || m_eLayoutStyle == VclButtonBoxStyle::Center); |
506 | |
|
507 | 0 | std::vector<tools::Long> aMainGroupSizes; |
508 | 0 | std::vector<bool> aMainGroupNonHomogeneous; |
509 | 0 | std::vector<tools::Long> aSubGroupSizes; |
510 | 0 | std::vector<bool> aSubGroupNonHomogeneous; |
511 | |
|
512 | 0 | for (const vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next)) |
513 | 0 | { |
514 | 0 | if (!pChild->IsVisible()) |
515 | 0 | continue; |
516 | 0 | Size aChildSize = getLayoutRequisition(*pChild); |
517 | 0 | if (bIgnoreSecondaryPacking || !pChild->get_secondary()) |
518 | 0 | { |
519 | | //set the max secondary dimension |
520 | 0 | nMainGroupSecondary = std::max(nMainGroupSecondary, getSecondaryDimension(aChildSize)); |
521 | | //collect the primary dimensions |
522 | 0 | aMainGroupSizes.push_back(getPrimaryDimension(aChildSize)); |
523 | 0 | aMainGroupNonHomogeneous.push_back(pChild->get_non_homogeneous()); |
524 | 0 | } |
525 | 0 | else |
526 | 0 | { |
527 | 0 | nSubGroupSecondary = std::max(nSubGroupSecondary, getSecondaryDimension(aChildSize)); |
528 | 0 | aSubGroupSizes.push_back(getPrimaryDimension(aChildSize)); |
529 | 0 | aSubGroupNonHomogeneous.push_back(pChild->get_non_homogeneous()); |
530 | 0 | } |
531 | 0 | } |
532 | |
|
533 | 0 | if (m_bHomogeneous) |
534 | 0 | { |
535 | 0 | tools::Long nMaxMainDimension = aMainGroupSizes.empty() ? 0 : |
536 | 0 | *std::max_element(aMainGroupSizes.begin(), aMainGroupSizes.end()); |
537 | 0 | nMaxMainDimension = std::max(nMaxMainDimension, nMinMainGroupPrimary); |
538 | 0 | tools::Long nMaxSubDimension = aSubGroupSizes.empty() ? 0 : |
539 | 0 | *std::max_element(aSubGroupSizes.begin(), aSubGroupSizes.end()); |
540 | 0 | nMaxSubDimension = std::max(nMaxSubDimension, nMinSubGroupPrimary); |
541 | 0 | tools::Long nMaxDimension = std::max(nMaxMainDimension, nMaxSubDimension); |
542 | 0 | aReq.m_aMainGroupDimensions.resize(aMainGroupSizes.size(), nMaxDimension); |
543 | 0 | aReq.m_aSubGroupDimensions.resize(aSubGroupSizes.size(), nMaxDimension); |
544 | 0 | } |
545 | 0 | else |
546 | 0 | { |
547 | | //Ideally set everything to the same size, but find outlier widgets |
548 | | //that are way wider than the average and leave them |
549 | | //at their natural size and set the remainder to share the |
550 | | //max size of the remaining members of the buttonbox |
551 | 0 | tools::Long nAccDimension = std::accumulate(aMainGroupSizes.begin(), |
552 | 0 | aMainGroupSizes.end(), 0); |
553 | 0 | nAccDimension = std::accumulate(aSubGroupSizes.begin(), |
554 | 0 | aSubGroupSizes.end(), nAccDimension); |
555 | |
|
556 | 0 | size_t nTotalSize = aMainGroupSizes.size() + aSubGroupSizes.size(); |
557 | |
|
558 | 0 | tools::Long nAvgDimension = nTotalSize ? nAccDimension / nTotalSize : 0; |
559 | |
|
560 | 0 | tools::Long nMaxMainNonOutlier = getMaxNonOutlier(aMainGroupSizes, |
561 | 0 | nAvgDimension); |
562 | 0 | tools::Long nMaxSubNonOutlier = getMaxNonOutlier(aSubGroupSizes, |
563 | 0 | nAvgDimension); |
564 | 0 | tools::Long nMaxNonOutlier = std::max(nMaxMainNonOutlier, nMaxSubNonOutlier); |
565 | |
|
566 | 0 | aReq.m_aMainGroupDimensions = setButtonSizes(aMainGroupSizes, |
567 | 0 | aMainGroupNonHomogeneous, |
568 | 0 | nAvgDimension, nMaxNonOutlier, nMinMainGroupPrimary); |
569 | 0 | aReq.m_aSubGroupDimensions = setButtonSizes(aSubGroupSizes, |
570 | 0 | aSubGroupNonHomogeneous, |
571 | 0 | nAvgDimension, nMaxNonOutlier, nMinSubGroupPrimary); |
572 | 0 | } |
573 | |
|
574 | 0 | if (!aReq.m_aMainGroupDimensions.empty()) |
575 | 0 | { |
576 | 0 | setSecondaryDimension(aReq.m_aMainGroupSize, nMainGroupSecondary); |
577 | 0 | setPrimaryDimension(aReq.m_aMainGroupSize, |
578 | 0 | std::accumulate(aReq.m_aMainGroupDimensions.begin(), |
579 | 0 | aReq.m_aMainGroupDimensions.end(), 0)); |
580 | 0 | } |
581 | 0 | if (!aReq.m_aSubGroupDimensions.empty()) |
582 | 0 | { |
583 | 0 | setSecondaryDimension(aReq.m_aSubGroupSize, nSubGroupSecondary); |
584 | 0 | setPrimaryDimension(aReq.m_aSubGroupSize, |
585 | 0 | std::accumulate(aReq.m_aSubGroupDimensions.begin(), |
586 | 0 | aReq.m_aSubGroupDimensions.end(), 0)); |
587 | 0 | } |
588 | |
|
589 | 0 | return aReq; |
590 | 0 | } |
591 | | |
592 | | Size VclButtonBox::addSpacing(const Size &rSize, sal_uInt16 nVisibleChildren) const |
593 | 0 | { |
594 | 0 | Size aRet; |
595 | |
|
596 | 0 | if (nVisibleChildren) |
597 | 0 | { |
598 | 0 | tools::Long nPrimaryDimension = getPrimaryDimension(rSize); |
599 | 0 | setPrimaryDimension(aRet, |
600 | 0 | nPrimaryDimension + m_nSpacing * (nVisibleChildren-1)); |
601 | 0 | setSecondaryDimension(aRet, getSecondaryDimension(rSize)); |
602 | 0 | } |
603 | |
|
604 | 0 | return aRet; |
605 | 0 | } |
606 | | |
607 | | Size VclButtonBox::calculateRequisition() const |
608 | 0 | { |
609 | 0 | Requisition aReq(calculatePrimarySecondaryRequisitions()); |
610 | 0 | sal_uInt16 nVisibleChildren = aReq.m_aMainGroupDimensions.size() + |
611 | 0 | aReq.m_aSubGroupDimensions.size(); |
612 | 0 | return addSpacing(addReqGroups(aReq), nVisibleChildren); |
613 | 0 | } |
614 | | |
615 | | bool VclButtonBox::set_property(const OUString &rKey, const OUString &rValue) |
616 | 0 | { |
617 | 0 | if (rKey == "layout-style") |
618 | 0 | { |
619 | 0 | VclButtonBoxStyle eStyle = VclButtonBoxStyle::Default; |
620 | 0 | if (rValue == "spread") |
621 | 0 | eStyle = VclButtonBoxStyle::Spread; |
622 | 0 | else if (rValue == "edge") |
623 | 0 | eStyle = VclButtonBoxStyle::Edge; |
624 | 0 | else if (rValue == "start") |
625 | 0 | eStyle = VclButtonBoxStyle::Start; |
626 | 0 | else if (rValue == "end") |
627 | 0 | eStyle = VclButtonBoxStyle::End; |
628 | 0 | else if (rValue == "center") |
629 | 0 | eStyle = VclButtonBoxStyle::Center; |
630 | 0 | else |
631 | 0 | { |
632 | 0 | SAL_WARN("vcl.layout", "unknown layout style " << rValue); |
633 | 0 | } |
634 | 0 | m_eLayoutStyle = eStyle; |
635 | 0 | } |
636 | 0 | else |
637 | 0 | return VclBox::set_property(rKey, rValue); |
638 | 0 | return true; |
639 | 0 | } |
640 | | |
641 | | void VclButtonBox::setAllocation(const Size &rAllocation) |
642 | 0 | { |
643 | 0 | Requisition aReq(calculatePrimarySecondaryRequisitions()); |
644 | |
|
645 | 0 | if (aReq.m_aMainGroupDimensions.empty() && aReq.m_aSubGroupDimensions.empty()) |
646 | 0 | return; |
647 | | |
648 | 0 | tools::Long nAllocPrimaryDimension = getPrimaryDimension(rAllocation); |
649 | |
|
650 | 0 | Point aMainGroupPos, aOtherGroupPos; |
651 | 0 | int nSpacing = m_nSpacing; |
652 | | |
653 | | //To-Do, other layout styles |
654 | 0 | switch (m_eLayoutStyle) |
655 | 0 | { |
656 | 0 | case VclButtonBoxStyle::Start: |
657 | 0 | if (!aReq.m_aSubGroupDimensions.empty()) |
658 | 0 | { |
659 | 0 | tools::Long nOtherPrimaryDimension = getPrimaryDimension( |
660 | 0 | addSpacing(aReq.m_aSubGroupSize, aReq.m_aSubGroupDimensions.size())); |
661 | 0 | setPrimaryCoordinate(aOtherGroupPos, |
662 | 0 | nAllocPrimaryDimension - nOtherPrimaryDimension); |
663 | 0 | } |
664 | 0 | break; |
665 | 0 | case VclButtonBoxStyle::Spread: |
666 | 0 | if (!aReq.m_aMainGroupDimensions.empty()) |
667 | 0 | { |
668 | 0 | tools::Long nMainPrimaryDimension = getPrimaryDimension( |
669 | 0 | addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size())); |
670 | 0 | tools::Long nExtraSpace = nAllocPrimaryDimension - nMainPrimaryDimension; |
671 | 0 | nExtraSpace += (aReq.m_aMainGroupDimensions.size()-1) * nSpacing; |
672 | 0 | nSpacing = nExtraSpace/(aReq.m_aMainGroupDimensions.size()+1); |
673 | 0 | setPrimaryCoordinate(aMainGroupPos, nSpacing); |
674 | 0 | } |
675 | 0 | break; |
676 | 0 | case VclButtonBoxStyle::Center: |
677 | 0 | if (!aReq.m_aMainGroupDimensions.empty()) |
678 | 0 | { |
679 | 0 | tools::Long nMainPrimaryDimension = getPrimaryDimension( |
680 | 0 | addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size())); |
681 | 0 | tools::Long nExtraSpace = nAllocPrimaryDimension - nMainPrimaryDimension; |
682 | 0 | setPrimaryCoordinate(aMainGroupPos, nExtraSpace/2); |
683 | 0 | } |
684 | 0 | break; |
685 | 0 | default: |
686 | 0 | SAL_WARN("vcl.layout", "todo unimplemented layout style"); |
687 | 0 | [[fallthrough]]; |
688 | 0 | case VclButtonBoxStyle::Default: |
689 | 0 | case VclButtonBoxStyle::End: |
690 | 0 | if (!aReq.m_aMainGroupDimensions.empty()) |
691 | 0 | { |
692 | 0 | tools::Long nMainPrimaryDimension = getPrimaryDimension( |
693 | 0 | addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size())); |
694 | 0 | setPrimaryCoordinate(aMainGroupPos, |
695 | 0 | nAllocPrimaryDimension - nMainPrimaryDimension); |
696 | 0 | } |
697 | 0 | break; |
698 | 0 | } |
699 | | |
700 | 0 | Size aChildSize; |
701 | 0 | setSecondaryDimension(aChildSize, getSecondaryDimension(rAllocation)); |
702 | |
|
703 | 0 | std::vector<tools::Long>::const_iterator aPrimaryI = aReq.m_aMainGroupDimensions.begin(); |
704 | 0 | std::vector<tools::Long>::const_iterator aSecondaryI = aReq.m_aSubGroupDimensions.begin(); |
705 | 0 | bool bIgnoreSecondaryPacking = (m_eLayoutStyle == VclButtonBoxStyle::Spread || m_eLayoutStyle == VclButtonBoxStyle::Center); |
706 | 0 | for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next)) |
707 | 0 | { |
708 | 0 | if (!pChild->IsVisible()) |
709 | 0 | continue; |
710 | | |
711 | 0 | if (bIgnoreSecondaryPacking || !pChild->get_secondary()) |
712 | 0 | { |
713 | 0 | tools::Long nMainGroupPrimaryDimension = *aPrimaryI++; |
714 | 0 | setPrimaryDimension(aChildSize, nMainGroupPrimaryDimension); |
715 | 0 | setLayoutAllocation(*pChild, aMainGroupPos, aChildSize); |
716 | 0 | tools::Long nPrimaryCoordinate = getPrimaryCoordinate(aMainGroupPos); |
717 | 0 | setPrimaryCoordinate(aMainGroupPos, nPrimaryCoordinate + nMainGroupPrimaryDimension + nSpacing); |
718 | 0 | } |
719 | 0 | else |
720 | 0 | { |
721 | 0 | tools::Long nSubGroupPrimaryDimension = *aSecondaryI++; |
722 | 0 | setPrimaryDimension(aChildSize, nSubGroupPrimaryDimension); |
723 | 0 | setLayoutAllocation(*pChild, aOtherGroupPos, aChildSize); |
724 | 0 | tools::Long nPrimaryCoordinate = getPrimaryCoordinate(aOtherGroupPos); |
725 | 0 | setPrimaryCoordinate(aOtherGroupPos, nPrimaryCoordinate + nSubGroupPrimaryDimension + nSpacing); |
726 | 0 | } |
727 | 0 | } |
728 | 0 | } |
729 | | |
730 | | void VclButtonBox::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) |
731 | 0 | { |
732 | 0 | VclBox::DumpAsPropertyTree(rJsonWriter); |
733 | 0 | rJsonWriter.put("type", "buttonbox"); |
734 | |
|
735 | 0 | switch(m_eLayoutStyle) |
736 | 0 | { |
737 | 0 | case VclButtonBoxStyle::Default: |
738 | 0 | rJsonWriter.put("layoutstyle", "default"); |
739 | 0 | break; |
740 | | |
741 | 0 | case VclButtonBoxStyle::Spread: |
742 | 0 | rJsonWriter.put("layoutstyle", "spread"); |
743 | 0 | break; |
744 | | |
745 | 0 | case VclButtonBoxStyle::Edge: |
746 | 0 | rJsonWriter.put("layoutstyle", "edge"); |
747 | 0 | break; |
748 | | |
749 | 0 | case VclButtonBoxStyle::Center: |
750 | 0 | rJsonWriter.put("layoutstyle", "center"); |
751 | 0 | break; |
752 | | |
753 | 0 | case VclButtonBoxStyle::Start: |
754 | 0 | rJsonWriter.put("layoutstyle", "start"); |
755 | 0 | break; |
756 | | |
757 | 0 | case VclButtonBoxStyle::End: |
758 | 0 | rJsonWriter.put("layoutstyle", "end"); |
759 | 0 | break; |
760 | 0 | } |
761 | 0 | } |
762 | | |
763 | | namespace { |
764 | | |
765 | | struct ButtonOrder |
766 | | { |
767 | | std::u16string_view m_aType; |
768 | | int m_nPriority; |
769 | | }; |
770 | | |
771 | | } |
772 | | |
773 | | static int getButtonPriority(std::u16string_view rType) |
774 | 0 | { |
775 | 0 | static const size_t N_TYPES = 6; |
776 | 0 | static const ButtonOrder aDiscardCancelSave[N_TYPES] = |
777 | 0 | { |
778 | 0 | { u"discard", 0 }, |
779 | 0 | { u"cancel", 1 }, |
780 | 0 | { u"no", 2 }, |
781 | 0 | { u"save", 3 }, |
782 | 0 | { u"yes", 3 }, |
783 | 0 | { u"ok", 3 } |
784 | 0 | }; |
785 | |
|
786 | 0 | static const ButtonOrder aSaveDiscardCancel[N_TYPES] = |
787 | 0 | { |
788 | 0 | { u"save", 0 }, |
789 | 0 | { u"yes", 0 }, |
790 | 0 | { u"ok", 0 }, |
791 | 0 | { u"discard", 1 }, |
792 | 0 | { u"no", 1 }, |
793 | 0 | { u"cancel", 2 } |
794 | 0 | }; |
795 | |
|
796 | 0 | const ButtonOrder* pOrder = &aDiscardCancelSave[0]; |
797 | |
|
798 | 0 | const OUString &rEnv = Application::GetDesktopEnvironment(); |
799 | |
|
800 | 0 | if (rEnv.equalsIgnoreAsciiCase("windows") || |
801 | 0 | rEnv.equalsIgnoreAsciiCase("lxqt") || |
802 | 0 | rEnv.startsWithIgnoreAsciiCase("plasma")) |
803 | 0 | { |
804 | 0 | pOrder = &aSaveDiscardCancel[0]; |
805 | 0 | } |
806 | |
|
807 | 0 | for (size_t i = 0; i < N_TYPES; ++i, ++pOrder) |
808 | 0 | { |
809 | 0 | if (rType == pOrder->m_aType) |
810 | 0 | return pOrder->m_nPriority; |
811 | 0 | } |
812 | | |
813 | 0 | return -1; |
814 | 0 | } |
815 | | |
816 | | namespace { |
817 | | |
818 | | class sortButtons |
819 | | { |
820 | | bool m_bVerticalContainer; |
821 | | public: |
822 | | explicit sortButtons(bool bVerticalContainer) |
823 | 0 | : m_bVerticalContainer(bVerticalContainer) |
824 | 0 | { |
825 | 0 | } |
826 | | bool operator()(const vcl::Window *pA, const vcl::Window *pB) const; |
827 | | }; |
828 | | |
829 | | } |
830 | | |
831 | | bool sortButtons::operator()(const vcl::Window *pA, const vcl::Window *pB) const |
832 | 0 | { |
833 | | //sort into two groups of pack start and pack end |
834 | 0 | VclPackType ePackA = pA->get_pack_type(); |
835 | 0 | VclPackType ePackB = pB->get_pack_type(); |
836 | 0 | if (ePackA < ePackB) |
837 | 0 | return true; |
838 | 0 | if (ePackA > ePackB) |
839 | 0 | return false; |
840 | 0 | bool bPackA = pA->get_secondary(); |
841 | 0 | bool bPackB = pB->get_secondary(); |
842 | 0 | if (!m_bVerticalContainer) |
843 | 0 | { |
844 | | //for horizontal boxes group secondaries before primaries |
845 | 0 | if (bPackA > bPackB) |
846 | 0 | return true; |
847 | 0 | if (bPackA < bPackB) |
848 | 0 | return false; |
849 | 0 | } |
850 | 0 | else |
851 | 0 | { |
852 | | //for vertical boxes group secondaries after primaries |
853 | 0 | if (bPackA < bPackB) |
854 | 0 | return true; |
855 | 0 | if (bPackA > bPackB) |
856 | 0 | return false; |
857 | 0 | } |
858 | | |
859 | | //now order within groups according to platform rules |
860 | 0 | return getButtonPriority(pA->get_id()) < getButtonPriority(pB->get_id()); |
861 | 0 | } |
862 | | |
863 | | void sort_native_button_order(const VclBox& rContainer) |
864 | 0 | { |
865 | 0 | std::vector<vcl::Window*> aChilds; |
866 | 0 | for (vcl::Window* pChild = rContainer.GetWindow(GetWindowType::FirstChild); pChild; |
867 | 0 | pChild = pChild->GetWindow(GetWindowType::Next)) |
868 | 0 | { |
869 | 0 | aChilds.push_back(pChild); |
870 | 0 | } |
871 | | |
872 | | //sort child order within parent so that we match the platform |
873 | | //button order |
874 | 0 | std::stable_sort(aChilds.begin(), aChilds.end(), sortButtons(rContainer.get_orientation())); |
875 | 0 | BuilderUtils::reorderWithinParent(aChilds, true); |
876 | 0 | } |
877 | | |
878 | | namespace { |
879 | | |
880 | | struct GridEntry |
881 | | { |
882 | | VclPtr<vcl::Window> pChild; |
883 | | sal_Int32 nSpanWidth; |
884 | | sal_Int32 nSpanHeight; |
885 | | int x; |
886 | | int y; |
887 | | GridEntry() |
888 | 0 | : pChild(nullptr) |
889 | 0 | , nSpanWidth(0) |
890 | 0 | , nSpanHeight(0) |
891 | 0 | , x(-1) |
892 | 0 | , y(-1) |
893 | 0 | { |
894 | 0 | } |
895 | | }; |
896 | | |
897 | | } |
898 | | |
899 | | typedef boost::multi_array<GridEntry, 2> array_type; |
900 | | |
901 | | #if defined _MSC_VER |
902 | | #pragma warning(push) |
903 | | #pragma warning(disable : 4459) |
904 | | #pragma warning(disable : 4996) |
905 | | #endif |
906 | | static array_type assembleGrid(const VclGrid &rGrid) |
907 | 0 | { |
908 | | #if defined _MSC_VER |
909 | | #pragma warning(pop) |
910 | | #endif |
911 | 0 | array_type A; |
912 | |
|
913 | 0 | for (vcl::Window* pChild = rGrid.GetWindow(GetWindowType::FirstChild); pChild; |
914 | 0 | pChild = pChild->GetWindow(GetWindowType::Next)) |
915 | 0 | { |
916 | 0 | sal_Int32 nLeftAttach = std::max<sal_Int32>(pChild->get_grid_left_attach(), 0); |
917 | 0 | sal_Int32 nWidth = pChild->get_grid_width(); |
918 | 0 | sal_Int32 nMaxXPos = nLeftAttach+nWidth-1; |
919 | |
|
920 | 0 | sal_Int32 nTopAttach = std::max<sal_Int32>(pChild->get_grid_top_attach(), 0); |
921 | 0 | sal_Int32 nHeight = pChild->get_grid_height(); |
922 | 0 | sal_Int32 nMaxYPos = nTopAttach+nHeight-1; |
923 | |
|
924 | 0 | sal_Int32 nCurrentMaxXPos = A.shape()[0]-1; |
925 | 0 | sal_Int32 nCurrentMaxYPos = A.shape()[1]-1; |
926 | 0 | if (nMaxXPos > nCurrentMaxXPos || nMaxYPos > nCurrentMaxYPos) |
927 | 0 | { |
928 | 0 | nCurrentMaxXPos = std::max(nMaxXPos, nCurrentMaxXPos); |
929 | 0 | nCurrentMaxYPos = std::max(nMaxYPos, nCurrentMaxYPos); |
930 | 0 | A.resize(boost::extents[nCurrentMaxXPos+1][nCurrentMaxYPos+1]); |
931 | 0 | } |
932 | |
|
933 | | #if defined _MSC_VER |
934 | | #pragma warning(push) |
935 | | #pragma warning(disable : 4459) |
936 | | #pragma warning(disable : 4996) |
937 | | #endif |
938 | 0 | GridEntry &rEntry = A[nLeftAttach][nTopAttach]; |
939 | | #if defined _MSC_VER |
940 | | #pragma warning(pop) |
941 | | #endif |
942 | 0 | rEntry.pChild = pChild; |
943 | 0 | rEntry.nSpanWidth = nWidth; |
944 | 0 | rEntry.nSpanHeight = nHeight; |
945 | 0 | rEntry.x = nLeftAttach; |
946 | 0 | rEntry.y = nTopAttach; |
947 | |
|
948 | 0 | for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX) |
949 | 0 | { |
950 | 0 | for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY) |
951 | 0 | { |
952 | 0 | GridEntry &rSpan = A[nLeftAttach+nSpanX][nTopAttach+nSpanY]; |
953 | 0 | rSpan.x = nLeftAttach; |
954 | 0 | rSpan.y = nTopAttach; |
955 | 0 | } |
956 | 0 | } |
957 | 0 | } |
958 | | |
959 | | //see if we have any empty rows/cols |
960 | 0 | sal_Int32 nMaxX = A.shape()[0]; |
961 | 0 | sal_Int32 nMaxY = A.shape()[1]; |
962 | |
|
963 | 0 | std::vector<bool> aNonEmptyCols(nMaxX); |
964 | 0 | std::vector<bool> aNonEmptyRows(nMaxY); |
965 | |
|
966 | 0 | for (sal_Int32 x = 0; x < nMaxX; ++x) |
967 | 0 | { |
968 | 0 | for (sal_Int32 y = 0; y < nMaxY; ++y) |
969 | 0 | { |
970 | | #if defined __GNUC__ && !defined __clang__ && __GNUC__ >= 13 && __GNUC__ <= 16 |
971 | | #pragma GCC diagnostic push |
972 | | #pragma GCC diagnostic ignored "-Wdangling-reference" |
973 | | #endif |
974 | 0 | const GridEntry &rEntry = A[x][y]; |
975 | | #if defined __GNUC__ && !defined __clang__ && __GNUC__ >= 13 && __GNUC__ <= 16 |
976 | | #pragma GCC diagnostic pop |
977 | | #endif |
978 | 0 | const vcl::Window *pChild = rEntry.pChild; |
979 | 0 | if (pChild && pChild->IsVisible()) |
980 | 0 | { |
981 | 0 | aNonEmptyCols[x] = true; |
982 | 0 | if (rGrid.get_column_homogeneous()) |
983 | 0 | { |
984 | 0 | for (sal_Int32 nSpanX = 1; nSpanX < rEntry.nSpanWidth; ++nSpanX) |
985 | 0 | aNonEmptyCols[x+nSpanX] = true; |
986 | 0 | } |
987 | 0 | aNonEmptyRows[y] = true; |
988 | 0 | if (rGrid.get_row_homogeneous()) |
989 | 0 | { |
990 | 0 | for (sal_Int32 nSpanY = 1; nSpanY < rEntry.nSpanHeight; ++nSpanY) |
991 | 0 | aNonEmptyRows[y+nSpanY] = true; |
992 | 0 | } |
993 | 0 | } |
994 | 0 | } |
995 | 0 | } |
996 | |
|
997 | 0 | if (!rGrid.get_column_homogeneous()) |
998 | 0 | { |
999 | | //reduce the spans of elements that span empty columns |
1000 | 0 | for (sal_Int32 x = 0; x < nMaxX; ++x) |
1001 | 0 | { |
1002 | 0 | std::set<GridEntry*> candidates; |
1003 | 0 | for (sal_Int32 y = 0; y < nMaxY; ++y) |
1004 | 0 | { |
1005 | 0 | if (aNonEmptyCols[x]) |
1006 | 0 | continue; |
1007 | 0 | GridEntry &rSpan = A[x][y]; |
1008 | | //cell x/y is spanned by the widget at cell rSpan.x/rSpan.y, |
1009 | | //just points back to itself if there's no cell spanning |
1010 | 0 | if ((rSpan.x == -1) || (rSpan.y == -1)) |
1011 | 0 | { |
1012 | | //there is no entry for this cell, i.e. this is a cell |
1013 | | //with no widget in it, or spanned by any other widget |
1014 | 0 | continue; |
1015 | 0 | } |
1016 | 0 | GridEntry &rEntry = A[rSpan.x][rSpan.y]; |
1017 | 0 | candidates.insert(&rEntry); |
1018 | 0 | } |
1019 | 0 | for (auto const& candidate : candidates) |
1020 | 0 | { |
1021 | 0 | GridEntry *pEntry = candidate; |
1022 | 0 | --pEntry->nSpanWidth; |
1023 | 0 | } |
1024 | 0 | } |
1025 | 0 | } |
1026 | |
|
1027 | 0 | if (!rGrid.get_row_homogeneous()) |
1028 | 0 | { |
1029 | | //reduce the spans of elements that span empty rows |
1030 | 0 | for (sal_Int32 y = 0; y < nMaxY; ++y) |
1031 | 0 | { |
1032 | 0 | std::set<GridEntry*> candidates; |
1033 | 0 | for (sal_Int32 x = 0; x < nMaxX; ++x) |
1034 | 0 | { |
1035 | 0 | if (aNonEmptyRows[y]) |
1036 | 0 | continue; |
1037 | 0 | GridEntry &rSpan = A[x][y]; |
1038 | | //cell x/y is spanned by the widget at cell rSpan.x/rSpan.y, |
1039 | | //just points back to itself if there's no cell spanning |
1040 | 0 | if ((rSpan.x == -1) || (rSpan.y == -1)) |
1041 | 0 | { |
1042 | | //there is no entry for this cell, i.e. this is a cell |
1043 | | //with no widget in it, or spanned by any other widget |
1044 | 0 | continue; |
1045 | 0 | } |
1046 | 0 | GridEntry &rEntry = A[rSpan.x][rSpan.y]; |
1047 | 0 | candidates.insert(&rEntry); |
1048 | 0 | } |
1049 | 0 | for (auto const& candidate : candidates) |
1050 | 0 | { |
1051 | 0 | GridEntry *pEntry = candidate; |
1052 | 0 | --pEntry->nSpanHeight; |
1053 | 0 | } |
1054 | 0 | } |
1055 | 0 | } |
1056 | |
|
1057 | 0 | sal_Int32 nNonEmptyCols = std::count(aNonEmptyCols.begin(), aNonEmptyCols.end(), true); |
1058 | 0 | sal_Int32 nNonEmptyRows = std::count(aNonEmptyRows.begin(), aNonEmptyRows.end(), true); |
1059 | | |
1060 | | //make new grid without empty rows and columns |
1061 | | #if defined _MSC_VER |
1062 | | #pragma warning(push) |
1063 | | #pragma warning(disable : 4459) |
1064 | | #pragma warning(disable : 4996) |
1065 | | #endif |
1066 | 0 | array_type B(boost::extents[nNonEmptyCols][nNonEmptyRows]); |
1067 | | #if defined _MSC_VER |
1068 | | #pragma warning(pop) |
1069 | | #endif |
1070 | 0 | for (sal_Int32 x = 0, x2 = 0; x < nMaxX; ++x) |
1071 | 0 | { |
1072 | 0 | if (!aNonEmptyCols[x]) |
1073 | 0 | continue; |
1074 | 0 | for (sal_Int32 y = 0, y2 = 0; y < nMaxY; ++y) |
1075 | 0 | { |
1076 | 0 | if (!aNonEmptyRows[y]) |
1077 | 0 | continue; |
1078 | 0 | GridEntry &rEntry = A[x][y]; |
1079 | 0 | B[x2][y2++] = rEntry; |
1080 | 0 | } |
1081 | 0 | ++x2; |
1082 | 0 | } |
1083 | |
|
1084 | 0 | return B; |
1085 | 0 | } |
1086 | | |
1087 | | static bool isNullGrid(const array_type &A) |
1088 | 0 | { |
1089 | 0 | sal_Int32 nMaxX = A.shape()[0]; |
1090 | 0 | sal_Int32 nMaxY = A.shape()[1]; |
1091 | |
|
1092 | 0 | return !nMaxX || !nMaxY; |
1093 | 0 | } |
1094 | | |
1095 | | static void calcMaxs(const array_type &A, std::vector<VclGrid::Value> &rWidths, std::vector<VclGrid::Value> &rHeights) |
1096 | 0 | { |
1097 | 0 | sal_Int32 nMaxX = A.shape()[0]; |
1098 | 0 | sal_Int32 nMaxY = A.shape()[1]; |
1099 | |
|
1100 | 0 | rWidths.resize(nMaxX); |
1101 | 0 | rHeights.resize(nMaxY); |
1102 | | |
1103 | | //first use the non spanning entries to set default width/heights |
1104 | 0 | for (sal_Int32 x = 0; x < nMaxX; ++x) |
1105 | 0 | { |
1106 | 0 | for (sal_Int32 y = 0; y < nMaxY; ++y) |
1107 | 0 | { |
1108 | | #if defined __GNUC__ && !defined __clang__ && __GNUC__ >= 13 && __GNUC__ <= 16 |
1109 | | #pragma GCC diagnostic push |
1110 | | #pragma GCC diagnostic ignored "-Wdangling-reference" |
1111 | | #elif defined _MSC_VER |
1112 | | #pragma warning(push) |
1113 | | #pragma warning(disable : 4459) |
1114 | | #pragma warning(disable : 4996) |
1115 | | #endif |
1116 | 0 | const GridEntry &rEntry = A[x][y]; |
1117 | | #if defined __GNUC__ && !defined __clang__ && __GNUC__ >= 13 && __GNUC__ <= 16 |
1118 | | #pragma GCC diagnostic pop |
1119 | | #elif defined _MSC_VER |
1120 | | #pragma warning(pop) |
1121 | | #endif |
1122 | 0 | const vcl::Window *pChild = rEntry.pChild; |
1123 | 0 | if (!pChild || !pChild->IsVisible()) |
1124 | 0 | continue; |
1125 | | |
1126 | 0 | sal_Int32 nWidth = rEntry.nSpanWidth; |
1127 | 0 | sal_Int32 nHeight = rEntry.nSpanHeight; |
1128 | |
|
1129 | 0 | for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX) |
1130 | 0 | rWidths[x+nSpanX].m_bExpand |= pChild->get_hexpand(); |
1131 | |
|
1132 | 0 | for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY) |
1133 | 0 | rHeights[y+nSpanY].m_bExpand |= pChild->get_vexpand(); |
1134 | |
|
1135 | 0 | if (nWidth == 1 || nHeight == 1) |
1136 | 0 | { |
1137 | 0 | Size aChildSize = VclContainer::getLayoutRequisition(*pChild); |
1138 | 0 | if (nWidth == 1) |
1139 | 0 | rWidths[x].m_nValue = std::max(rWidths[x].m_nValue, aChildSize.Width()); |
1140 | 0 | if (nHeight == 1) |
1141 | 0 | rHeights[y].m_nValue = std::max(rHeights[y].m_nValue, aChildSize.Height()); |
1142 | 0 | } |
1143 | 0 | } |
1144 | 0 | } |
1145 | | |
1146 | | //now use the spanning entries and split any extra sizes across expanding rows/cols |
1147 | | //where possible |
1148 | 0 | for (sal_Int32 x = 0; x < nMaxX; ++x) |
1149 | 0 | { |
1150 | 0 | for (sal_Int32 y = 0; y < nMaxY; ++y) |
1151 | 0 | { |
1152 | | #if defined __GNUC__ && !defined __clang__ && __GNUC__ >= 13 && __GNUC__ <= 16 |
1153 | | #pragma GCC diagnostic push |
1154 | | #pragma GCC diagnostic ignored "-Wdangling-reference" |
1155 | | #endif |
1156 | 0 | const GridEntry &rEntry = A[x][y]; |
1157 | | #if defined __GNUC__ && !defined __clang__ && __GNUC__ >= 13 && __GNUC__ <= 16 |
1158 | | #pragma GCC diagnostic pop |
1159 | | #endif |
1160 | 0 | const vcl::Window *pChild = rEntry.pChild; |
1161 | 0 | if (!pChild || !pChild->IsVisible()) |
1162 | 0 | continue; |
1163 | | |
1164 | 0 | sal_Int32 nWidth = rEntry.nSpanWidth; |
1165 | 0 | sal_Int32 nHeight = rEntry.nSpanHeight; |
1166 | |
|
1167 | 0 | if (nWidth == 1 && nHeight == 1) |
1168 | 0 | continue; |
1169 | | |
1170 | 0 | Size aChildSize = VclContainer::getLayoutRequisition(*pChild); |
1171 | |
|
1172 | 0 | if (nWidth > 1) |
1173 | 0 | { |
1174 | 0 | sal_Int32 nExistingWidth = 0; |
1175 | 0 | for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX) |
1176 | 0 | nExistingWidth += rWidths[x+nSpanX].m_nValue; |
1177 | |
|
1178 | 0 | sal_Int32 nExtraWidth = aChildSize.Width() - nExistingWidth; |
1179 | |
|
1180 | 0 | if (nExtraWidth > 0) |
1181 | 0 | { |
1182 | 0 | bool bForceExpandAll = false; |
1183 | 0 | sal_Int32 nExpandables = 0; |
1184 | 0 | for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX) |
1185 | 0 | if (rWidths[x+nSpanX].m_bExpand) |
1186 | 0 | ++nExpandables; |
1187 | 0 | if (nExpandables == 0) |
1188 | 0 | { |
1189 | 0 | nExpandables = nWidth; |
1190 | 0 | bForceExpandAll = true; |
1191 | 0 | } |
1192 | |
|
1193 | 0 | for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX) |
1194 | 0 | { |
1195 | 0 | if (rWidths[x+nSpanX].m_bExpand || bForceExpandAll) |
1196 | 0 | rWidths[x+nSpanX].m_nValue += nExtraWidth/nExpandables; |
1197 | 0 | } |
1198 | 0 | } |
1199 | 0 | } |
1200 | |
|
1201 | 0 | if (nHeight > 1) |
1202 | 0 | { |
1203 | 0 | sal_Int32 nExistingHeight = 0; |
1204 | 0 | for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY) |
1205 | 0 | nExistingHeight += rHeights[y+nSpanY].m_nValue; |
1206 | |
|
1207 | 0 | sal_Int32 nExtraHeight = aChildSize.Height() - nExistingHeight; |
1208 | |
|
1209 | 0 | if (nExtraHeight > 0) |
1210 | 0 | { |
1211 | 0 | bool bForceExpandAll = false; |
1212 | 0 | sal_Int32 nExpandables = 0; |
1213 | 0 | for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY) |
1214 | 0 | if (rHeights[y+nSpanY].m_bExpand) |
1215 | 0 | ++nExpandables; |
1216 | 0 | if (nExpandables == 0) |
1217 | 0 | { |
1218 | 0 | nExpandables = nHeight; |
1219 | 0 | bForceExpandAll = true; |
1220 | 0 | } |
1221 | |
|
1222 | 0 | for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY) |
1223 | 0 | { |
1224 | 0 | if (rHeights[y+nSpanY].m_bExpand || bForceExpandAll) |
1225 | 0 | rHeights[y+nSpanY].m_nValue += nExtraHeight/nExpandables; |
1226 | 0 | } |
1227 | 0 | } |
1228 | 0 | } |
1229 | 0 | } |
1230 | 0 | } |
1231 | 0 | } |
1232 | | |
1233 | | static bool compareValues(const VclGrid::Value &i, const VclGrid::Value &j) |
1234 | 0 | { |
1235 | 0 | return i.m_nValue < j.m_nValue; |
1236 | 0 | } |
1237 | | |
1238 | | static VclGrid::Value accumulateValues(const VclGrid::Value &i, const VclGrid::Value &j) |
1239 | 0 | { |
1240 | 0 | VclGrid::Value aRet; |
1241 | 0 | aRet.m_nValue = i.m_nValue + j.m_nValue; |
1242 | 0 | aRet.m_bExpand = i.m_bExpand || j.m_bExpand; |
1243 | 0 | return aRet; |
1244 | 0 | } |
1245 | | |
1246 | | Size VclGrid::calculateRequisition() const |
1247 | 0 | { |
1248 | 0 | return calculateRequisitionForSpacings(get_row_spacing(), get_column_spacing()); |
1249 | 0 | } |
1250 | | |
1251 | | Size VclGrid::calculateRequisitionForSpacings(sal_Int32 nRowSpacing, sal_Int32 nColSpacing) const |
1252 | 0 | { |
1253 | 0 | array_type A = assembleGrid(*this); |
1254 | |
|
1255 | 0 | if (isNullGrid(A)) |
1256 | 0 | return Size(); |
1257 | | |
1258 | 0 | std::vector<Value> aWidths; |
1259 | 0 | std::vector<Value> aHeights; |
1260 | 0 | calcMaxs(A, aWidths, aHeights); |
1261 | |
|
1262 | 0 | tools::Long nTotalWidth = 0; |
1263 | 0 | if (get_column_homogeneous()) |
1264 | 0 | { |
1265 | 0 | nTotalWidth = std::max_element(aWidths.begin(), aWidths.end(), compareValues)->m_nValue; |
1266 | 0 | nTotalWidth *= aWidths.size(); |
1267 | 0 | } |
1268 | 0 | else |
1269 | 0 | { |
1270 | 0 | nTotalWidth = std::accumulate(aWidths.begin(), aWidths.end(), Value(), accumulateValues).m_nValue; |
1271 | 0 | } |
1272 | |
|
1273 | 0 | nTotalWidth += nColSpacing * (aWidths.size()-1); |
1274 | |
|
1275 | 0 | tools::Long nTotalHeight = 0; |
1276 | 0 | if (get_row_homogeneous()) |
1277 | 0 | { |
1278 | 0 | nTotalHeight = std::max_element(aHeights.begin(), aHeights.end(), compareValues)->m_nValue; |
1279 | 0 | nTotalHeight *= aHeights.size(); |
1280 | 0 | } |
1281 | 0 | else |
1282 | 0 | { |
1283 | 0 | nTotalHeight = std::accumulate(aHeights.begin(), aHeights.end(), Value(), accumulateValues).m_nValue; |
1284 | 0 | } |
1285 | |
|
1286 | 0 | nTotalHeight += nRowSpacing * (aHeights.size()-1); |
1287 | |
|
1288 | 0 | return Size(nTotalWidth, nTotalHeight); |
1289 | 0 | } |
1290 | | |
1291 | | void VclGrid::setAllocation(const Size& rAllocation) |
1292 | 0 | { |
1293 | 0 | array_type A = assembleGrid(*this); |
1294 | |
|
1295 | 0 | if (isNullGrid(A)) |
1296 | 0 | return; |
1297 | | |
1298 | 0 | sal_Int32 nMaxX = A.shape()[0]; |
1299 | 0 | sal_Int32 nMaxY = A.shape()[1]; |
1300 | |
|
1301 | 0 | Size aRequisition; |
1302 | 0 | std::vector<Value> aWidths(nMaxX); |
1303 | 0 | std::vector<Value> aHeights(nMaxY); |
1304 | 0 | if (!get_column_homogeneous() || !get_row_homogeneous()) |
1305 | 0 | { |
1306 | 0 | aRequisition = calculateRequisition(); |
1307 | 0 | calcMaxs(A, aWidths, aHeights); |
1308 | 0 | } |
1309 | |
|
1310 | 0 | sal_Int32 nColSpacing(get_column_spacing()); |
1311 | 0 | sal_Int32 nRowSpacing(get_row_spacing()); |
1312 | |
|
1313 | 0 | tools::Long nAvailableWidth = rAllocation.Width(); |
1314 | 0 | if (nMaxX) |
1315 | 0 | nAvailableWidth -= nColSpacing * (nMaxX - 1); |
1316 | 0 | if (get_column_homogeneous()) |
1317 | 0 | { |
1318 | 0 | for (sal_Int32 x = 0; x < nMaxX; ++x) |
1319 | 0 | aWidths[x].m_nValue = nAvailableWidth/nMaxX; |
1320 | 0 | } |
1321 | 0 | else if (rAllocation.Width() != aRequisition.Width()) |
1322 | 0 | { |
1323 | 0 | sal_Int32 nExpandables = 0; |
1324 | 0 | for (sal_Int32 x = 0; x < nMaxX; ++x) |
1325 | 0 | if (aWidths[x].m_bExpand) |
1326 | 0 | ++nExpandables; |
1327 | 0 | tools::Long nExtraWidthForExpanders = nExpandables ? (rAllocation.Width() - aRequisition.Width()) / nExpandables : 0; |
1328 | | |
1329 | | //We don't fit and there is no volunteer to be shrunk |
1330 | 0 | if (!nExpandables && rAllocation.Width() < aRequisition.Width()) |
1331 | 0 | { |
1332 | | //first reduce spacing |
1333 | 0 | while (nColSpacing) |
1334 | 0 | { |
1335 | 0 | nColSpacing /= 2; |
1336 | 0 | aRequisition = calculateRequisitionForSpacings(nRowSpacing, nColSpacing); |
1337 | 0 | if (aRequisition.Width() <= rAllocation.Width()) |
1338 | 0 | break; |
1339 | 0 | } |
1340 | | |
1341 | | //share out the remaining pain to everyone |
1342 | 0 | tools::Long nExtraWidth = (rAllocation.Width() - aRequisition.Width()) / nMaxX; |
1343 | |
|
1344 | 0 | for (sal_Int32 x = 0; x < nMaxX; ++x) |
1345 | 0 | aWidths[x].m_nValue += nExtraWidth; |
1346 | 0 | } |
1347 | |
|
1348 | 0 | if (nExtraWidthForExpanders) |
1349 | 0 | { |
1350 | 0 | for (sal_Int32 x = 0; x < nMaxX; ++x) |
1351 | 0 | if (aWidths[x].m_bExpand) |
1352 | 0 | aWidths[x].m_nValue += nExtraWidthForExpanders; |
1353 | 0 | } |
1354 | 0 | } |
1355 | |
|
1356 | 0 | tools::Long nAvailableHeight = rAllocation.Height(); |
1357 | 0 | if (nMaxY) |
1358 | 0 | nAvailableHeight -= nRowSpacing * (nMaxY - 1); |
1359 | 0 | if (get_row_homogeneous()) |
1360 | 0 | { |
1361 | 0 | for (sal_Int32 y = 0; y < nMaxY; ++y) |
1362 | 0 | aHeights[y].m_nValue = nAvailableHeight/nMaxY; |
1363 | 0 | } |
1364 | 0 | else if (rAllocation.Height() != aRequisition.Height()) |
1365 | 0 | { |
1366 | 0 | sal_Int32 nExpandables = 0; |
1367 | 0 | for (sal_Int32 y = 0; y < nMaxY; ++y) |
1368 | 0 | if (aHeights[y].m_bExpand) |
1369 | 0 | ++nExpandables; |
1370 | 0 | tools::Long nExtraHeightForExpanders = nExpandables ? (rAllocation.Height() - aRequisition.Height()) / nExpandables : 0; |
1371 | | |
1372 | | //We don't fit and there is no volunteer to be shrunk |
1373 | 0 | if (!nExpandables && rAllocation.Height() < aRequisition.Height()) |
1374 | 0 | { |
1375 | | //first reduce spacing |
1376 | 0 | while (nRowSpacing) |
1377 | 0 | { |
1378 | 0 | nRowSpacing /= 2; |
1379 | 0 | aRequisition = calculateRequisitionForSpacings(nRowSpacing, nColSpacing); |
1380 | 0 | if (aRequisition.Height() <= rAllocation.Height()) |
1381 | 0 | break; |
1382 | 0 | } |
1383 | | |
1384 | | //share out the remaining pain to everyone |
1385 | 0 | tools::Long nExtraHeight = (rAllocation.Height() - aRequisition.Height()) / nMaxY; |
1386 | |
|
1387 | 0 | for (sal_Int32 y = 0; y < nMaxY; ++y) |
1388 | 0 | aHeights[y].m_nValue += nExtraHeight; |
1389 | 0 | } |
1390 | |
|
1391 | 0 | if (nExtraHeightForExpanders) |
1392 | 0 | { |
1393 | 0 | for (sal_Int32 y = 0; y < nMaxY; ++y) |
1394 | 0 | if (aHeights[y].m_bExpand) |
1395 | 0 | aHeights[y].m_nValue += nExtraHeightForExpanders; |
1396 | 0 | } |
1397 | 0 | } |
1398 | |
|
1399 | 0 | Point aAllocPos(0, 0); |
1400 | 0 | for (sal_Int32 x = 0; x < nMaxX; ++x) |
1401 | 0 | { |
1402 | 0 | for (sal_Int32 y = 0; y < nMaxY; ++y) |
1403 | 0 | { |
1404 | | #if defined __GNUC__ && !defined __clang__ && __GNUC__ == 13 |
1405 | | #pragma GCC diagnostic push |
1406 | | #pragma GCC diagnostic ignored "-Wdangling-reference" |
1407 | | #endif |
1408 | 0 | GridEntry &rEntry = A[x][y]; |
1409 | | #if defined __GNUC__ && !defined __clang__ && __GNUC__ == 13 |
1410 | | #pragma GCC diagnostic pop |
1411 | | #endif |
1412 | 0 | vcl::Window *pChild = rEntry.pChild; |
1413 | 0 | if (pChild) |
1414 | 0 | { |
1415 | 0 | Size aChildAlloc(0, 0); |
1416 | |
|
1417 | 0 | sal_Int32 nWidth = rEntry.nSpanWidth; |
1418 | 0 | for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX) |
1419 | 0 | aChildAlloc.AdjustWidth(aWidths[x+nSpanX].m_nValue ); |
1420 | 0 | aChildAlloc.AdjustWidth(nColSpacing*(nWidth-1) ); |
1421 | |
|
1422 | 0 | sal_Int32 nHeight = rEntry.nSpanHeight; |
1423 | 0 | for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY) |
1424 | 0 | aChildAlloc.AdjustHeight(aHeights[y+nSpanY].m_nValue ); |
1425 | 0 | aChildAlloc.AdjustHeight(nRowSpacing*(nHeight-1) ); |
1426 | |
|
1427 | 0 | setLayoutAllocation(*pChild, aAllocPos, aChildAlloc); |
1428 | 0 | } |
1429 | 0 | aAllocPos.AdjustY(aHeights[y].m_nValue + nRowSpacing ); |
1430 | 0 | } |
1431 | 0 | aAllocPos.AdjustX(aWidths[x].m_nValue + nColSpacing ); |
1432 | 0 | aAllocPos.setY( 0 ); |
1433 | 0 | } |
1434 | 0 | } |
1435 | | |
1436 | | void VclGrid::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) |
1437 | 0 | { |
1438 | 0 | VclContainer::DumpAsPropertyTree(rJsonWriter); |
1439 | 0 | rJsonWriter.put("type", "grid"); |
1440 | 0 | } |
1441 | | |
1442 | | bool VclGrid::set_property(const OUString &rKey, const OUString &rValue) |
1443 | 0 | { |
1444 | 0 | if (rKey == "row-spacing") |
1445 | 0 | set_row_spacing(rValue.toInt32()); |
1446 | 0 | else if (rKey == "column-spacing") |
1447 | 0 | set_column_spacing(rValue.toInt32()); |
1448 | 0 | else if (rKey == "row-homogeneous") |
1449 | 0 | m_bRowHomogeneous = toBool(rValue); |
1450 | 0 | else if (rKey == "column-homogeneous") |
1451 | 0 | m_bColumnHomogeneous = toBool(rValue); |
1452 | 0 | else if (rKey == "n-rows") |
1453 | 0 | /*nothing to do*/; |
1454 | 0 | else |
1455 | 0 | return VclContainer::set_property(rKey, rValue); |
1456 | 0 | return true; |
1457 | 0 | } |
1458 | | |
1459 | | const vcl::Window *VclBin::get_child() const |
1460 | 0 | { |
1461 | 0 | const WindowImpl* pWindowImpl = ImplGetWindowImpl(); |
1462 | |
|
1463 | 0 | return pWindowImpl->mpFirstChild; |
1464 | 0 | } |
1465 | | |
1466 | | vcl::Window *VclBin::get_child() |
1467 | 0 | { |
1468 | 0 | return const_cast<vcl::Window*>(std::as_const(*this).get_child()); |
1469 | 0 | } |
1470 | | |
1471 | | Size VclBin::calculateRequisition() const |
1472 | 0 | { |
1473 | 0 | const vcl::Window *pChild = get_child(); |
1474 | 0 | if (pChild && pChild->IsVisible()) |
1475 | 0 | return getLayoutRequisition(*pChild); |
1476 | 0 | return Size(0, 0); |
1477 | 0 | } |
1478 | | |
1479 | | void VclBin::setAllocation(const Size &rAllocation) |
1480 | 0 | { |
1481 | 0 | vcl::Window *pChild = get_child(); |
1482 | 0 | if (pChild && pChild->IsVisible()) |
1483 | 0 | setLayoutAllocation(*pChild, Point(0, 0), rAllocation); |
1484 | 0 | } |
1485 | | |
1486 | | VclFrame::~VclFrame() |
1487 | 0 | { |
1488 | 0 | disposeOnce(); |
1489 | 0 | } |
1490 | | |
1491 | | void VclFrame::dispose() |
1492 | 0 | { |
1493 | 0 | m_pLabel.reset(); |
1494 | 0 | VclBin::dispose(); |
1495 | 0 | } |
1496 | | |
1497 | | //To-Do, hook a DecorationView into VclFrame ? |
1498 | | |
1499 | | Size VclFrame::calculateRequisition() const |
1500 | 0 | { |
1501 | 0 | Size aRet(0, 0); |
1502 | |
|
1503 | 0 | const vcl::Window *pChild = get_child(); |
1504 | 0 | const vcl::Window *pLabel = get_label_widget(); |
1505 | |
|
1506 | 0 | if (pChild && pChild->IsVisible()) |
1507 | 0 | aRet = getLayoutRequisition(*pChild); |
1508 | |
|
1509 | 0 | if (pLabel && pLabel->IsVisible()) |
1510 | 0 | { |
1511 | 0 | Size aLabelSize = getLayoutRequisition(*pLabel); |
1512 | 0 | aRet.AdjustHeight(aLabelSize.Height() ); |
1513 | 0 | aRet.setWidth( std::max(aLabelSize.Width(), aRet.Width()) ); |
1514 | 0 | } |
1515 | |
|
1516 | 0 | return aRet; |
1517 | 0 | } |
1518 | | |
1519 | | void VclFrame::setAllocation(const Size &rAllocation) |
1520 | 0 | { |
1521 | | //SetBackground( Color(0xFF, 0x00, 0xFF) ); |
1522 | |
|
1523 | 0 | Size aAllocation(rAllocation); |
1524 | 0 | Point aChildPos; |
1525 | |
|
1526 | 0 | vcl::Window *pChild = get_child(); |
1527 | 0 | vcl::Window *pLabel = get_label_widget(); |
1528 | |
|
1529 | 0 | if (pLabel && pLabel->IsVisible()) |
1530 | 0 | { |
1531 | 0 | Size aLabelSize = getLayoutRequisition(*pLabel); |
1532 | 0 | aLabelSize.setHeight( std::min(aLabelSize.Height(), aAllocation.Height()) ); |
1533 | 0 | aLabelSize.setWidth( std::min(aLabelSize.Width(), aAllocation.Width()) ); |
1534 | 0 | setLayoutAllocation(*pLabel, aChildPos, aLabelSize); |
1535 | 0 | aAllocation.AdjustHeight( -(aLabelSize.Height()) ); |
1536 | 0 | aChildPos.AdjustY(aLabelSize.Height() ); |
1537 | 0 | } |
1538 | |
|
1539 | 0 | if (pChild && pChild->IsVisible()) |
1540 | 0 | setLayoutAllocation(*pChild, aChildPos, aAllocation); |
1541 | 0 | } |
1542 | | |
1543 | | IMPL_LINK(VclFrame, WindowEventListener, VclWindowEvent&, rEvent, void) |
1544 | 0 | { |
1545 | 0 | if (rEvent.GetId() == VclEventId::ObjectDying) |
1546 | 0 | designate_label(nullptr); |
1547 | 0 | } |
1548 | | |
1549 | | void VclFrame::designate_label(vcl::Window *pWindow) |
1550 | 0 | { |
1551 | 0 | assert(!pWindow || pWindow->GetParent() == this); |
1552 | 0 | if (m_pLabel) |
1553 | 0 | m_pLabel->RemoveEventListener(LINK(this, VclFrame, WindowEventListener)); |
1554 | 0 | m_pLabel = pWindow; |
1555 | 0 | if (m_pLabel) |
1556 | 0 | m_pLabel->AddEventListener(LINK(this, VclFrame, WindowEventListener)); |
1557 | 0 | } |
1558 | | |
1559 | | const vcl::Window *VclFrame::get_label_widget() const |
1560 | 0 | { |
1561 | 0 | if (m_pLabel) |
1562 | 0 | return m_pLabel; |
1563 | 0 | assert(GetChildCount() <= 2); |
1564 | | //The label widget is normally the first (of two) children |
1565 | 0 | const WindowImpl* pWindowImpl = ImplGetWindowImpl(); |
1566 | 0 | if (pWindowImpl->mpFirstChild == pWindowImpl->mpLastChild) //no label exists |
1567 | 0 | return nullptr; |
1568 | 0 | return pWindowImpl->mpFirstChild; |
1569 | 0 | } |
1570 | | |
1571 | | vcl::Window *VclFrame::get_label_widget() |
1572 | 0 | { |
1573 | 0 | return const_cast<vcl::Window*>(std::as_const(*this).get_label_widget()); |
1574 | 0 | } |
1575 | | |
1576 | | const vcl::Window *VclFrame::get_child() const |
1577 | 0 | { |
1578 | | //The child widget is the normally the last (of two) children |
1579 | 0 | const WindowImpl* pWindowImpl = ImplGetWindowImpl(); |
1580 | 0 | assert(GetChildCount() == 2 || pWindowImpl->mbInDispose); |
1581 | 0 | if (!m_pLabel) |
1582 | 0 | return pWindowImpl->mpLastChild; |
1583 | 0 | if (pWindowImpl->mpFirstChild == pWindowImpl->mpLastChild) //only label exists |
1584 | 0 | return nullptr; |
1585 | 0 | return pWindowImpl->mpLastChild; |
1586 | 0 | } |
1587 | | |
1588 | | vcl::Window *VclFrame::get_child() |
1589 | 0 | { |
1590 | 0 | return const_cast<vcl::Window*>(std::as_const(*this).get_child()); |
1591 | 0 | } |
1592 | | |
1593 | | void VclFrame::set_label(const OUString &rLabel) |
1594 | 0 | { |
1595 | 0 | vcl::Window *pLabel = get_label_widget(); |
1596 | 0 | assert(pLabel); |
1597 | 0 | pLabel->SetText(rLabel); |
1598 | 0 | } |
1599 | | |
1600 | | OUString VclFrame::get_label() const |
1601 | 0 | { |
1602 | 0 | const vcl::Window *pLabel = get_label_widget(); |
1603 | 0 | assert(pLabel); |
1604 | 0 | return pLabel->GetText(); |
1605 | 0 | } |
1606 | | |
1607 | | OUString VclFrame::getDefaultAccessibleName() const |
1608 | 0 | { |
1609 | 0 | const vcl::Window *pLabel = get_label_widget(); |
1610 | 0 | if (pLabel) |
1611 | 0 | return pLabel->GetAccessibleName(); |
1612 | 0 | return VclBin::getDefaultAccessibleName(); |
1613 | 0 | } |
1614 | | |
1615 | | void VclFrame::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) |
1616 | 0 | { |
1617 | 0 | VclBin::DumpAsPropertyTree(rJsonWriter); |
1618 | 0 | rJsonWriter.put("type", "frame"); |
1619 | 0 | } |
1620 | | |
1621 | | class DisclosureButton final : public CheckBox |
1622 | | { |
1623 | | virtual void ImplDrawCheckBoxState(vcl::RenderContext& rRenderContext) override |
1624 | 0 | { |
1625 | | /* HACK: DisclosureButton is currently assuming, that the disclosure sign |
1626 | | will fit into the rectangle occupied by a normal checkbox on all themes. |
1627 | | If this does not hold true for some theme, ImplGetCheckImageSize |
1628 | | would have to be overridden for DisclosureButton; also GetNativeControlRegion |
1629 | | for ControlType::ListNode would have to be implemented and taken into account |
1630 | | */ |
1631 | |
|
1632 | 0 | tools::Rectangle aStateRect(GetStateRect()); |
1633 | |
|
1634 | 0 | ImplControlValue aControlValue(GetState() == TRISTATE_TRUE ? ButtonValue::On : ButtonValue::Off); |
1635 | 0 | tools::Rectangle aCtrlRegion(aStateRect); |
1636 | 0 | ControlState nState = ControlState::NONE; |
1637 | |
|
1638 | 0 | if (HasFocus()) |
1639 | 0 | nState |= ControlState::FOCUSED; |
1640 | 0 | if (GetButtonState() & DrawButtonFlags::Default) |
1641 | 0 | nState |= ControlState::DEFAULT; |
1642 | 0 | if (Window::IsEnabled()) |
1643 | 0 | nState |= ControlState::ENABLED; |
1644 | 0 | if (IsMouseOver() && GetMouseRect().Contains(GetPointerPosPixel())) |
1645 | 0 | nState |= ControlState::ROLLOVER; |
1646 | |
|
1647 | 0 | if (rRenderContext.DrawNativeControl(ControlType::ListNode, ControlPart::Entire, aCtrlRegion, |
1648 | 0 | nState, aControlValue, OUString())) |
1649 | 0 | return; |
1650 | | |
1651 | 0 | ImplSVCtrlData& rCtrlData(ImplGetSVData()->maCtrlData); |
1652 | 0 | if (!rCtrlData.moDisclosurePlus) |
1653 | 0 | rCtrlData.moDisclosurePlus.emplace(StockImage::Yes, SV_DISCLOSURE_PLUS); |
1654 | 0 | if (!rCtrlData.moDisclosureMinus) |
1655 | 0 | rCtrlData.moDisclosureMinus.emplace(StockImage::Yes, SV_DISCLOSURE_MINUS); |
1656 | |
|
1657 | 0 | Image* pImg |
1658 | 0 | = IsChecked() ? &*rCtrlData.moDisclosureMinus : &*rCtrlData.moDisclosurePlus; |
1659 | |
|
1660 | 0 | DrawImageFlags nStyle = DrawImageFlags::NONE; |
1661 | 0 | if (!IsEnabled()) |
1662 | 0 | nStyle |= DrawImageFlags::Disable; |
1663 | |
|
1664 | 0 | Size aSize(aStateRect.GetSize()); |
1665 | 0 | Size aImgSize(pImg->GetSizePixel()); |
1666 | 0 | Point aOff((aSize.Width() - aImgSize.Width()) / 2, |
1667 | 0 | (aSize.Height() - aImgSize.Height()) / 2); |
1668 | 0 | aOff += aStateRect.TopLeft(); |
1669 | 0 | rRenderContext.DrawImage(aOff, *pImg, nStyle); |
1670 | 0 | } |
1671 | | |
1672 | | public: |
1673 | | explicit DisclosureButton(vcl::Window* pParent) |
1674 | 0 | : CheckBox(pParent, 0) |
1675 | 0 | { |
1676 | 0 | } |
1677 | | |
1678 | | virtual void KeyInput( const KeyEvent& rKEvt ) override |
1679 | 0 | { |
1680 | 0 | vcl::KeyCode aKeyCode = rKEvt.GetKeyCode(); |
1681 | |
|
1682 | 0 | if( !aKeyCode.GetModifier() && |
1683 | 0 | ( ( aKeyCode.GetCode() == KEY_ADD ) || |
1684 | 0 | ( aKeyCode.GetCode() == KEY_SUBTRACT ) ) |
1685 | 0 | ) |
1686 | 0 | { |
1687 | 0 | Check( aKeyCode.GetCode() == KEY_ADD ); |
1688 | 0 | } |
1689 | 0 | else |
1690 | 0 | CheckBox::KeyInput( rKEvt ); |
1691 | 0 | } |
1692 | | }; |
1693 | | |
1694 | | VclExpander::VclExpander(vcl::Window *pParent) |
1695 | 0 | : VclBin(pParent) |
1696 | 0 | , m_bResizeTopLevel(false) |
1697 | 0 | , m_pDisclosureButton(VclPtr<DisclosureButton>::Create(this)) |
1698 | 0 | { |
1699 | 0 | m_pDisclosureButton->SetToggleHdl(LINK(this, VclExpander, ClickHdl)); |
1700 | 0 | m_pDisclosureButton->Show(); |
1701 | 0 | } Unexecuted instantiation: VclExpander::VclExpander(vcl::Window*) Unexecuted instantiation: VclExpander::VclExpander(vcl::Window*) |
1702 | | |
1703 | | VclExpander::~VclExpander() |
1704 | 0 | { |
1705 | 0 | disposeOnce(); |
1706 | 0 | } |
1707 | | |
1708 | | bool VclExpander::get_expanded() const |
1709 | 0 | { |
1710 | 0 | return m_pDisclosureButton->IsChecked(); |
1711 | 0 | } |
1712 | | |
1713 | | void VclExpander::set_expanded(bool bExpanded) |
1714 | 0 | { |
1715 | 0 | m_pDisclosureButton->Check(bExpanded); |
1716 | 0 | } |
1717 | | |
1718 | | void VclExpander::set_label(const OUString& rLabel) |
1719 | 0 | { |
1720 | 0 | m_pDisclosureButton->SetText(rLabel); |
1721 | 0 | } |
1722 | | |
1723 | | OUString VclExpander::get_label() const |
1724 | 0 | { |
1725 | 0 | return m_pDisclosureButton->GetText(); |
1726 | 0 | } |
1727 | | |
1728 | | void VclExpander::dispose() |
1729 | 0 | { |
1730 | 0 | m_pDisclosureButton.disposeAndClear(); |
1731 | 0 | VclBin::dispose(); |
1732 | 0 | } |
1733 | | |
1734 | | const vcl::Window *VclExpander::get_child() const |
1735 | 0 | { |
1736 | 0 | const WindowImpl* pWindowImpl = ImplGetWindowImpl(); |
1737 | |
|
1738 | 0 | assert(pWindowImpl->mpFirstChild == m_pDisclosureButton); |
1739 | |
|
1740 | 0 | return pWindowImpl->mpFirstChild->GetWindow(GetWindowType::Next); |
1741 | 0 | } |
1742 | | |
1743 | | vcl::Window *VclExpander::get_child() |
1744 | 0 | { |
1745 | 0 | return const_cast<vcl::Window*>(std::as_const(*this).get_child()); |
1746 | 0 | } |
1747 | | |
1748 | | Size VclExpander::calculateRequisition() const |
1749 | 0 | { |
1750 | 0 | Size aRet(0, 0); |
1751 | |
|
1752 | 0 | WindowImpl* pWindowImpl = ImplGetWindowImpl(); |
1753 | |
|
1754 | 0 | const vcl::Window *pChild = get_child(); |
1755 | 0 | const vcl::Window *pLabel = pChild != pWindowImpl->mpLastChild ? pWindowImpl->mpLastChild.get() : nullptr; |
1756 | |
|
1757 | 0 | if (pChild && pChild->IsVisible() && m_pDisclosureButton->IsChecked()) |
1758 | 0 | aRet = getLayoutRequisition(*pChild); |
1759 | |
|
1760 | 0 | Size aExpanderSize = getLayoutRequisition(*m_pDisclosureButton); |
1761 | |
|
1762 | 0 | if (pLabel && pLabel->IsVisible()) |
1763 | 0 | { |
1764 | 0 | Size aLabelSize = getLayoutRequisition(*pLabel); |
1765 | 0 | aExpanderSize.setHeight( std::max(aExpanderSize.Height(), aLabelSize.Height()) ); |
1766 | 0 | aExpanderSize.AdjustWidth(aLabelSize.Width() ); |
1767 | 0 | } |
1768 | |
|
1769 | 0 | aRet.AdjustHeight(aExpanderSize.Height() ); |
1770 | 0 | aRet.setWidth( std::max(aExpanderSize.Width(), aRet.Width()) ); |
1771 | |
|
1772 | 0 | return aRet; |
1773 | 0 | } |
1774 | | |
1775 | | void VclExpander::setAllocation(const Size &rAllocation) |
1776 | 0 | { |
1777 | 0 | Size aAllocation(rAllocation); |
1778 | 0 | Point aChildPos; |
1779 | |
|
1780 | 0 | WindowImpl* pWindowImpl = ImplGetWindowImpl(); |
1781 | | |
1782 | | //The label widget is the last (of two) children |
1783 | 0 | vcl::Window *pChild = get_child(); |
1784 | 0 | vcl::Window *pLabel = pChild != pWindowImpl->mpLastChild.get() ? pWindowImpl->mpLastChild.get() : nullptr; |
1785 | |
|
1786 | 0 | Size aButtonSize = getLayoutRequisition(*m_pDisclosureButton); |
1787 | 0 | Size aLabelSize; |
1788 | 0 | Size aExpanderSize = aButtonSize; |
1789 | 0 | if (pLabel && pLabel->IsVisible()) |
1790 | 0 | { |
1791 | 0 | aLabelSize = getLayoutRequisition(*pLabel); |
1792 | 0 | aExpanderSize.setHeight( std::max(aExpanderSize.Height(), aLabelSize.Height()) ); |
1793 | 0 | aExpanderSize.AdjustWidth(aLabelSize.Width() ); |
1794 | 0 | } |
1795 | |
|
1796 | 0 | aExpanderSize.setHeight( std::min(aExpanderSize.Height(), aAllocation.Height()) ); |
1797 | 0 | aExpanderSize.setWidth( std::min(aExpanderSize.Width(), aAllocation.Width()) ); |
1798 | |
|
1799 | 0 | aButtonSize.setHeight( std::min(aButtonSize.Height(), aExpanderSize.Height()) ); |
1800 | 0 | aButtonSize.setWidth( std::min(aButtonSize.Width(), aExpanderSize.Width()) ); |
1801 | |
|
1802 | 0 | tools::Long nExtraExpanderHeight = aExpanderSize.Height() - aButtonSize.Height(); |
1803 | 0 | Point aButtonPos(aChildPos.X(), aChildPos.Y() + nExtraExpanderHeight/2); |
1804 | 0 | setLayoutAllocation(*m_pDisclosureButton, aButtonPos, aButtonSize); |
1805 | |
|
1806 | 0 | if (pLabel && pLabel->IsVisible()) |
1807 | 0 | { |
1808 | 0 | aLabelSize.setHeight( std::min(aLabelSize.Height(), aExpanderSize.Height()) ); |
1809 | 0 | aLabelSize.setWidth( std::min(aLabelSize.Width(), |
1810 | 0 | aExpanderSize.Width() - aButtonSize.Width()) ); |
1811 | |
|
1812 | 0 | tools::Long nExtraLabelHeight = aExpanderSize.Height() - aLabelSize.Height(); |
1813 | 0 | Point aLabelPos(aChildPos.X() + aButtonSize.Width(), aChildPos.Y() + nExtraLabelHeight/2); |
1814 | 0 | setLayoutAllocation(*pLabel, aLabelPos, aLabelSize); |
1815 | 0 | } |
1816 | |
|
1817 | 0 | aAllocation.AdjustHeight( -(aExpanderSize.Height()) ); |
1818 | 0 | aChildPos.AdjustY(aExpanderSize.Height() ); |
1819 | |
|
1820 | 0 | if (pChild && pChild->IsVisible()) |
1821 | 0 | { |
1822 | 0 | if (!m_pDisclosureButton->IsChecked()) |
1823 | 0 | aAllocation = Size(); |
1824 | 0 | setLayoutAllocation(*pChild, aChildPos, aAllocation); |
1825 | 0 | } |
1826 | 0 | } |
1827 | | |
1828 | | bool VclExpander::set_property(const OUString &rKey, const OUString &rValue) |
1829 | 0 | { |
1830 | 0 | if (rKey == "expanded") |
1831 | 0 | set_expanded(toBool(rValue)); |
1832 | 0 | else if (rKey == "resize-toplevel") |
1833 | 0 | m_bResizeTopLevel = toBool(rValue); |
1834 | 0 | else |
1835 | 0 | return VclBin::set_property(rKey, rValue); |
1836 | 0 | return true; |
1837 | 0 | } |
1838 | | |
1839 | | void VclExpander::StateChanged(StateChangedType nType) |
1840 | 0 | { |
1841 | 0 | VclBin::StateChanged( nType ); |
1842 | |
|
1843 | 0 | if (nType == StateChangedType::InitShow) |
1844 | 0 | { |
1845 | 0 | vcl::Window *pChild = get_child(); |
1846 | 0 | if (pChild) |
1847 | 0 | pChild->Show(m_pDisclosureButton->IsChecked()); |
1848 | 0 | } |
1849 | 0 | } |
1850 | | |
1851 | | const vcl::Window *VclExpander::get_label_widget() const |
1852 | 0 | { |
1853 | 0 | return m_pDisclosureButton; |
1854 | 0 | } |
1855 | | |
1856 | | vcl::Window *VclExpander::get_label_widget() |
1857 | 0 | { |
1858 | 0 | return const_cast<vcl::Window*>(std::as_const(*this).get_label_widget()); |
1859 | 0 | } |
1860 | | |
1861 | | void VclExpander::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) |
1862 | 0 | { |
1863 | 0 | VclContainer::DumpAsPropertyTree(rJsonWriter); |
1864 | 0 | rJsonWriter.put("type", "expander"); |
1865 | 0 | } |
1866 | | |
1867 | | FactoryFunction VclExpander::GetUITestFactory() const |
1868 | 0 | { |
1869 | 0 | return ExpanderUIObject::create; |
1870 | 0 | } |
1871 | | |
1872 | | IMPL_LINK( VclExpander, ClickHdl, CheckBox&, rBtn, void ) |
1873 | 0 | { |
1874 | 0 | vcl::Window *pChild = get_child(); |
1875 | 0 | if (pChild) |
1876 | 0 | { |
1877 | 0 | pChild->Show(rBtn.IsChecked()); |
1878 | 0 | queue_resize(); |
1879 | 0 | Dialog* pResizeDialog = m_bResizeTopLevel ? GetParentDialog() : nullptr; |
1880 | 0 | if (pResizeDialog) |
1881 | 0 | pResizeDialog->setOptimalLayoutSize(true); |
1882 | 0 | } |
1883 | 0 | maExpandedHdl.Call(*this); |
1884 | 0 | } |
1885 | | |
1886 | | VclScrolledWindow::VclScrolledWindow(vcl::Window *pParent) |
1887 | 0 | : VclBin(pParent, WB_HIDE | WB_CLIPCHILDREN | WB_AUTOHSCROLL | WB_AUTOVSCROLL | WB_TABSTOP) |
1888 | 0 | , m_bUserManagedScrolling(false) |
1889 | 0 | , m_eDrawFrameStyle(DrawFrameStyle::NONE) |
1890 | 0 | , m_eDrawFrameFlags(DrawFrameFlags::WindowBorder) |
1891 | 0 | , m_pVScroll(VclPtr<ScrollBar>::Create(this, WB_HIDE | WB_VERT)) |
1892 | 0 | , m_pHScroll(VclPtr<ScrollBar>::Create(this, WB_HIDE | WB_HORZ)) |
1893 | 0 | , m_aScrollBarBox(VclPtr<ScrollBarBox>::Create(this, WB_HIDE)) |
1894 | 0 | { |
1895 | 0 | SetType(WindowType::SCROLLWINDOW); |
1896 | |
|
1897 | 0 | AllSettings aAllSettings = GetSettings(); |
1898 | 0 | StyleSettings aStyle = aAllSettings.GetStyleSettings(); |
1899 | 0 | aStyle.SetMonoColor(aStyle.GetShadowColor()); |
1900 | 0 | aAllSettings.SetStyleSettings(aStyle); |
1901 | 0 | GetOutDev()->SetSettings(aAllSettings); |
1902 | |
|
1903 | 0 | Link<ScrollBar*,void> aLink( LINK( this, VclScrolledWindow, ScrollBarHdl ) ); |
1904 | 0 | m_pVScroll->SetScrollHdl(aLink); |
1905 | 0 | m_pHScroll->SetScrollHdl(aLink); |
1906 | |
|
1907 | 0 | m_nBorderWidth = CalcBorderWidth(); |
1908 | 0 | } Unexecuted instantiation: VclScrolledWindow::VclScrolledWindow(vcl::Window*) Unexecuted instantiation: VclScrolledWindow::VclScrolledWindow(vcl::Window*) |
1909 | | |
1910 | | int VclScrolledWindow::CalcBorderWidth() const |
1911 | 0 | { |
1912 | 0 | if (m_eDrawFrameStyle == DrawFrameStyle::NONE) |
1913 | 0 | return 0; |
1914 | 0 | const tools::Rectangle aRect(tools::Rectangle(Point(0, 0), Size(100, 100))); |
1915 | 0 | DecorationView aDecoView(const_cast<OutputDevice*>(GetOutDev())); |
1916 | | // don't actually draw anything, just measure what size it would be and the diff is the desired border size to reserve |
1917 | 0 | const tools::Rectangle aContentRect = aDecoView.DrawFrame(aRect, m_eDrawFrameStyle, m_eDrawFrameFlags | DrawFrameFlags::NoDraw); |
1918 | 0 | const auto nBorderWidth = (aRect.GetWidth() - aContentRect.GetWidth()) / 2; |
1919 | 0 | return std::max<int>(nBorderWidth, 1); |
1920 | 0 | } |
1921 | | |
1922 | | void VclScrolledWindow::dispose() |
1923 | 0 | { |
1924 | 0 | m_pVScroll.disposeAndClear(); |
1925 | 0 | m_pHScroll.disposeAndClear(); |
1926 | 0 | m_aScrollBarBox.disposeAndClear(); |
1927 | 0 | VclBin::dispose(); |
1928 | 0 | } |
1929 | | |
1930 | | IMPL_LINK_NOARG(VclScrolledWindow, ScrollBarHdl, ScrollBar*, void) |
1931 | 0 | { |
1932 | 0 | vcl::Window *pChild = get_child(); |
1933 | 0 | if (!pChild) |
1934 | 0 | return; |
1935 | | |
1936 | 0 | assert(dynamic_cast<VclViewport*>(pChild) && "scrolledwindow child should be a Viewport"); |
1937 | |
|
1938 | 0 | pChild = pChild->GetWindow(GetWindowType::FirstChild); |
1939 | |
|
1940 | 0 | if (!pChild) |
1941 | 0 | return; |
1942 | | |
1943 | 0 | Point aWinPos(-m_pHScroll->GetThumbPos(), -m_pVScroll->GetThumbPos()); |
1944 | 0 | pChild->SetPosPixel(aWinPos); |
1945 | 0 | } |
1946 | | |
1947 | | const vcl::Window *VclScrolledWindow::get_child() const |
1948 | 0 | { |
1949 | 0 | const WindowImpl* pWindowImpl = ImplGetWindowImpl(); |
1950 | 0 | assert(GetChildCount() == 4 || pWindowImpl->mbInDispose); |
1951 | 0 | return pWindowImpl->mpLastChild; |
1952 | 0 | } |
1953 | | |
1954 | | vcl::Window *VclScrolledWindow::get_child() |
1955 | 0 | { |
1956 | 0 | return const_cast<vcl::Window*>(std::as_const(*this).get_child()); |
1957 | 0 | } |
1958 | | |
1959 | | Size VclScrolledWindow::calculateRequisition() const |
1960 | 0 | { |
1961 | 0 | Size aRet(0, 0); |
1962 | |
|
1963 | 0 | const vcl::Window *pChild = get_child(); |
1964 | 0 | if (pChild && pChild->IsVisible()) |
1965 | 0 | aRet = getLayoutRequisition(*pChild); |
1966 | |
|
1967 | 0 | if (GetStyle() & WB_VSCROLL) |
1968 | 0 | aRet.AdjustWidth(getLayoutRequisition(*m_pVScroll).Width() ); |
1969 | |
|
1970 | 0 | if (GetStyle() & WB_HSCROLL) |
1971 | 0 | aRet.AdjustHeight(getLayoutRequisition(*m_pHScroll).Height() ); |
1972 | |
|
1973 | 0 | aRet.AdjustHeight(2 * m_nBorderWidth); |
1974 | 0 | aRet.AdjustWidth(2 * m_nBorderWidth); |
1975 | |
|
1976 | 0 | return aRet; |
1977 | 0 | } |
1978 | | |
1979 | | void VclScrolledWindow::InitScrollBars(const Size &rRequest) |
1980 | 0 | { |
1981 | 0 | const vcl::Window *pChild = get_child(); |
1982 | 0 | if (!pChild || !pChild->IsVisible()) |
1983 | 0 | return; |
1984 | | |
1985 | 0 | Size aOutSize(getVisibleChildSize()); |
1986 | |
|
1987 | 0 | m_pVScroll->SetRangeMax(rRequest.Height()); |
1988 | 0 | m_pVScroll->SetVisibleSize(aOutSize.Height()); |
1989 | 0 | m_pVScroll->SetPageSize(16); |
1990 | |
|
1991 | 0 | m_pHScroll->SetRangeMax(rRequest.Width()); |
1992 | 0 | m_pHScroll->SetVisibleSize(aOutSize.Width()); |
1993 | 0 | m_pHScroll->SetPageSize(16); |
1994 | |
|
1995 | 0 | m_pVScroll->Scroll(); |
1996 | 0 | m_pHScroll->Scroll(); |
1997 | 0 | } |
1998 | | |
1999 | | void VclScrolledWindow::doSetAllocation(const Size &rAllocation, bool bRetryOnFailure) |
2000 | 0 | { |
2001 | 0 | Size aChildReq; |
2002 | |
|
2003 | 0 | vcl::Window *pChild = get_child(); |
2004 | 0 | if (pChild && pChild->IsVisible()) |
2005 | 0 | aChildReq = getLayoutRequisition(*pChild); |
2006 | |
|
2007 | 0 | tools::Long nAvailHeight = rAllocation.Height() - 2 * m_nBorderWidth; |
2008 | 0 | tools::Long nAvailWidth = rAllocation.Width() - 2 * m_nBorderWidth; |
2009 | | |
2010 | | // vert. ScrollBar |
2011 | 0 | bool bShowVScroll; |
2012 | 0 | if (GetStyle() & WB_AUTOVSCROLL) |
2013 | 0 | bShowVScroll = nAvailHeight < aChildReq.Height(); |
2014 | 0 | else |
2015 | 0 | bShowVScroll = (GetStyle() & WB_VSCROLL) != 0; |
2016 | |
|
2017 | 0 | if (bShowVScroll) |
2018 | 0 | nAvailWidth -= getLayoutRequisition(*m_pVScroll).Width(); |
2019 | | |
2020 | | // horz. ScrollBar |
2021 | 0 | bool bShowHScroll; |
2022 | 0 | if (GetStyle() & WB_AUTOHSCROLL) |
2023 | 0 | { |
2024 | 0 | bShowHScroll = nAvailWidth < aChildReq.Width(); |
2025 | |
|
2026 | 0 | if (bShowHScroll) |
2027 | 0 | nAvailHeight -= getLayoutRequisition(*m_pHScroll).Height(); |
2028 | |
|
2029 | 0 | if (GetStyle() & WB_AUTOVSCROLL) |
2030 | 0 | bShowVScroll = nAvailHeight < aChildReq.Height(); |
2031 | 0 | } |
2032 | 0 | else |
2033 | 0 | bShowHScroll = (GetStyle() & WB_HSCROLL) != 0; |
2034 | |
|
2035 | 0 | if (m_pHScroll->IsVisible() != bShowHScroll) |
2036 | 0 | m_pHScroll->Show(bShowHScroll); |
2037 | 0 | if (m_pVScroll->IsVisible() != bShowVScroll) |
2038 | 0 | m_pVScroll->Show(bShowVScroll); |
2039 | |
|
2040 | 0 | Size aInnerSize(rAllocation); |
2041 | 0 | aInnerSize.AdjustWidth(-2 * m_nBorderWidth); |
2042 | 0 | aInnerSize.AdjustHeight(-2 * m_nBorderWidth); |
2043 | |
|
2044 | 0 | bool bBothVisible = m_pVScroll->IsVisible() && m_pHScroll->IsVisible(); |
2045 | 0 | auto nScrollBarWidth = getLayoutRequisition(*m_pVScroll).Width(); |
2046 | 0 | auto nScrollBarHeight = getLayoutRequisition(*m_pHScroll).Height(); |
2047 | |
|
2048 | 0 | if (m_pVScroll->IsVisible()) |
2049 | 0 | { |
2050 | 0 | Point aScrollPos(rAllocation.Width() - nScrollBarWidth - m_nBorderWidth, m_nBorderWidth); |
2051 | 0 | Size aScrollSize(nScrollBarWidth, rAllocation.Height() - 2 * m_nBorderWidth); |
2052 | 0 | if (bBothVisible) |
2053 | 0 | aScrollSize.AdjustHeight(-nScrollBarHeight); |
2054 | 0 | setLayoutAllocation(*m_pVScroll, aScrollPos, aScrollSize); |
2055 | 0 | aInnerSize.AdjustWidth( -nScrollBarWidth ); |
2056 | 0 | } |
2057 | |
|
2058 | 0 | if (m_pHScroll->IsVisible()) |
2059 | 0 | { |
2060 | 0 | Point aScrollPos(m_nBorderWidth, rAllocation.Height() - nScrollBarHeight); |
2061 | 0 | Size aScrollSize(rAllocation.Width() - 2 * m_nBorderWidth, nScrollBarHeight); |
2062 | 0 | if (bBothVisible) |
2063 | 0 | aScrollSize.AdjustWidth(-nScrollBarWidth); |
2064 | 0 | setLayoutAllocation(*m_pHScroll, aScrollPos, aScrollSize); |
2065 | 0 | aInnerSize.AdjustHeight( -nScrollBarHeight ); |
2066 | 0 | } |
2067 | |
|
2068 | 0 | if (bBothVisible) |
2069 | 0 | { |
2070 | 0 | Point aBoxPos(aInnerSize.Width() + m_nBorderWidth, aInnerSize.Height() + m_nBorderWidth); |
2071 | 0 | m_aScrollBarBox->SetPosSizePixel(aBoxPos, Size(nScrollBarWidth, nScrollBarHeight)); |
2072 | 0 | m_aScrollBarBox->Show(); |
2073 | 0 | } |
2074 | 0 | else |
2075 | 0 | { |
2076 | 0 | m_aScrollBarBox->Hide(); |
2077 | 0 | } |
2078 | |
|
2079 | 0 | if (pChild && pChild->IsVisible()) |
2080 | 0 | { |
2081 | 0 | assert(dynamic_cast<VclViewport*>(pChild) && "scrolledwindow child should be a Viewport"); |
2082 | |
|
2083 | 0 | WinBits nOldBits = (GetStyle() & (WB_AUTOVSCROLL | WB_VSCROLL | WB_AUTOHSCROLL | WB_HSCROLL)); |
2084 | |
|
2085 | 0 | setLayoutAllocation(*pChild, Point(m_nBorderWidth, m_nBorderWidth), aInnerSize); |
2086 | | |
2087 | | // tdf#128758 if the layout allocation triggered some callback that |
2088 | | // immediately invalidates the layout by adding scrollbars then |
2089 | | // normally this would simply retrigger layout and another toplevel |
2090 | | // attempt is made later. But the initial layout attempt blocks |
2091 | | // relayouts, so just make another single effort here. |
2092 | 0 | WinBits nNewBits = (GetStyle() & (WB_AUTOVSCROLL | WB_VSCROLL | WB_AUTOHSCROLL | WB_HSCROLL)); |
2093 | 0 | if (nOldBits != nNewBits && bRetryOnFailure) |
2094 | 0 | { |
2095 | 0 | doSetAllocation(rAllocation, false); |
2096 | 0 | return; |
2097 | 0 | } |
2098 | 0 | } |
2099 | | |
2100 | 0 | if (!m_bUserManagedScrolling) |
2101 | 0 | InitScrollBars(aChildReq); |
2102 | 0 | } |
2103 | | |
2104 | | void VclScrolledWindow::setAllocation(const Size &rAllocation) |
2105 | 0 | { |
2106 | 0 | doSetAllocation(rAllocation, true); |
2107 | 0 | } |
2108 | | |
2109 | | Size VclScrolledWindow::getVisibleChildSize() const |
2110 | 0 | { |
2111 | 0 | Size aRet(GetSizePixel()); |
2112 | 0 | if (m_pVScroll->IsVisible()) |
2113 | 0 | aRet.AdjustWidth( -(m_pVScroll->GetSizePixel().Width()) ); |
2114 | 0 | if (m_pHScroll->IsVisible()) |
2115 | 0 | aRet.AdjustHeight( -(m_pHScroll->GetSizePixel().Height()) ); |
2116 | 0 | aRet.AdjustHeight(-2 * m_nBorderWidth); |
2117 | 0 | aRet.AdjustWidth(-2 * m_nBorderWidth); |
2118 | 0 | return aRet; |
2119 | 0 | } |
2120 | | |
2121 | | bool VclScrolledWindow::set_property(const OUString &rKey, const OUString &rValue) |
2122 | 0 | { |
2123 | 0 | if (rKey == "shadow-type" || rKey == "name") |
2124 | 0 | { |
2125 | 0 | if (rKey == "shadow-type") |
2126 | 0 | { |
2127 | | // despite the style names, this looks like the best mapping |
2128 | 0 | if (rValue == "in") |
2129 | 0 | m_eDrawFrameStyle = DrawFrameStyle::Out; |
2130 | 0 | else if (rValue == "out") |
2131 | 0 | m_eDrawFrameStyle = DrawFrameStyle::In; |
2132 | 0 | else if (rValue == "etched-in") |
2133 | 0 | m_eDrawFrameStyle = DrawFrameStyle::DoubleOut; |
2134 | 0 | else if (rValue == "etched-out") |
2135 | 0 | m_eDrawFrameStyle = DrawFrameStyle::DoubleIn; |
2136 | 0 | else if (rValue == "none") |
2137 | 0 | m_eDrawFrameStyle = DrawFrameStyle::NONE; |
2138 | 0 | } |
2139 | 0 | else if (rKey == "name") |
2140 | 0 | { |
2141 | 0 | m_eDrawFrameFlags = DrawFrameFlags::WindowBorder; |
2142 | 0 | if (rValue == "monoborder") |
2143 | 0 | m_eDrawFrameFlags |= DrawFrameFlags::Mono; |
2144 | 0 | } |
2145 | |
|
2146 | 0 | auto nBorderWidth = CalcBorderWidth(); |
2147 | 0 | if (m_nBorderWidth != nBorderWidth) |
2148 | 0 | { |
2149 | 0 | m_nBorderWidth = nBorderWidth; |
2150 | 0 | queue_resize(); |
2151 | 0 | } |
2152 | |
|
2153 | 0 | return true; |
2154 | 0 | } |
2155 | | |
2156 | 0 | bool bRet = VclBin::set_property(rKey, rValue); |
2157 | 0 | m_pVScroll->Show((GetStyle() & WB_VSCROLL) != 0); |
2158 | 0 | m_pHScroll->Show((GetStyle() & WB_HSCROLL) != 0); |
2159 | 0 | return bRet; |
2160 | 0 | } |
2161 | | |
2162 | | bool VclScrolledWindow::EventNotify(NotifyEvent& rNEvt) |
2163 | 0 | { |
2164 | 0 | bool bDone = false; |
2165 | 0 | if ( rNEvt.GetType() == NotifyEventType::COMMAND ) |
2166 | 0 | { |
2167 | 0 | const CommandEvent& rCEvt = *rNEvt.GetCommandEvent(); |
2168 | 0 | if ( rCEvt.GetCommand() == CommandEventId::Wheel ) |
2169 | 0 | { |
2170 | 0 | const CommandWheelData* pData = rCEvt.GetWheelData(); |
2171 | 0 | if( !pData->GetModifier() && ( pData->GetMode() == CommandWheelMode::SCROLL ) ) |
2172 | 0 | { |
2173 | | // tdf#140537 only handle scroll commands in the valid shown scrollbars |
2174 | 0 | bDone = HandleScrollCommand(rCEvt, |
2175 | 0 | m_pHScroll->IsVisible() ? m_pHScroll : nullptr, |
2176 | 0 | m_pVScroll->IsVisible() ? m_pVScroll : nullptr); |
2177 | 0 | } |
2178 | 0 | } |
2179 | 0 | else if (rCEvt.GetCommand() == CommandEventId::GesturePan) |
2180 | 0 | { |
2181 | 0 | bDone = HandleScrollCommand(rCEvt, m_pHScroll->IsVisible() ? m_pHScroll : nullptr, |
2182 | 0 | m_pVScroll->IsVisible() ? m_pVScroll : nullptr); |
2183 | 0 | } |
2184 | 0 | } |
2185 | |
|
2186 | 0 | return bDone || VclBin::EventNotify( rNEvt ); |
2187 | 0 | } |
2188 | | |
2189 | | void VclScrolledWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) |
2190 | 0 | { |
2191 | 0 | VclBin::Paint(rRenderContext, rRect); |
2192 | 0 | if (m_eDrawFrameStyle == DrawFrameStyle::NONE) |
2193 | 0 | return; |
2194 | 0 | const tools::Rectangle aRect(tools::Rectangle(Point(0,0), GetSizePixel())); |
2195 | 0 | DecorationView aDecoView(&rRenderContext); |
2196 | 0 | const tools::Rectangle aContentRect = aDecoView.DrawFrame(aRect, m_eDrawFrameStyle, m_eDrawFrameFlags); |
2197 | 0 | const auto nBorderWidth = (aRect.GetWidth() - aContentRect.GetWidth()) / 2; |
2198 | 0 | SAL_WARN_IF(nBorderWidth > m_nBorderWidth, "vcl.layout", "desired border at paint " << |
2199 | 0 | nBorderWidth << " is larger than expected " << m_nBorderWidth); |
2200 | 0 | } |
2201 | | |
2202 | | namespace { |
2203 | | void lcl_dumpScrollbar(::tools::JsonWriter& rJsonWriter, const ScrollBar& rScrollBar) |
2204 | 0 | { |
2205 | 0 | rJsonWriter.put("lower", rScrollBar.GetRangeMin()); |
2206 | 0 | rJsonWriter.put("upper", rScrollBar.GetRangeMax()); |
2207 | 0 | rJsonWriter.put("step_increment", rScrollBar.GetLineSize()); |
2208 | 0 | rJsonWriter.put("page_increment", rScrollBar.GetPageSize()); |
2209 | 0 | rJsonWriter.put("value", rScrollBar.GetThumbPos()); |
2210 | 0 | rJsonWriter.put("page_size", rScrollBar.GetVisibleSize()); |
2211 | 0 | } |
2212 | | }; |
2213 | | |
2214 | | void VclScrolledWindow::DumpAsPropertyTree(::tools::JsonWriter& rJsonWriter) |
2215 | 0 | { |
2216 | 0 | VclBin::DumpAsPropertyTree(rJsonWriter); |
2217 | |
|
2218 | 0 | rJsonWriter.put("user_managed_scrolling", m_bUserManagedScrolling); |
2219 | |
|
2220 | 0 | { |
2221 | 0 | auto aVertical = rJsonWriter.startNode("vertical"); |
2222 | |
|
2223 | 0 | ScrollBar& rScrollBar = getVertScrollBar(); |
2224 | 0 | lcl_dumpScrollbar(rJsonWriter, rScrollBar); |
2225 | |
|
2226 | 0 | WinBits nWinBits = GetStyle(); |
2227 | 0 | if (nWinBits & WB_VSCROLL) |
2228 | 0 | rJsonWriter.put("policy", "always"); |
2229 | 0 | else if (nWinBits & WB_AUTOVSCROLL) |
2230 | 0 | rJsonWriter.put("policy", "auto"); |
2231 | 0 | else |
2232 | 0 | rJsonWriter.put("policy", "never"); |
2233 | 0 | } |
2234 | |
|
2235 | 0 | { |
2236 | 0 | auto aHorizontal = rJsonWriter.startNode("horizontal"); |
2237 | |
|
2238 | 0 | ScrollBar& rScrollBar = getHorzScrollBar(); |
2239 | 0 | lcl_dumpScrollbar(rJsonWriter, rScrollBar); |
2240 | |
|
2241 | 0 | WinBits nWinBits = GetStyle(); |
2242 | 0 | if (nWinBits & WB_HSCROLL) |
2243 | 0 | rJsonWriter.put("policy", "always"); |
2244 | 0 | else if (nWinBits & WB_AUTOHSCROLL) |
2245 | 0 | rJsonWriter.put("policy", "auto"); |
2246 | 0 | else |
2247 | 0 | rJsonWriter.put("policy", "never"); |
2248 | 0 | } |
2249 | 0 | } |
2250 | | |
2251 | | void VclViewport::setAllocation(const Size &rAllocation) |
2252 | 0 | { |
2253 | 0 | vcl::Window *pChild = get_child(); |
2254 | 0 | if (!(pChild && pChild->IsVisible())) |
2255 | 0 | return; |
2256 | | |
2257 | 0 | Size aReq(getLayoutRequisition(*pChild)); |
2258 | 0 | aReq.setWidth( std::max(aReq.Width(), rAllocation.Width()) ); |
2259 | 0 | aReq.setHeight( std::max(aReq.Height(), rAllocation.Height()) ); |
2260 | 0 | Point aKeepPos(pChild->GetPosPixel()); |
2261 | 0 | if (m_bInitialAllocation) |
2262 | 0 | { |
2263 | 0 | aKeepPos = Point(0, 0); |
2264 | 0 | m_bInitialAllocation = false; |
2265 | 0 | } |
2266 | 0 | setLayoutAllocation(*pChild, aKeepPos, aReq); |
2267 | 0 | } |
2268 | | |
2269 | | const vcl::Window *VclEventBox::get_child() const |
2270 | 0 | { |
2271 | 0 | const WindowImpl* pWindowImpl = ImplGetWindowImpl(); |
2272 | |
|
2273 | 0 | assert(pWindowImpl->mpFirstChild.get() == m_aEventBoxHelper.get()); |
2274 | |
|
2275 | 0 | return pWindowImpl->mpFirstChild->GetWindow(GetWindowType::Next); |
2276 | 0 | } |
2277 | | |
2278 | | vcl::Window *VclEventBox::get_child() |
2279 | 0 | { |
2280 | 0 | return const_cast<vcl::Window*>(std::as_const(*this).get_child()); |
2281 | 0 | } |
2282 | | |
2283 | | void VclEventBox::setAllocation(const Size& rAllocation) |
2284 | 0 | { |
2285 | 0 | Point aChildPos(0, 0); |
2286 | 0 | for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next)) |
2287 | 0 | { |
2288 | 0 | if (!pChild->IsVisible()) |
2289 | 0 | continue; |
2290 | 0 | setLayoutAllocation(*pChild, aChildPos, rAllocation); |
2291 | 0 | } |
2292 | 0 | } |
2293 | | |
2294 | | Size VclEventBox::calculateRequisition() const |
2295 | 0 | { |
2296 | 0 | Size aRet(0, 0); |
2297 | |
|
2298 | 0 | for (const vcl::Window* pChild = get_child(); pChild; |
2299 | 0 | pChild = pChild->GetWindow(GetWindowType::Next)) |
2300 | 0 | { |
2301 | 0 | if (!pChild->IsVisible()) |
2302 | 0 | continue; |
2303 | 0 | Size aChildSize = getLayoutRequisition(*pChild); |
2304 | 0 | aRet.setWidth( std::max(aRet.Width(), aChildSize.Width()) ); |
2305 | 0 | aRet.setHeight( std::max(aRet.Height(), aChildSize.Height()) ); |
2306 | 0 | } |
2307 | |
|
2308 | 0 | return aRet; |
2309 | 0 | } |
2310 | | |
2311 | | void VclEventBox::Command(const CommandEvent&) |
2312 | 0 | { |
2313 | | //discard events by default to block them reaching children |
2314 | 0 | } |
2315 | | |
2316 | | VclEventBox::~VclEventBox() |
2317 | 0 | { |
2318 | 0 | disposeOnce(); |
2319 | 0 | } |
2320 | | |
2321 | | void VclEventBox::dispose() |
2322 | 0 | { |
2323 | 0 | m_aEventBoxHelper.disposeAndClear(); |
2324 | 0 | VclBin::dispose(); |
2325 | 0 | } |
2326 | | |
2327 | | void VclSizeGroup::trigger_queue_resize() |
2328 | 0 | { |
2329 | | //sufficient to trigger one widget to trigger all of them |
2330 | 0 | if (!m_aWindows.empty()) |
2331 | 0 | { |
2332 | 0 | (*m_aWindows.begin())->queue_resize(); |
2333 | 0 | } |
2334 | 0 | } |
2335 | | |
2336 | | void VclSizeGroup::set_ignore_hidden(bool bIgnoreHidden) |
2337 | 0 | { |
2338 | 0 | if (bIgnoreHidden != m_bIgnoreHidden) |
2339 | 0 | { |
2340 | 0 | m_bIgnoreHidden = bIgnoreHidden; |
2341 | 0 | trigger_queue_resize(); |
2342 | 0 | } |
2343 | 0 | } |
2344 | | |
2345 | | void VclSizeGroup::set_mode(VclSizeGroupMode eMode) |
2346 | 0 | { |
2347 | 0 | if (eMode != m_eMode) |
2348 | 0 | { |
2349 | 0 | m_eMode = eMode; |
2350 | 0 | trigger_queue_resize(); |
2351 | 0 | } |
2352 | |
|
2353 | 0 | } |
2354 | | |
2355 | | void VclSizeGroup::set_property(const OUString &rKey, const OUString &rValue) |
2356 | 0 | { |
2357 | 0 | if (rKey == "ignore-hidden") |
2358 | 0 | set_ignore_hidden(toBool(rValue)); |
2359 | 0 | else if (rKey == "mode") |
2360 | 0 | { |
2361 | 0 | VclSizeGroupMode eMode = VclSizeGroupMode::Horizontal; |
2362 | 0 | if (rValue == "none") |
2363 | 0 | eMode = VclSizeGroupMode::NONE; |
2364 | 0 | else if (rValue == "horizontal") |
2365 | 0 | eMode = VclSizeGroupMode::Horizontal; |
2366 | 0 | else if (rValue == "vertical") |
2367 | 0 | eMode = VclSizeGroupMode::Vertical; |
2368 | 0 | else if (rValue == "both") |
2369 | 0 | eMode = VclSizeGroupMode::Both; |
2370 | 0 | else |
2371 | 0 | { |
2372 | 0 | SAL_WARN("vcl.layout", "unknown size group mode" << rValue); |
2373 | 0 | } |
2374 | 0 | set_mode(eMode); |
2375 | 0 | } |
2376 | 0 | else |
2377 | 0 | { |
2378 | 0 | SAL_INFO("vcl.layout", "unhandled property: " << rKey); |
2379 | 0 | } |
2380 | 0 | } |
2381 | | |
2382 | | void MessageDialog::create_message_area() |
2383 | 0 | { |
2384 | 0 | setDeferredProperties(); |
2385 | |
|
2386 | 0 | if (m_pGrid) |
2387 | 0 | return; |
2388 | | |
2389 | 0 | VclContainer *pContainer = get_content_area(); |
2390 | 0 | assert(pContainer); |
2391 | |
|
2392 | 0 | m_pGrid.reset( VclPtr<VclGrid>::Create(pContainer) ); |
2393 | 0 | m_pGrid->reorderWithinParent(0); |
2394 | 0 | m_pGrid->set_column_spacing(12); |
2395 | 0 | m_pMessageBox.reset(VclPtr<VclVBox>::Create(m_pGrid)); |
2396 | 0 | m_pMessageBox->set_grid_left_attach(1); |
2397 | 0 | m_pMessageBox->set_grid_top_attach(0); |
2398 | 0 | m_pMessageBox->set_spacing(GetTextHeight()); |
2399 | |
|
2400 | 0 | m_pImage = VclPtr<FixedImage>::Create(m_pGrid, WB_CENTER | WB_VCENTER | WB_3DLOOK); |
2401 | 0 | switch (m_eMessageType) |
2402 | 0 | { |
2403 | 0 | case VclMessageType::Info: |
2404 | 0 | m_pImage->SetImage(GetStandardInfoBoxImage()); |
2405 | 0 | break; |
2406 | 0 | case VclMessageType::Warning: |
2407 | 0 | m_pImage->SetImage(GetStandardWarningBoxImage()); |
2408 | 0 | break; |
2409 | 0 | case VclMessageType::Question: |
2410 | 0 | m_pImage->SetImage(GetStandardQueryBoxImage()); |
2411 | 0 | break; |
2412 | 0 | case VclMessageType::Error: |
2413 | 0 | m_pImage->SetImage(GetStandardErrorBoxImage()); |
2414 | 0 | break; |
2415 | 0 | case VclMessageType::Other: |
2416 | 0 | break; |
2417 | 0 | } |
2418 | 0 | m_pImage->set_grid_left_attach(0); |
2419 | 0 | m_pImage->set_grid_top_attach(0); |
2420 | 0 | m_pImage->set_valign(VclAlign::Start); |
2421 | 0 | m_pImage->Show(m_eMessageType != VclMessageType::Other); |
2422 | |
|
2423 | 0 | WinBits nWinStyle = WB_CLIPCHILDREN | WB_LEFT | WB_VCENTER | WB_NOLABEL | WB_NOTABSTOP; |
2424 | |
|
2425 | 0 | bool bHasSecondaryText = !m_sSecondaryString.isEmpty(); |
2426 | |
|
2427 | 0 | m_pPrimaryMessage = VclPtr<VclMultiLineEdit>::Create(m_pMessageBox, nWinStyle); |
2428 | 0 | m_pPrimaryMessage->SetPaintTransparent(true); |
2429 | 0 | m_pPrimaryMessage->EnableCursor(false); |
2430 | |
|
2431 | 0 | m_pPrimaryMessage->set_hexpand(true); |
2432 | 0 | m_pPrimaryMessage->SetText(m_sPrimaryString); |
2433 | 0 | m_pPrimaryMessage->Show(!m_sPrimaryString.isEmpty()); |
2434 | |
|
2435 | 0 | m_pSecondaryMessage = VclPtr<VclMultiLineEdit>::Create(m_pMessageBox, nWinStyle); |
2436 | 0 | m_pSecondaryMessage->SetPaintTransparent(true); |
2437 | 0 | m_pSecondaryMessage->EnableCursor(false); |
2438 | 0 | m_pSecondaryMessage->set_hexpand(true); |
2439 | 0 | m_pSecondaryMessage->SetText(m_sSecondaryString); |
2440 | 0 | m_pSecondaryMessage->Show(bHasSecondaryText); |
2441 | |
|
2442 | 0 | MessageDialog::SetMessagesWidths(this, m_pPrimaryMessage, bHasSecondaryText ? m_pSecondaryMessage.get() : nullptr); |
2443 | |
|
2444 | 0 | VclButtonBox *pButtonBox = get_action_area(); |
2445 | 0 | assert(pButtonBox); |
2446 | |
|
2447 | 0 | VclPtr<PushButton> pBtn; |
2448 | 0 | short nDefaultResponse = get_default_response(); |
2449 | 0 | switch (m_eButtonsType) |
2450 | 0 | { |
2451 | 0 | case VclButtonsType::NONE: |
2452 | 0 | break; |
2453 | 0 | case VclButtonsType::Ok: |
2454 | 0 | pBtn.reset( VclPtr<OKButton>::Create(pButtonBox) ); |
2455 | 0 | pBtn->SetStyle(pBtn->GetStyle() & WB_DEFBUTTON); |
2456 | 0 | pBtn->Show(); |
2457 | 0 | pBtn->set_id(u"ok"_ustr); |
2458 | 0 | add_button(pBtn, RET_OK, true); |
2459 | 0 | nDefaultResponse = RET_OK; |
2460 | 0 | break; |
2461 | 0 | case VclButtonsType::Close: |
2462 | 0 | pBtn.reset( VclPtr<CloseButton>::Create(pButtonBox) ); |
2463 | 0 | pBtn->SetStyle(pBtn->GetStyle() & WB_DEFBUTTON); |
2464 | 0 | pBtn->Show(); |
2465 | 0 | pBtn->set_id(u"close"_ustr); |
2466 | 0 | add_button(pBtn, RET_CLOSE, true); |
2467 | 0 | nDefaultResponse = RET_CLOSE; |
2468 | 0 | break; |
2469 | 0 | case VclButtonsType::Cancel: |
2470 | 0 | pBtn.reset( VclPtr<CancelButton>::Create(pButtonBox) ); |
2471 | 0 | pBtn->SetStyle(pBtn->GetStyle() & WB_DEFBUTTON); |
2472 | 0 | pBtn->Show(); |
2473 | 0 | pBtn->set_id(u"cancel"_ustr); |
2474 | 0 | add_button(pBtn, RET_CANCEL, true); |
2475 | 0 | nDefaultResponse = RET_CANCEL; |
2476 | 0 | break; |
2477 | 0 | case VclButtonsType::YesNo: |
2478 | 0 | pBtn = VclPtr<PushButton>::Create(pButtonBox); |
2479 | 0 | pBtn->SetText(GetStandardText(StandardButtonType::Yes)); |
2480 | 0 | pBtn->Show(); |
2481 | 0 | pBtn->set_id(u"yes"_ustr); |
2482 | 0 | add_button(pBtn, RET_YES, true); |
2483 | |
|
2484 | 0 | pBtn.reset( VclPtr<PushButton>::Create(pButtonBox) ); |
2485 | 0 | pBtn->SetText(GetStandardText(StandardButtonType::No)); |
2486 | 0 | pBtn->Show(); |
2487 | 0 | pBtn->set_id(u"no"_ustr); |
2488 | 0 | add_button(pBtn, RET_NO, true); |
2489 | 0 | nDefaultResponse = RET_NO; |
2490 | 0 | break; |
2491 | 0 | case VclButtonsType::OkCancel: |
2492 | 0 | pBtn.reset( VclPtr<OKButton>::Create(pButtonBox) ); |
2493 | 0 | pBtn->Show(); |
2494 | 0 | pBtn->set_id(u"ok"_ustr); |
2495 | 0 | add_button(pBtn, RET_OK, true); |
2496 | |
|
2497 | 0 | pBtn.reset( VclPtr<CancelButton>::Create(pButtonBox) ); |
2498 | 0 | pBtn->Show(); |
2499 | 0 | pBtn->set_id(u"cancel"_ustr); |
2500 | 0 | add_button(pBtn, RET_CANCEL, true); |
2501 | 0 | nDefaultResponse = RET_CANCEL; |
2502 | 0 | break; |
2503 | 0 | } |
2504 | 0 | set_default_response(nDefaultResponse); |
2505 | 0 | sort_native_button_order(*pButtonBox); |
2506 | 0 | m_pMessageBox->Show(); |
2507 | 0 | m_pGrid->Show(); |
2508 | 0 | } |
2509 | | |
2510 | | void MessageDialog::create_owned_areas() |
2511 | 0 | { |
2512 | | #if defined _WIN32 |
2513 | | set_border_width(3); |
2514 | | #else |
2515 | 0 | set_border_width(12); |
2516 | 0 | #endif |
2517 | 0 | m_pOwnedContentArea.reset(VclPtr<VclVBox>::Create(this, false, 24)); |
2518 | 0 | set_content_area(m_pOwnedContentArea); |
2519 | 0 | m_pOwnedContentArea->Show(); |
2520 | 0 | m_pOwnedActionArea.reset( VclPtr<VclHButtonBox>::Create(m_pOwnedContentArea) ); |
2521 | 0 | set_action_area(m_pOwnedActionArea); |
2522 | 0 | m_pOwnedActionArea->Show(); |
2523 | 0 | } |
2524 | | |
2525 | | MessageDialog::MessageDialog(vcl::Window* pParent, WinBits nStyle) |
2526 | 0 | : Dialog(pParent, nStyle) |
2527 | 0 | , m_eButtonsType(VclButtonsType::NONE) |
2528 | 0 | , m_eMessageType(VclMessageType::Info) |
2529 | 0 | , m_pOwnedContentArea(nullptr) |
2530 | 0 | , m_pOwnedActionArea(nullptr) |
2531 | 0 | , m_pGrid(nullptr) |
2532 | 0 | , m_pMessageBox(nullptr) |
2533 | 0 | , m_pImage(nullptr) |
2534 | 0 | , m_pPrimaryMessage(nullptr) |
2535 | 0 | , m_pSecondaryMessage(nullptr) |
2536 | 0 | { |
2537 | 0 | SetType(WindowType::MESSBOX); |
2538 | 0 | } Unexecuted instantiation: MessageDialog::MessageDialog(vcl::Window*, long) Unexecuted instantiation: MessageDialog::MessageDialog(vcl::Window*, long) |
2539 | | |
2540 | | MessageDialog::MessageDialog(vcl::Window* pParent, |
2541 | | OUString aMessage, |
2542 | | VclMessageType eMessageType, |
2543 | | VclButtonsType eButtonsType) |
2544 | 0 | : Dialog(pParent, WB_MOVEABLE | WB_3DLOOK | WB_CLOSEABLE) |
2545 | 0 | , m_eButtonsType(eButtonsType) |
2546 | 0 | , m_eMessageType(eMessageType) |
2547 | 0 | , m_pGrid(nullptr) |
2548 | 0 | , m_pMessageBox(nullptr) |
2549 | 0 | , m_pImage(nullptr) |
2550 | 0 | , m_pPrimaryMessage(nullptr) |
2551 | 0 | , m_pSecondaryMessage(nullptr) |
2552 | 0 | , m_sPrimaryString(std::move(aMessage)) |
2553 | 0 | { |
2554 | 0 | SetType(WindowType::MESSBOX); |
2555 | 0 | create_owned_areas(); |
2556 | 0 | create_message_area(); |
2557 | |
|
2558 | 0 | switch (m_eMessageType) |
2559 | 0 | { |
2560 | 0 | case VclMessageType::Info: |
2561 | 0 | SetText(GetStandardInfoBoxText()); |
2562 | 0 | break; |
2563 | 0 | case VclMessageType::Warning: |
2564 | 0 | SetText(GetStandardWarningBoxText()); |
2565 | 0 | break; |
2566 | 0 | case VclMessageType::Question: |
2567 | 0 | SetText(GetStandardQueryBoxText()); |
2568 | 0 | break; |
2569 | 0 | case VclMessageType::Error: |
2570 | 0 | SetText(GetStandardErrorBoxText()); |
2571 | 0 | SetTaskBarState(VclTaskBarStates::Error); |
2572 | 0 | break; |
2573 | 0 | case VclMessageType::Other: |
2574 | 0 | SetText(Application::GetDisplayName()); |
2575 | 0 | break; |
2576 | 0 | } |
2577 | 0 | } Unexecuted instantiation: MessageDialog::MessageDialog(vcl::Window*, rtl::OUString, VclMessageType, VclButtonsType) Unexecuted instantiation: MessageDialog::MessageDialog(vcl::Window*, rtl::OUString, VclMessageType, VclButtonsType) |
2578 | | |
2579 | | void MessageDialog::dispose() |
2580 | 0 | { |
2581 | 0 | SetTaskBarState(VclTaskBarStates::Normal); |
2582 | |
|
2583 | 0 | disposeOwnedButtons(); |
2584 | 0 | m_pPrimaryMessage.disposeAndClear(); |
2585 | 0 | m_pSecondaryMessage.disposeAndClear(); |
2586 | 0 | m_pImage.disposeAndClear(); |
2587 | 0 | m_pMessageBox.disposeAndClear(); |
2588 | 0 | m_pGrid.disposeAndClear(); |
2589 | 0 | m_pOwnedActionArea.disposeAndClear(); |
2590 | 0 | m_pOwnedContentArea.disposeAndClear(); |
2591 | 0 | Dialog::dispose(); |
2592 | 0 | } |
2593 | | |
2594 | | MessageDialog::~MessageDialog() |
2595 | 0 | { |
2596 | 0 | disposeOnce(); |
2597 | 0 | } |
2598 | | |
2599 | | void MessageDialog::SetMessagesWidths(vcl::Window const *pParent, |
2600 | | VclMultiLineEdit *pPrimaryMessage, VclMultiLineEdit *pSecondaryMessage) |
2601 | 0 | { |
2602 | 0 | if (pSecondaryMessage) |
2603 | 0 | { |
2604 | 0 | assert(pPrimaryMessage); |
2605 | 0 | vcl::Font aFont = pParent->GetSettings().GetStyleSettings().GetLabelFont(); |
2606 | 0 | aFont.SetFontSize(Size(0, aFont.GetFontSize().Height() * 1.2)); |
2607 | 0 | aFont.SetWeight(WEIGHT_BOLD); |
2608 | 0 | pPrimaryMessage->SetControlFont(aFont); |
2609 | 0 | pPrimaryMessage->SetMaxTextWidth(pPrimaryMessage->approximate_char_width() * 44); |
2610 | 0 | pSecondaryMessage->SetMaxTextWidth(pSecondaryMessage->approximate_char_width() * 60); |
2611 | 0 | } |
2612 | 0 | else |
2613 | 0 | pPrimaryMessage->SetMaxTextWidth(pPrimaryMessage->approximate_char_width() * 60); |
2614 | 0 | } |
2615 | | |
2616 | | OUString const & MessageDialog::get_primary_text() const |
2617 | 0 | { |
2618 | 0 | const_cast<MessageDialog*>(this)->setDeferredProperties(); |
2619 | |
|
2620 | 0 | return m_sPrimaryString; |
2621 | 0 | } |
2622 | | |
2623 | | OUString const & MessageDialog::get_secondary_text() const |
2624 | 0 | { |
2625 | 0 | const_cast<MessageDialog*>(this)->setDeferredProperties(); |
2626 | |
|
2627 | 0 | return m_sSecondaryString; |
2628 | 0 | } |
2629 | | |
2630 | | bool MessageDialog::set_property(const OUString &rKey, const OUString &rValue) |
2631 | 0 | { |
2632 | 0 | if (rKey == "text") |
2633 | 0 | set_primary_text(rValue); |
2634 | 0 | else if (rKey == "secondary-text") |
2635 | 0 | set_secondary_text(rValue); |
2636 | 0 | else if (rKey == "message-type") |
2637 | 0 | { |
2638 | 0 | VclMessageType eMode = VclMessageType::Info; |
2639 | 0 | if (rValue == "info") |
2640 | 0 | eMode = VclMessageType::Info; |
2641 | 0 | else if (rValue == "warning") |
2642 | 0 | eMode = VclMessageType::Warning; |
2643 | 0 | else if (rValue == "question") |
2644 | 0 | eMode = VclMessageType::Question; |
2645 | 0 | else if (rValue == "error") |
2646 | 0 | eMode = VclMessageType::Error; |
2647 | 0 | else if (rValue == "other") |
2648 | 0 | eMode = VclMessageType::Other; |
2649 | 0 | else |
2650 | 0 | { |
2651 | 0 | SAL_WARN("vcl.layout", "unknown message type mode" << rValue); |
2652 | 0 | } |
2653 | 0 | m_eMessageType = eMode; |
2654 | 0 | } |
2655 | 0 | else if (rKey == "buttons") |
2656 | 0 | { |
2657 | 0 | m_eButtonsType = BuilderBase::mapGtkToVclButtonsType(rValue); |
2658 | 0 | } |
2659 | 0 | else |
2660 | 0 | return Dialog::set_property(rKey, rValue); |
2661 | 0 | return true; |
2662 | 0 | } |
2663 | | |
2664 | | void MessageDialog::set_primary_text(const OUString &rPrimaryString) |
2665 | 0 | { |
2666 | 0 | m_sPrimaryString = rPrimaryString; |
2667 | 0 | if (m_pPrimaryMessage) |
2668 | 0 | { |
2669 | 0 | m_pPrimaryMessage->SetText(m_sPrimaryString); |
2670 | 0 | m_pPrimaryMessage->Show(!m_sPrimaryString.isEmpty()); |
2671 | 0 | MessageDialog::SetMessagesWidths(this, m_pPrimaryMessage, !m_sSecondaryString.isEmpty() ? m_pSecondaryMessage.get() : nullptr); |
2672 | 0 | } |
2673 | 0 | } |
2674 | | |
2675 | | void MessageDialog::set_secondary_text(const OUString &rSecondaryString) |
2676 | 0 | { |
2677 | 0 | m_sSecondaryString = rSecondaryString; |
2678 | 0 | if (m_pSecondaryMessage) |
2679 | 0 | { |
2680 | 0 | m_pSecondaryMessage->SetText("\n" + m_sSecondaryString); |
2681 | 0 | m_pSecondaryMessage->Show(!m_sSecondaryString.isEmpty()); |
2682 | 0 | MessageDialog::SetMessagesWidths(this, m_pPrimaryMessage, !m_sSecondaryString.isEmpty() ? m_pSecondaryMessage.get() : nullptr); |
2683 | 0 | } |
2684 | 0 | } |
2685 | | |
2686 | | void MessageDialog::StateChanged(StateChangedType nType) |
2687 | 0 | { |
2688 | 0 | Dialog::StateChanged(nType); |
2689 | 0 | if (nType == StateChangedType::InitShow) |
2690 | 0 | { |
2691 | | // MessageBox should be at least as wide as to see the title |
2692 | 0 | auto nTitleWidth = CalcTitleWidth(); |
2693 | | // Extra-Width for Close button |
2694 | 0 | nTitleWidth += mpWindowImpl->mnTopBorder; |
2695 | 0 | if (get_preferred_size().Width() < nTitleWidth) |
2696 | 0 | { |
2697 | 0 | set_width_request(nTitleWidth); |
2698 | 0 | DoInitialLayout(); |
2699 | 0 | } |
2700 | 0 | } |
2701 | 0 | } |
2702 | | |
2703 | | VclPaned::VclPaned(vcl::Window *pParent, bool bVertical) |
2704 | 0 | : VclContainer(pParent, WB_HIDE | WB_CLIPCHILDREN) |
2705 | 0 | , m_pSplitter(VclPtr<Splitter>::Create(this, bVertical ? WB_VSCROLL : WB_HSCROLL)) |
2706 | 0 | , m_nPosition(-1) |
2707 | 0 | { |
2708 | 0 | m_pSplitter->SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetFaceColor())); |
2709 | 0 | m_pSplitter->Show(); |
2710 | 0 | } |
2711 | | |
2712 | | void VclPaned::dispose() |
2713 | 0 | { |
2714 | 0 | m_pSplitter.disposeAndClear(); |
2715 | 0 | VclContainer::dispose(); |
2716 | 0 | } |
2717 | | |
2718 | | VclVPaned::VclVPaned(vcl::Window *pParent) |
2719 | 0 | : VclPaned(pParent, true) |
2720 | 0 | { |
2721 | 0 | m_pSplitter->SetSplitHdl(LINK(this, VclVPaned, SplitHdl)); |
2722 | 0 | } Unexecuted instantiation: VclVPaned::VclVPaned(vcl::Window*) Unexecuted instantiation: VclVPaned::VclVPaned(vcl::Window*) |
2723 | | |
2724 | | IMPL_LINK(VclVPaned, SplitHdl, Splitter*, pSplitter, void) |
2725 | 0 | { |
2726 | 0 | tools::Long nSize = pSplitter->GetSplitPosPixel(); |
2727 | 0 | Size aSplitterSize(m_pSplitter->GetSizePixel()); |
2728 | 0 | Size aAllocation(GetSizePixel()); |
2729 | 0 | arrange(aAllocation, nSize, aAllocation.Height() - nSize - aSplitterSize.Height()); |
2730 | 0 | } |
2731 | | |
2732 | | void VclVPaned::arrange(const Size& rAllocation, tools::Long nFirstHeight, tools::Long nSecondHeight) |
2733 | 0 | { |
2734 | 0 | Size aSplitterSize(rAllocation.Width(), getLayoutRequisition(*m_pSplitter).Height()); |
2735 | 0 | Size aFirstChildSize(rAllocation.Width(), nFirstHeight); |
2736 | 0 | Size aSecondChildSize(rAllocation.Width(), nSecondHeight); |
2737 | 0 | int nElement = 0; |
2738 | 0 | for (vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild; |
2739 | 0 | pChild = pChild->GetWindow(GetWindowType::Next)) |
2740 | 0 | { |
2741 | 0 | if (!pChild->IsVisible()) |
2742 | 0 | continue; |
2743 | 0 | if (nElement == 0) |
2744 | 0 | { |
2745 | 0 | Point aSplitterPos(0, aFirstChildSize.Height()); |
2746 | 0 | setLayoutAllocation(*m_pSplitter, aSplitterPos, aSplitterSize); |
2747 | 0 | m_nPosition = aSplitterPos.Y() + aSplitterSize.Height() / 2; |
2748 | 0 | } |
2749 | 0 | else if (nElement == 1) |
2750 | 0 | { |
2751 | 0 | Point aChildPos(0, 0); |
2752 | 0 | setLayoutAllocation(*pChild, aChildPos, aFirstChildSize); |
2753 | 0 | } |
2754 | 0 | else if (nElement == 2) |
2755 | 0 | { |
2756 | 0 | Point aChildPos(0, aFirstChildSize.Height() + aSplitterSize.Height()); |
2757 | 0 | setLayoutAllocation(*pChild, aChildPos, aSecondChildSize); |
2758 | 0 | } |
2759 | 0 | ++nElement; |
2760 | 0 | } |
2761 | 0 | } |
2762 | | |
2763 | | void VclVPaned::set_position(tools::Long nPosition) |
2764 | 0 | { |
2765 | 0 | VclPaned::set_position(nPosition); |
2766 | |
|
2767 | 0 | Size aAllocation(GetSizePixel()); |
2768 | 0 | Size aSplitterSize(m_pSplitter->GetSizePixel()); |
2769 | |
|
2770 | 0 | nPosition -= aSplitterSize.Height() / 2; |
2771 | |
|
2772 | 0 | arrange(aAllocation, nPosition, aAllocation.Height() - nPosition - aSplitterSize.Height()); |
2773 | 0 | } |
2774 | | |
2775 | | void VclVPaned::setAllocation(const Size& rAllocation) |
2776 | 0 | { |
2777 | | //supporting "shrink" could be done by adjusting the allowed drag rectangle |
2778 | 0 | m_pSplitter->SetDragRectPixel(tools::Rectangle(Point(0, 0), rAllocation)); |
2779 | 0 | Size aSplitterSize(rAllocation.Width(), getLayoutRequisition(*m_pSplitter).Height()); |
2780 | 0 | const tools::Long nHeight = rAllocation.Height() - aSplitterSize.Height(); |
2781 | |
|
2782 | 0 | tools::Long nFirstHeight = 0; |
2783 | 0 | tools::Long nSecondHeight = 0; |
2784 | 0 | bool bFirstCanResize = true; |
2785 | 0 | bool bSecondCanResize = true; |
2786 | 0 | const bool bInitialAllocation = get_position() < 0; |
2787 | 0 | int nElement = 0; |
2788 | 0 | for (const vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild; |
2789 | 0 | pChild = pChild->GetWindow(GetWindowType::Next)) |
2790 | 0 | { |
2791 | 0 | if (!pChild->IsVisible()) |
2792 | 0 | continue; |
2793 | 0 | if (nElement == 1) |
2794 | 0 | { |
2795 | 0 | if (bInitialAllocation) |
2796 | 0 | nFirstHeight = getLayoutRequisition(*pChild).Height(); |
2797 | 0 | else |
2798 | 0 | nFirstHeight = pChild->GetSizePixel().Height() + pChild->get_margin_top() + pChild->get_margin_bottom(); |
2799 | 0 | bFirstCanResize = pChild->get_expand(); |
2800 | 0 | } |
2801 | 0 | else if (nElement == 2) |
2802 | 0 | { |
2803 | 0 | if (bInitialAllocation) |
2804 | 0 | nSecondHeight = getLayoutRequisition(*pChild).Height(); |
2805 | 0 | else |
2806 | 0 | nSecondHeight = pChild->GetSizePixel().Height() + pChild->get_margin_top() + pChild->get_margin_bottom(); |
2807 | 0 | bSecondCanResize = pChild->get_expand(); |
2808 | 0 | } |
2809 | 0 | ++nElement; |
2810 | 0 | } |
2811 | 0 | tools::Long nHeightRequest = nFirstHeight + nSecondHeight; |
2812 | 0 | tools::Long nHeightDiff = nHeight - nHeightRequest; |
2813 | 0 | if (bFirstCanResize == bSecondCanResize) |
2814 | 0 | nFirstHeight += nHeightDiff/2; |
2815 | 0 | else if (bFirstCanResize) |
2816 | 0 | nFirstHeight += nHeightDiff; |
2817 | 0 | arrange(rAllocation, nFirstHeight, rAllocation.Height() - nFirstHeight - aSplitterSize.Height()); |
2818 | 0 | } |
2819 | | |
2820 | | Size VclVPaned::calculateRequisition() const |
2821 | 0 | { |
2822 | 0 | Size aRet(0, 0); |
2823 | |
|
2824 | 0 | for (const vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild; |
2825 | 0 | pChild = pChild->GetWindow(GetWindowType::Next)) |
2826 | 0 | { |
2827 | 0 | if (!pChild->IsVisible()) |
2828 | 0 | continue; |
2829 | 0 | Size aChildSize = getLayoutRequisition(*pChild); |
2830 | 0 | aRet.setWidth( std::max(aRet.Width(), aChildSize.Width()) ); |
2831 | 0 | aRet.AdjustHeight(aChildSize.Height() ); |
2832 | 0 | } |
2833 | |
|
2834 | 0 | return aRet; |
2835 | 0 | } |
2836 | | |
2837 | | VclHPaned::VclHPaned(vcl::Window *pParent) |
2838 | 0 | : VclPaned(pParent, false) |
2839 | 0 | { |
2840 | 0 | m_pSplitter->SetSplitHdl(LINK(this, VclHPaned, SplitHdl)); |
2841 | 0 | } Unexecuted instantiation: VclHPaned::VclHPaned(vcl::Window*) Unexecuted instantiation: VclHPaned::VclHPaned(vcl::Window*) |
2842 | | |
2843 | | IMPL_LINK(VclHPaned, SplitHdl, Splitter*, pSplitter, void) |
2844 | 0 | { |
2845 | 0 | tools::Long nSize = pSplitter->GetSplitPosPixel(); |
2846 | 0 | Size aSplitterSize(m_pSplitter->GetSizePixel()); |
2847 | 0 | Size aAllocation(GetSizePixel()); |
2848 | 0 | arrange(aAllocation, nSize, aAllocation.Width() - nSize - aSplitterSize.Width()); |
2849 | 0 | } |
2850 | | |
2851 | | void VclHPaned::arrange(const Size& rAllocation, tools::Long nFirstWidth, tools::Long nSecondWidth) |
2852 | 0 | { |
2853 | 0 | Size aSplitterSize(getLayoutRequisition(*m_pSplitter).Width(), rAllocation.Height()); |
2854 | 0 | Size aFirstChildSize(nFirstWidth, rAllocation.Height()); |
2855 | 0 | Size aSecondChildSize(nSecondWidth, rAllocation.Height()); |
2856 | 0 | int nElement = 0; |
2857 | 0 | for (vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild; |
2858 | 0 | pChild = pChild->GetWindow(GetWindowType::Next)) |
2859 | 0 | { |
2860 | 0 | if (!pChild->IsVisible()) |
2861 | 0 | continue; |
2862 | 0 | if (nElement == 0) |
2863 | 0 | { |
2864 | 0 | Point aSplitterPos(aFirstChildSize.Width(), 0); |
2865 | 0 | setLayoutAllocation(*m_pSplitter, aSplitterPos, aSplitterSize); |
2866 | 0 | m_nPosition = aSplitterPos.X() + aSplitterSize.Width() / 2; |
2867 | 0 | } |
2868 | 0 | else if (nElement == 1) |
2869 | 0 | { |
2870 | 0 | Point aChildPos(0, 0); |
2871 | 0 | setLayoutAllocation(*pChild, aChildPos, aFirstChildSize); |
2872 | 0 | } |
2873 | 0 | else if (nElement == 2) |
2874 | 0 | { |
2875 | 0 | Point aChildPos(aFirstChildSize.Width() + aSplitterSize.Width(), 0); |
2876 | 0 | setLayoutAllocation(*pChild, aChildPos, aSecondChildSize); |
2877 | 0 | } |
2878 | 0 | ++nElement; |
2879 | 0 | } |
2880 | 0 | } |
2881 | | |
2882 | | void VclHPaned::set_position(tools::Long nPosition) |
2883 | 0 | { |
2884 | 0 | VclPaned::set_position(nPosition); |
2885 | |
|
2886 | 0 | Size aAllocation(GetSizePixel()); |
2887 | 0 | Size aSplitterSize(m_pSplitter->GetSizePixel()); |
2888 | |
|
2889 | 0 | nPosition -= aSplitterSize.Width() / 2; |
2890 | |
|
2891 | 0 | arrange(aAllocation, nPosition, aAllocation.Width() - nPosition - aSplitterSize.Width()); |
2892 | 0 | } |
2893 | | |
2894 | | void VclHPaned::setAllocation(const Size& rAllocation) |
2895 | 0 | { |
2896 | | //supporting "shrink" could be done by adjusting the allowed drag rectangle |
2897 | 0 | m_pSplitter->SetDragRectPixel(tools::Rectangle(Point(0, 0), rAllocation)); |
2898 | 0 | Size aSplitterSize(getLayoutRequisition(*m_pSplitter).Width(), rAllocation.Height()); |
2899 | 0 | const tools::Long nWidth = rAllocation.Width() - aSplitterSize.Width(); |
2900 | |
|
2901 | 0 | tools::Long nFirstWidth = 0; |
2902 | 0 | tools::Long nSecondWidth = 0; |
2903 | 0 | bool bFirstCanResize = true; |
2904 | 0 | bool bSecondCanResize = true; |
2905 | 0 | const bool bInitialAllocation = get_position() < 0; |
2906 | 0 | int nElement = 0; |
2907 | 0 | for (const vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild; |
2908 | 0 | pChild = pChild->GetWindow(GetWindowType::Next)) |
2909 | 0 | { |
2910 | 0 | if (!pChild->IsVisible()) |
2911 | 0 | continue; |
2912 | 0 | if (nElement == 1) |
2913 | 0 | { |
2914 | 0 | if (bInitialAllocation) |
2915 | 0 | nFirstWidth = getLayoutRequisition(*pChild).Width(); |
2916 | 0 | else |
2917 | 0 | nFirstWidth = pChild->GetSizePixel().Width() + pChild->get_margin_start() + pChild->get_margin_end(); |
2918 | 0 | bFirstCanResize = pChild->get_expand(); |
2919 | 0 | } |
2920 | 0 | else if (nElement == 2) |
2921 | 0 | { |
2922 | 0 | if (bInitialAllocation) |
2923 | 0 | nSecondWidth = getLayoutRequisition(*pChild).Width(); |
2924 | 0 | else |
2925 | 0 | nSecondWidth = pChild->GetSizePixel().Width() + pChild->get_margin_start() + pChild->get_margin_end(); |
2926 | 0 | bSecondCanResize = pChild->get_expand(); |
2927 | 0 | } |
2928 | 0 | ++nElement; |
2929 | 0 | } |
2930 | 0 | tools::Long nWidthRequest = nFirstWidth + nSecondWidth; |
2931 | 0 | tools::Long nWidthDiff = nWidth - nWidthRequest; |
2932 | 0 | if (bFirstCanResize == bSecondCanResize) |
2933 | 0 | nFirstWidth += nWidthDiff/2; |
2934 | 0 | else if (bFirstCanResize) |
2935 | 0 | nFirstWidth += nWidthDiff; |
2936 | 0 | arrange(rAllocation, nFirstWidth, rAllocation.Width() - nFirstWidth - aSplitterSize.Width()); |
2937 | 0 | } |
2938 | | |
2939 | | Size VclHPaned::calculateRequisition() const |
2940 | 0 | { |
2941 | 0 | Size aRet(0, 0); |
2942 | |
|
2943 | 0 | for (const vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild; |
2944 | 0 | pChild = pChild->GetWindow(GetWindowType::Next)) |
2945 | 0 | { |
2946 | 0 | if (!pChild->IsVisible()) |
2947 | 0 | continue; |
2948 | 0 | Size aChildSize = getLayoutRequisition(*pChild); |
2949 | 0 | aRet.setHeight( std::max(aRet.Height(), aChildSize.Height()) ); |
2950 | 0 | aRet.AdjustWidth(aChildSize.Width() ); |
2951 | 0 | } |
2952 | |
|
2953 | 0 | return aRet; |
2954 | 0 | } |
2955 | | |
2956 | | Size getLegacyBestSizeForChildren(const vcl::Window &rWindow) |
2957 | 0 | { |
2958 | 0 | tools::Rectangle aBounds; |
2959 | |
|
2960 | 0 | for (const vcl::Window* pChild = rWindow.GetWindow(GetWindowType::FirstChild); pChild; |
2961 | 0 | pChild = pChild->GetWindow(GetWindowType::Next)) |
2962 | 0 | { |
2963 | 0 | if (!pChild->IsVisible()) |
2964 | 0 | continue; |
2965 | | |
2966 | 0 | tools::Rectangle aChildBounds(pChild->GetPosPixel(), pChild->GetSizePixel()); |
2967 | 0 | aBounds.Union(aChildBounds); |
2968 | 0 | } |
2969 | |
|
2970 | 0 | if (aBounds.IsEmpty()) |
2971 | 0 | return rWindow.GetSizePixel(); |
2972 | | |
2973 | 0 | Size aRet(aBounds.GetSize()); |
2974 | 0 | Point aTopLeft(aBounds.TopLeft()); |
2975 | 0 | aRet.AdjustWidth(aTopLeft.X()*2 ); |
2976 | 0 | aRet.AdjustHeight(aTopLeft.Y()*2 ); |
2977 | |
|
2978 | 0 | return aRet; |
2979 | 0 | } |
2980 | | |
2981 | | vcl::Window* getNonLayoutParent(vcl::Window *pWindow) |
2982 | 0 | { |
2983 | 0 | while (pWindow) |
2984 | 0 | { |
2985 | 0 | pWindow = pWindow->GetParent(); |
2986 | 0 | if (!pWindow || !isContainerWindow(*pWindow)) |
2987 | 0 | break; |
2988 | 0 | } |
2989 | 0 | return pWindow; |
2990 | 0 | } |
2991 | | |
2992 | | bool isVisibleInLayout(const vcl::Window *pWindow) |
2993 | 0 | { |
2994 | 0 | bool bVisible = true; |
2995 | 0 | while (bVisible) |
2996 | 0 | { |
2997 | 0 | bVisible = pWindow->IsVisible(); |
2998 | 0 | pWindow = pWindow->GetParent(); |
2999 | 0 | if (!pWindow || !isContainerWindow(*pWindow)) |
3000 | 0 | break; |
3001 | 0 | } |
3002 | 0 | return bVisible; |
3003 | 0 | } |
3004 | | |
3005 | | bool isEnabledInLayout(const vcl::Window *pWindow) |
3006 | 0 | { |
3007 | 0 | bool bEnabled = true; |
3008 | 0 | while (bEnabled) |
3009 | 0 | { |
3010 | 0 | bEnabled = pWindow->IsEnabled(); |
3011 | 0 | pWindow = pWindow->GetParent(); |
3012 | 0 | if (!pWindow || !isContainerWindow(*pWindow)) |
3013 | 0 | break; |
3014 | 0 | } |
3015 | 0 | return bEnabled; |
3016 | 0 | } |
3017 | | |
3018 | | bool isLayoutEnabled(const vcl::Window *pWindow) |
3019 | 46.0k | { |
3020 | | //Child is a container => we're layout enabled |
3021 | 46.0k | const vcl::Window *pChild = pWindow ? pWindow->GetWindow(GetWindowType::FirstChild) : nullptr; |
3022 | 46.0k | return pChild && isContainerWindow(*pChild) && !pChild->GetWindow(GetWindowType::Next); |
3023 | 46.0k | } |
3024 | | |
3025 | | void VclDrawingArea::RequestHelp(const HelpEvent& rHelpEvent) |
3026 | 0 | { |
3027 | 0 | if (!(rHelpEvent.GetMode() & (HelpEventMode::QUICK | HelpEventMode::BALLOON))) |
3028 | 0 | return; |
3029 | | |
3030 | 0 | Point aPos(ScreenToOutputPixel(rHelpEvent.GetMousePosPixel())); |
3031 | 0 | tools::Rectangle aHelpArea(aPos.X(), aPos.Y()); |
3032 | 0 | OUString sHelpTip = m_aQueryTooltipHdl.Call(aHelpArea); |
3033 | 0 | if (sHelpTip.isEmpty()) |
3034 | 0 | { |
3035 | 0 | Control::RequestHelp(rHelpEvent); |
3036 | 0 | return; |
3037 | 0 | } |
3038 | 0 | Point aPt = OutputToScreenPixel(aHelpArea.TopLeft()); |
3039 | 0 | aHelpArea.SetLeft(aPt.X()); |
3040 | 0 | aHelpArea.SetTop(aPt.Y()); |
3041 | 0 | aPt = OutputToScreenPixel(aHelpArea.BottomRight()); |
3042 | 0 | aHelpArea.SetRight(aPt.X()); |
3043 | 0 | aHelpArea.SetBottom(aPt.Y()); |
3044 | | // tdf#125369 recover newline support of tdf#101779 |
3045 | 0 | QuickHelpFlags eHelpWinStyle = sHelpTip.indexOf('\n') != -1 ? QuickHelpFlags::TipStyleBalloon : QuickHelpFlags::NONE; |
3046 | 0 | Help::ShowQuickHelp(this, aHelpArea, sHelpTip, eHelpWinStyle); |
3047 | 0 | } |
3048 | | |
3049 | | void VclDrawingArea::StartDrag(sal_Int8, const Point&) |
3050 | 0 | { |
3051 | 0 | if (m_aStartDragHdl.Call(this)) |
3052 | 0 | return; |
3053 | | |
3054 | 0 | if (!m_xTransferHelper.is()) |
3055 | 0 | return; |
3056 | | |
3057 | 0 | m_xTransferHelper->StartDrag(this, m_nDragAction); |
3058 | 0 | } |
3059 | | |
3060 | | OUString VclDrawingArea::GetSurroundingText() const |
3061 | 0 | { |
3062 | 0 | if (!m_aGetSurroundingHdl.IsSet()) |
3063 | 0 | return Control::GetSurroundingText(); |
3064 | 0 | OUString sSurroundingText; |
3065 | 0 | m_aGetSurroundingHdl.Call(sSurroundingText); |
3066 | 0 | return sSurroundingText; |
3067 | 0 | } |
3068 | | |
3069 | | Selection VclDrawingArea::GetSurroundingTextSelection() const |
3070 | 0 | { |
3071 | 0 | if (!m_aGetSurroundingHdl.IsSet()) |
3072 | 0 | return Control::GetSurroundingTextSelection(); |
3073 | 0 | OUString sSurroundingText; |
3074 | 0 | int nCursor = m_aGetSurroundingHdl.Call(sSurroundingText); |
3075 | 0 | return Selection(nCursor, nCursor); |
3076 | 0 | } |
3077 | | |
3078 | | bool VclDrawingArea::DeleteSurroundingText(const Selection& rSelection) |
3079 | 0 | { |
3080 | 0 | if (!m_aDeleteSurroundingHdl.IsSet()) |
3081 | 0 | return Control::DeleteSurroundingText(rSelection); |
3082 | 0 | return m_aDeleteSurroundingHdl.Call(rSelection); |
3083 | 0 | } |
3084 | | |
3085 | | VclHPaned::~VclHPaned() |
3086 | 0 | { |
3087 | 0 | } |
3088 | | |
3089 | | VclVPaned::~VclVPaned() |
3090 | 0 | { |
3091 | 0 | } |
3092 | | |
3093 | | VclPaned::~VclPaned() |
3094 | 0 | { |
3095 | 0 | disposeOnce(); |
3096 | 0 | } |
3097 | | |
3098 | | VclScrolledWindow::~VclScrolledWindow() |
3099 | 0 | { |
3100 | 0 | disposeOnce(); |
3101 | 0 | } |
3102 | | |
3103 | | void VclDrawingArea::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) |
3104 | 0 | { |
3105 | 0 | Control::DumpAsPropertyTree(rJsonWriter); |
3106 | 0 | rJsonWriter.put("type", "drawingarea"); |
3107 | |
|
3108 | 0 | ScopedVclPtrInstance<VirtualDevice> pDevice; |
3109 | 0 | OutputDevice* pRefDevice = GetOutDev(); |
3110 | 0 | Size aRenderSize(pRefDevice->PixelToLogic(GetOutputSizePixel())); |
3111 | 0 | Size aOutputSize = GetSizePixel(); |
3112 | 0 | pDevice->SetOutputSize(aRenderSize); |
3113 | 0 | tools::Rectangle aRect(Point(0,0), aRenderSize); |
3114 | | |
3115 | | // Dark mode support |
3116 | 0 | pDevice->DrawWallpaper(aRect, pRefDevice->GetBackground()); |
3117 | |
|
3118 | 0 | Paint(*pDevice, aRect); |
3119 | |
|
3120 | 0 | Bitmap aImage = pDevice->GetBitmap(Point(0,0), aRenderSize); |
3121 | 0 | aImage.Scale(aOutputSize); |
3122 | 0 | rJsonWriter.put("imagewidth", aRenderSize.Width()); |
3123 | 0 | rJsonWriter.put("imageheight", aRenderSize.Height()); |
3124 | |
|
3125 | 0 | SvMemoryStream aOStm(65535, 65535); |
3126 | 0 | if(GraphicConverter::Export(aOStm, aImage, ConvertDataFormat::PNG) == ERRCODE_NONE) |
3127 | 0 | { |
3128 | 0 | css::uno::Sequence<sal_Int8> aSeq( static_cast<sal_Int8 const *>(aOStm.GetData()), aOStm.Tell()); |
3129 | 0 | OStringBuffer aBuffer("data:image/png;base64,"); |
3130 | 0 | ::comphelper::Base64::encode(aBuffer, aSeq); |
3131 | 0 | rJsonWriter.put("image", aBuffer); |
3132 | 0 | } |
3133 | 0 | rJsonWriter.put("text", GetQuickHelpText()); |
3134 | 0 | } |
3135 | | |
3136 | | FactoryFunction VclDrawingArea::GetUITestFactory() const |
3137 | 0 | { |
3138 | 0 | if (m_pFactoryFunction) |
3139 | 0 | return m_pFactoryFunction; |
3140 | 0 | return DrawingAreaUIObject::create; |
3141 | 0 | } |
3142 | | |
3143 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |