Skip to content

Commit 80e620b

Browse files
committed
Alternative design
1 parent f4580b0 commit 80e620b

File tree

10 files changed

+976
-664
lines changed

10 files changed

+976
-664
lines changed

frontend/cmake/ui-components.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ target_sources(
3030
components/DisplayCaptureToolbar.cpp
3131
components/DisplayCaptureToolbar.hpp
3232
components/EditWidget.hpp
33+
components/FlowLayout.cpp
34+
components/FlowLayout.hpp
3335
components/FocusList.cpp
3436
components/FocusList.hpp
3537
components/GameCaptureToolbar.cpp
@@ -58,6 +60,8 @@ target_sources(
5860
components/SceneTree.hpp
5961
components/SilentUpdateCheckBox.hpp
6062
components/SilentUpdateSpinBox.hpp
63+
components/SourceSelectButton.cpp
64+
components/SourceSelectButton.hpp
6165
components/SourceToolbar.cpp
6266
components/SourceToolbar.hpp
6367
components/SourceTree.cpp

frontend/components/FlowLayout.cpp

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/******************************************************************************
2+
Example provided by Qt
3+
<https://doc.qt.io/qt-6/qtwidgets-layouts-flowlayout-example.html>
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 2 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
******************************************************************************/
18+
19+
#include "FlowLayout.hpp"
20+
21+
#include <QWidget>
22+
23+
FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
24+
: QLayout(parent),
25+
m_hSpace(hSpacing),
26+
m_vSpace(vSpacing)
27+
{
28+
setContentsMargins(margin, margin, margin, margin);
29+
}
30+
31+
FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing) : m_hSpace(hSpacing), m_vSpace(vSpacing)
32+
{
33+
setContentsMargins(margin, margin, margin, margin);
34+
}
35+
36+
FlowLayout::~FlowLayout()
37+
{
38+
QLayoutItem *item;
39+
while ((item = takeAt(0)))
40+
delete item;
41+
}
42+
43+
void FlowLayout::addItem(QLayoutItem *item)
44+
{
45+
itemList.append(item);
46+
}
47+
48+
int FlowLayout::horizontalSpacing() const
49+
{
50+
if (m_hSpace >= 0) {
51+
return m_hSpace;
52+
} else {
53+
return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
54+
}
55+
}
56+
57+
int FlowLayout::verticalSpacing() const
58+
{
59+
if (m_vSpace >= 0) {
60+
return m_vSpace;
61+
} else {
62+
return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
63+
}
64+
}
65+
66+
int FlowLayout::count() const
67+
{
68+
return itemList.size();
69+
}
70+
71+
QLayoutItem *FlowLayout::itemAt(int index) const
72+
{
73+
return itemList.value(index);
74+
}
75+
76+
QLayoutItem *FlowLayout::takeAt(int index)
77+
{
78+
if (index >= 0 && index < itemList.size())
79+
return itemList.takeAt(index);
80+
return nullptr;
81+
}
82+
83+
Qt::Orientations FlowLayout::expandingDirections() const
84+
{
85+
return {};
86+
}
87+
88+
bool FlowLayout::hasHeightForWidth() const
89+
{
90+
return true;
91+
}
92+
93+
int FlowLayout::heightForWidth(int width) const
94+
{
95+
int height = doLayout(QRect(0, 0, width, 0), true);
96+
return height;
97+
}
98+
99+
void FlowLayout::setGeometry(const QRect &rect)
100+
{
101+
QLayout::setGeometry(rect);
102+
doLayout(rect, false);
103+
}
104+
105+
QSize FlowLayout::sizeHint() const
106+
{
107+
return minimumSize();
108+
}
109+
110+
QSize FlowLayout::minimumSize() const
111+
{
112+
QSize size;
113+
for (const QLayoutItem *item : std::as_const(itemList))
114+
size = size.expandedTo(item->minimumSize());
115+
116+
const QMargins margins = contentsMargins();
117+
size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom());
118+
return size;
119+
}
120+
121+
int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
122+
{
123+
int left, top, right, bottom;
124+
getContentsMargins(&left, &top, &right, &bottom);
125+
QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
126+
int x = effectiveRect.x();
127+
int y = effectiveRect.y();
128+
int lineHeight = 0;
129+
130+
for (QLayoutItem *item : std::as_const(itemList)) {
131+
const QWidget *wid = item->widget();
132+
int spaceX = horizontalSpacing();
133+
if (spaceX == -1)
134+
spaceX = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton,
135+
Qt::Horizontal);
136+
int spaceY = verticalSpacing();
137+
if (spaceY == -1)
138+
spaceY = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton,
139+
Qt::Vertical);
140+
141+
int nextX = x + item->sizeHint().width() + spaceX;
142+
if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
143+
x = effectiveRect.x();
144+
y = y + lineHeight + spaceY;
145+
nextX = x + item->sizeHint().width() + spaceX;
146+
lineHeight = 0;
147+
}
148+
149+
if (!testOnly)
150+
item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
151+
152+
x = nextX;
153+
lineHeight = qMax(lineHeight, item->sizeHint().height());
154+
}
155+
return y + lineHeight - rect.y() + bottom;
156+
}
157+
158+
int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
159+
{
160+
QObject *parent = this->parent();
161+
if (!parent) {
162+
return -1;
163+
} else if (parent->isWidgetType()) {
164+
QWidget *pw = static_cast<QWidget *>(parent);
165+
return pw->style()->pixelMetric(pm, nullptr, pw);
166+
} else {
167+
return static_cast<QLayout *>(parent)->spacing();
168+
}
169+
}

frontend/components/FlowLayout.hpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/******************************************************************************
2+
Example provided by Qt
3+
<https://doc.qt.io/qt-6/qtwidgets-layouts-flowlayout-example.html>
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 2 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
******************************************************************************/
18+
19+
#pragma once
20+
21+
#include <QLayout>
22+
#include <QStyle>
23+
24+
class FlowLayout : public QLayout {
25+
public:
26+
explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
27+
explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
28+
~FlowLayout();
29+
30+
void addItem(QLayoutItem *item) override;
31+
int horizontalSpacing() const;
32+
int verticalSpacing() const;
33+
Qt::Orientations expandingDirections() const override;
34+
bool hasHeightForWidth() const override;
35+
int heightForWidth(int) const override;
36+
int count() const override;
37+
QLayoutItem *itemAt(int index) const override;
38+
QSize minimumSize() const override;
39+
void setGeometry(const QRect &rect) override;
40+
QSize sizeHint() const override;
41+
QLayoutItem *takeAt(int index) override;
42+
43+
private:
44+
int doLayout(const QRect &rect, bool testOnly) const;
45+
int smartSpacing(QStyle::PixelMetric pm) const;
46+
47+
QList<QLayoutItem *> itemList;
48+
int m_hSpace;
49+
int m_vSpace;
50+
};
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/******************************************************************************
2+
Copyright (C) 2025 by Taylor Giampaolo <[email protected]>
3+
4+
This program is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 2 of the License, or
7+
(at your option) any later version.
8+
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
******************************************************************************/
17+
18+
#include "SourceSelectButton.hpp"
19+
20+
#include <QFrame>
21+
#include <QPainter>
22+
#include <QStyleOptionButton>
23+
24+
#include <widgets/OBSBasic.hpp>
25+
26+
SourceSelectButton::SourceSelectButton(obs_source_t *source_, QWidget *parent) : QFrame(parent)
27+
{
28+
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
29+
30+
source = source_;
31+
const char *sourceName = obs_source_get_name(source);
32+
const char *id = obs_source_get_id(source);
33+
34+
uint32_t flags = obs_source_get_output_flags(source);
35+
bool hasVideo = (flags & OBS_SOURCE_VIDEO) == OBS_SOURCE_VIDEO;
36+
37+
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
38+
39+
button = new QPushButton(this);
40+
button->setCheckable(true);
41+
button->setAttribute(Qt::WA_Moved);
42+
button->setAccessibleName(sourceName);
43+
button->show();
44+
45+
layout = new QVBoxLayout();
46+
layout->setContentsMargins(0, 0, 0, 0);
47+
layout->setSpacing(0);
48+
setLayout(layout);
49+
50+
label = new QLabel(sourceName);
51+
label->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred);
52+
label->setAttribute(Qt::WA_TransparentForMouseEvents);
53+
label->setObjectName("name");
54+
55+
if (hasVideo) {
56+
QFrame *thumbnail = new QFrame(this);
57+
// OBSSourceWidget *thumbnail = new OBSSourceWidget(this);
58+
// thumbnail->setSource(source);
59+
thumbnail->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
60+
thumbnail->setAttribute(Qt::WA_TransparentForMouseEvents);
61+
thumbnail->setObjectName("thumbnail");
62+
thumbnail->setMinimumSize(160, 90);
63+
thumbnail->setMaximumSize(160, 90);
64+
65+
layout->addWidget(thumbnail);
66+
} else {
67+
QLabel *thumbnail = new QLabel();
68+
thumbnail->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
69+
thumbnail->setAttribute(Qt::WA_TransparentForMouseEvents);
70+
thumbnail->setObjectName("thumbnail");
71+
thumbnail->setMinimumSize(160, 90);
72+
thumbnail->setMaximumSize(160, 90);
73+
thumbnail->setAlignment(Qt::AlignCenter);
74+
75+
QIcon icon;
76+
icon = main->GetSourceIcon(id);
77+
78+
thumbnail->setPixmap(icon.pixmap(45, 45));
79+
layout->addWidget(thumbnail);
80+
}
81+
82+
layout->addWidget(label);
83+
84+
button->setFixedSize(width(), height());
85+
button->move(0, 0);
86+
}
87+
88+
SourceSelectButton::~SourceSelectButton() {}
89+
90+
QPointer<QPushButton> SourceSelectButton::getButton()
91+
{
92+
return button;
93+
}
94+
95+
QString SourceSelectButton::text()
96+
{
97+
return label->text();
98+
}
99+
100+
void SourceSelectButton::resizeEvent(QResizeEvent *event)
101+
{
102+
button->setFixedSize(width(), height());
103+
button->move(0, 0);
104+
}
105+
106+
void SourceSelectButton::moveEvent(QMoveEvent *event)
107+
{
108+
button->setFixedSize(width(), height());
109+
button->move(0, 0);
110+
}

0 commit comments

Comments
 (0)