summaryrefslogtreecommitdiffstats
path: root/src/Authoring/Studio/Controls/LazyFlow.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/Authoring/Studio/Controls/LazyFlow.h')
-rw-r--r--src/Authoring/Studio/Controls/LazyFlow.h267
1 files changed, 267 insertions, 0 deletions
diff --git a/src/Authoring/Studio/Controls/LazyFlow.h b/src/Authoring/Studio/Controls/LazyFlow.h
new file mode 100644
index 00000000..c5fb7fd3
--- /dev/null
+++ b/src/Authoring/Studio/Controls/LazyFlow.h
@@ -0,0 +1,267 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#pragma once
+#ifndef LAZYFLOWH
+#define LAZYFLOWH
+#include "Control.h"
+
+#ifdef WIN32
+#include <minmax.h>
+#endif
+
+namespace Q3DStudio {
+namespace Control {
+
+ // Specializers used to specialize the layout algorithm in the X or Y direction.
+ // You could, in fact, specialzie the algorithm in any arbitrary direction including
+ // 3d where components are sumed in the chosen direction and maxed in any other
+ // orthogonal non-chosen directions.
+
+ // Specializes the general layout algorithm in the x or y direction.
+ struct ILazyFlowLayoutSpecializer
+ {
+ protected:
+ virtual ~ILazyFlowLayoutSpecializer() {}
+
+ public:
+ static inline long SafeSum(long lhs, long rhs)
+ {
+ if (lhs == LONG_MAX || rhs == LONG_MAX)
+ return LONG_MAX;
+ return lhs + rhs;
+ }
+ // These functions allow us to apply the lazy flow layout algorithm to
+ // either horizontal or vertical layouts.
+ // Sum the variable in the direction we are going, and max any other variables
+ CPt SumMax(const CPt &inCurrentSum, const CPt &inOther)
+ {
+ long curSum = GetSummedVariable(inCurrentSum);
+ long nextSum = GetSummedVariable(inOther);
+ long resultSum = SafeSum(curSum, nextSum);
+#ifdef WIN32
+ // windows.h redefines max
+ long resultMax = max(GetMaxedVariable(inCurrentSum), GetMaxedVariable(inOther));
+#else
+ long resultMax = std::max(GetMaxedVariable(inCurrentSum), GetMaxedVariable(inOther));
+#endif
+ return ToPoint(resultSum, resultMax);
+ }
+ // Return the summed variable
+ virtual long &GetSummedVariable(CPt &inPt) = 0;
+ const long &GetSummedVariable(const CPt &inPt)
+ {
+ return GetSummedVariable(const_cast<CPt &>(inPt));
+ }
+ // return the maxed variable
+ virtual long &GetMaxedVariable(CPt &inPt) = 0;
+ const long &GetMaxedVariable(const CPt &inPt)
+ {
+ return GetMaxedVariable(const_cast<CPt &>(inPt));
+ }
+ // Create a new point from the combination of a summed variable and a maxed variable.
+ virtual CPt ToPoint(long inSummedVariable, long inMaxedVariable) = 0;
+ };
+
+ struct SVerticalLayoutSpecializer : public ILazyFlowLayoutSpecializer
+ {
+ long &GetSummedVariable(CPt &inPt) override { return inPt.y; }
+ long &GetMaxedVariable(CPt &inPt) override { return inPt.x; }
+ CPt ToPoint(long inSummedVariable, long inMaxedVariable) override
+ {
+ return CPt(inMaxedVariable, inSummedVariable);
+ }
+ };
+
+ struct SHorizontalLayoutSpecializer : public ILazyFlowLayoutSpecializer
+ {
+ long &GetSummedVariable(CPt &inPt) override { return inPt.x; }
+ long &GetMaxedVariable(CPt &inPt) override { return inPt.y; }
+ CPt ToPoint(long inSummedVariable, long inMaxedVariable) override
+ {
+ return CPt(inSummedVariable, inMaxedVariable);
+ }
+ };
+
+ struct SSizeGroup
+ {
+ CPt m_Min;
+ CPt m_Max;
+ CPt m_Pref;
+ };
+
+ class CLazyFlowBase : public CControl
+ {
+ mutable bool m_MinMaxPreferredDirty;
+ mutable bool m_CalculatingMinMaxPref;
+ bool m_AutoMinMaxPref;
+ CPt m_BeginMargin;
+ CPt m_EndMargin;
+
+ public:
+ typedef vector<pair<std::shared_ptr<CControlData>, CPt>> TControlSizeList;
+
+ CLazyFlowBase()
+ : m_MinMaxPreferredDirty(true)
+ , m_CalculatingMinMaxPref(false)
+ , m_AutoMinMaxPref(true)
+ , m_ChildGap(0)
+ {
+ }
+
+ CPt GetMinimumSize() override;
+ CPt GetPreferredSize() override;
+ CPt GetMaximumSize() override;
+
+ virtual void SetGapBetweenChildren(long inGap)
+ {
+ m_ChildGap = inGap;
+ MarkChildrenNeedLayout();
+ }
+ virtual long GetGapBetweenChildren() const { return m_ChildGap; }
+
+ // Also sets min max preferred dirty.
+ void LayoutChildren() override;
+ void MarkChildrenNeedLayout() override;
+ void NotifyParentNeedsLayout() override;
+ void SetLayout(CPt inSize, CPt inPosition) override;
+
+ virtual void SetAutoMinMaxPref(bool inAuto) { m_AutoMinMaxPref = inAuto; }
+ bool GetAutoMinMaxPref() const { return m_AutoMinMaxPref; }
+
+ // Legacy with FlowLayout.
+ virtual void SetAutoMin(bool inAuto) { m_AutoMinMaxPref = inAuto; }
+
+ virtual void SetTopMargin(long inPixels)
+ {
+ m_BeginMargin.y = inPixels;
+ MarkChildrenNeedLayout();
+ }
+ virtual long GetTopMargin() const { return m_BeginMargin.y; }
+
+ virtual void SetLeftMargin(long inPixels)
+ {
+ m_BeginMargin.x = inPixels;
+ MarkChildrenNeedLayout();
+ }
+ virtual long GetLeftMargin() const { return m_BeginMargin.x; }
+
+ virtual void SetBottomMargin(long inPixels)
+ {
+ m_EndMargin.y = inPixels;
+ MarkChildrenNeedLayout();
+ }
+ virtual long GetBottomMargin() const { return m_EndMargin.y; }
+
+ virtual void SetRightMargin(long inPixels)
+ {
+ m_EndMargin.x = inPixels;
+ MarkChildrenNeedLayout();
+ }
+ virtual long GetRightMargin() const { return m_EndMargin.x; }
+
+ protected:
+ void SetMinMaxPrefDirty() { m_MinMaxPreferredDirty = true; }
+ virtual ILazyFlowLayoutSpecializer &GetSpecializer() = 0;
+
+ long m_ChildGap;
+ long GetGapTotal();
+ // Margins are begin/end meaning before any children, after any children
+ long GetBeginMargin() { return GetSpecializer().GetSummedVariable(m_BeginMargin); }
+ long GetEndMargin() { return GetSpecializer().GetSummedVariable(m_EndMargin); }
+ // And then margines that are beside the row of children, either before the row or after it.
+ long GetBeforeRowMargin() { return GetSpecializer().GetMaxedVariable(m_BeginMargin); }
+ long GetAfterRowMargin() { return GetSpecializer().GetMaxedVariable(m_EndMargin); }
+
+ // I only implement these algorithms once, and I use a specializer to make them apply
+ // to either a left-to-right or a top-to-bottom layout.
+ void DistributeChildSizes(TControlSizeList &ioList);
+ void PerformLayout(TControlSizeList &ioList);
+ SSizeGroup CalcChildrenMinMaxPref();
+
+ virtual SSizeGroup GetChildSizes(std::shared_ptr<CControlData> inControl);
+
+ void RecalcMinMaxPref();
+ void MaybeRecalcMinMaxPerf() const;
+ };
+
+ template <typename TSpecializerType>
+ class TLazyFlowBase : public CLazyFlowBase
+ {
+ TSpecializerType m_Specializer;
+
+ public:
+ ILazyFlowLayoutSpecializer &GetSpecializer() override { return m_Specializer; }
+ };
+
+ struct SVerticalLazyFlow : public TLazyFlowBase<SVerticalLayoutSpecializer>
+ {
+ };
+
+ struct SHorizontalLazyFlow : public TLazyFlowBase<SHorizontalLayoutSpecializer>
+ {
+ };
+
+ class CRuntimeLazyFlow : public CLazyFlowBase
+ {
+ public:
+ enum EFlowDirection {
+ FLOW_VERTICAL,
+ FLOW_HORIZONTAL,
+ };
+
+ private:
+ SHorizontalLayoutSpecializer m_HorizontalSpecifier;
+ SVerticalLayoutSpecializer m_VerticalSpecifier;
+ EFlowDirection m_FlowDirection;
+
+ public:
+ CRuntimeLazyFlow()
+ : m_FlowDirection(FLOW_VERTICAL)
+ {
+ }
+
+ virtual void SetFlowDirection(EFlowDirection inFlowDirection)
+ {
+ m_FlowDirection = inFlowDirection;
+ MarkChildrenNeedLayout();
+ }
+
+ protected:
+ ILazyFlowLayoutSpecializer &GetSpecializer() override
+ {
+ if (m_FlowDirection == FLOW_VERTICAL)
+ return m_VerticalSpecifier;
+ return m_HorizontalSpecifier;
+ }
+ };
+}
+}
+
+#endif