665 lines
20 KiB
C++
665 lines
20 KiB
C++
// src/CommonWidgets.cpp
|
|
|
|
#include "CommonWidgets.h"
|
|
#include "Theme.h"
|
|
#include <QBoxLayout>
|
|
#include <QFileInfo>
|
|
#include <QHBoxLayout>
|
|
#include <QListWidget>
|
|
#include <QMouseEvent>
|
|
#include <QPainter>
|
|
#include <QPropertyAnimation>
|
|
#include <QPushButton>
|
|
#include <QResizeEvent>
|
|
#include <QScrollArea>
|
|
#include <QShowEvent>
|
|
#include <QVBoxLayout>
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
// --- TouchSlider ---
|
|
|
|
TouchSlider::TouchSlider(QWidget *parent) : QWidget(parent) {
|
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
|
setFixedHeight(Theme::Dims::SliderHeight);
|
|
}
|
|
|
|
void TouchSlider::setRange(int min, int max) {
|
|
m_min = min;
|
|
m_max = max;
|
|
m_value = std::clamp(m_value, m_min, m_max);
|
|
update();
|
|
}
|
|
|
|
void TouchSlider::setValue(int val) {
|
|
val = std::clamp(val, m_min, m_max);
|
|
if (val == m_value) return;
|
|
m_value = val;
|
|
update();
|
|
emit valueChanged(m_value);
|
|
}
|
|
|
|
QSize TouchSlider::sizeHint() const {
|
|
return QSize(200, Theme::Dims::SliderHeight);
|
|
}
|
|
|
|
int TouchSlider::trackLeft() const { return Theme::Dims::TrackPad; }
|
|
int TouchSlider::trackRight() const { return width() - Theme::Dims::TrackPad; }
|
|
|
|
int TouchSlider::handleX() const {
|
|
if (m_max == m_min) return trackLeft();
|
|
float frac = float(m_value - m_min) / float(m_max - m_min);
|
|
return trackLeft() + frac * (trackRight() - trackLeft());
|
|
}
|
|
|
|
void TouchSlider::paintEvent(QPaintEvent *) {
|
|
QPainter p(this);
|
|
p.setRenderHint(QPainter::Antialiasing);
|
|
|
|
int cy = height() / 2;
|
|
int tl = trackLeft();
|
|
int tr = trackRight();
|
|
int hx = handleX();
|
|
int hh = Theme::Dims::TrackH / 2;
|
|
|
|
p.setPen(Qt::NoPen);
|
|
p.setBrush(Theme::Colors::TrackBg);
|
|
p.drawRoundedRect(QRectF(tl, cy - hh, tr - tl, Theme::Dims::TrackH), hh, hh);
|
|
|
|
p.setBrush(Theme::Colors::Accent);
|
|
if (hx > tl)
|
|
p.drawRoundedRect(QRectF(tl, cy - hh, hx - tl, Theme::Dims::TrackH), hh, hh);
|
|
|
|
p.setBrush(Qt::white);
|
|
p.drawEllipse(QPointF(hx, cy), Theme::Dims::HandleRadius,
|
|
Theme::Dims::HandleRadius);
|
|
}
|
|
|
|
void TouchSlider::mousePressEvent(QMouseEvent *event) {
|
|
int hx = handleX();
|
|
int dx = event->pos().x() - hx;
|
|
int dy = event->pos().y() - height() / 2;
|
|
int hr = Theme::Dims::HitRadius;
|
|
if (dx * dx + dy * dy <= hr * hr) {
|
|
m_dragging = true;
|
|
emit sliderPressed();
|
|
}
|
|
}
|
|
|
|
void TouchSlider::mouseMoveEvent(QMouseEvent *event) {
|
|
if (!m_dragging) return;
|
|
int tl = trackLeft();
|
|
int tr = trackRight();
|
|
float frac = float(event->pos().x() - tl) / float(tr - tl);
|
|
frac = std::clamp(frac, 0.0f, 1.0f);
|
|
int newVal = m_min + frac * (m_max - m_min);
|
|
if (newVal != m_value) {
|
|
m_value = newVal;
|
|
update();
|
|
emit valueChanged(m_value);
|
|
}
|
|
}
|
|
|
|
void TouchSlider::mouseReleaseEvent(QMouseEvent *) {
|
|
if (m_dragging) {
|
|
m_dragging = false;
|
|
emit sliderReleased();
|
|
}
|
|
}
|
|
|
|
// --- ToggleSwitch ---
|
|
|
|
ToggleSwitch::ToggleSwitch(const QString &label, QWidget *parent)
|
|
: QWidget(parent), m_label(label) {
|
|
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
|
setFixedHeight(Theme::Dims::ToggleRow);
|
|
setCursor(Qt::PointingHandCursor);
|
|
}
|
|
|
|
void ToggleSwitch::setChecked(bool checked) {
|
|
if (m_checked == checked) return;
|
|
m_checked = checked;
|
|
|
|
if (m_anim) m_anim->stop();
|
|
m_anim = new QPropertyAnimation(this, "knobX", this);
|
|
connect(m_anim, &QObject::destroyed, this, [this]() { m_anim = nullptr; });
|
|
m_anim->setDuration(150);
|
|
m_anim->setStartValue(m_knobX);
|
|
m_anim->setEndValue(checked ? 1.0f : 0.0f);
|
|
m_anim->start(QAbstractAnimation::DeleteWhenStopped);
|
|
|
|
emit toggled(checked);
|
|
}
|
|
|
|
void ToggleSwitch::setKnobX(float x) {
|
|
m_knobX = x;
|
|
update();
|
|
}
|
|
|
|
QSize ToggleSwitch::sizeHint() const {
|
|
QFontMetrics fm(font());
|
|
int textW = m_label.isEmpty() ? 0 : fm.horizontalAdvance(m_label) + 8;
|
|
return QSize(Theme::Dims::ToggleW + textW, Theme::Dims::ToggleRow);
|
|
}
|
|
|
|
void ToggleSwitch::paintEvent(QPaintEvent *) {
|
|
QPainter p(this);
|
|
p.setRenderHint(QPainter::Antialiasing);
|
|
|
|
constexpr int tw = Theme::Dims::ToggleW;
|
|
constexpr int th = Theme::Dims::ToggleH;
|
|
constexpr int kd = Theme::Dims::ToggleKnob;
|
|
constexpr int pad = 2;
|
|
|
|
int ty = (height() - th) / 2;
|
|
|
|
auto off = Theme::Colors::TrackOff;
|
|
auto on = Theme::Colors::Accent;
|
|
QColor trackColor = QColor::fromRgbF(
|
|
off.redF() + (on.redF() - off.redF()) * m_knobX,
|
|
off.greenF() + (on.greenF() - off.greenF()) * m_knobX,
|
|
off.blueF() + (on.blueF() - off.blueF()) * m_knobX);
|
|
p.setPen(Qt::NoPen);
|
|
p.setBrush(trackColor);
|
|
p.drawRoundedRect(QRectF(0, ty, tw, th), th / 2.0, th / 2.0);
|
|
|
|
float knobLeft = pad + m_knobX * (tw - kd - 2 * pad);
|
|
float knobCX = knobLeft + kd / 2.0;
|
|
float knobCY = ty + th / 2.0;
|
|
p.setBrush(Qt::white);
|
|
p.drawEllipse(QPointF(knobCX, knobCY), kd / 2.0, kd / 2.0);
|
|
|
|
if (!m_label.isEmpty()) {
|
|
p.setPen(Qt::white);
|
|
QFont f = font();
|
|
f.setPointSize(13);
|
|
p.setFont(f);
|
|
p.drawText(QRectF(tw + 8, 0, width() - tw - 8, height()),
|
|
Qt::AlignLeft | Qt::AlignVCenter, m_label);
|
|
}
|
|
}
|
|
|
|
void ToggleSwitch::mousePressEvent(QMouseEvent *) { setChecked(!m_checked); }
|
|
|
|
// --- PlaylistDelegate ---
|
|
|
|
void PlaylistDelegate::paint(QPainter *painter,
|
|
const QStyleOptionViewItem &option,
|
|
const QModelIndex &index) const {
|
|
painter->save();
|
|
painter->setRenderHint(QPainter::Antialiasing);
|
|
|
|
if (option.state & QStyle::State_Selected)
|
|
painter->fillRect(option.rect, Theme::Colors::ListSelected);
|
|
else
|
|
painter->fillRect(option.rect, Theme::Colors::SurfaceDark);
|
|
|
|
QRect r = option.rect.adjusted(Theme::Dims::ListPad, Theme::Dims::ListPad,
|
|
-Theme::Dims::ListPad, -Theme::Dims::ListPad);
|
|
|
|
constexpr int iconSize = Theme::Dims::ListIcon;
|
|
QPixmap art = index.data(Qt::DecorationRole).value<QPixmap>();
|
|
QRect iconRect(r.left(), r.top(), iconSize, iconSize);
|
|
|
|
if (!art.isNull()) {
|
|
int x = iconRect.x() + (iconRect.width() - art.width()) / 2;
|
|
int y = iconRect.y() + (iconRect.height() - art.height()) / 2;
|
|
painter->drawPixmap(x, y, art);
|
|
} else {
|
|
painter->fillRect(iconRect, Theme::Colors::AlbumArtPlaceholder);
|
|
}
|
|
|
|
QRect textRect = r.adjusted(iconSize + 10, 0, 0, 0);
|
|
QString title = index.data(Qt::DisplayRole).toString();
|
|
QString artist = index.data(Qt::UserRole + 1).toString();
|
|
|
|
painter->setPen(Theme::Colors::TextPrimary);
|
|
QFont f = option.font;
|
|
f.setBold(true);
|
|
f.setPointSize(Theme::Dims::ListTitlePt);
|
|
painter->setFont(f);
|
|
|
|
QFontMetrics fmTitle(f);
|
|
QRect titleRect = textRect;
|
|
titleRect.setHeight(fmTitle.height());
|
|
|
|
QString elidedTitle =
|
|
fmTitle.elidedText(title, Qt::ElideRight, titleRect.width());
|
|
painter->drawText(titleRect, Qt::AlignLeft | Qt::AlignTop, elidedTitle);
|
|
|
|
painter->setPen(Theme::Colors::TextSecondary);
|
|
f.setBold(false);
|
|
f.setPointSize(Theme::Dims::ListArtistPt);
|
|
painter->setFont(f);
|
|
|
|
QFontMetrics fmArtist(f);
|
|
QRect artistRect = textRect;
|
|
artistRect.setTop(titleRect.bottom() + 2);
|
|
artistRect.setHeight(fmArtist.height());
|
|
|
|
QString elidedArtist =
|
|
fmArtist.elidedText(artist, Qt::ElideRight, artistRect.width());
|
|
painter->drawText(artistRect, Qt::AlignLeft | Qt::AlignTop, elidedArtist);
|
|
|
|
painter->setPen(Theme::Colors::ListSeparator);
|
|
painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
|
|
|
|
painter->restore();
|
|
}
|
|
|
|
QSize PlaylistDelegate::sizeHint(const QStyleOptionViewItem &,
|
|
const QModelIndex &) const {
|
|
return QSize(0, Theme::Dims::ListRow);
|
|
}
|
|
|
|
// --- XYPad ---
|
|
|
|
XYPad::XYPad(const QString &title, QWidget *parent)
|
|
: QWidget(parent), m_title(title) {
|
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
setMinimumHeight(Theme::Dims::XYMinH);
|
|
setCursor(Qt::CrossCursor);
|
|
}
|
|
|
|
void XYPad::setFormatter(std::function<QString(float, float)> formatter) {
|
|
m_formatter = formatter;
|
|
}
|
|
|
|
void XYPad::setValues(float x, float y) {
|
|
m_x = std::clamp(x, 0.0f, 1.0f);
|
|
m_y = std::clamp(y, 0.0f, 1.0f);
|
|
update();
|
|
}
|
|
|
|
void XYPad::paintEvent(QPaintEvent *) {
|
|
QPainter p(this);
|
|
p.setRenderHint(QPainter::Antialiasing);
|
|
|
|
p.fillRect(rect(), Theme::Colors::XYBg);
|
|
p.setPen(QPen(Theme::Colors::XYBorder, 1));
|
|
p.drawRect(rect().adjusted(0, 0, -1, -1));
|
|
|
|
p.setPen(QPen(Theme::Colors::XYGrid, 1, Qt::DotLine));
|
|
p.drawLine(width() / 2, 0, width() / 2, height());
|
|
p.drawLine(0, height() / 2, width(), height() / 2);
|
|
|
|
int px = m_x * width();
|
|
int py = (1.0f - m_y) * height();
|
|
|
|
p.setPen(Qt::NoPen);
|
|
p.setBrush(Theme::Colors::XYAccentDim);
|
|
p.drawEllipse(QPoint(px, py), Theme::Dims::XYIndicator,
|
|
Theme::Dims::XYIndicator);
|
|
p.setBrush(Qt::white);
|
|
p.drawEllipse(QPoint(px, py), Theme::Dims::XYInner, Theme::Dims::XYInner);
|
|
|
|
p.setPen(QPen(Theme::Colors::XYAccentFaint, 1));
|
|
p.drawLine(px, 0, px, height());
|
|
p.drawLine(0, py, width(), py);
|
|
|
|
p.setPen(Qt::white);
|
|
QFont f = font();
|
|
f.setBold(true);
|
|
f.setPointSize(10);
|
|
p.setFont(f);
|
|
|
|
QString text = m_title;
|
|
if (m_formatter)
|
|
text += "\n" + m_formatter(m_x, m_y);
|
|
p.drawText(rect().adjusted(10, 10, -10, -10), Qt::AlignLeft | Qt::AlignTop,
|
|
text);
|
|
}
|
|
|
|
void XYPad::mousePressEvent(QMouseEvent *event) {
|
|
int px = m_x * width();
|
|
int py = (1.0f - m_y) * height();
|
|
QPoint diff = event->pos() - QPoint(px, py);
|
|
int hr = Theme::Dims::HitRadius;
|
|
if (diff.x() * diff.x() + diff.y() * diff.y() <= hr * hr) {
|
|
m_dragging = true;
|
|
m_lastPos = event->pos();
|
|
}
|
|
}
|
|
|
|
void XYPad::mouseMoveEvent(QMouseEvent *event) {
|
|
if (!m_dragging) return;
|
|
QPoint delta = event->pos() - m_lastPos;
|
|
m_lastPos = event->pos();
|
|
m_x = std::clamp(m_x + delta.x() * 0.7f / width(), 0.0f, 1.0f);
|
|
m_y = std::clamp(m_y - delta.y() * 0.7f / height(), 0.0f, 1.0f);
|
|
update();
|
|
emit valuesChanged(m_x, m_y);
|
|
}
|
|
|
|
void XYPad::mouseReleaseEvent(QMouseEvent *) { m_dragging = false; }
|
|
|
|
// --- ExpandedXYPad ---
|
|
|
|
ExpandedXYPad::ExpandedXYPad(QWidget *parent) : QWidget(parent) {
|
|
hide();
|
|
}
|
|
|
|
void ExpandedXYPad::open(const QString &title,
|
|
std::function<QString(float, float)> formatter,
|
|
float x, float y) {
|
|
m_title = title;
|
|
m_formatter = formatter;
|
|
m_x = x;
|
|
m_y = y;
|
|
m_dragging = false;
|
|
raise();
|
|
show();
|
|
update();
|
|
}
|
|
|
|
QRect ExpandedXYPad::padRect() const {
|
|
int side = std::min(width(), height()) * 85 / 100;
|
|
int cx = (width() - side) / 2;
|
|
int cy = (height() - side) / 2;
|
|
return QRect(cx, cy, side, side);
|
|
}
|
|
|
|
void ExpandedXYPad::paintEvent(QPaintEvent *) {
|
|
QPainter p(this);
|
|
p.setRenderHint(QPainter::Antialiasing);
|
|
|
|
p.fillRect(rect(), m_dragging ? Theme::Colors::ExpandedXYBgDragging
|
|
: Theme::Colors::ExpandedXYBg);
|
|
|
|
QRect pr = padRect();
|
|
|
|
p.fillRect(pr, Theme::Colors::XYBg);
|
|
p.setPen(QPen(Theme::Colors::XYBorder, 1));
|
|
p.drawRect(pr.adjusted(0, 0, -1, -1));
|
|
|
|
p.setPen(QPen(Theme::Colors::XYGrid, 1, Qt::DotLine));
|
|
p.drawLine(pr.center().x(), pr.top(), pr.center().x(), pr.bottom());
|
|
p.drawLine(pr.left(), pr.center().y(), pr.right(), pr.center().y());
|
|
|
|
int px = pr.left() + m_x * pr.width();
|
|
int py = pr.top() + (1.0f - m_y) * pr.height();
|
|
|
|
p.setPen(Qt::NoPen);
|
|
p.setBrush(Theme::Colors::XYAccentDim);
|
|
p.drawEllipse(QPoint(px, py), Theme::Dims::XYIndicator,
|
|
Theme::Dims::XYIndicator);
|
|
p.setBrush(Qt::white);
|
|
p.drawEllipse(QPoint(px, py), Theme::Dims::XYInner, Theme::Dims::XYInner);
|
|
|
|
p.setPen(QPen(Theme::Colors::XYAccentFaint, 1));
|
|
p.drawLine(px, pr.top(), px, pr.bottom());
|
|
p.drawLine(pr.left(), py, pr.right(), py);
|
|
|
|
p.setPen(Qt::white);
|
|
QFont f = font();
|
|
f.setBold(true);
|
|
f.setPointSize(12);
|
|
p.setFont(f);
|
|
|
|
QString text = m_title;
|
|
if (m_formatter)
|
|
text += "\n" + m_formatter(m_x, m_y);
|
|
p.drawText(pr.adjusted(10, 10, -10, -10), Qt::AlignLeft | Qt::AlignTop, text);
|
|
}
|
|
|
|
void ExpandedXYPad::mousePressEvent(QMouseEvent *event) {
|
|
QRect pr = padRect();
|
|
int hr = Theme::Dims::HitRadius;
|
|
|
|
int px = pr.left() + m_x * pr.width();
|
|
int py = pr.top() + (1.0f - m_y) * pr.height();
|
|
QPoint diff = event->pos() - QPoint(px, py);
|
|
if (diff.x() * diff.x() + diff.y() * diff.y() <= hr * hr) {
|
|
m_dragging = true;
|
|
m_lastPos = event->pos();
|
|
update();
|
|
return;
|
|
}
|
|
|
|
QRect cushion = pr.adjusted(-hr, -hr, hr, hr);
|
|
if (!cushion.contains(event->pos())) {
|
|
hide();
|
|
emit closed();
|
|
}
|
|
}
|
|
|
|
void ExpandedXYPad::mouseMoveEvent(QMouseEvent *event) {
|
|
if (!m_dragging) return;
|
|
QRect pr = padRect();
|
|
QPoint delta = event->pos() - m_lastPos;
|
|
m_lastPos = event->pos();
|
|
m_x = std::clamp(m_x + delta.x() * 0.7f / pr.width(), 0.0f, 1.0f);
|
|
m_y = std::clamp(m_y - delta.y() * 0.7f / pr.height(), 0.0f, 1.0f);
|
|
update();
|
|
emit valuesChanged(m_x, m_y);
|
|
}
|
|
|
|
void ExpandedXYPad::mouseReleaseEvent(QMouseEvent *) {
|
|
m_dragging = false;
|
|
update();
|
|
}
|
|
|
|
// --- OverlayWidget ---
|
|
|
|
OverlayWidget::OverlayWidget(QWidget *content, QWidget *parent)
|
|
: QWidget(parent) {
|
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
|
layout->setAlignment(Qt::AlignCenter);
|
|
layout->setContentsMargins(20, 20, 20, 20);
|
|
|
|
QScrollArea *scroll = new QScrollArea(this);
|
|
scroll->setWidget(content);
|
|
scroll->setWidgetResizable(true);
|
|
scroll->setFrameShape(QFrame::NoFrame);
|
|
scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
scroll->setMaximumWidth(500);
|
|
scroll->setStyleSheet(
|
|
"QScrollArea { background: transparent; border: none; }"
|
|
"QScrollArea > QWidget > QWidget { background: transparent; }");
|
|
scroll->viewport()->setStyleSheet("background: transparent;");
|
|
|
|
m_content = scroll;
|
|
layout->addWidget(scroll);
|
|
hide();
|
|
}
|
|
|
|
void OverlayWidget::showEvent(QShowEvent *event) {
|
|
QWidget::showEvent(event);
|
|
if constexpr (Theme::FrostedGlass) {
|
|
if (auto *w = window()) {
|
|
QPixmap shot = w->grab();
|
|
int sw = shot.width() / 10;
|
|
int sh = shot.height() / 10;
|
|
m_blurredBg = shot.scaled(sw, sh, Qt::IgnoreAspectRatio,
|
|
Qt::SmoothTransformation)
|
|
.scaled(shot.size(), Qt::IgnoreAspectRatio,
|
|
Qt::SmoothTransformation);
|
|
}
|
|
}
|
|
}
|
|
|
|
void OverlayWidget::mousePressEvent(QMouseEvent *event) {
|
|
if (!m_content->geometry().contains(event->pos()))
|
|
hide();
|
|
}
|
|
|
|
void OverlayWidget::paintEvent(QPaintEvent *) {
|
|
QPainter p(this);
|
|
if constexpr (Theme::FrostedGlass) {
|
|
if (!m_blurredBg.isNull())
|
|
p.drawPixmap(0, 0, m_blurredBg);
|
|
}
|
|
p.fillRect(rect(), Theme::Colors::OverlayDim);
|
|
}
|
|
|
|
// --- WelcomeWidget ---
|
|
|
|
WelcomeWidget::WelcomeWidget(QWidget *parent) : QWidget(parent) {
|
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
|
layout->setAlignment(Qt::AlignCenter);
|
|
layout->setSpacing(20);
|
|
layout->setContentsMargins(40, 40, 40, 40);
|
|
|
|
QLabel *title = new QLabel("Yr Crystals", this);
|
|
title->setStyleSheet("color: white; font-size: 32px; font-weight: bold;");
|
|
title->setAlignment(Qt::AlignCenter);
|
|
layout->addWidget(title);
|
|
|
|
QString minSizeRule = Theme::Dims::BtnMinSize > 0
|
|
? QString(" min-height: %1px;").arg(Theme::Dims::BtnMinSize)
|
|
: QString();
|
|
|
|
QString btnStyle = QString(
|
|
"QPushButton { background-color: %1; color: %2; border: 1px solid "
|
|
"%3; border-radius: 8px; padding: 15px; font-size: 18px;%4 } "
|
|
"QPushButton:pressed { background-color: %5; }")
|
|
.arg(Theme::hex(Theme::Colors::SurfaceLight),
|
|
Theme::hex(Theme::Colors::TextPrimary),
|
|
Theme::hex(Theme::Colors::BorderMid),
|
|
minSizeRule,
|
|
Theme::hex(Theme::Colors::BorderMid));
|
|
|
|
QString listStyle = QString(
|
|
"QListWidget { background: transparent; border: none; color: %1; "
|
|
"font-size: 16px; }"
|
|
"QListWidget::item { padding: %2px; border-bottom: 1px solid %3; }"
|
|
"QListWidget::item:hover { background: %4; }"
|
|
"QListWidget::item:selected { background: %5; }")
|
|
.arg(Theme::hex(Theme::Colors::TextMuted))
|
|
.arg(Theme::Dims::ListItemPad)
|
|
.arg(Theme::hex(Theme::Colors::SurfaceLight),
|
|
Theme::hex(Theme::Colors::SurfaceMid),
|
|
Theme::hex(Theme::Colors::SurfaceLight));
|
|
|
|
QHBoxLayout *btnLayout = new QHBoxLayout();
|
|
btnLayout->setSpacing(20);
|
|
|
|
QPushButton *btnFile = new QPushButton("Open File", this);
|
|
btnFile->setStyleSheet(btnStyle);
|
|
btnFile->setCursor(Qt::PointingHandCursor);
|
|
connect(btnFile, &QPushButton::clicked, this,
|
|
&WelcomeWidget::openFileClicked);
|
|
btnLayout->addWidget(btnFile);
|
|
|
|
QPushButton *btnFolder = new QPushButton("Open Folder", this);
|
|
btnFolder->setStyleSheet(btnStyle);
|
|
btnFolder->setCursor(Qt::PointingHandCursor);
|
|
connect(btnFolder, &QPushButton::clicked, this,
|
|
&WelcomeWidget::openFolderClicked);
|
|
btnLayout->addWidget(btnFolder);
|
|
|
|
layout->addLayout(btnLayout);
|
|
|
|
QString labelStyle = QString("color: %1; font-size: 16px; margin-top: 20px;")
|
|
.arg(Theme::hex(Theme::Colors::TextSecondary));
|
|
|
|
m_listsContainer = new QWidget(this);
|
|
|
|
QWidget *recentCol = new QWidget(m_listsContainer);
|
|
QVBoxLayout *recentLayout = new QVBoxLayout(recentCol);
|
|
recentLayout->setContentsMargins(0, 0, 0, 0);
|
|
QLabel *recentLabel = new QLabel("Recent", recentCol);
|
|
recentLabel->setStyleSheet(labelStyle);
|
|
recentLayout->addWidget(recentLabel);
|
|
m_recentList = new QListWidget(recentCol);
|
|
m_recentList->setStyleSheet(listStyle);
|
|
m_recentList->setFocusPolicy(Qt::NoFocus);
|
|
m_recentList->setCursor(Qt::PointingHandCursor);
|
|
m_recentList->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
connect(m_recentList, &QListWidget::itemClicked, this,
|
|
&WelcomeWidget::onRecentClicked);
|
|
recentLayout->addWidget(m_recentList);
|
|
|
|
QWidget *freqCol = new QWidget(m_listsContainer);
|
|
QVBoxLayout *freqLayout = new QVBoxLayout(freqCol);
|
|
freqLayout->setContentsMargins(0, 0, 0, 0);
|
|
QLabel *freqLabel = new QLabel("Frequents", freqCol);
|
|
freqLabel->setStyleSheet(labelStyle);
|
|
freqLayout->addWidget(freqLabel);
|
|
m_frequentList = new QListWidget(freqCol);
|
|
m_frequentList->setStyleSheet(listStyle);
|
|
m_frequentList->setFocusPolicy(Qt::NoFocus);
|
|
m_frequentList->setCursor(Qt::PointingHandCursor);
|
|
m_frequentList->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
connect(m_frequentList, &QListWidget::itemClicked, this,
|
|
&WelcomeWidget::onRecentClicked);
|
|
freqLayout->addWidget(m_frequentList);
|
|
|
|
m_listsLayout = new QVBoxLayout(m_listsContainer);
|
|
m_listsLayout->setContentsMargins(0, 0, 0, 0);
|
|
m_listsLayout->addWidget(recentCol);
|
|
m_listsLayout->addWidget(freqCol);
|
|
m_isHorizontal = false;
|
|
|
|
layout->addWidget(m_listsContainer, 1);
|
|
|
|
refreshRecents();
|
|
}
|
|
|
|
void WelcomeWidget::refreshRecents() {
|
|
m_recentList->clear();
|
|
QStringList files = Utils::getRecentFiles();
|
|
QStringList folders = Utils::getRecentFolders();
|
|
|
|
for (const auto &path : folders) {
|
|
QListWidgetItem *item =
|
|
new QListWidgetItem("📁 " + QFileInfo(path).fileName());
|
|
item->setData(Qt::UserRole, path);
|
|
item->setToolTip(path);
|
|
m_recentList->addItem(item);
|
|
}
|
|
for (const auto &path : files) {
|
|
QListWidgetItem *item =
|
|
new QListWidgetItem("🎵 " + QFileInfo(path).fileName());
|
|
item->setData(Qt::UserRole, path);
|
|
item->setToolTip(path);
|
|
m_recentList->addItem(item);
|
|
}
|
|
|
|
m_frequentList->clear();
|
|
auto freqs = Utils::getFrequentPaths(10);
|
|
for (const auto &pair : freqs) {
|
|
QString name = QFileInfo(pair.first).fileName();
|
|
QListWidgetItem *item =
|
|
new QListWidgetItem(name + " (" + QString::number(pair.second) + ")");
|
|
item->setData(Qt::UserRole, pair.first);
|
|
item->setToolTip(pair.first);
|
|
m_frequentList->addItem(item);
|
|
}
|
|
}
|
|
|
|
void WelcomeWidget::resizeEvent(QResizeEvent *event) {
|
|
QWidget::resizeEvent(event);
|
|
updateListsLayout();
|
|
}
|
|
|
|
void WelcomeWidget::updateListsLayout() {
|
|
bool wantHorizontal = (width() > height());
|
|
if (wantHorizontal == m_isHorizontal)
|
|
return;
|
|
m_isHorizontal = wantHorizontal;
|
|
|
|
QList<QWidget *> children;
|
|
while (m_listsLayout->count() > 0) {
|
|
QLayoutItem *item = m_listsLayout->takeAt(0);
|
|
if (item->widget())
|
|
children.append(item->widget());
|
|
delete item;
|
|
}
|
|
delete m_listsLayout;
|
|
|
|
if (m_isHorizontal)
|
|
m_listsLayout = new QHBoxLayout(m_listsContainer);
|
|
else
|
|
m_listsLayout = new QVBoxLayout(m_listsContainer);
|
|
m_listsLayout->setContentsMargins(0, 0, 0, 0);
|
|
for (auto *w : children)
|
|
m_listsLayout->addWidget(w);
|
|
}
|
|
|
|
void WelcomeWidget::onRecentClicked(QListWidgetItem *item) {
|
|
if (item) {
|
|
emit pathSelected(item->data(Qt::UserRole).toString());
|
|
}
|
|
}
|