15.1.166. tablet_qt/layouts/flowlayouthfw.h

// As per https://doc.qt.io/qt-6.5/qtwidgets-layouts-flowlayout-example.html

/*===========================================================================
==
== Copyright (C) 2016 The Qt Company Ltd.
== Contact: https://www.qt.io/licensing/
==
== This file is part of the examples of the Qt Toolkit.
==
== $QT_BEGIN_LICENSE:BSD$
== 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.
==
== BSD License Usage
== Alternatively, you may use this file under the terms of the BSD license
== as follows:
==
== "Redistribution and use in source and binary forms, with or without
== modification, are permitted provided that the following conditions are
== met:
==   * Redistributions of source code must retain the above copyright
==     notice, this list of conditions and the following disclaimer.
==   * Redistributions in binary form must reproduce the above copyright
==     notice, this list of conditions and the following disclaimer in
==     the documentation and/or other materials provided with the
==     distribution.
==   * Neither the name of The Qt Company Ltd nor the names of its
==     contributors may be used to endorse or promote products derived
==     from this software without specific prior written permission.
==
==
== THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
== "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
== LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
== A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
== OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
== SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
== LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
== DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
== THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
== (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
== OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
==
== $QT_END_LICENSE$
==
===========================================================================*/

#pragma once
#include <QLayout>
#include <QMap>  // RNC
#include <QRect>
#include <QStyle>


class FlowLayoutHfw : public QLayout
{
    // Flow layout, as per FlowLayout Qt demo, but modified to support
    // height-for-width better (better as in: word-wrapping labels etc. get the
    // maximum width allowed, aiming for the minimum height).

    // NOTE THAT THIS IS NOT A "TOP-LEVEL" HFW WIDGET THAT CAN RESIZE ITS
    // PARENT WIDGET (compare BoxLayoutHfw, GridLayoutHfw). So it should be
    // displayed within one of those.

    Q_OBJECT  // RNC
public:
    explicit FlowLayoutHfw(QWidget* parent, int margin = -1,
                           int h_spacing = -1, int v_spacing = -1);
    explicit FlowLayoutHfw(int margin = -1,
                           int h_spacing = -1, int v_spacing = -1);
    ~FlowLayoutHfw() override;

    // QLayout supplies: void addWidget(QWidget* w);  // no alignment option
    // QVBoxLayout/QHBoxLayout supply:
    //    void addWidget(QWidget* widget, int stretch, Qt::Alignment alignment);
    // Alignment does make sense, specifically top alignment.
    void addWidget(QWidget* w);  // RNC
    void addWidget(QWidget* w, Qt::Alignment alignment);  // RNC
    virtual void addItem(QLayoutItem* item) override;

    void setHorizontalAlignmentOfContents(Qt::Alignment halign);
    virtual int horizontalSpacing() const;
    virtual int verticalSpacing() const;
    virtual Qt::Orientations expandingDirections() const override;
    virtual bool hasHeightForWidth() const override;
    virtual int heightForWidth(int) const override;
    virtual int count() const override;
    virtual QLayoutItem* itemAt(int index) const override;
    virtual QSize minimumSize() const override;
    virtual void setGeometry(const QRect& rect) override;
    virtual QSize sizeHint() const override;
    virtual QLayoutItem* takeAt(int index) override;
    virtual void invalidate() override;  // RNC

protected:  // RNC (was private)

    // The main thinking function.
    virtual QSize doLayout(const QRect& rect, bool test_only) const;

    // Autocalculate spacing between items when none is specified explicitly.
    int smartSpacing(QStyle::PixelMetric pm) const;

    // Vertical coordinate of a given item, taking into account vertical
    // alignment.
    int itemTop(int row_top, int item_height, int row_height,
                Qt::Alignment valignment) const;  // RNC

    // Number of pixels to shift an entire row right, to satisfy the horizontal
    // alignment.
    int rowShiftToRight(int layout_width, int width_of_all_items) const;

    QVector<QLayoutItem*> m_item_list;  // our widgets
    int m_h_space;  // horizontal spacing between items
    int m_v_space;  // vertical spacing between rows
    mutable QSize m_size_hint;  // cached size hint
    mutable QMap<int, int> m_width_to_height;  // cached width-to-height map
    Qt::Alignment m_halign;  // horizontal alignment

    struct ItemCalc {
        QLayoutItem* item;  // the layout item
        QWidget* widget;  // the widget
        int layout_row;  // the row number this item will sit in
        QSize item_size;  // the item's size
        QPoint layout_cell_top_left;  // the item's top-left coordinate
    };
};