mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-03-26 18:32:07 -04:00
frontend: Create AlignmentSelector widget
This commit is contained in:
@@ -144,6 +144,15 @@ UncleanLaunchAction handleUncleanShutdown(bool enableCrashUpload)
|
||||
|
||||
return launchAction;
|
||||
}
|
||||
|
||||
QAccessibleInterface *alignmentSelectorFactory(const QString &classname, QObject *object)
|
||||
{
|
||||
if (classname == QLatin1String("AlignmentSelector")) {
|
||||
if (auto *w = qobject_cast<AlignmentSelector *>(object))
|
||||
return new AccessibleAlignmentSelector(w);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
QObject *CreateShortcutFilter()
|
||||
@@ -1022,6 +1031,8 @@ void OBSApp::AppInit()
|
||||
{
|
||||
ProfileScope("OBSApp::AppInit");
|
||||
|
||||
QAccessible::installFactory(alignmentSelectorFactory);
|
||||
|
||||
if (!MakeUserDirs())
|
||||
throw "Failed to create required user directories";
|
||||
if (!InitGlobalConfig())
|
||||
|
||||
@@ -12,6 +12,12 @@ target_sources(
|
||||
PRIVATE
|
||||
components/AbsoluteSlider.cpp
|
||||
components/AbsoluteSlider.hpp
|
||||
components/AccessibleAlignmentCell.cpp
|
||||
components/AccessibleAlignmentCell.hpp
|
||||
components/AccessibleAlignmentSelector.cpp
|
||||
components/AccessibleAlignmentSelector.hpp
|
||||
components/AlignmentSelector.cpp
|
||||
components/AlignmentSelector.hpp
|
||||
components/ApplicationAudioCaptureToolbar.cpp
|
||||
components/ApplicationAudioCaptureToolbar.hpp
|
||||
components/AudioCaptureToolbar.cpp
|
||||
|
||||
71
frontend/components/AccessibleAlignmentCell.cpp
Normal file
71
frontend/components/AccessibleAlignmentCell.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/******************************************************************************
|
||||
Copyright (C) 2025 by Taylor Giampaolo <warchamp7@obsproject.com>
|
||||
|
||||
This program 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "AccessibleAlignmentCell.hpp"
|
||||
|
||||
#include <OBSApp.hpp>
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
constexpr std::array indexToStrings = {
|
||||
"Basic.TransformWindow.Alignment.TopLeft"sv, "Basic.TransformWindow.Alignment.TopCenter"sv,
|
||||
"Basic.TransformWindow.Alignment.TopRight"sv, "Basic.TransformWindow.Alignment.CenterLeft"sv,
|
||||
"Basic.TransformWindow.Alignment.Center"sv, "Basic.TransformWindow.Alignment.CenterRight"sv,
|
||||
"Basic.TransformWindow.Alignment.BottomLeft"sv, "Basic.TransformWindow.Alignment.BottomCenter"sv,
|
||||
"Basic.TransformWindow.Alignment.BottomRight"sv};
|
||||
|
||||
AccessibleAlignmentCell::AccessibleAlignmentCell(QAccessibleInterface *parent, AlignmentSelector *widget, int index)
|
||||
: parent_(parent),
|
||||
widget(widget),
|
||||
index_(index)
|
||||
{
|
||||
}
|
||||
|
||||
QRect AccessibleAlignmentCell::rect() const
|
||||
{
|
||||
return widget->cellRect(index_);
|
||||
}
|
||||
|
||||
QString AccessibleAlignmentCell::text(QAccessible::Text text) const
|
||||
{
|
||||
if (text == QAccessible::Name || text == QAccessible::Value) {
|
||||
return QString(indexToStrings[index_].data());
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QAccessible::State AccessibleAlignmentCell::state() const
|
||||
{
|
||||
QAccessible::State state;
|
||||
bool enabled = widget->isEnabled();
|
||||
|
||||
bool isSelectedCell = widget->currentIndex() == index_;
|
||||
bool isFocusedCell = widget->focusedCell == index_;
|
||||
|
||||
state.disabled = !enabled;
|
||||
state.focusable = enabled;
|
||||
state.focused = widget->hasFocus() && isFocusedCell;
|
||||
state.checkable = true;
|
||||
state.checked = isSelectedCell;
|
||||
state.selected = isSelectedCell;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
QAccessible::Role AccessibleAlignmentCell::role() const
|
||||
{
|
||||
return QAccessible::CheckBox;
|
||||
}
|
||||
51
frontend/components/AccessibleAlignmentCell.hpp
Normal file
51
frontend/components/AccessibleAlignmentCell.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
/******************************************************************************
|
||||
Copyright (C) 2025 by Taylor Giampaolo <warchamp7@obsproject.com>
|
||||
|
||||
This program 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <components/AlignmentSelector.hpp>
|
||||
|
||||
#include <QAccessibleInterface>
|
||||
#include <QRect>
|
||||
|
||||
class AlignmentSelector;
|
||||
|
||||
class AccessibleAlignmentCell : public QAccessibleInterface {
|
||||
QAccessibleInterface *parent_;
|
||||
AlignmentSelector *widget;
|
||||
int index_;
|
||||
|
||||
public:
|
||||
AccessibleAlignmentCell(QAccessibleInterface *parent, AlignmentSelector *widget, int index);
|
||||
|
||||
int index() const { return index_; }
|
||||
|
||||
QRect rect() const override;
|
||||
QString text(QAccessible::Text t) const override;
|
||||
QAccessible::State state() const override;
|
||||
QAccessible::Role role() const override;
|
||||
|
||||
QObject *object() const override { return nullptr; }
|
||||
QAccessibleInterface *child(int) const override { return nullptr; }
|
||||
QAccessibleInterface *childAt(int, int) const override { return nullptr; }
|
||||
int childCount() const override { return 0; }
|
||||
int indexOfChild(const QAccessibleInterface *) const override { return -1; }
|
||||
QAccessibleInterface *parent() const override { return parent_; }
|
||||
QAccessibleInterface *focusChild() const override { return nullptr; }
|
||||
bool isValid() const override { return widget != nullptr; }
|
||||
void setText(QAccessible::Text, const QString &) override {}
|
||||
};
|
||||
126
frontend/components/AccessibleAlignmentSelector.cpp
Normal file
126
frontend/components/AccessibleAlignmentSelector.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/******************************************************************************
|
||||
Copyright (C) 2025 by Taylor Giampaolo <warchamp7@obsproject.com>
|
||||
|
||||
This program 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "AccessibleAlignmentSelector.hpp"
|
||||
|
||||
#include <OBSApp.hpp>
|
||||
|
||||
AccessibleAlignmentSelector::AccessibleAlignmentSelector(AlignmentSelector *widget_)
|
||||
: QAccessibleWidget(widget_, QAccessible::Grouping)
|
||||
{
|
||||
for (int i = 0; i < cellCount; ++i) {
|
||||
AccessibleAlignmentCell *cell = new AccessibleAlignmentCell(this, widget_, i);
|
||||
QAccessible::registerAccessibleInterface(cell);
|
||||
cellInterfaces.insert(i, QAccessible::uniqueId(cell));
|
||||
}
|
||||
}
|
||||
|
||||
AccessibleAlignmentSelector::~AccessibleAlignmentSelector()
|
||||
{
|
||||
for (QAccessible::Id id : std::as_const(cellInterfaces)) {
|
||||
QAccessible::deleteAccessibleInterface(id);
|
||||
}
|
||||
}
|
||||
|
||||
int AccessibleAlignmentSelector::childCount() const
|
||||
{
|
||||
return cellCount;
|
||||
}
|
||||
|
||||
QAccessibleInterface *AccessibleAlignmentSelector::child(int index) const
|
||||
{
|
||||
if (QAccessible::Id id = cellInterfaces.value(index)) {
|
||||
return QAccessible::accessibleInterface(id);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int AccessibleAlignmentSelector::indexOfChild(const QAccessibleInterface *child) const
|
||||
{
|
||||
if (!child) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
QAccessible::Id id = QAccessible::uniqueId(const_cast<QAccessibleInterface *>(child));
|
||||
return cellInterfaces.key(id, -1);
|
||||
}
|
||||
|
||||
bool AccessibleAlignmentSelector::isValid() const
|
||||
{
|
||||
return widget() != nullptr;
|
||||
}
|
||||
|
||||
QAccessibleInterface *AccessibleAlignmentSelector::focusChild() const
|
||||
{
|
||||
for (int i = 0; i < childCount(); ++i) {
|
||||
if (child(i)->state().focused) {
|
||||
return child(i);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QRect AccessibleAlignmentSelector::rect() const
|
||||
{
|
||||
return widget()->rect();
|
||||
}
|
||||
|
||||
QString AccessibleAlignmentSelector::text(QAccessible::Text textType) const
|
||||
{
|
||||
if (textType == QAccessible::Name) {
|
||||
QString str = widget()->accessibleName();
|
||||
if (str.isEmpty()) {
|
||||
str = QTStr("Accessible.Widget.Name.AlignmentSelector");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
if (textType == QAccessible::Value) {
|
||||
return value().toString();
|
||||
}
|
||||
|
||||
return QAccessibleWidget::text(textType);
|
||||
}
|
||||
|
||||
QAccessible::Role AccessibleAlignmentSelector::role() const
|
||||
{
|
||||
return QAccessible::Grouping;
|
||||
}
|
||||
|
||||
QAccessible::State AccessibleAlignmentSelector::state() const
|
||||
{
|
||||
QAccessible::State state;
|
||||
|
||||
state.focusable = true;
|
||||
state.focused = widget()->hasFocus();
|
||||
state.disabled = !widget()->isEnabled();
|
||||
state.readOnly = false;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
QVariant AccessibleAlignmentSelector::value() const
|
||||
{
|
||||
for (int i = 0; i < childCount(); ++i) {
|
||||
if (child(i)->state().checked) {
|
||||
return child(i)->text(QAccessible::Name);
|
||||
}
|
||||
}
|
||||
|
||||
return QTStr("None");
|
||||
}
|
||||
47
frontend/components/AccessibleAlignmentSelector.hpp
Normal file
47
frontend/components/AccessibleAlignmentSelector.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/******************************************************************************
|
||||
Copyright (C) 2025 by Taylor Giampaolo <warchamp7@obsproject.com>
|
||||
|
||||
This program 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <components/AccessibleAlignmentCell.hpp>
|
||||
|
||||
#include <QAccessible>
|
||||
#include <QAccessibleInterface>
|
||||
#include <QAccessibleWidget>
|
||||
|
||||
class AlignmentSelector;
|
||||
|
||||
class AccessibleAlignmentSelector : public QAccessibleWidget {
|
||||
mutable QHash<int, QAccessible::Id> cellInterfaces{};
|
||||
static constexpr int cellCount = 9;
|
||||
|
||||
public:
|
||||
explicit AccessibleAlignmentSelector(AlignmentSelector *widget);
|
||||
~AccessibleAlignmentSelector();
|
||||
|
||||
QRect rect() const override;
|
||||
QAccessible::Role role() const override;
|
||||
QAccessible::State state() const override;
|
||||
QString text(QAccessible::Text t) const override;
|
||||
QAccessibleInterface *child(int index) const override;
|
||||
int childCount() const override;
|
||||
int indexOfChild(const QAccessibleInterface *child) const override;
|
||||
bool isValid() const override;
|
||||
QAccessibleInterface *focusChild() const override;
|
||||
|
||||
QVariant value() const;
|
||||
};
|
||||
324
frontend/components/AlignmentSelector.cpp
Normal file
324
frontend/components/AlignmentSelector.cpp
Normal file
@@ -0,0 +1,324 @@
|
||||
/******************************************************************************
|
||||
Copyright (C) 2025 by Taylor Giampaolo <warchamp7@obsproject.com>
|
||||
|
||||
This program 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "AlignmentSelector.hpp"
|
||||
|
||||
#include <util/base.h>
|
||||
|
||||
#include <QAccessible>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionButton>
|
||||
|
||||
AlignmentSelector::AlignmentSelector(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
setMouseTracking(true);
|
||||
setAttribute(Qt::WA_Hover);
|
||||
}
|
||||
|
||||
QSize AlignmentSelector::sizeHint() const
|
||||
{
|
||||
int base = fontMetrics().height() * 2;
|
||||
return QSize(base, base);
|
||||
}
|
||||
|
||||
QSize AlignmentSelector::minimumSizeHint() const
|
||||
{
|
||||
return QSize(16, 16);
|
||||
}
|
||||
|
||||
Qt::Alignment AlignmentSelector::value() const
|
||||
{
|
||||
return cellAlignment(selectedCell);
|
||||
}
|
||||
|
||||
int AlignmentSelector::currentIndex() const
|
||||
{
|
||||
return selectedCell;
|
||||
}
|
||||
|
||||
void AlignmentSelector::setAlignment(Qt::Alignment value)
|
||||
{
|
||||
alignment = value;
|
||||
}
|
||||
|
||||
void AlignmentSelector::setCurrentIndex(int index)
|
||||
{
|
||||
selectCell(index);
|
||||
}
|
||||
|
||||
void AlignmentSelector::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter painter(this);
|
||||
QStyle *style = this->style();
|
||||
|
||||
int cellW = gridRect().width() / 3;
|
||||
int cellH = gridRect().height() / 3;
|
||||
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
QRect rect = cellRect(i);
|
||||
rect = rect.adjusted(0, 0, -1, -1);
|
||||
|
||||
QStyleOptionFrame frameOpt;
|
||||
frameOpt.rect = rect;
|
||||
frameOpt.state = isEnabled() ? QStyle::State_Enabled : QStyle::State_None;
|
||||
frameOpt.lineWidth = 1;
|
||||
frameOpt.midLineWidth = 0;
|
||||
if (i == hoveredCell) {
|
||||
frameOpt.state |= QStyle::State_MouseOver;
|
||||
}
|
||||
if (i == selectedCell) {
|
||||
frameOpt.state |= QStyle::State_On;
|
||||
}
|
||||
if (i == focusedCell && hasFocus()) {
|
||||
frameOpt.state |= QStyle::State_HasFocus;
|
||||
}
|
||||
|
||||
QStyleOptionButton radioOpt;
|
||||
radioOpt.state = isEnabled() ? QStyle::State_Enabled : QStyle::State_None;
|
||||
radioOpt.rect = rect.adjusted(cellW / 6, cellH / 6, -cellW / 6, -cellH / 6);
|
||||
if (i == hoveredCell) {
|
||||
radioOpt.state |= QStyle::State_MouseOver;
|
||||
}
|
||||
if (i == selectedCell) {
|
||||
radioOpt.state |= QStyle::State_On;
|
||||
}
|
||||
|
||||
if (i == focusedCell && hasFocus()) {
|
||||
radioOpt.state |= QStyle::State_HasFocus;
|
||||
}
|
||||
style->drawPrimitive(QStyle::PE_IndicatorRadioButton, &radioOpt, &painter, this);
|
||||
|
||||
style->drawPrimitive(QStyle::PE_Frame, &frameOpt, &painter, this);
|
||||
|
||||
if (i == focusedCell && hasFocus()) {
|
||||
QStyleOptionFocusRect focusOpt;
|
||||
focusOpt.initFrom(this);
|
||||
focusOpt.rect = rect.adjusted(1, 1, -1, -1);
|
||||
focusOpt.state = isEnabled() ? QStyle::State_Enabled : QStyle::State_None;
|
||||
focusOpt.state |= QStyle::State_HasFocus;
|
||||
style->drawPrimitive(QStyle::PE_FrameFocusRect, &focusOpt, &painter, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QRect AlignmentSelector::cellRect(int index) const
|
||||
{
|
||||
int col = index % 3;
|
||||
int row = index / 3;
|
||||
|
||||
QRect gridRect = this->gridRect();
|
||||
int cellW = gridRect.width() / 3;
|
||||
int cellH = gridRect.height() / 3;
|
||||
|
||||
return QRect(col * cellW + gridRect.left(), row * cellH + gridRect.top(), cellW, cellH);
|
||||
}
|
||||
|
||||
Qt::Alignment AlignmentSelector::cellAlignment(int index) const
|
||||
{
|
||||
Qt::Alignment hAlign;
|
||||
Qt::Alignment vAlign;
|
||||
|
||||
switch (index % 3) {
|
||||
case 0:
|
||||
hAlign = Qt::AlignLeft;
|
||||
break;
|
||||
case 1:
|
||||
hAlign = Qt::AlignHCenter;
|
||||
break;
|
||||
case 2:
|
||||
hAlign = Qt::AlignRight;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (index / 3) {
|
||||
case 0:
|
||||
vAlign = Qt::AlignTop;
|
||||
break;
|
||||
case 1:
|
||||
vAlign = Qt::AlignVCenter;
|
||||
break;
|
||||
case 2:
|
||||
vAlign = Qt::AlignBottom;
|
||||
break;
|
||||
}
|
||||
|
||||
return hAlign | vAlign;
|
||||
}
|
||||
|
||||
void AlignmentSelector::leaveEvent(QEvent *)
|
||||
{
|
||||
hoveredCell = -1;
|
||||
update();
|
||||
}
|
||||
|
||||
void AlignmentSelector::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
QRect grid = gridRect();
|
||||
int cellW = grid.width() / 3;
|
||||
int cellH = grid.height() / 3;
|
||||
|
||||
QPoint pos = event->position().toPoint();
|
||||
if (!grid.contains(pos)) {
|
||||
hoveredCell = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
int col = (pos.x() - grid.left()) / cellW;
|
||||
int row = (pos.y() - grid.top()) / cellH;
|
||||
int cell = row * 3 + col;
|
||||
|
||||
if (hoveredCell != cell) {
|
||||
hoveredCell = cell;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void AlignmentSelector::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
QRect grid = gridRect();
|
||||
int cellW = grid.width() / 3;
|
||||
int cellH = grid.height() / 3;
|
||||
|
||||
QPoint pos = event->position().toPoint();
|
||||
if (!grid.contains(pos)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int col = (pos.x() - grid.left()) / cellW;
|
||||
int row = (pos.y() - grid.top()) / cellH;
|
||||
int cell = row * 3 + col;
|
||||
|
||||
selectCell(cell);
|
||||
}
|
||||
|
||||
void AlignmentSelector::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
int moveX = 0;
|
||||
int moveY = 0;
|
||||
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Left:
|
||||
moveX = -1;
|
||||
break;
|
||||
case Qt::Key_Right:
|
||||
moveX = 1;
|
||||
break;
|
||||
case Qt::Key_Up:
|
||||
moveY = -1;
|
||||
break;
|
||||
case Qt::Key_Down:
|
||||
moveY = 1;
|
||||
break;
|
||||
case Qt::Key_Space:
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter:
|
||||
selectCell(focusedCell);
|
||||
return;
|
||||
default:
|
||||
QWidget::keyPressEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
moveFocusedCell(moveX, moveY);
|
||||
}
|
||||
|
||||
QRect AlignmentSelector::gridRect() const
|
||||
{
|
||||
int side = std::min(width(), height());
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
if (alignment & Qt::AlignHCenter) {
|
||||
x = (width() - side) / 2;
|
||||
} else if (alignment & Qt::AlignRight) {
|
||||
x = width() - side;
|
||||
}
|
||||
|
||||
if (alignment & Qt::AlignVCenter) {
|
||||
y = (height() - side) / 2;
|
||||
} else if (alignment & Qt::AlignBottom) {
|
||||
y = height() - side;
|
||||
}
|
||||
|
||||
return QRect(x, y, side, side);
|
||||
}
|
||||
|
||||
void AlignmentSelector::moveFocusedCell(int moveX, int moveY)
|
||||
{
|
||||
int row = focusedCell / 3;
|
||||
int col = focusedCell % 3;
|
||||
|
||||
row = std::clamp(row + moveY, 0, 2);
|
||||
col = std::clamp(col + moveX, 0, 2);
|
||||
|
||||
int newCell = row * 3 + col;
|
||||
setFocusedCell(newCell);
|
||||
}
|
||||
|
||||
void AlignmentSelector::setFocusedCell(int cell)
|
||||
{
|
||||
if (cell != focusedCell) {
|
||||
focusedCell = cell;
|
||||
update();
|
||||
|
||||
if (AccessibleAlignmentSelector *interface =
|
||||
dynamic_cast<AccessibleAlignmentSelector *>(QAccessible::queryAccessibleInterface(this))) {
|
||||
if (QAccessibleInterface *child = interface->child(cell)) {
|
||||
QAccessibleEvent event(child, QAccessible::Focus);
|
||||
QAccessible::updateAccessibility(&event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AlignmentSelector::selectCell(int cell)
|
||||
{
|
||||
setFocusedCell(cell);
|
||||
if (cell != selectedCell) {
|
||||
selectedCell = cell;
|
||||
|
||||
emit valueChanged(cellAlignment(cell));
|
||||
emit currentIndexChanged(cell);
|
||||
}
|
||||
update();
|
||||
|
||||
if (AccessibleAlignmentSelector *interface =
|
||||
dynamic_cast<AccessibleAlignmentSelector *>(QAccessible::queryAccessibleInterface(this))) {
|
||||
if (QAccessibleInterface *child = interface->child(cell)) {
|
||||
QAccessible::State state;
|
||||
state.checked = true;
|
||||
|
||||
QAccessibleStateChangeEvent event(child, state);
|
||||
QAccessible::updateAccessibility(&event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AlignmentSelector::focusInEvent(QFocusEvent *)
|
||||
{
|
||||
setFocusedCell(selectedCell);
|
||||
update();
|
||||
}
|
||||
|
||||
void AlignmentSelector::focusOutEvent(QFocusEvent *)
|
||||
{
|
||||
hoveredCell = -1;
|
||||
setFocusedCell(-1);
|
||||
update();
|
||||
}
|
||||
71
frontend/components/AlignmentSelector.hpp
Normal file
71
frontend/components/AlignmentSelector.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/******************************************************************************
|
||||
Copyright (C) 2025 by Taylor Giampaolo <warchamp7@obsproject.com>
|
||||
|
||||
This program 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <components/AccessibleAlignmentSelector.hpp>
|
||||
|
||||
#include <QFocusEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QWidget>
|
||||
|
||||
class AlignmentSelector : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
friend class AccessibleAlignmentSelector;
|
||||
friend class AccessibleAlignmentCell;
|
||||
|
||||
public:
|
||||
explicit AlignmentSelector(QWidget *parent = nullptr);
|
||||
|
||||
QSize sizeHint() const override;
|
||||
QSize minimumSizeHint() const override;
|
||||
Qt::Alignment value() const;
|
||||
int currentIndex() const;
|
||||
|
||||
void setAlignment(Qt::Alignment alignment);
|
||||
void setCurrentIndex(int index);
|
||||
|
||||
signals:
|
||||
void valueChanged(Qt::Alignment value);
|
||||
void currentIndexChanged(int value);
|
||||
|
||||
protected:
|
||||
QRect cellRect(int index) const;
|
||||
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void focusInEvent(QFocusEvent *event) override;
|
||||
void focusOutEvent(QFocusEvent *event) override;
|
||||
|
||||
private:
|
||||
Qt::Alignment alignment = Qt::AlignTop | Qt::AlignLeft;
|
||||
|
||||
int hoveredCell = -1;
|
||||
int focusedCell = 4;
|
||||
int selectedCell = 4;
|
||||
|
||||
QRect gridRect() const;
|
||||
|
||||
void moveFocusedCell(int moveX, int moveY);
|
||||
void setFocusedCell(int cell);
|
||||
void selectCell(int cell);
|
||||
Qt::Alignment cellAlignment(int index) const;
|
||||
};
|
||||
@@ -2513,3 +2513,43 @@ idian--RowFrame.hover .row-buddy {
|
||||
idian--RowFrame.hover idian--ExpandButton::indicator {
|
||||
border-color: var(--grey1);
|
||||
}
|
||||
|
||||
AlignmentSelector {
|
||||
border: 1px solid var(--input_border);
|
||||
margin: 0px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
AlignmentSelector:focus,
|
||||
AlignmentSelector:hover {
|
||||
border: 1px solid var(--white3);
|
||||
}
|
||||
|
||||
AlignmentSelector:checked:hover {
|
||||
border: 1px solid var(--primary_lighter);
|
||||
}
|
||||
|
||||
AlignmentSelector::indicator {
|
||||
margin: 0px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
AlignmentSelector::indicator:checked {
|
||||
background: var(--primary);
|
||||
}
|
||||
|
||||
AlignmentSelector::indicator:checked:focus {
|
||||
background: var(--primary_light);
|
||||
}
|
||||
|
||||
AlignmentSelector:disabled {
|
||||
border: 1px solid var(--grey3);
|
||||
}
|
||||
|
||||
AlignmentSelector::indicator:disabled {
|
||||
background: var(--grey5);
|
||||
}
|
||||
|
||||
AlignmentSelector::indicator:checked:disabled {
|
||||
background: var(--grey3);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "OBSMainWindow.hpp"
|
||||
|
||||
#include <OBSApp.hpp>
|
||||
#include <components/AccessibleAlignmentSelector.hpp>
|
||||
#include <oauth/Auth.hpp>
|
||||
#include <utility/BasicOutputHandler.hpp>
|
||||
#include <utility/OBSCanvas.hpp>
|
||||
@@ -38,6 +39,7 @@
|
||||
#include <util/threading.h>
|
||||
#include <util/util.hpp>
|
||||
|
||||
#include <QAccessible>
|
||||
#include <QSystemTrayIcon>
|
||||
|
||||
#include <deque>
|
||||
|
||||
Reference in New Issue
Block a user