Qt: initial grid layout work

This commit is contained in:
Brad Parker 2018-05-02 23:04:10 -04:00
parent 19f6798947
commit 5f7abb068b
6 changed files with 466 additions and 11 deletions

View File

@ -332,7 +332,8 @@ OBJ += ui/drivers/ui_qt.o \
ui/drivers/qt/ui_qt_window.o \
ui/drivers/qt/ui_qt_browser_window.o \
ui/drivers/qt/ui_qt_load_core_window.o \
ui/drivers/qt/ui_qt_msg_window.o
ui/drivers/qt/ui_qt_msg_window.o \
ui/drivers/qt/flowlayout.o
MOC_HEADERS += ui/drivers/ui_qt.h \
ui/drivers/qt/ui_qt_load_core_window.h

View File

@ -0,0 +1,200 @@
/****************************************************************************
**
** 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$
**
****************************************************************************/
#include <QtWidgets>
#include "flowlayout.h"
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()
{
QLayoutItem *item;
while ((item = takeAt(0)))
delete item;
}
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);
else
return 0;
}
Qt::Orientations FlowLayout::expandingDirections() const
{
return 0;
}
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;
QLayoutItem *item;
foreach (item, itemList)
size = size.expandedTo(item->minimumSize());
size += QSize(2*margin(), 2*margin());
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;
QLayoutItem *item;
foreach (item, itemList) {
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<QWidget *>(parent);
return pw->style()->pixelMetric(pm, 0, pw);
} else {
return static_cast<QLayout *>(parent)->spacing();
}
}

View File

@ -0,0 +1,89 @@
/****************************************************************************
**
** 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$
**
****************************************************************************/
/* bparker: Removed C++11 override keyword from original source */
#ifndef FLOWLAYOUT_H
#define FLOWLAYOUT_H
#include <QLayout>
#include <QRect>
#include <QStyle>
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);
int horizontalSpacing() const;
int verticalSpacing() const;
Qt::Orientations expandingDirections() const;
bool hasHeightForWidth() const;
int heightForWidth(int) const;
int count() const;
QLayoutItem *itemAt(int index) const;
QSize minimumSize() const;
void setGeometry(const QRect &rect);
QSize sizeHint() const;
QLayoutItem *takeAt(int index);
private:
int doLayout(const QRect &rect, bool testOnly) const;
int smartSpacing(QStyle::PixelMetric pm) const;
QList<QLayoutItem *> itemList;
int m_hSpace;
int m_vSpace;
};
#endif // FLOWLAYOUT_H

View File

@ -33,6 +33,7 @@
#include "../ui_qt.h"
#include "ui_qt_load_core_window.h"
#include "ui_qt_themes.h"
#include "flowlayout.h"
extern "C" {
#include "../../../version.h"
@ -487,13 +488,30 @@ MainWindow::MainWindow(QWidget *parent) :
,m_historyPlaylistsItem(NULL)
,m_folderIcon()
,m_customThemeString()
,m_gridLayout(new FlowLayout())
,m_gridWidget(new QWidget(this))
,m_gridScrollArea(new QScrollArea(m_gridWidget))
,m_gridItems()
{
settings_t *settings = config_get_ptr();
QDir playlistDir(settings->paths.directory_playlist);
QString configDir = QFileInfo(path_get(RARCH_PATH_CONFIG)).dir().absolutePath();
QToolButton *searchResetButton = NULL;
QWidget *gridLayoutWidget = new QWidget();
int i = 0;
m_gridWidget->setLayout(new QVBoxLayout());
gridLayoutWidget->setLayout(m_gridLayout);
m_gridScrollArea->setAlignment(Qt::AlignCenter);
m_gridScrollArea->setFrameShape(QFrame::NoFrame);
m_gridScrollArea->setWidgetResizable(true);
m_gridScrollArea->setWidget(gridLayoutWidget);
m_gridWidget->layout()->addWidget(m_gridScrollArea);
m_gridWidget->layout()->setAlignment(Qt::AlignCenter);
m_tableWidget->setAlternatingRowColors(true);
m_logWidget->setObjectName("logWidget");
@ -658,6 +676,7 @@ MainWindow::~MainWindow()
delete m_thumbnailPixmap2;
if (m_thumbnailPixmap3)
delete m_thumbnailPixmap3;
removeGridItems();
}
void MainWindow::showWelcomeScreen()
@ -2512,7 +2531,8 @@ void MainWindow::onCurrentListItemChanged(QListWidgetItem *current, QListWidgetI
if (m_browserAndPlaylistTabWidget->tabText(m_browserAndPlaylistTabWidget->currentIndex()) != msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_TAB_PLAYLISTS))
return;
initContentTableWidget();
//initContentTableWidget();
initContentGridLayout();
setCoreActions();
}
@ -2521,6 +2541,16 @@ TableWidget* MainWindow::contentTableWidget()
return m_tableWidget;
}
QWidget* MainWindow::contentGridWidget()
{
return m_gridWidget;
}
FlowLayout* MainWindow::contentGridLayout()
{
return m_gridLayout;
}
void MainWindow::onBrowserDownloadsClicked()
{
settings_t *settings = config_get_ptr();
@ -2700,6 +2730,98 @@ void MainWindow::onLoadCoreClicked(const QStringList &extensionFilters)
m_loadCoreWindow->initCoreList(extensionFilters);
}
void MainWindow::removeGridItems()
{
if (m_gridItems.count() > 0)
{
QMutableListIterator<GridItem*> items(m_gridItems);
while (items.hasNext())
{
GridItem *item = items.next();
if (item)
{
items.remove();
m_gridLayout->removeWidget(item->widget);
delete item->widget;
delete item;
}
}
}
}
void MainWindow::addPlaylistItemsToGrid(QString pathString)
{
QList<QHash<QString, QString> > items = getPlaylistItems(pathString);
settings_t *settings = config_get_ptr();
int i = 0;
for (i = 0; i < items.count(); i++)
{
const QHash<QString, QString> &hash = items.at(i);
GridItem *item = new GridItem();
ThumbnailLabel *label = NULL;
QPixmap pixmap;
QString thumbnailFileNameNoExt;
QLabel *newLabel = NULL;
thumbnailFileNameNoExt = hash["label_noext"];
thumbnailFileNameNoExt.replace(m_fileSanitizerRegex, "_");
item->hash = hash;
item->widget = new ThumbnailWidget();
item->widget->setFixedSize(item->widget->sizeHint());
item->widget->setLayout(new QVBoxLayout());
item->widget->setStyleSheet("background-color: #555555");
label = new ThumbnailLabel(item->widget);
pixmap = QPixmap(QString(settings->paths.directory_thumbnails) + "/" + hash.value("db_name") + "/" + THUMBNAIL_BOXART + "/" + thumbnailFileNameNoExt + ".png");
label->setPixmap(pixmap);
item->widget->layout()->addWidget(label);
newLabel = new QLabel(hash.value("label"), item->widget);
newLabel->setAlignment(Qt::AlignCenter);
item->widget->layout()->addWidget(newLabel);
qobject_cast<QVBoxLayout*>(item->widget->layout())->setStretchFactor(label, 1);
m_gridLayout->addWidget(item->widget);
m_gridItems.append(item);
}
}
void MainWindow::initContentGridLayout()
{
QListWidgetItem *item = m_listWidget->currentItem();
QString path;
if (!item)
return;
removeGridItems();
path = item->data(Qt::UserRole).toString();
if (path == ALL_PLAYLISTS_TOKEN)
{
settings_t *settings = config_get_ptr();
QDir playlistDir(settings->paths.directory_playlist);
foreach (QString playlist, m_playlistFiles)
{
addPlaylistItemsToGrid(playlistDir.absoluteFilePath(playlist));
}
}
else
addPlaylistItemsToGrid(path);
}
void MainWindow::initContentTableWidget()
{
QListWidgetItem *item = m_listWidget->currentItem();
@ -2759,14 +2881,14 @@ void MainWindow::initContentTableWidget()
onSearchEnterPressed();
}
void MainWindow::addPlaylistItemsToTable(QString pathString)
QList<QHash<QString, QString> > MainWindow::getPlaylistItems(QString pathString)
{
QByteArray pathArray;
QList<QHash<QString, QString> > items;
const char *pathData = NULL;
playlist_t *playlist = NULL;
unsigned playlistSize = 0;
unsigned i = 0;
int oldRowCount = m_tableWidget->rowCount();
pathArray.append(pathString);
pathData = pathArray.constData();
@ -2774,8 +2896,6 @@ void MainWindow::addPlaylistItemsToTable(QString pathString)
playlist = playlist_init(pathData, COLLECTION_SIZE);
playlistSize = playlist_get_size(playlist);
m_tableWidget->setRowCount(oldRowCount + playlistSize);
for (i = 0; i < playlistSize; i++)
{
const char *path = NULL;
@ -2784,7 +2904,6 @@ void MainWindow::addPlaylistItemsToTable(QString pathString)
const char *core_name = NULL;
const char *crc32 = NULL;
const char *db_name = NULL;
QTableWidgetItem *labelItem = NULL;
QHash<QString, QString> hash;
playlist_get_index(playlist, i,
@ -2822,15 +2941,40 @@ void MainWindow::addPlaylistItemsToTable(QString pathString)
hash["db_name"].remove(file_path_str(FILE_PATH_LPL_EXTENSION));
}
labelItem = new QTableWidgetItem(hash["label"]);
items.append(hash);
}
playlist_free(playlist);
playlist = NULL;
return items;
}
void MainWindow::addPlaylistItemsToTable(QString pathString)
{
QList<QHash<QString, QString> > items = getPlaylistItems(pathString);
int i = 0;
int oldRowCount = m_tableWidget->rowCount();
m_tableWidget->setRowCount(oldRowCount + items.count());
for (i = 0; i < items.count(); i++)
{
const char *path = NULL;
const char *label = NULL;
const char *core_path = NULL;
const char *core_name = NULL;
const char *crc32 = NULL;
const char *db_name = NULL;
QTableWidgetItem *labelItem = NULL;
const QHash<QString, QString> &hash = items.at(i);
labelItem = new QTableWidgetItem(hash.value("label"));
labelItem->setData(Qt::UserRole, QVariant::fromValue<QHash<QString, QString> >(hash));
labelItem->setFlags(labelItem->flags() & ~Qt::ItemIsEditable);
m_tableWidget->setItem(oldRowCount + i, 0, labelItem);
}
playlist_free(playlist);
playlist = NULL;
}
void MainWindow::keyPressEvent(QKeyEvent *event)

View File

@ -256,6 +256,9 @@ static void* ui_companion_qt_init(void)
layout = new QVBoxLayout();
layout->addWidget(mainwindow->contentTableWidget());
layout->addWidget(mainwindow->contentGridWidget());
mainwindow->contentTableWidget()->hide();
widget->setLayout(layout);

View File

@ -57,6 +57,14 @@ class QStyle;
class QScrollArea;
class LoadCoreWindow;
class MainWindow;
class ThumbnailWidget;
class FlowLayout;
struct GridItem
{
ThumbnailWidget *widget;
QHash<QString, QString> hash;
};
class ThumbnailWidget : public QWidget
{
@ -223,6 +231,8 @@ public:
TreeView* dirTreeView();
QListWidget* playlistListWidget();
TableWidget* contentTableWidget();
FlowLayout* contentGridLayout();
QWidget* contentGridWidget();
QWidget* searchWidget();
QLineEdit* searchLineEdit();
QComboBox* launchWithComboBox();
@ -259,6 +269,7 @@ public slots:
void onBrowserUpClicked();
void onBrowserStartClicked();
void initContentTableWidget();
void initContentGridLayout();
void onViewClosedDocksAboutToShow();
void onShowHiddenDockWidgetAction();
void setCoreActions();
@ -288,6 +299,7 @@ private slots:
void onSearchEnterPressed();
void onSearchLineEditEdited(const QString &text);
void addPlaylistItemsToTable(QString path);
void addPlaylistItemsToGrid(QString path);
void onContentItemDoubleClicked(QTableWidgetItem *item);
void onCoreLoadWindowClosed();
void onTabWidgetIndexChanged(int index);
@ -303,6 +315,8 @@ private:
void getPlaylistFiles();
bool isCoreLoaded();
bool isContentLessCore();
void removeGridItems();
QList<QHash<QString, QString> > getPlaylistItems(QString pathString);
LoadCoreWindow *m_loadCoreWindow;
QTimer *m_timer;
@ -344,6 +358,10 @@ private:
QListWidgetItem *m_historyPlaylistsItem;
QIcon m_folderIcon;
QString m_customThemeString;
FlowLayout *m_gridLayout;
QWidget *m_gridWidget;
QScrollArea *m_gridScrollArea;
QList<GridItem*> m_gridItems;
protected:
void closeEvent(QCloseEvent *event);