Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / basctl / source / basicide / layout.cxx
blob57d5a9369753c1b9cca62a8d23a26b2f632204cb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <layout.hxx>
22 #include <bastypes.hxx>
23 #include <vcl/settings.hxx>
25 namespace basctl
28 namespace
30 // the thickness of the splitting lines
31 static long const nSplitThickness = 3;
32 } // namespace
34 // ctor for derived classes
35 // pParent: the parent window (Shell)
36 Layout::Layout (vcl::Window* pParent) :
37 Window(pParent, WB_CLIPCHILDREN),
38 pChild(nullptr),
39 bFirstSize(true),
40 aLeftSide(this, SplittedSide::Side::Left),
41 aBottomSide(this, SplittedSide::Side::Bottom)
43 SetBackground(GetSettings().GetStyleSettings().GetWindowColor());
45 vcl::Font aFont = GetFont();
46 Size aSz = aFont.GetFontSize();
47 aSz.setHeight( aSz.Height() * 1.5 );
48 aFont.SetFontSize(aSz);
49 aFont.SetWeight(WEIGHT_BOLD);
50 aFont.SetColor(GetSettings().GetStyleSettings().GetWindowTextColor());
51 SetFont(aFont);
54 Layout::~Layout()
56 disposeOnce();
59 void Layout::dispose()
61 aLeftSide.dispose();
62 aBottomSide.dispose();
63 pChild.clear();
64 Window::dispose();
67 // removes a docking window
68 void Layout::Remove (DockingWindow* pWin)
70 aLeftSide.Remove(pWin);
71 aBottomSide.Remove(pWin);
74 // called by Window when resized
75 void Layout::Resize()
77 if (IsVisible())
78 ArrangeWindows();
81 // ArrangeWindows() -- arranges the child windows
82 void Layout::ArrangeWindows ()
84 // prevent recursion via OnFirstSize() -> Add() -> ArrangeWindows()
85 static bool bInArrangeWindows = false;
86 if (bInArrangeWindows)
87 return;
88 bInArrangeWindows = true;
90 Size const aSize = GetOutputSizePixel();
91 long const nWidth = aSize.Width(), nHeight = aSize.Height();
92 if (nWidth && nHeight) // non-empty size
94 // On first call the derived classes initializes the sizes of the
95 // docking windows. This cannot be done at construction because
96 // the Layout has empty size at that point.
97 if (bFirstSize)
99 bFirstSize = false;
100 OnFirstSize(nWidth, nHeight); // virtual
103 // sides
104 aBottomSide.ArrangeIn(tools::Rectangle(Point(0, 0), aSize));
105 aLeftSide.ArrangeIn(tools::Rectangle(Point(0, 0), Size(nWidth, nHeight - aBottomSide.GetSize())));
106 // child in the middle
107 pChild->SetPosSizePixel(
108 Point(aLeftSide.GetSize(), 0),
109 Size(nWidth - aLeftSide.GetSize(), nHeight - aBottomSide.GetSize())
113 bInArrangeWindows = false;
116 void Layout::Activating (BaseWindow& rWindow)
118 // first activation
119 pChild = &rWindow;
120 ArrangeWindows();
121 Show();
122 pChild->Activating();
125 void Layout::Deactivating ()
127 if (pChild)
128 pChild->Deactivating();
129 Hide();
130 pChild = nullptr;
133 // virtual
134 void Layout::DataChanged (DataChangedEvent const& rDCEvt)
136 Window::DataChanged(rDCEvt);
137 if (rDCEvt.GetType() == DataChangedEventType::SETTINGS && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
139 bool bInvalidate = false;
140 Color aColor = GetSettings().GetStyleSettings().GetWindowColor();
141 const AllSettings* pOldSettings = rDCEvt.GetOldSettings();
142 if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetWindowColor())
144 SetBackground(Wallpaper(aColor));
145 bInvalidate = true;
147 aColor = GetSettings().GetStyleSettings().GetWindowTextColor();
148 if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetWindowTextColor())
150 vcl::Font aFont(GetFont());
151 aFont.SetColor(aColor);
152 SetFont(aFont);
153 bInvalidate = true;
155 if (bInvalidate)
156 Invalidate();
161 // SplittedSide
164 // ctor
165 Layout::SplittedSide::SplittedSide (Layout* pParent, Side eSide) :
166 rLayout(*pParent),
167 bVertical(eSide == Side::Left),
168 bLower(eSide == Side::Left),
169 nSize(0),
170 aSplitter(VclPtr<Splitter>::Create(pParent, bVertical ? WB_HSCROLL : WB_VSCROLL))
172 InitSplitter(*aSplitter.get());
175 void Layout::SplittedSide::dispose()
177 aSplitter.disposeAndClear();
178 for (auto & item : vItems)
180 item.pSplit.disposeAndClear();
181 item.pWin.clear();
185 // Add() -- adds a new window to the side (after construction)
186 void Layout::SplittedSide::Add (DockingWindow* pWin, Size const& rSize)
188 long const nSize1 = (bVertical ? rSize.Width() : rSize.Height()) + nSplitThickness;
189 long const nSize2 = bVertical ? rSize.Height() : rSize.Width();
190 // nSize
191 if (nSize1 > nSize)
192 nSize = nSize1;
193 // window
194 Item aItem;
195 aItem.pWin = pWin;
196 aItem.nStartPos = vItems.empty() ? 0 : vItems.back().nEndPos + nSplitThickness;
197 aItem.nEndPos = aItem.nStartPos + nSize2;
198 // splitter
199 if (!vItems.empty())
201 aItem.pSplit = VclPtr<Splitter>::Create(&rLayout, bVertical ? WB_VSCROLL : WB_HSCROLL);
202 aItem.pSplit->SetSplitPosPixel(aItem.nStartPos - nSplitThickness);
203 InitSplitter(*aItem.pSplit);
205 vItems.push_back(aItem);
206 // refresh
207 rLayout.ArrangeWindows();
210 // Remove() -- removes a window from the side (if contains)
211 void Layout::SplittedSide::Remove (DockingWindow* pWin)
213 // contains?
214 std::vector<Item>::size_type iWin;
215 for (iWin = 0; iWin != vItems.size(); ++iWin)
216 if (vItems[iWin].pWin == pWin)
217 break;
218 if (iWin == vItems.size())
219 return;
220 // remove
221 vItems[iWin].pSplit.disposeAndClear();
222 vItems[iWin].pWin.clear();
223 vItems.erase(vItems.begin() + iWin);
224 // if that was the first one, remove the first splitter line
225 if (iWin == 0 && !vItems.empty())
226 vItems.front().pSplit.reset();
229 // creating a Point or a Size object
230 // The coordinate order depends on bVertical (reversed if true).
231 inline Size Layout::SplittedSide::MakeSize (long A, long B) const
233 return bVertical ? Size(B, A) : Size(A, B);
235 inline Point Layout::SplittedSide::MakePoint (long A, long B) const
237 return bVertical ? Point(B, A) : Point(A, B);
240 // IsDocking() -- is this window currently docking in the strip?
241 bool Layout::SplittedSide::IsDocking (DockingWindow const& rWin)
243 return rWin.IsVisible() && !rWin.IsFloatingMode();
246 // IsEmpty() -- are there no windows docked in this strip?
247 bool Layout::SplittedSide::IsEmpty () const
249 for (auto const & i: vItems)
250 if (IsDocking(*i.pWin))
251 return false;
252 return true;
255 // GetSize() -- returns the width or height of the strip (depending on the direction)
256 long Layout::SplittedSide::GetSize () const
258 return IsEmpty() ? 0 : nSize;
261 // Arrange() -- arranges the docking windows
262 // rRect: the available space
263 void Layout::SplittedSide::ArrangeIn (tools::Rectangle const& rRect)
265 // saving the rectangle
266 aRect = rRect;
268 // the length of the side
269 long const nLength = bVertical ? aRect.GetSize().Height() : aRect.GetSize().Width();
270 long const nOtherSize = bVertical ? aRect.GetSize().Width() : aRect.GetSize().Height();
271 // bVertical ? horizontal position : vertical position
272 long const nPos1 = (bVertical ? aRect.Left() : aRect.Top()) +
273 (bLower ? 0 : nOtherSize - (nSize - nSplitThickness));
274 // bVertical ? vertical position : horizontal position
275 long const nPos2 = bVertical ? aRect.Top() : aRect.Left();
277 // main line
278 bool const bEmpty = IsEmpty();
279 // shown if any of the windows is docked
280 if (!bEmpty)
282 aSplitter->Show();
283 // split position
284 aSplitter->SetSplitPosPixel((bLower ? nSize : nPos1) - nSplitThickness);
285 // the actual position and size
286 aSplitter->SetPosSizePixel(
287 MakePoint(nPos2, aSplitter->GetSplitPosPixel()),
288 MakeSize(nLength, nSplitThickness)
290 // dragging rectangle
291 aSplitter->SetDragRectPixel(aRect);
293 else
294 aSplitter->Hide();
296 // positioning separator lines and windows
297 bool bPrevDocking = false; // is the previous window docked?
298 long nStartPos = 0; // window position in the strip
299 std::vector<Item>::size_type iLastWin = vItems.size(); // index of last docking window in the strip
301 for (std::vector<Item>::size_type i = 0; i != vItems.size(); ++i)
303 // window
304 DockingWindow& rWin = *vItems[i].pWin;
305 bool const bDocking = IsDocking(rWin);
306 if (bDocking)
307 iLastWin = i;
308 // sizing window
309 rWin.ResizeIfDocking(
310 MakePoint(nPos2 + nStartPos, nPos1),
311 MakeSize(vItems[i].nEndPos - nStartPos, nSize - nSplitThickness)
313 // splitting line before the window
314 if (i > 0)
316 Splitter& rSplit = *vItems[i].pSplit;
317 // If neither of two adjacent windows are docked,
318 // the splitting line is hidden.
319 // If this window is docking but the previous isn't,
320 // then the splitting line is also hidden, because this window
321 // will occupy the space of the previous.
322 if (bPrevDocking)
324 rSplit.Show();
325 // the actual position and size of the line
326 rSplit.SetPosSizePixel(
327 MakePoint(nPos2 + nStartPos - nSplitThickness, nPos1),
328 MakeSize(nSplitThickness, nSize - nSplitThickness)
330 // the dragging rectangle
331 rSplit.SetDragRectPixel(tools::Rectangle(
332 MakePoint(nPos2, nPos1),
333 MakeSize(nLength, nSize - nSplitThickness)
336 else
337 rSplit.Hide();
339 // next
340 bPrevDocking = bDocking;
341 if (bDocking)
342 nStartPos = vItems[i].nEndPos + nSplitThickness;
343 // We only set nStartPos if this window is docking, because otherwise
344 // the next window will occupy also the space of this window.
347 // filling the remaining space with the last docking window
348 if (!bEmpty && vItems[iLastWin].nEndPos != nLength)
350 Item& rItem = vItems[iLastWin];
351 Size aSize = rItem.pWin->GetDockingSize();
352 if (bVertical)
353 aSize.AdjustHeight( nLength - rItem.nEndPos );
354 else
355 aSize.AdjustWidth( nLength - rItem.nEndPos );
356 rItem.pWin->ResizeIfDocking(aSize);
357 // and hiding the split line after the window
358 if (iLastWin < vItems.size() - 1)
359 vItems[iLastWin + 1].pSplit->Hide();
363 IMPL_LINK(Layout::SplittedSide, SplitHdl, Splitter*, pSplitter, void)
365 // checking margins
366 CheckMarginsFor(pSplitter);
367 // changing stored sizes
368 if (pSplitter == aSplitter.get())
370 // nSize
371 if (bLower)
372 nSize = pSplitter->GetSplitPosPixel();
373 else
374 nSize = (bVertical ? aRect.Right() : aRect.Bottom()) + 1 - pSplitter->GetSplitPosPixel();
376 else
378 // Item::nStartPos, Item::nLength
379 for (size_t i = 1; i < vItems.size(); ++i)
381 if (vItems[i].pSplit.get() == pSplitter)
383 // before the line
384 vItems[i - 1].nEndPos = pSplitter->GetSplitPosPixel();
385 // after the line
386 vItems[i].nStartPos = pSplitter->GetSplitPosPixel() + nSplitThickness;
390 // arranging windows
391 rLayout.ArrangeWindows();
394 void Layout::SplittedSide::CheckMarginsFor (Splitter* pSplitter)
396 // The splitter line cannot be closer to the edges than nMargin pixels.
397 static long const nMargin = 16;
398 // Checking margins:
399 if (long const nLength = pSplitter->IsHorizontal() ?
400 aRect.GetWidth() : aRect.GetHeight()
402 // bounds
403 long const nLower = (pSplitter->IsHorizontal() ? aRect.Left() : aRect.Top()) + nMargin;
404 long const nUpper = nLower + nLength - 2*nMargin;
405 // split position
406 long const nPos = pSplitter->GetSplitPosPixel();
407 // checking bounds
408 if (nPos < nLower)
409 pSplitter->SetSplitPosPixel(nLower);
410 if (nPos > nUpper)
411 pSplitter->SetSplitPosPixel(nUpper);
415 void Layout::SplittedSide::InitSplitter (Splitter& rSplitter)
417 // link
418 rSplitter.SetSplitHdl(LINK(this, SplittedSide, SplitHdl));
419 // color
420 Color aColor = rLayout.GetSettings().GetStyleSettings().GetShadowColor();
421 rSplitter.SetLineColor(aColor);
422 rSplitter.SetFillColor(aColor);
426 } // namespace basctl
428 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */