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