commit fac2260a01ebc50c47bc03cc5a7dd8c8f4c693a7 Author: Ikatono Date: Mon May 20 03:23:01 2024 -0500 bunch of stuff. very basic drag/drop now working diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..28db11b --- /dev/null +++ b/.gitignore @@ -0,0 +1,75 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* +CMakeLists.txt.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + +build diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e0e6566 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,84 @@ +cmake_minimum_required(VERSION 3.5) + +project(qt-app VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Network) + +set(PROJECT_SOURCES + main.cpp + mainwindow.cpp + mainwindow.h + mainwindow.ui +) + +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) + qt_add_executable(qt-app + MANUAL_FINALIZATION + ${PROJECT_SOURCES} + tiercard.hpp tiercard.cpp + flowlayout.cpp flowlayout.h flowlayout.pro + tiercardlayout.hpp tiercardlayout.cpp + aspectratiopixmaplabel.hpp aspectratiopixmaplabel.cpp + fullsizelayout.hpp fullsizelayout.cpp + tierrow.hpp tierrow.cpp + tierrowtitlecard.hpp tierrowtitlecard.cpp + myflowlayout.hpp myflowlayout.cpp + utils.hpp + rowholder.hpp rowholder.cpp + settings.hpp settings.cpp + + ) +# Define target properties for Android with Qt 6 as: +# set_property(TARGET qt-app APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR +# ${CMAKE_CURRENT_SOURCE_DIR}/android) +# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation +else() + if(ANDROID) + add_library(qt-app SHARED + ${PROJECT_SOURCES} + ) +# Define properties for Android with Qt 5 after find_package() calls as: +# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") + else() + add_executable(qt-app + ${PROJECT_SOURCES} + ) + endif() +endif() + +target_link_libraries(qt-app PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) +target_link_libraries(qt-app PRIVATE Qt${QT_VERISON_MAJOR}::Network) + +# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. +# If you are developing for iOS or macOS you should consider setting an +# explicit, fixed bundle identifier manually though. +if(${QT_VERSION} VERSION_LESS 6.1.0) + set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.qt-app) +endif() +set_target_properties(qt-app PROPERTIES + ${BUNDLE_ID_OPTION} + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +include(GNUInstallDirs) +install(TARGETS qt-app + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +if(QT_VERSION_MAJOR EQUAL 6) + qt_finalize_executable(qt-app) +endif() diff --git a/aspectratiopixmaplabel.cpp b/aspectratiopixmaplabel.cpp new file mode 100644 index 0000000..d1a4d7d --- /dev/null +++ b/aspectratiopixmaplabel.cpp @@ -0,0 +1,36 @@ +#include "aspectratiopixmaplabel.hpp" + +AspectRatioPixmapLabel::AspectRatioPixmapLabel(QWidget *parent) : + QLabel(parent) +{ + this->setMinimumSize(1,1); + setScaledContents(false); +} + +void AspectRatioPixmapLabel::setPixmap ( const QPixmap & p) +{ + pix = p; + QLabel::setPixmap(scaledPixmap()); +} + +int AspectRatioPixmapLabel::heightForWidth( int width ) const +{ + return pix.isNull() ? this->height() : ((qreal)pix.height()*width)/pix.width(); +} + +QSize AspectRatioPixmapLabel::sizeHint() const +{ + int w = this->width(); + return QSize( w, heightForWidth(w) ); +} + +QPixmap AspectRatioPixmapLabel::scaledPixmap() const +{ + return pix.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); +} + +void AspectRatioPixmapLabel::resizeEvent(QResizeEvent * e) +{ + if(!pix.isNull()) + QLabel::setPixmap(scaledPixmap()); +} diff --git a/aspectratiopixmaplabel.hpp b/aspectratiopixmaplabel.hpp new file mode 100644 index 0000000..a7b2232 --- /dev/null +++ b/aspectratiopixmaplabel.hpp @@ -0,0 +1,23 @@ +#ifndef ASPECTRATIOPIXMAPLABEL_HPP +#define ASPECTRATIOPIXMAPLABEL_HPP + +#include +#include +#include + +class AspectRatioPixmapLabel : public QLabel +{ + Q_OBJECT +public: + explicit AspectRatioPixmapLabel(QWidget *parent = 0); + virtual int heightForWidth( int width ) const; + virtual QSize sizeHint() const; + QPixmap scaledPixmap() const; +public slots: + void setPixmap ( const QPixmap & ); + void resizeEvent(QResizeEvent *); +private: + QPixmap pix; +}; + +#endif // ASPECTRATIOPIXMAPLABEL_HPP diff --git a/flowlayout.cpp b/flowlayout.cpp new file mode 100644 index 0000000..9ce3c4e --- /dev/null +++ b/flowlayout.cpp @@ -0,0 +1,154 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include + +#include "flowlayout.h" +//! [1] +FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing) + : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing) +{ + setContentsMargins(margin, margin, margin, margin); +} + +FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing) + : m_hSpace(hSpacing), m_vSpace(vSpacing) +{ + setContentsMargins(margin, margin, margin, margin); +} + +FlowLayout::~FlowLayout() +{ + for (auto& child : itemList) + { + delete child; + child = nullptr; + } + itemList.clear(); +} + +void FlowLayout::addItem(QLayoutItem *item) +{ + itemList.append(item); +} + +int FlowLayout::horizontalSpacing() const +{ + if (m_hSpace >= 0) { + return m_hSpace; + } else { + return smartSpacing(QStyle::PM_LayoutHorizontalSpacing); + } +} + +int FlowLayout::verticalSpacing() const +{ + if (m_vSpace >= 0) { + return m_vSpace; + } else { + return smartSpacing(QStyle::PM_LayoutVerticalSpacing); + } +} + +int FlowLayout::count() const +{ + return itemList.size(); +} + +QLayoutItem *FlowLayout::itemAt(int index) const +{ + return itemList.value(index); +} + +QLayoutItem *FlowLayout::takeAt(int index) +{ + if (index >= 0 && index < itemList.size()) + return itemList.takeAt(index); + return nullptr; +} + +Qt::Orientations FlowLayout::expandingDirections() const +{ + return { }; +} + +bool FlowLayout::hasHeightForWidth() const +{ + return true; +} + +int FlowLayout::heightForWidth(int width) const +{ + int height = doLayout(QRect(0, 0, width, 0), true); + return height; +} + +void FlowLayout::setGeometry(const QRect &rect) +{ + QLayout::setGeometry(rect); + doLayout(rect, false); +} + +QSize FlowLayout::sizeHint() const +{ + return minimumSize(); +} + +QSize FlowLayout::minimumSize() const +{ + QSize size; + for (const QLayoutItem* item : std::as_const(itemList)) + size = size.expandedTo(item->minimumSize()); + + const QMargins margins = contentsMargins(); + size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom()); + return size; +} + +int FlowLayout::doLayout(const QRect &rect, bool testOnly) const +{ + int left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); + int x = effectiveRect.x(); + int y = effectiveRect.y(); + int lineHeight = 0; + for (QLayoutItem* item : std::as_const(itemList)) { + const QWidget* wid = item->widget(); + int spaceX = horizontalSpacing(); + if (spaceX == -1) + spaceX = wid->style()->layoutSpacing( + QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal); + int spaceY = verticalSpacing(); + if (spaceY == -1) + spaceY = wid->style()->layoutSpacing( + QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); + int nextX = x + item->sizeHint().width() + spaceX; + if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) { + x = effectiveRect.x(); + y = y + lineHeight + spaceY; + nextX = x + item->sizeHint().width() + spaceX; + lineHeight = 0; + } + + if (!testOnly) + item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); + + x = nextX; + lineHeight = qMax(lineHeight, item->sizeHint().height()); + } + return y + lineHeight - rect.y() + bottom; +} + +int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const +{ + QObject* parent = this->parent(); + if (!parent) { + return -1; + } else if (parent->isWidgetType()) { + QWidget* pw = static_cast(parent); + return pw->style()->pixelMetric(pm, nullptr, pw); + } else { + return static_cast(parent)->spacing(); + } +} diff --git a/flowlayout.h b/flowlayout.h new file mode 100644 index 0000000..3c5291b --- /dev/null +++ b/flowlayout.h @@ -0,0 +1,41 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef FLOWLAYOUT_H +#define FLOWLAYOUT_H + +#include +#include +#include +//! [0] +class FlowLayout : public QLayout +{ +public: + explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1); + explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1); + ~FlowLayout(); + + void addItem(QLayoutItem *item) override; + int horizontalSpacing() const; + int verticalSpacing() const; + Qt::Orientations expandingDirections() const override; + bool hasHeightForWidth() const override; + int heightForWidth(int) const override; + int count() const override; + QLayoutItem *itemAt(int index) const override; + QSize minimumSize() const override; + void setGeometry(const QRect &rect) override; + QSize sizeHint() const override; + QLayoutItem *takeAt(int index) override; + +private: + int doLayout(const QRect &rect, bool testOnly) const; + int smartSpacing(QStyle::PixelMetric pm) const; + + QList itemList; + int m_hSpace; + int m_vSpace; +}; +//! [0] + +#endif // FLOWLAYOUT_H diff --git a/flowlayout.pro b/flowlayout.pro new file mode 100644 index 0000000..a0cfd40 --- /dev/null +++ b/flowlayout.pro @@ -0,0 +1,11 @@ +QT += widgets + +HEADERS = flowlayout.h \ + window.h +SOURCES = flowlayout.cpp \ + main.cpp \ + window.cpp + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/widgets/layouts/flowlayout +INSTALLS += target diff --git a/fullsizelayout.cpp b/fullsizelayout.cpp new file mode 100644 index 0000000..af9f6f2 --- /dev/null +++ b/fullsizelayout.cpp @@ -0,0 +1,91 @@ +#include "fullsizelayout.hpp" +#include "qdebug.h" +#include "qwidget.h" +#include + +FullSizeLayout::FullSizeLayout() {} + +FullSizeLayout::~FullSizeLayout() +{ + for (auto& child : itemList) + { + delete child; + child = nullptr; + } + itemList.clear(); +} +void FullSizeLayout::addItem(QLayoutItem* item) +{ + itemList.append(item); +} +int FullSizeLayout::horizontalSpacing() const +{ + return 0; +} +int FullSizeLayout::verticalSpacing() const +{ + return 0; +} +Qt::Orientations FullSizeLayout::expandingDirections() const +{ + return Qt::Vertical | Qt::Horizontal; +} +bool FullSizeLayout::hasHeightForWidth() const +{ + for (auto child : itemList) + { + if (child->hasHeightForWidth()) + return true; + } + return false; +} +int FullSizeLayout::heightForWidth(int width) const +{ + int h = -1; + for (auto child : itemList) + { + h = std::max(h, child->heightForWidth(width)); + } + return h; +} +int FullSizeLayout::count() const +{ + return static_cast(itemList.count()); +} +QLayoutItem* FullSizeLayout::itemAt(int index) const +{ + return itemList.value(index); +} +QSize FullSizeLayout::minimumSize() const +{ + QSize size; + for (auto child : itemList) + { + // auto wid = child->widget(); + if (std::max(child->minimumSize().height(), child->minimumSize().width()) >= 200) + child->minimumSize(); + // if (wid) + size = size.expandedTo(child->minimumSize()); + } + return size; +} +void FullSizeLayout::setGeometry(const QRect &rect) +{ + for (auto child : itemList) + { + child->setGeometry(rect); + } +} +QSize FullSizeLayout::sizeHint() const +{ + QSize size(1,1); + for (auto child : itemList) + { + size = size.expandedTo(child->sizeHint()); + } + return size; +} +QLayoutItem* FullSizeLayout::takeAt(int index) +{ + return itemList.takeAt(index); +} diff --git a/fullsizelayout.hpp b/fullsizelayout.hpp new file mode 100644 index 0000000..cbd63d8 --- /dev/null +++ b/fullsizelayout.hpp @@ -0,0 +1,28 @@ +#ifndef FULLSIZELAYOUT_HPP +#define FULLSIZELAYOUT_HPP + +#include + +class FullSizeLayout : public QLayout +{ +public: + FullSizeLayout(); + ~FullSizeLayout(); + void addItem(QLayoutItem *item) override; + int horizontalSpacing() const; + int verticalSpacing() const; + Qt::Orientations expandingDirections() const override; + bool hasHeightForWidth() const override; + int heightForWidth(int) const override; + int count() const override; + QLayoutItem *itemAt(int index) const override; + QSize minimumSize() const override; + void setGeometry(const QRect &rect) override; + QSize sizeHint() const override; + QLayoutItem *takeAt(int index) override; + +private: + QList itemList; +}; + +#endif // FULLSIZELAYOUT_HPP diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..0ac1f55 --- /dev/null +++ b/main.cpp @@ -0,0 +1,141 @@ +#include "mainwindow.h" +#include "tiercard.hpp" +#include "tierrow.hpp" +#include "tiercardlayout.hpp" +#include "utils.hpp" +#include "rowholder.hpp" + +#include +#include +#include +#include +#include +#include +#include + +// int main(int argc, char *argv[]) +// { +// QApplication a(argc, argv); +// // MainWindow w; +// // w.show(); +// TierCard card; +// // card.setGeometry(0, 0, 200, 200); +// card.setFixedSize(200, 200); +// card.set_text("SOME TEXT"); +// card.set_bg_color(QColor(255, 255, 255)); +// card.show(); + +// QNetworkAccessManager qnam; +// QNetworkRequest req(QUrl("https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png")); +// auto resp = qnam.get(req); +// QObject::connect(resp, &QNetworkReply::finished, [&card, resp]() +// { +// QImageReader reader(resp); +// reader.setAutoDetectImageFormat(true); +// QPixmap image = QPixmap::fromImageReader(&reader); +// card.set_image(image); +// }); + +// int fontSize = 10; +// QColor bg_switcher(255, 128, 128); +// QTimer bg_changer; +// bg_changer.setTimerType(Qt::PreciseTimer); +// bg_changer.setSingleShot(false); +// bg_changer.setInterval(1000); +// QObject::connect(&bg_changer, &QTimer::timeout, [&card, &bg_switcher, &fontSize, &a]() +// { +// card.set_bg_color(bg_switcher); +// a.setStyleSheet(QString("*[cssClass=\"tierCardText\"]{font-size: %1pt}").arg(fontSize)); +// bg_switcher = QColor(bg_switcher.green(), bg_switcher.blue(), bg_switcher.red()); +// fontSize+=3; +// }); +// bg_changer.start(); + +// return a.exec(); +// } + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + // QDockWidget dock; + QScrollArea scroll; + TierRow* row = TierRow::create(); + row->setColor(QColor(255, 128, 64)); + row->setText("Row Title"); + TierCard* card1 = TierCard::create(); + row->setStyleSheet(makeBgColorString(QColor(35,35,35))); + card1->setText("CARD1"); + card1->setBgColor(QColor(64,255,64)); + card1->setFixedSize(150,150); + TierCard* card2 = TierCard::create(); + card2->setText("CARD2"); + card2->setBgColor(QColor(64,64,255)); + card2->setFixedSize(150,150); + row->addCard(card1); + row->addCard(card2); + + TierRow* row2 = TierRow::create(); + row2->setColor(QColor(128, 128, 255)); + row2->setText("Row Title"); + TierCard* card3 = TierCard::create(); + card3->setText("CARD1"); + card3->setBgColor(QColor(64,12,164)); + card3->setFixedSize(150,150); + TierCard* card4 = TierCard::create(); + card4->setText("CARD2"); + card4->setBgColor(QColor(164,64,155)); + card4->setFixedSize(150,150); + auto card5 = TierCard::clone(card4); + card5->setFixedSize(150,150); + row->addCard(card5); + row2->addCard(card3); + row2->addCard(card4); + // row.show(); + + RowHolder holder; + holder.setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + // auto holderLayout = new QVBoxLayout(); + holder.addRow(row); + holder.addRow(row2); + + scroll.setWidget(&holder); + scroll.setWidgetResizable(true); + // dock.setWidget(&scroll); + // w.dockWidgetArea(&dock); + w.setCentralWidget(&scroll); + w.show(); + + w.setStyleSheet(a.styleSheet() + .append("#tierCardText {" + " font-style: bold;" + " font-size: 52; }") + .append("#tierCardId {" + " font-size: 24; }")); + // a.setFont() + // QTimer bg_changer; + // bg_changer.setTimerType(Qt::PreciseTimer); + // bg_changer.setSingleShot(false); + // bg_changer.setInterval(1000); + // QObject::connect(&bg_changer, &QTimer::timeout, [&row]() + // { + // row.updateGeometry(); + // }); + // bg_changer.start(); + // w.show(); + + // callOnMeAndChildren(&row, [](TierRow* obj) + // { + // auto wid = dynamic_cast(obj); + // if (wid) + // { + // auto size = wid->minimumSize(); + // if (std::max(size.height(), size.width()) >= 200) + // { + // qDebug() << wid->objectName() << ": " << size; + // } + // } + // }); + // qDebug() << row.minimumSize() << row.layout()->minimumSize(); + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..83e32a9 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,15 @@ +#include "mainwindow.h" +#include "./ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); +} + +MainWindow::~MainWindow() +{ + delete ui; + ui = nullptr; +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..f7a3da3 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,23 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { +class MainWindow; +} +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +private: + Ui::MainWindow *ui; +}; +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..b07f62d --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,31 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + 0 + 0 + 800 + 25 + + + + + + + + diff --git a/myflowlayout.cpp b/myflowlayout.cpp new file mode 100644 index 0000000..5feba13 --- /dev/null +++ b/myflowlayout.cpp @@ -0,0 +1,109 @@ +// #include "myflowlayout.hpp" +// #include "qexception.h" +// #include "qwidget.h" + +// MyFlowLayout::MyFlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing) +// : QLayout(parent), hSpace(hSpacing), vSpace(vSpacing) +// { + +// } + +// MyFlowLayout::MyFlowLayout(int margin, int hSpacing, int vSpacing) +// : hSpace(hSpacing), vSpace(vSpacing) +// { + +// } + +// MyFlowLayout::~MyFlowLayout() +// { +// for (auto child : itemList) +// { +// delete child; +// } +// } + +// void MyFlowLayout::addItem(QLayoutItem* item) +// { +// itemList.append(item); +// } + +// int MyFlowLayout::horizontalSpacing() const +// { +// return hSpace; +// } + +// int MyFlowLayout::verticalSpacing() const +// { +// return vSpace; +// } + +// Qt::Orientations MyFlowLayout::expandingDirections() const +// { +// return { }; +// } + +// bool MyFlowLayout::hasHeightForWidth() const +// { +// return true; +// } + +// int MyFlowLayout::heightForWidth(int width) const +// { +// QRect rect(0, 0, width, 0); +// return doLayout(rect, false); +// } + +// QSize MyFlowLayout::minimumSize() const +// { +// QSize size(1,1); +// for (auto child : itemList) +// { +// size = size.expandedTo(child->minimumSize()); +// } +// return size; +// } + +// QLayoutItem* MyFlowLayout::itemAt(int index) const +// { +// return itemList.at(index); +// } + +// QLayoutItem* MyFlowLayout::takeAt(int index) +// { +// return itemList.takeAt(index); +// } + +// int MyFlowLayout::doLayout(const QRect &rect, bool apply) const +// { +// int left, top, right, bottom; +// getContentsMargins(&left, &top, &right, &bottom); +// QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); +// int x = effectiveRect.x(); +// int y = effectiveRect.y(); +// int lineHeight = 0; +// for (QLayoutItem *item : std::as_const(itemList)) { +// const QWidget *wid = item->widget(); +// int spaceX = horizontalSpacing(); +// if (spaceX == -1) +// spaceX = wid->style()->layoutSpacing( +// QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal); +// int spaceY = verticalSpacing(); +// if (spaceY == -1) +// spaceY = wid->style()->layoutSpacing( +// QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); +// int nextX = x + item->sizeHint().width() + spaceX; +// if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) { +// x = effectiveRect.x(); +// y = y + lineHeight + spaceY; +// nextX = x + item->sizeHint().width() + spaceX; +// lineHeight = 0; +// } + +// if (apply) +// item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); + +// x = nextX; +// lineHeight = qMax(lineHeight, item->sizeHint().height()); +// } +// return y + lineHeight - rect.y() + bottom; +// } diff --git a/myflowlayout.hpp b/myflowlayout.hpp new file mode 100644 index 0000000..4a91699 --- /dev/null +++ b/myflowlayout.hpp @@ -0,0 +1,36 @@ +// #ifndef MYFLOWLAYOUT_HPP +// #define MYFLOWLAYOUT_HPP + +// #include +// #include + +// class MyFlowLayout : public QLayout +// { +// public: +// explicit MyFlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1); +// explicit MyFlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1); +// ~MyFlowLayout(); + +// void addItem(QLayoutItem *item) override; +// int horizontalSpacing() const; +// int verticalSpacing() const; +// Qt::Orientations expandingDirections() const override; +// bool hasHeightForWidth() const override; +// int heightForWidth(int width) const override; +// int count() const override; +// QLayoutItem* itemAt(int index) const override; +// QSize minimumSize() const override; +// void setGeometry(const QRect &rect) override; +// QSize sizeHint() const override; +// QLayoutItem* takeAt(int index) override; + +// private: +// int doLayout(const QRect &rect, bool apply=true) const; +// int smartSpacing(QStyle::PixelMetric pm) const; + +// QList itemList; +// int hSpace; +// int vSpace; +// }; + +// #endif // MYFLOWLAYOUT_HPP diff --git a/rowholder.cpp b/rowholder.cpp new file mode 100644 index 0000000..23840f3 --- /dev/null +++ b/rowholder.cpp @@ -0,0 +1,19 @@ +#include "rowholder.hpp" + +RowHolder::RowHolder() +{ + _layout = new QVBoxLayout(); + _layout->setAlignment(Qt::AlignTop); + setLayout(_layout); +} + +void RowHolder::addRow(TierRow* row) +{ + row->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + _layout->addWidget(row, 0, Qt::AlignTop); +} + +RowHolder::~RowHolder() +{ + +} diff --git a/rowholder.hpp b/rowholder.hpp new file mode 100644 index 0000000..5af5089 --- /dev/null +++ b/rowholder.hpp @@ -0,0 +1,25 @@ +#ifndef ROWHOLDER_HPP +#define ROWHOLDER_HPP + +#include "tierrow.hpp" + +#include +#include +#include +#include + +class RowHolder : public QFrame +{ + Q_OBJECT +public: + using IdType = uint32_t; + RowHolder(); + ~RowHolder(); + void addRow(TierRow* row); + + +private: + QVBoxLayout* _layout; +}; + +#endif // ROWHOLDER_HPP diff --git a/settings.cpp b/settings.cpp new file mode 100644 index 0000000..a83f6d4 --- /dev/null +++ b/settings.cpp @@ -0,0 +1,5 @@ +#include "settings.hpp" + +Settings::Settings(QObject *parent) + : QObject{parent} +{} diff --git a/settings.hpp b/settings.hpp new file mode 100644 index 0000000..d68a30e --- /dev/null +++ b/settings.hpp @@ -0,0 +1,15 @@ +#ifndef SETTINGS_HPP +#define SETTINGS_HPP + +#include + +class Settings : public QObject +{ + Q_OBJECT +public: + explicit Settings(QObject *parent = nullptr); + +signals: +}; + +#endif // SETTINGS_HPP diff --git a/tiercard.cpp b/tiercard.cpp new file mode 100644 index 0000000..a9b4b84 --- /dev/null +++ b/tiercard.cpp @@ -0,0 +1,185 @@ +#include "tiercard.hpp" +#include "fullsizelayout.hpp" +#include "qmimedata.h" +#include "utils.hpp" + +#include + +// TierCard::TierCard(QWidget *parent) +// : QWidget{parent} +// { +// auto bg_layout= new QVBoxLayout(this); +// bg_layout->setSpacing(0); +// bg_layout->setContentsMargins(0, 0, 0, 0); +// background = new QWidget(); +// bg_layout->addWidget(background); +// auto img_layout = new QVBoxLayout(background); +// img_layout->setSpacing(0); +// img_layout->setContentsMargins(0, 0, 0, 0); +// image = new AspectRatioPixmapLabel(); +// img_layout->addWidget(image, 0, Qt::AlignCenter); +// image->setAttribute(Qt::WA_TranslucentBackground); +// image->setAlignment(Qt::AlignCenter); +// auto txt_layout = new QVBoxLayout(image); +// txt_layout->setSpacing(0); +// txt_layout->setContentsMargins(0, 0, 0, 0); +// text_label = new QLabel(); +// id_label = new QLabel("4"); +// text_label->setWordWrap(true); +// // text_label->setTextFormat(Qt::RichText); +// text_label->setAlignment(Qt::AlignHCenter | Qt::AlignTop); +// id_label->setAlignment(Qt::AlignLeft | Qt::AlignBottom); +// text_label->setAttribute(Qt::WA_TranslucentBackground); +// id_label->setAttribute(Qt::WA_TranslucentBackground); +// txt_layout->addWidget(text_label, Qt::AlignTop | Qt::AlignHCenter); +// txt_layout->addWidget(id_label, Qt::AlignBottom, Qt::AlignLeft); +// text_label->setProperty("cssClass", "tierCardText"); +// id_label->setProperty("cssClass", "tierCardId"); +// } + +TierCard::IdType TierCard::getAvailableId() +{ + for (IdType id = 1;; id++) + { + if (idMap.find(id) == idMap.end()) + { + return id; + } + } +} + +void TierCard::releaseId(IdType id) +{ + if (idMap.erase(id) == 0) + { + qDebug() << "Card id not found during destructor"; + } +} + +TierCard* TierCard::create(QWidget* parent) +{ + TierCard* card; + auto id = getAvailableId(); + card = new TierCard(id, parent); + idMap[id] = card; + return card; +} + +TierCard* TierCard::clone(TierCard *other, QWidget* parent) +{ + TierCard* card; + auto id = getAvailableId(); + card = new TierCard(id, parent); + card->setText(other->getText()); + auto img = other->getImage(); + card->setImage(img); + card->setBgColor(other->getBgColor()); + idMap[id] = card; + return card; +} + +TierCard::TierCard(IdType id, QWidget* parent) + : QWidget{parent} +{ + background = new QWidget(); + image = new AspectRatioPixmapLabel(); + image->setAttribute(Qt::WA_TranslucentBackground); + image->setAlignment(Qt::AlignCenter); + textLabel = new QLabel(); + idLabel = new QLabel(); + textLabel->setWordWrap(true); + // text_label->setTextFormat(Qt::RichText); + textLabel->setAlignment(Qt::AlignHCenter | Qt::AlignTop); + idLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom); + textLabel->setAttribute(Qt::WA_TranslucentBackground); + idLabel->setAttribute(Qt::WA_TranslucentBackground); + textLabel->setObjectName("tierCardText"); + idLabel->setObjectName("tierCardId"); + idLabel->setText(QString::number(id)); + auto layout = new FullSizeLayout(); + layout->addWidget(background); + layout->addWidget(image); + layout->addWidget(textLabel); + layout->addWidget(idLabel); + this->setLayout(layout); +} + +TierCard::~TierCard() +{ + releaseId(getId()); + // delete text_label; + // text_label = nullptr; + // delete id_label; + // id_label = nullptr; +} + +void TierCard::setText(QString str) +{ + textLabel->setText(str); +} + +QString TierCard::getText() const +{ + return textLabel->text(); +} + +uint32_t TierCard::getId() const +{ + return static_cast(idLabel->text().toUInt()); +} + +void TierCard::setBgColor(QColor color) +{ + bgColor = color; + auto str = makeBgColorString(color); + background->setStyleSheet(str); +} + +QColor TierCard::getBgColor() +{ + return bgColor; +} + +void TierCard::setImage(const QPixmap img) +{ + // QMetaObject::invokeMethod() + image->setPixmap(img); +} + +QPixmap TierCard::getImage() const +{ + return image->pixmap(); +} + +void TierCard::mousePressEvent(QMouseEvent* event) +{ + qDebug() << "mouse press event"; + QPixmap pix(size()); + render(&pix); + QDrag drag(this); + drag.setPixmap(pix); + QByteArray itemData; + QDataStream dataStream(&itemData, QIODevice::WriteOnly); + auto _id = getId(); + dataStream.writeRawData(reinterpret_cast(&_id), sizeof(_id)); + QMimeData *mimeData = new QMimeData; + mimeData->setData(MimeType, itemData); + drag.setMimeData(mimeData); + hide(); + if (drag.exec() == Qt::MoveAction) + { + show(); + } + else + { + show(); + } +} + +TierCard* TierCard::getFromId(IdType id) +{ + auto iter = idMap.find(id); + if (iter == idMap.end()) + return nullptr; + return &(*iter->second); +} diff --git a/tiercard.hpp b/tiercard.hpp new file mode 100644 index 0000000..2139a3a --- /dev/null +++ b/tiercard.hpp @@ -0,0 +1,49 @@ +#ifndef TIERCARD_H +#define TIERCARD_H + +#include "aspectratiopixmaplabel.hpp" + +#include +#include +#include + +#include + +class TierCard : public QWidget +{ + Q_OBJECT +public: + using IdType = uint32_t; + inline static const char* MimeType = "application/x-tiercard"; + TierCard(TierCard const&) = delete; + ~TierCard(); + static TierCard* create(QWidget *parent = nullptr); + static TierCard* clone(TierCard *other, QWidget* parent = nullptr); + static TierCard* getFromId(IdType id); + void setText(QString str); + QString getText() const; + void setImage(const QPixmap img); + QPixmap getImage() const; + IdType getId() const; + void setBgColor(QColor color); + QColor getBgColor(); + // QColor bg_color() const; + +protected: + void mousePressEvent(QMouseEvent* event); + +private: + explicit TierCard(IdType id, QWidget *parent = nullptr); + QWidget* background; + AspectRatioPixmapLabel* image; + QLabel* textLabel; + QLabel* idLabel; + QColor bgColor; + static IdType getAvailableId(); + static void releaseId(IdType id); + inline static std::unordered_map idMap; + +signals: +}; + +#endif // TIERCARD_H diff --git a/tiercardlayout.cpp b/tiercardlayout.cpp new file mode 100644 index 0000000..7409e4e --- /dev/null +++ b/tiercardlayout.cpp @@ -0,0 +1,30 @@ +// #include "tiercardlayout.hpp" +// #include + +// TierCardLayout::TierCardLayout() +// { +// // itemList.append(nullptr); +// // itemList.append(nullptr); +// // itemList.append(nullptr); +// } + +// TierCardLayout::~TierCardLayout() +// { +// // QLayoutItem *item; +// // while ((item = takeAt(0))) +// // delete item; +// delete image; +// delete text; +// delete id; +// } + +// void TierCardLayout::addItem(QLayoutItem *item) +// { +// // itemList.append(item); +// throw new QException(); +// } + +// QLayoutItem* TierCardLayout::itemAt(int index) const +// { +// throw new QException(); +// } diff --git a/tiercardlayout.hpp b/tiercardlayout.hpp new file mode 100644 index 0000000..35cc1ee --- /dev/null +++ b/tiercardlayout.hpp @@ -0,0 +1,31 @@ +// #ifndef TIERCARDLAYOUT_HPP +// #define TIERCARDLAYOUT_HPP + +// #include +// #include + +// class TierCardLayout : public QLayout +// { +// public: +// TierCardLayout(); +// ~TierCardLayout(); +// void addItem(QLayoutItem *item) override; +// Qt::Orientations expandingDirections() const override; +// bool hasHeightForWidth() const override; +// int heightForWidth(int) const override; +// int count() const override; +// QLayoutItem *itemAt(int index) const override; +// QSize minimumSize() const override; +// void setGeometry(const QRect &rect) override; +// QSize sizeHint() const override; +// QLayoutItem *takeAt(int index) override; +// public + +// private: +// QList itemList; +// QLabel* image; +// QLabel* text; +// QLabel* id; +// }; + +// #endif // TIERCARDLAYOUT_HPP diff --git a/tierrow.cpp b/tierrow.cpp new file mode 100644 index 0000000..5a368a9 --- /dev/null +++ b/tierrow.cpp @@ -0,0 +1,198 @@ +#include "tierrow.hpp" +#include "fullsizelayout.hpp" +#include "qmimedata.h" +#include "utils.hpp" + +#include + +TierRow::TierRow(IdType id, QWidget *parent) + : QWidget{parent} +{ + setAcceptDrops(true); + auto fadeLayout = new FullSizeLayout(); + fadeLayout->setSizeConstraint(QLayout::SetMinimumSize); + fadeLayout->setContentsMargins(0, 0, 0, 0); + fadeLayout->setSpacing(0); + bgFadeContainer = new QWidget(); + bgFadeContainer->setStyleSheet(makeBgColorString(QColor(255,255,255,100))); + bgFadeContainer->setMinimumSize(0, 0); + fadeLayout->addWidget(bgFadeContainer); + this->setLayout(fadeLayout); + auto splitLayout = new QHBoxLayout(); + splitLayout->setSizeConstraint(QLayout::SetMinimumSize); + splitLayout->setContentsMargins(0, 0, 0, 0); + splitLayout->setSpacing(0); + titleCard = new TierRowTitleCard(id); + cardContainer = new QWidget(); + cardContainer->setMinimumSize(0, 0); + titleCard->setFixedSize(150, 150); + cardContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + splitLayout->addWidget(titleCard, 0, Qt::AlignLeft | Qt::AlignTop); + splitLayout->addWidget(cardContainer, 1, Qt::AlignTop); + + cardContainer->setStyleSheet(makeBgColorString(QColor(60,60,60,100))); + + bgFadeContainer->setLayout(splitLayout); + cardLayout = new FlowLayout(); + cardLayout->setSizeConstraint(QLayout::SetMinimumSize); + cardLayout->setContentsMargins(0, 0, 0, 0); + cardLayout->setSpacing(0); + cardContainer->setLayout(cardLayout); + // setMinimumSize(0, 0); +} + +TierRow::~TierRow() +{ + qDebug() << "Row destructor called " << id(); + if (idMap.erase(id()) == 0) + { + qDebug() << "Row id not found during destructor"; + } +} + +void TierRow::addCard(TierCard* card) +{ + cardContainer->layout()->addWidget(card); +} +// TierCard* TierRow::takeCard(uint32_t id) +// { +// for (auto i : cardContainer->children()) +// } +void TierRow::setColor(QColor color) +{ + _color = color; + titleCard->setColor(color); + auto str = makeBgColorString(color); + setStyleSheet(str); +} +QColor TierRow::color() +{ + return _color; +} +void TierRow::setText(QString text) +{ + titleCard->setText(text); +} +QString TierRow::text() +{ + return titleCard->text(); +} +uint32_t TierRow::id() +{ + return titleCard->id(); +} + +void TierRow::resizeEvent(QResizeEvent* event) +{ + this->QWidget::resizeEvent(event); + recalcMaxHeight(); +} + +void TierRow::recalcMaxHeight() +{ + setMaximumHeight(cardLayout->totalMinimumHeightForWidth(cardContainer->width())); +} + +TierRow* TierRow::create(QWidget* parent) +{ + TierRow* row; + for (IdType id = 1;; id++) + { + if (idMap.find(id) == idMap.end()) + { + row = new TierRow(id, parent); + idMap[id] = row; + return row; + } + } +} + +TierRow* TierRow::getFromId(IdType id) +{ + auto iter = idMap.find(id); + if (iter == idMap.end()) + { + return nullptr; + } + return iter->second; +} + +void TierRow::dropEvent(QDropEvent *event) +{ + qDebug() << "drop event"; + //card dragged to this row + if (event->mimeData()->hasFormat(TierCard::MimeType)) + { + if (event->proposedAction() == Qt::MoveAction) + { + auto data = event->mimeData()->data(TierCard::MimeType); + QDataStream stream(&data, QIODevice::ReadOnly); + TierCard::IdType cardId; + uint dataLen = 0; + stream.readRawData(reinterpret_cast(&cardId), dataLen); + auto card = TierCard::getFromId(cardId); + addCard(card); + event->acceptProposedAction(); + } + else + { + event->ignore(); + } + } + //image(s) dragged to make new card(s) + else if (event->mimeData()->hasImage()) + { + + } +} + +void TierRow::dragEnterEvent(QDragEnterEvent *event) +{ + qDebug() << "drag enter event"; + if (event->mimeData()->hasFormat(TierCard::MimeType)) + { + if (event->proposedAction() == Qt::MoveAction) + { + event->setDropAction(Qt::MoveAction); + event->accept(cardContainer->rect()); + } + else + { + event->setDropAction(Qt::MoveAction); + event->accept(cardContainer->geometry()); + } + } + else if (event->mimeData()->hasImage()) + { + event->setDropAction(Qt::CopyAction); + event->accept(); + } + else { + event->ignore(); + } +} + +void TierRow::dragMoveEvent(QDragMoveEvent *event) +{ + qDebug() << "drag move event"; + if (event->mimeData()->hasFormat(TierCard::MimeType)) + { + if (event->proposedAction() == Qt::MoveAction) + { + event->acceptProposedAction(); + } + else + { + event->setDropAction(Qt::MoveAction); + event->accept(cardContainer->geometry()); + } + } + else if (event->mimeData()->hasImage()) + { + event->setDropAction(Qt::CopyAction); + event->accept(); + } + else { + event->ignore(); + } +} diff --git a/tierrow.hpp b/tierrow.hpp new file mode 100644 index 0000000..c745a29 --- /dev/null +++ b/tierrow.hpp @@ -0,0 +1,51 @@ +#ifndef TIERROW_HPP +#define TIERROW_HPP + +#include "tiercard.hpp" +#include "tierrowtitlecard.hpp" +#include "flowlayout.h" + +#include +#include + +class TierRow : public QWidget +{ + Q_OBJECT +public: + using IdType = TierRowTitleCard::IdType; + static TierRow* create(QWidget* parent = nullptr); + static TierRow* getFromId(IdType id); + ~TierRow(); + void addCard(TierCard* card); + TierCard* takeCard(uint32_t id); + void setColor(QColor color); + QColor color(); + void setText(QString text); + QString text(); + uint32_t id(); + +protected: + void resizeEvent(QResizeEvent* event) override; + // void mousePressEvent(QMouseEvent* event) override; + void dropEvent(QDropEvent *event) override; + void dragEnterEvent(QDragEnterEvent *event) override; + void dragMoveEvent(QDragMoveEvent *event) override; + +private: + explicit TierRow(IdType id, QWidget* parent = nullptr); + TierRowTitleCard* titleCard; + QWidget* bgFadeContainer; + QWidget* cardContainer; + QLayout* cardLayout; + QColor _color; + void recalcMaxHeight(); + inline static std::unordered_map idMap; + +public slots: + void cardResize(QRect newSize); + +signals: + +}; + +#endif // TIERROW_HPP diff --git a/tierrowtitlecard.cpp b/tierrowtitlecard.cpp new file mode 100644 index 0000000..f1e95f7 --- /dev/null +++ b/tierrowtitlecard.cpp @@ -0,0 +1,42 @@ +#include "tierrowtitlecard.hpp" +#include "fullsizelayout.hpp" +#include "utils.hpp" + +#include + +TierRowTitleCard::TierRowTitleCard(IdType id, QWidget *parent) + : QFrame{parent} +{ + this->setFrameStyle(QFrame::Box | QFrame::Plain); + auto layout = new FullSizeLayout(); + titleLabel = new QLabel(); + idLabel = new QLabel(); + layout->addWidget(titleLabel); + layout->addWidget(idLabel); + setLayout(layout); +} +QString TierRowTitleCard::text() const +{ + return titleLabel->text(); +} + +QColor TierRowTitleCard::color() const +{ + return _color; +} + +void TierRowTitleCard::setText(QString& str) +{ + titleLabel->setText(str); +} + +void TierRowTitleCard::setColor(QColor color) +{ + _color = color; + setStyleSheet(makeBgColorString(color)); +} + +uint32_t TierRowTitleCard::id() const +{ + return static_cast(idLabel->text().toUInt()); +} diff --git a/tierrowtitlecard.hpp b/tierrowtitlecard.hpp new file mode 100644 index 0000000..c6ca041 --- /dev/null +++ b/tierrowtitlecard.hpp @@ -0,0 +1,27 @@ +#ifndef TIERROWTITLECARD_HPP +#define TIERROWTITLECARD_HPP + +#include +#include + +class TierRowTitleCard : public QFrame +{ + Q_OBJECT +public: + using IdType = uint32_t; + explicit TierRowTitleCard(IdType id, QWidget *parent = nullptr); + void setColor(QColor color); + QColor color() const; + void setText(QString& text); + QString text() const; + uint32_t id() const; + +private: + QColor _color; + QLabel* titleLabel; + QLabel* idLabel; + +signals: +}; + +#endif // TIERROWTITLECARD_HPP diff --git a/utils.hpp b/utils.hpp new file mode 100644 index 0000000..88f4ad7 --- /dev/null +++ b/utils.hpp @@ -0,0 +1,56 @@ +#ifndef UTILS_HPP +#define UTILS_HPP + +#include "tierrow.hpp" + +#include +#include + +//change this stupid name +inline void callOnMeAndChildren(QObject* obj, void (*func)(QObject*)) +{ + func(obj); + for (auto w : obj->children()) + { + callOnMeAndChildren(w, func); + } +} +template +void callOnMeAndChildren(QObject* obj, void (*func)(T*)) +{ + if (auto casted = dynamic_cast(obj)) + { + func(casted); + } + for (auto w : obj->children()) + { + callOnMeAndChildren(w, func); + } +} + +inline QString makeBgColorString(QColor color) +{ + return QString("background-color: rgba(%1,%2,%3,%4)") + .arg(QString::number(color.red()), + QString::number(color.green()), + QString::number(color.blue()), + QString::number(color.alphaF())); +} + +template +T* findParentOfType(QObject* obj) +{ + auto parent = obj->parent(); + if (!parent) + return nullptr; + else if (auto asT = dynamic_cast(parent)) + { + return asT; + } + else + { + return findParentOfType(parent); + } +} + +#endif // UTILS_HPP