AbdulElahGwaith's picture
Upload folder using huggingface_hub
a5ffdcd verified
/****************************************************************************
**
** This file is part of the LibreCAD project, a 2D CAD program
**
** Copyright (C) 2024 sand1024
**
** This file is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**
** This copyright notice MUST APPEAR in all copies of the script!
**
**********************************************************************/
#include <QWidget>
#include "lc_flexlayout.h"
LC_FlexLayout::LC_FlexLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
:QLayout(parent), m_hSpacing(hSpacing), m_vSpacing(vSpacing){
setContentsMargins(margin, margin, margin, margin);
}
LC_FlexLayout::LC_FlexLayout(int margin, int hSpacing, int vSpacing, int widthOfFirstColumn)
:m_hSpacing(hSpacing), m_vSpacing(vSpacing), m_firstColumnWidth(widthOfFirstColumn){
setContentsMargins(margin, margin, margin, margin);
}
LC_FlexLayout::~LC_FlexLayout(){
QLayoutItem *item;
while ((item = takeAt(0))) {
delete item;
}
}
/**
* Fills the layout by another layout. Items are removed from source layout.
* This method allows to convert layouts created in designer into flex layouts.
* @param source
*/
void LC_FlexLayout::fillFromLayout(QLayout* source){
QLayoutItem* pItem = source->itemAt(0);
while (pItem != nullptr) {
QWidget* widget = pItem->widget();
if (widget != nullptr){
this->addWidget(widget);
}
source->removeItem(pItem);
pItem = source->itemAt(0);
}
}
bool LC_FlexLayout::hasHeightForWidth() const{
return true;
}
int LC_FlexLayout::heightForWidth(int width) const{
int height = performLayout(QRect(0, 0, width, 0), true);
return height;
}
void LC_FlexLayout::setGeometry(const QRect &rect){
QLayout::setGeometry(rect);
performLayout(rect, false);
}
QSize LC_FlexLayout::sizeHint() const{
return minimumSize();
}
int LC_FlexLayout::performLayout(const QRect &rect, bool geometryCheck) const{
int left, top, right, bottom;
getContentsMargins(&left, &top, &right, &bottom);
QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
int columnX = effectiveRect.x();
int rowY = effectiveRect.y();
int effectiveRight = effectiveRect.right();
int lineHeight = 0;
int size = m_items.size();
std::vector<int> linesHeight;
int nextY = rowY;
// do first pass to determine height for each line and overall height
for (int i = 0; i < size; i++) {
QLayoutItem *item = std::as_const(m_items.at(i));
const QWidget *wid = item->widget();
QLayoutItem *itemNext = nullptr;
bool checkForNextBreak = false;
int nextIndex = i + 1;
if (nextIndex < size){
if (m_softBreakItems.find(i) != m_softBreakItems.end()){
itemNext = m_items.at(nextIndex);
checkForNextBreak = true;
}
}
int spaceX = getSpaceX(wid);
int spaceY = getSpaceY(wid);
QSize itemSizeHint = item->sizeHint();
int itemHeight = itemSizeHint.height();
int itemWidth = itemSizeHint.width();
int nextX = columnX + itemWidth + spaceX;
bool doBreak = false;
if (checkForNextBreak){
int nextWidgetNextX = nextX + itemNext->sizeHint().width();
doBreak = nextWidgetNextX > effectiveRight;
}
int widgetEndX = nextX - spaceX;
if ((widgetEndX > effectiveRight && lineHeight > 0) || doBreak){
columnX = effectiveRect.x();
rowY = rowY + lineHeight + spaceY;
nextY = rowY;
if (m_fullWidthItems.find(i) != m_fullWidthItems.end()){
linesHeight.emplace_back(lineHeight);
nextY = rowY + itemHeight + spaceY;
nextX = columnX;
}
else {
if (m_firstColumnWidth > 0){
itemWidth = m_firstColumnWidth;
}
nextX = columnX + itemWidth + spaceX;
}
linesHeight.emplace_back(qMax(lineHeight, itemHeight));
lineHeight = 0;
}
lineHeight = qMax(lineHeight, itemHeight);
rowY = nextY;
columnX = nextX;
}
linesHeight.emplace_back(lineHeight);
int result = rowY + lineHeight - rect.y() + bottom;
// second pass with actual setting geometry, line height is calculated on previous step
// here the actual placing of items is performed
if (!geometryCheck){
columnX = effectiveRect.x();
rowY = effectiveRect.y();
nextY = rowY;
int lineIndex = 0;
int currentLineHeight;
// second pass that takes into consideration lines height
for (int i = 0; i < size; i++) {
QLayoutItem *item = std::as_const(m_items.at(i));
const QWidget *wid = item->widget();
QLayoutItem *itemNext = nullptr;
bool checkForNextBreak = false;
int nextIndex = i + 1;
if (nextIndex < size){
if (m_softBreakItems.find(i) != m_softBreakItems.end()){
itemNext = m_items.at(nextIndex);
checkForNextBreak = true;
}
}
int spaceX = getSpaceX(wid);
int spaceY = getSpaceY(wid);
QSize itemSizeHint = item->sizeHint();
currentLineHeight = linesHeight.at(lineIndex);
int itemWidth = itemSizeHint.width();
int nextX = columnX + itemWidth + spaceX;
bool doBreak = false;
if (checkForNextBreak){
int nextWidgetNextX = nextX + itemNext->sizeHint().width();
doBreak = nextWidgetNextX > effectiveRight;
}
int widgetEndX = nextX - spaceX;
if ((widgetEndX > effectiveRight) || doBreak){
columnX = effectiveRect.x();
rowY = rowY + currentLineHeight + spaceY;
nextY = rowY;
if (m_fullWidthItems.find(i) != m_fullWidthItems.end()){
itemWidth = effectiveRect.width();
nextY = rowY + currentLineHeight + spaceY;
nextX = columnX;
} else {
if (m_firstColumnWidth > 0){
itemWidth = m_firstColumnWidth;
}
nextX = columnX + itemWidth + spaceX;
}
lineIndex++;
}
itemSizeHint = QSize(itemWidth, currentLineHeight);
item->setGeometry(QRect(QPoint(columnX, rowY), itemSizeHint));
rowY = nextY;
columnX = nextX;
}
}
return result;
}
int LC_FlexLayout::getSpaceY(const QWidget *wid) const{
int spacingX = verticalSpacing();
if (spacingX == -1)
spacingX = wid->style()->layoutSpacing(
QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
return spacingX;
}
int LC_FlexLayout::getSpaceX(const QWidget *wid) const{
int spacingY = horizontalSpacing();
if (spacingY == -1)
spacingY = wid->style()->layoutSpacing(
QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
return spacingY;
}
int LC_FlexLayout::defaultSpacing(QStyle::PixelMetric pm) const{
QObject *parent = this->parent();
if (!parent) {
return -1;
} else if (parent->isWidgetType()) {
auto *pw = dynamic_cast<QWidget *>(parent);
return pw->style()->pixelMetric(pm, nullptr, pw);
} else {
return dynamic_cast<QLayout *>(parent)->spacing();
}
}
int LC_FlexLayout::horizontalSpacing() const{
if (m_hSpacing >= 0) {
return m_hSpacing;
} else {
return defaultSpacing(QStyle::PM_LayoutHorizontalSpacing);
}
}
int LC_FlexLayout::verticalSpacing() const{
if (m_vSpacing >= 0) {
return m_vSpacing;
} else {
return defaultSpacing(QStyle::PM_LayoutVerticalSpacing);
}
}
QLayoutItem*LC_FlexLayout::takeAt(int index){
QLayoutItem* result = nullptr;
if (index >= 0 && index < m_items.size()){
result = m_items.takeAt(index);
}
return result;
}
Qt::Orientations LC_FlexLayout::expandingDirections() const{
return {};
}
QSize LC_FlexLayout::minimumSize() const{
QSize size;
for (const QLayoutItem *item : std::as_const(m_items))
size = size.expandedTo(item->minimumSize());
const QMargins margins = contentsMargins();
size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom());
return size;
}
void LC_FlexLayout::addItem(QLayoutItem *item){
m_items.append(item);
}
int LC_FlexLayout::count() const{
return m_items.size();
}
QLayoutItem *LC_FlexLayout::itemAt(int index) const{
return m_items.value(index);
}