mirror of
https://gitee.com/spark-store-project/spark-store
synced 2025-12-14 04:42:03 +08:00
New Non-DTK store client prototype
This commit is contained in:
288
gui/qt/qxcbatom.cpp
Normal file
288
gui/qt/qxcbatom.cpp
Normal file
@@ -0,0 +1,288 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
#include "qxcbatom.h"
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
namespace Priv
|
||||
{
|
||||
static const char *xcb_atomnames = {
|
||||
// window-manager <-> client protocols
|
||||
"WM_PROTOCOLS\0"
|
||||
"WM_DELETE_WINDOW\0"
|
||||
"WM_TAKE_FOCUS\0"
|
||||
"_NET_WM_PING\0"
|
||||
"_NET_WM_CONTEXT_HELP\0"
|
||||
"_NET_WM_SYNC_REQUEST\0"
|
||||
"_NET_WM_SYNC_REQUEST_COUNTER\0"
|
||||
"MANAGER\0"
|
||||
"_NET_SYSTEM_TRAY_OPCODE\0"
|
||||
|
||||
// ICCCM window state
|
||||
"WM_STATE\0"
|
||||
"WM_CHANGE_STATE\0"
|
||||
"WM_CLASS\0"
|
||||
"WM_NAME\0"
|
||||
|
||||
// Session management
|
||||
"WM_CLIENT_LEADER\0"
|
||||
"WM_WINDOW_ROLE\0"
|
||||
"SM_CLIENT_ID\0"
|
||||
"WM_CLIENT_MACHINE\0"
|
||||
|
||||
// Clipboard
|
||||
"CLIPBOARD\0"
|
||||
"INCR\0"
|
||||
"TARGETS\0"
|
||||
"MULTIPLE\0"
|
||||
"TIMESTAMP\0"
|
||||
"SAVE_TARGETS\0"
|
||||
"CLIP_TEMPORARY\0"
|
||||
"_QT_SELECTION\0"
|
||||
"_QT_CLIPBOARD_SENTINEL\0"
|
||||
"_QT_SELECTION_SENTINEL\0"
|
||||
"CLIPBOARD_MANAGER\0"
|
||||
|
||||
"RESOURCE_MANAGER\0"
|
||||
|
||||
"_XSETROOT_ID\0"
|
||||
|
||||
"_QT_SCROLL_DONE\0"
|
||||
"_QT_INPUT_ENCODING\0"
|
||||
|
||||
"_QT_CLOSE_CONNECTION\0"
|
||||
|
||||
"_MOTIF_WM_HINTS\0"
|
||||
|
||||
"DTWM_IS_RUNNING\0"
|
||||
"ENLIGHTENMENT_DESKTOP\0"
|
||||
"_DT_SAVE_MODE\0"
|
||||
"_SGI_DESKS_MANAGER\0"
|
||||
|
||||
// EWMH (aka NETWM)
|
||||
"_NET_SUPPORTED\0"
|
||||
"_NET_VIRTUAL_ROOTS\0"
|
||||
"_NET_WORKAREA\0"
|
||||
|
||||
"_NET_MOVERESIZE_WINDOW\0"
|
||||
"_NET_WM_MOVERESIZE\0"
|
||||
|
||||
"_NET_WM_NAME\0"
|
||||
"_NET_WM_ICON_NAME\0"
|
||||
"_NET_WM_ICON\0"
|
||||
|
||||
"_NET_WM_PID\0"
|
||||
|
||||
"_NET_WM_WINDOW_OPACITY\0"
|
||||
|
||||
"_NET_WM_STATE\0"
|
||||
"_NET_WM_STATE_ABOVE\0"
|
||||
"_NET_WM_STATE_BELOW\0"
|
||||
"_NET_WM_STATE_FULLSCREEN\0"
|
||||
"_NET_WM_STATE_MAXIMIZED_HORZ\0"
|
||||
"_NET_WM_STATE_MAXIMIZED_VERT\0"
|
||||
"_NET_WM_STATE_MODAL\0"
|
||||
"_NET_WM_STATE_STAYS_ON_TOP\0"
|
||||
"_NET_WM_STATE_DEMANDS_ATTENTION\0"
|
||||
"_NET_WM_STATE_HIDDEN\0"
|
||||
|
||||
"_NET_WM_USER_TIME\0"
|
||||
"_NET_WM_USER_TIME_WINDOW\0"
|
||||
"_NET_WM_FULL_PLACEMENT\0"
|
||||
|
||||
"_NET_WM_WINDOW_TYPE\0"
|
||||
"_NET_WM_WINDOW_TYPE_DESKTOP\0"
|
||||
"_NET_WM_WINDOW_TYPE_DOCK\0"
|
||||
"_NET_WM_WINDOW_TYPE_TOOLBAR\0"
|
||||
"_NET_WM_WINDOW_TYPE_MENU\0"
|
||||
"_NET_WM_WINDOW_TYPE_UTILITY\0"
|
||||
"_NET_WM_WINDOW_TYPE_SPLASH\0"
|
||||
"_NET_WM_WINDOW_TYPE_DIALOG\0"
|
||||
"_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0"
|
||||
"_NET_WM_WINDOW_TYPE_POPUP_MENU\0"
|
||||
"_NET_WM_WINDOW_TYPE_TOOLTIP\0"
|
||||
"_NET_WM_WINDOW_TYPE_NOTIFICATION\0"
|
||||
"_NET_WM_WINDOW_TYPE_COMBO\0"
|
||||
"_NET_WM_WINDOW_TYPE_DND\0"
|
||||
"_NET_WM_WINDOW_TYPE_NORMAL\0"
|
||||
"_KDE_NET_WM_WINDOW_TYPE_OVERRIDE\0"
|
||||
|
||||
"_KDE_NET_WM_FRAME_STRUT\0"
|
||||
"_NET_FRAME_EXTENTS\0"
|
||||
|
||||
"_NET_STARTUP_INFO\0"
|
||||
"_NET_STARTUP_INFO_BEGIN\0"
|
||||
|
||||
"_NET_SUPPORTING_WM_CHECK\0"
|
||||
|
||||
"_NET_WM_CM_S0\0"
|
||||
|
||||
"_NET_SYSTEM_TRAY_VISUAL\0"
|
||||
|
||||
"_NET_ACTIVE_WINDOW\0"
|
||||
|
||||
// Property formats
|
||||
"TEXT\0"
|
||||
"UTF8_STRING\0"
|
||||
"CARDINAL\0"
|
||||
|
||||
// xdnd
|
||||
"XdndEnter\0"
|
||||
"XdndPosition\0"
|
||||
"XdndStatus\0"
|
||||
"XdndLeave\0"
|
||||
"XdndDrop\0"
|
||||
"XdndFinished\0"
|
||||
"XdndTypeList\0"
|
||||
"XdndActionList\0"
|
||||
|
||||
"XdndSelection\0"
|
||||
|
||||
"XdndAware\0"
|
||||
"XdndProxy\0"
|
||||
|
||||
"XdndActionCopy\0"
|
||||
"XdndActionLink\0"
|
||||
"XdndActionMove\0"
|
||||
"XdndActionAsk\0"
|
||||
"XdndActionPrivate\0"
|
||||
|
||||
// Xkb
|
||||
"_XKB_RULES_NAMES\0"
|
||||
|
||||
// XEMBED
|
||||
"_XEMBED\0"
|
||||
"_XEMBED_INFO\0"
|
||||
|
||||
// XInput2
|
||||
"Button Left\0"
|
||||
"Button Middle\0"
|
||||
"Button Right\0"
|
||||
"Button Wheel Up\0"
|
||||
"Button Wheel Down\0"
|
||||
"Button Horiz Wheel Left\0"
|
||||
"Button Horiz Wheel Right\0"
|
||||
"Abs MT Position X\0"
|
||||
"Abs MT Position Y\0"
|
||||
"Abs MT Touch Major\0"
|
||||
"Abs MT Touch Minor\0"
|
||||
"Abs MT Orientation\0"
|
||||
"Abs MT Pressure\0"
|
||||
"Abs MT Tracking ID\0"
|
||||
"Max Contacts\0"
|
||||
"Rel X\0"
|
||||
"Rel Y\0"
|
||||
// XInput2 tablet
|
||||
"Abs X\0"
|
||||
"Abs Y\0"
|
||||
"Abs Pressure\0"
|
||||
"Abs Tilt X\0"
|
||||
"Abs Tilt Y\0"
|
||||
"Abs Wheel\0"
|
||||
"Abs Distance\0"
|
||||
"Wacom Serial IDs\0"
|
||||
"INTEGER\0"
|
||||
"Rel Horiz Wheel\0"
|
||||
"Rel Vert Wheel\0"
|
||||
"Rel Horiz Scroll\0"
|
||||
"Rel Vert Scroll\0"
|
||||
"_XSETTINGS_SETTINGS\0"
|
||||
"_COMPIZ_DECOR_PENDING\0"
|
||||
"_COMPIZ_DECOR_REQUEST\0"
|
||||
"_COMPIZ_DECOR_DELETE_PIXMAP\0"
|
||||
"_COMPIZ_TOOLKIT_ACTION\0"
|
||||
"_GTK_LOAD_ICONTHEMES\0"
|
||||
"AT_SPI_BUS\0"
|
||||
"EDID\0"
|
||||
"EDID_DATA\0"
|
||||
"XFree86_DDC_EDID1_RAWDATA\0"
|
||||
"_ICC_PROFILE\0"
|
||||
// \0\0 terminates loop.
|
||||
};
|
||||
|
||||
QXcbAtom::QXcbAtom()
|
||||
{
|
||||
}
|
||||
|
||||
void QXcbAtom::initialize(xcb_connection_t *connection)
|
||||
{
|
||||
initializeAllAtoms(connection);
|
||||
}
|
||||
|
||||
void QXcbAtom::initializeAllAtoms(xcb_connection_t *connection) {
|
||||
const char *names[QXcbAtom::NAtoms];
|
||||
const char *ptr = xcb_atomnames;
|
||||
|
||||
int i = 0;
|
||||
while (*ptr) {
|
||||
names[i++] = ptr;
|
||||
while (*ptr)
|
||||
++ptr;
|
||||
++ptr;
|
||||
}
|
||||
|
||||
Q_ASSERT(i == QXcbAtom::NAtoms);
|
||||
|
||||
xcb_intern_atom_cookie_t cookies[QXcbAtom::NAtoms];
|
||||
|
||||
Q_ASSERT(i == QXcbAtom::NAtoms);
|
||||
for (i = 0; i < QXcbAtom::NAtoms; ++i)
|
||||
cookies[i] = xcb_intern_atom(connection, false, strlen(names[i]), names[i]);
|
||||
|
||||
for (i = 0; i < QXcbAtom::NAtoms; ++i) {
|
||||
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookies[i], nullptr);
|
||||
m_allAtoms[i] = reply->atom;
|
||||
free(reply);
|
||||
}
|
||||
}
|
||||
|
||||
QXcbAtom::Atom QXcbAtom::qatom(xcb_atom_t xatom) const
|
||||
{
|
||||
return static_cast<QXcbAtom::Atom>(std::find(m_allAtoms, m_allAtoms + QXcbAtom::NAtoms, xatom) - m_allAtoms);
|
||||
}
|
||||
|
||||
QXcbAtom a;
|
||||
}
|
||||
}
|
||||
64
gui/qtxcb.cpp
Normal file
64
gui/qtxcb.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file contains code of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtxcb.h"
|
||||
|
||||
uint SpkUi::Priv::qtEdgesToXcbMoveResizeDirection(Qt::Edges edges)
|
||||
{
|
||||
if (edges == (Qt::TopEdge | Qt::LeftEdge))
|
||||
return 0;
|
||||
if (edges == Qt::TopEdge)
|
||||
return 1;
|
||||
if (edges == (Qt::TopEdge | Qt::RightEdge))
|
||||
return 2;
|
||||
if (edges == Qt::RightEdge)
|
||||
return 3;
|
||||
if (edges == (Qt::RightEdge | Qt::BottomEdge))
|
||||
return 4;
|
||||
if (edges == Qt::BottomEdge)
|
||||
return 5;
|
||||
if (edges == (Qt::BottomEdge | Qt::LeftEdge))
|
||||
return 6;
|
||||
if (edges == Qt::LeftEdge)
|
||||
return 7;
|
||||
|
||||
qWarning() << "Cannot convert " << edges << "to _NET_WM_MOVERESIZE direction.";
|
||||
return 0;
|
||||
}
|
||||
61
gui/spkcategoryselector.cpp
Normal file
61
gui/spkcategoryselector.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
#include "spkmainwindow.h"
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
SpkCategorySelector::SpkCategorySelector(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
mBtnLayout = new QVBoxLayout(this);
|
||||
mGroup = new QButtonGroup(this);
|
||||
}
|
||||
|
||||
void SpkCategorySelector::AddButton(QString aBtnText, int aCategoryId, QPixmap *aBtnIcon)
|
||||
{
|
||||
auto btn = new SpkCategoryButton(this);
|
||||
btn->SetText(aBtnText);
|
||||
if(aBtnIcon)
|
||||
btn->SetIcon(*aBtnIcon);
|
||||
mBtnList.append(btn);
|
||||
mGroup->addButton(btn, aCategoryId ? aCategoryId : -1);
|
||||
mBtnLayout->addWidget(btn);
|
||||
}
|
||||
|
||||
void SpkCategorySelector::DeleteAllButtons() // TODO: UNTESTED
|
||||
{
|
||||
foreach (auto i, mBtnList)
|
||||
{
|
||||
mBtnLayout->removeWidget(i);
|
||||
mGroup->removeButton(i);
|
||||
i->deleteLater();
|
||||
}
|
||||
mBtnList.clear();
|
||||
}
|
||||
|
||||
SpkCategoryButton::SpkCategoryButton(QWidget *parent) : QPushButton(parent)
|
||||
{
|
||||
mIcon = new QLabel(this);
|
||||
mIcon->setObjectName("spk_categorybtn_label");
|
||||
mText = new QLabel(this);
|
||||
mText->setObjectName("spk_categorybtn_text");
|
||||
mLayout = new QHBoxLayout;
|
||||
mLayout->setObjectName("spk_categorybtn_lay");
|
||||
mLayout->addSpacing(Spacing);
|
||||
mLayout->addWidget(mIcon);
|
||||
mLayout->addSpacing(Spacing);
|
||||
mLayout->addStretch();
|
||||
mLayout->addWidget(mText);
|
||||
mLayout->addStretch();
|
||||
mLayout->addSpacing(Spacing);
|
||||
setLayout(mLayout);
|
||||
}
|
||||
|
||||
void SpkCategoryButton::SetIcon(QPixmap aImage)
|
||||
{
|
||||
mIcon->setPixmap(aImage);
|
||||
}
|
||||
|
||||
void SpkCategoryButton::SetText(QString aText)
|
||||
{
|
||||
mText->setText(aText);
|
||||
}
|
||||
}
|
||||
92
gui/spkdialog.cpp
Normal file
92
gui/spkdialog.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
|
||||
#include <QEventLoop>
|
||||
#include "spkdialog.h"
|
||||
|
||||
SpkDialog::SpkDialog(QWidget *parent) :
|
||||
SpkWindow(parent)
|
||||
{
|
||||
mDialogWidget = new QWidget;
|
||||
mMainVLay = new QVBoxLayout(mDialogWidget);
|
||||
mWidgetsVLay = new QVBoxLayout();
|
||||
mBtnLay = new QHBoxLayout();
|
||||
mBtnGroup = new QButtonGroup(this);
|
||||
|
||||
mMainVLay->addLayout(mWidgetsVLay);
|
||||
mMainVLay->addLayout(mBtnLay);
|
||||
mMainVLay->setSizeConstraint(QLayout::SetMinimumSize);
|
||||
|
||||
mBtnLay->setAlignment(Qt::AlignCenter);
|
||||
|
||||
SetCentralWidget(mDialogWidget);
|
||||
|
||||
connect(mBtnGroup, QOverload<int>::of(&QButtonGroup::idClicked),
|
||||
this, &SpkDialog::ButtonPressed);
|
||||
connect(this, &SpkWindow::Closed, this, &SpkDialog::ForceClose);
|
||||
}
|
||||
|
||||
SpkDialog::~SpkDialog()
|
||||
{
|
||||
auto itp = mParentsList.begin();
|
||||
for(auto itw = mWidgetsList.begin(); itw != mWidgetsList.end(); itw++)
|
||||
{
|
||||
(*itw)->setParent(*(itp++)); // We shall never take the ownership of these widgets
|
||||
}
|
||||
delete mDialogWidget;
|
||||
}
|
||||
|
||||
void SpkDialog::AddButton(QString text, SpkUi::SpkButtonStyle style)
|
||||
{
|
||||
auto b = new QPushButton();
|
||||
b->setText(text);
|
||||
b->setMinimumWidth(100);
|
||||
b->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
switch(style)
|
||||
{
|
||||
|
||||
case SpkUi::SpkButtonStyle::Recommend:
|
||||
b->setObjectName("spk_styling_recommendbtn");
|
||||
break;
|
||||
case SpkUi::SpkButtonStyle::Warn:
|
||||
b->setObjectName("spk_styling_warnbtn");
|
||||
break;
|
||||
case SpkUi::SpkButtonStyle::Normal:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mBtnLay->addWidget(b);
|
||||
mBtnGroup->addButton(b);
|
||||
}
|
||||
|
||||
void SpkDialog::AddWidget(QWidget *w)
|
||||
{
|
||||
mWidgetsVLay->addWidget(w);
|
||||
mWidgetsList << w;
|
||||
mParentsList << w->parentWidget();
|
||||
}
|
||||
|
||||
void SpkDialog::AddSpacing(int a)
|
||||
{
|
||||
mWidgetsVLay->addSpacing(a);
|
||||
}
|
||||
|
||||
int SpkDialog::Exec()
|
||||
{
|
||||
QEventLoop loop;
|
||||
connect(this, &SpkDialog::ExitEventLoop, &loop, &QEventLoop::exit);
|
||||
connect(this, &SpkDialog::CloseWindow, this, &QMainWindow::close);
|
||||
show();
|
||||
return loop.exec();
|
||||
}
|
||||
|
||||
void SpkDialog::ButtonPressed(int aBtnId)
|
||||
{
|
||||
disconnect(this, &SpkWindow::Closed, this, &SpkDialog::ForceClose);
|
||||
emit ExitEventLoop(-aBtnId - 2);
|
||||
emit CloseWindow();
|
||||
}
|
||||
|
||||
void SpkDialog::ForceClose()
|
||||
{
|
||||
disconnect(this, &SpkDialog::CloseWindow, this, &QMainWindow::close);
|
||||
emit ExitEventLoop(-1);
|
||||
}
|
||||
121
gui/spkmainwindow.cpp
Normal file
121
gui/spkmainwindow.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
#include <QJsonArray>
|
||||
#include "spkmainwindow.h"
|
||||
#include "spklogging.h"
|
||||
#include "spkuimsg.h"
|
||||
|
||||
SpkMainWindow::SpkMainWindow(QWidget *parent) : SpkWindow(parent)
|
||||
{
|
||||
ui = new SpkUi::SpkMainWidget(parent);
|
||||
|
||||
SetUseTitleBar(false);
|
||||
SetCentralWidget(ui);
|
||||
SetTitleBar(ui->TitleBar, false);
|
||||
|
||||
auto size = QGuiApplication::primaryScreen()->size() * 0.25;
|
||||
resize(QGuiApplication::primaryScreen()->size() * 0.5);
|
||||
move(size.width(), size.height());
|
||||
}
|
||||
|
||||
void SpkMainWindow::PopulateCategories(QJsonObject aCategoryData)
|
||||
{
|
||||
auto w = ui->CategoryWidget;
|
||||
if(!aCategoryData.contains("code"))
|
||||
{
|
||||
SpkUiMessage::SendStoreNotification(tr("Failed to load categories; return code lost."));
|
||||
return;
|
||||
}
|
||||
auto OpRetCode = aCategoryData.value("code");
|
||||
if(!OpRetCode.isDouble())
|
||||
{
|
||||
SpkUiMessage::SendStoreNotification(tr("Failed to load categories; invalid return code."));
|
||||
return;
|
||||
}
|
||||
if(OpRetCode.toDouble() != 0)
|
||||
{
|
||||
SpkUiMessage::SendStoreNotification(tr("Failed to load categories; operation failed: %1.")
|
||||
.arg(OpRetCode.toDouble()));
|
||||
return;
|
||||
}
|
||||
|
||||
if(!aCategoryData.contains("data"))
|
||||
{
|
||||
SpkUiMessage::SendStoreNotification(tr("Failed to load categories; data lost."));
|
||||
return;
|
||||
}
|
||||
auto OpData = aCategoryData.value("data");
|
||||
if(!OpRetCode.isArray())
|
||||
{
|
||||
SpkUiMessage::SendStoreNotification(tr("Failed to load categories; invalid data."));
|
||||
return;
|
||||
}
|
||||
|
||||
auto OpDataArr = OpData.toArray();
|
||||
foreach(auto i, OpDataArr)
|
||||
{
|
||||
if(i.isObject())
|
||||
{
|
||||
auto j = i.toObject();
|
||||
double typeId;
|
||||
QString typeName;
|
||||
if(j.contains("type_id") && j.value("type_id").isDouble())
|
||||
typeId = j.value("type_id").toDouble();
|
||||
else goto WRONG_CATEGORY;
|
||||
if(j.contains("type_name") && j.value("type_name").isString())
|
||||
typeName = j.value("type_name").toString();
|
||||
else goto WRONG_CATEGORY;
|
||||
w->AddButton(tr(typeName.toLocal8Bit()), typeId /* TODO: ICONS */);
|
||||
continue;
|
||||
}
|
||||
WRONG_CATEGORY:
|
||||
sLog("One category ignored because of invalid data");
|
||||
}
|
||||
}
|
||||
|
||||
SpkUi::SpkMainWidget::SpkMainWidget(QWidget *parent) : QFrame(parent)
|
||||
{
|
||||
setObjectName("spk_mainwidget");
|
||||
|
||||
VLayCategoryButtons = new QVBoxLayout;
|
||||
VLayCategoryButtons->setObjectName("spk_mw_category_vlay");
|
||||
VLayCategoryButtons->addWidget(new QPushButton);
|
||||
|
||||
Pager = new QStackedWidget(this);
|
||||
Pager->setObjectName("spk_mw_pager");
|
||||
Pager->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
|
||||
TitleBar = new SpkTitleBar(this);
|
||||
TitleBar->setObjectName("spk_mw_titlebar");
|
||||
TitleBar->SetTitle("Title");
|
||||
|
||||
VLayMain = new QVBoxLayout;
|
||||
VLayMain->setObjectName("spk_mw_main_vlay");
|
||||
VLayMain->setSpacing(0);
|
||||
VLayMain->setContentsMargins(0, 0, 0, 0);
|
||||
VLayMain->addWidget(TitleBar);
|
||||
VLayMain->addWidget(Pager);
|
||||
|
||||
CategoryWidget = new SpkCategorySelector(this);
|
||||
CategoryWidget->setObjectName("spk_mw_category");
|
||||
CategoryWidget->setLayout(VLayCategoryButtons);
|
||||
CategoryWidget->setAutoFillBackground(true);
|
||||
CategoryWidget->setMaximumWidth(300);
|
||||
CategoryWidget->setMinimumWidth(300);
|
||||
CategoryWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||
|
||||
HorizontalDivide = new QHBoxLayout;
|
||||
HorizontalDivide->setObjectName("spk_mw_divide_hlay");
|
||||
HorizontalDivide->setSpacing(0);
|
||||
HorizontalDivide->setContentsMargins(0, 0, 0, 0);
|
||||
HorizontalDivide->setAlignment(Qt::AlignLeft);
|
||||
HorizontalDivide->addWidget(CategoryWidget);
|
||||
HorizontalDivide->addLayout(VLayMain);
|
||||
|
||||
// Initialize pages
|
||||
PageQssTest = new SpkUi::SpkPageQssTest(this);
|
||||
Pager->addWidget(PageQssTest);
|
||||
|
||||
setLayout(HorizontalDivide);
|
||||
}
|
||||
125
gui/spkmsgbox.cpp
Normal file
125
gui/spkmsgbox.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
|
||||
#include <QScrollArea>
|
||||
#include <QDebug>
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
#include "spkui_general.h"
|
||||
#include "spkmsgbox.h"
|
||||
|
||||
// Suppress unwanted Clazy check warnings
|
||||
// clazy:excludeall=connect-3arg-lambda,lambda-in-connect
|
||||
|
||||
const QSize SpkMsgBox::IconSize; // I don't know why I need it
|
||||
|
||||
SpkMsgBox::SpkMsgBox()
|
||||
{
|
||||
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
|
||||
}
|
||||
|
||||
int SpkMsgBox::StaticExec(QString msg, QString title, QMessageBox::Icon icon,
|
||||
QMessageBox::StandardButtons buttons, QString extra)
|
||||
{
|
||||
SpkMsgBox *b = new SpkMsgBox;
|
||||
QWidget *wMsgWidget = new QWidget;
|
||||
QHBoxLayout *wMsg = new QHBoxLayout(wMsgWidget);
|
||||
QPushButton *wExpandBtn;
|
||||
QScrollArea *wExtraArea;
|
||||
QLabel *wMsgText = new QLabel,
|
||||
*wExtraInfo,
|
||||
*wIcon;
|
||||
int InitialHeight;
|
||||
bool hasextra = extra.length() != 0;
|
||||
|
||||
if(icon)
|
||||
{
|
||||
wIcon = new QLabel;
|
||||
switch(icon)
|
||||
{
|
||||
case QMessageBox::Critical:
|
||||
wIcon->setPixmap(QIcon::fromTheme("dialog-error").pixmap(IconSize));
|
||||
break;
|
||||
case QMessageBox::Warning:
|
||||
wIcon->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(IconSize));
|
||||
break;
|
||||
case QMessageBox::Information:
|
||||
wIcon->setPixmap(QIcon::fromTheme("dialog-information").pixmap(IconSize));
|
||||
break;
|
||||
case QMessageBox::Question:
|
||||
wIcon->setPixmap(QIcon::fromTheme("dialog-question").pixmap(IconSize));
|
||||
break;
|
||||
case QMessageBox::NoIcon:
|
||||
break;
|
||||
}
|
||||
wMsg->addWidget(wIcon);
|
||||
}
|
||||
wMsgText->setText(msg);
|
||||
wMsgText->setAlignment(Qt::AlignCenter);
|
||||
wMsg->addWidget(wMsgText);
|
||||
wMsg->setSpacing(10);
|
||||
wMsgWidget->setLayout(wMsg);
|
||||
b->AddWidget(wMsgWidget);
|
||||
b->GetTitleBar()->SetTitle(title);
|
||||
b->GetTitleBar()->SetOperationButton(SpkTitleBar::OperationButton::Close);
|
||||
b->SetResizable(false);
|
||||
b->SetCentralMargin(Margin, Margin, Margin, Margin);
|
||||
b->setMaximumSize(SpkUi::PrimaryScreenSize * 0.6);
|
||||
|
||||
if(hasextra)
|
||||
{
|
||||
wExpandBtn = new QPushButton;
|
||||
wExtraInfo = new QLabel;
|
||||
wExtraArea = new QScrollArea;
|
||||
wExtraInfo->setText(extra);
|
||||
wExtraArea->setWidget(wExtraInfo);
|
||||
wExtraArea->setVisible(false);
|
||||
wExtraArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
wExpandBtn->setText(tr("Details"));
|
||||
wExpandBtn->setMaximumWidth(100);
|
||||
wExpandBtn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
wExpandBtn->setCheckable(true);
|
||||
wExpandBtn->setObjectName("spk_styling_msgboxexpandbtn");
|
||||
connect(wExpandBtn, &QPushButton::clicked,
|
||||
[&](){ // FIXME: hint doesn't change when visibility changes, this is a quirky hack
|
||||
wExtraArea->setVisible(wExpandBtn->isChecked());
|
||||
if(wExpandBtn->isChecked())
|
||||
b->setFixedHeight(b->sizeHint().height());
|
||||
else
|
||||
b->setFixedHeight(InitialHeight);
|
||||
});
|
||||
b->AddWidget(wExpandBtn);
|
||||
b->AddWidget(wExtraArea);
|
||||
}
|
||||
|
||||
b->AddSpacing(3);
|
||||
AddButtons(b, buttons);
|
||||
InitialHeight = b->minimumSizeHint().height();
|
||||
auto pos = (SpkUi::PrimaryScreenSize - b->sizeHint()) / 2;
|
||||
b->move(pos.width(), pos.height());
|
||||
b->setWindowModality(Qt::WindowModal);
|
||||
|
||||
auto r = b->Exec();
|
||||
if(r != -1)
|
||||
r = b->mButtonList[r]; // Retrieve the correct button
|
||||
|
||||
delete b;
|
||||
return r;
|
||||
}
|
||||
|
||||
void SpkMsgBox::AddButtons(SpkMsgBox *me, QMessageBox::StandardButtons b)
|
||||
{
|
||||
// If anyone can do it better, please let me know, I wrote this on the airplane
|
||||
using btn = QMessageBox::StandardButton;
|
||||
if(!b) return;
|
||||
if(b.testFlag(btn::Ok)) { me->AddButton(tr("OK")); me->mButtonList << btn::Ok; };
|
||||
if(b.testFlag(btn::Cancel)) { me->AddButton(tr("Cancel")); me->mButtonList << btn::Cancel; };
|
||||
if(b.testFlag(btn::Yes)) { me->AddButton(tr("Yes")); me->mButtonList << btn::Yes; };
|
||||
if(b.testFlag(btn::No)) { me->AddButton(tr("No")); me->mButtonList << btn::No; };
|
||||
if(b.testFlag(btn::Apply)) { me->AddButton(tr("Apply")); me->mButtonList << btn::Apply; };
|
||||
if(b.testFlag(btn::Reset)) { me->AddButton(tr("Reset")); me->mButtonList << btn::Reset; };
|
||||
if(b.testFlag(btn::Abort)) { me->AddButton(tr("Abort")); me->mButtonList << btn::Abort; };
|
||||
if(b.testFlag(btn::Retry)) { me->AddButton(tr("Retry")); me->mButtonList << btn::Retry; };
|
||||
if(b.testFlag(btn::Ignore)) { me->AddButton(tr("Ignore")); me->mButtonList << btn::Ignore; };
|
||||
if(b.testFlag(btn::Reset)) { me->AddButton(tr("Reset")); me->mButtonList << btn::Reset; };
|
||||
if(b.testFlag(btn::Close)) { me->AddButton(tr("Close")); me->mButtonList << btn::Close; };
|
||||
if(b.testFlag(btn::Open)) { me->AddButton(tr("Open")); me->mButtonList << btn::Open; };
|
||||
}
|
||||
99
gui/spkpageqsstest.cpp
Normal file
99
gui/spkpageqsstest.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
|
||||
#include <QApplication>
|
||||
#include "spkpageqsstest.h"
|
||||
#include "spkui_general.h"
|
||||
|
||||
SpkUi::SpkPageQssTest::SpkPageQssTest(QWidget *parent) : QSplitter(parent)
|
||||
{
|
||||
setObjectName("spk_pg_qsstest");
|
||||
|
||||
TextStylesheet = new QTextEdit(this);
|
||||
TextStylesheet->setObjectName("spk_pg_qsstest_qsstext");
|
||||
TextStylesheet->setPlainText(*SpkUi::CurrentStylesheet);
|
||||
|
||||
BtnApply = new QPushButton(this);
|
||||
BtnApply->setObjectName("spk_pg_qsstest_btnapply");
|
||||
BtnApply->setText("Apply");
|
||||
connect(BtnApply, &QPushButton::pressed, this, &SpkPageQssTest::SetStylesheet);
|
||||
|
||||
BtnFetch = new QPushButton(this);
|
||||
BtnFetch->setObjectName("spk_pg_qsstest_btnfetch");
|
||||
BtnFetch->setText("Fetch Stylesheet");
|
||||
connect(BtnFetch, &QPushButton::pressed, this, &SpkPageQssTest::FetchStylesheet);
|
||||
|
||||
HLayInputBtns = new QHBoxLayout;
|
||||
HLayInputBtns->setObjectName("spk_pg_qsstest_hlay_inputbtns");
|
||||
HLayInputBtns->addWidget(BtnFetch);
|
||||
HLayInputBtns->addWidget(BtnApply);
|
||||
|
||||
Btn = new QPushButton(this);
|
||||
Btn->setObjectName("spk_pg_qsstest_button");
|
||||
Btn->setText("TestButton");
|
||||
|
||||
Chk = new QCheckBox(this);
|
||||
Chk->setObjectName("spk_pg_qsstest_checkbox");
|
||||
Chk->setText("CheckBox");
|
||||
|
||||
Rad = new QRadioButton(this);
|
||||
Rad->setObjectName("spk_pg_qsstest_radiobtn");
|
||||
Rad->setText("RadioButton");
|
||||
|
||||
SlideV = new QSlider(this);
|
||||
SlideV->setObjectName("spk_pg_qsstest_slider_v");
|
||||
SlideV->setOrientation(Qt::Vertical);
|
||||
SlideV->setMaximum(1000);
|
||||
SlideV->setMinimum(0);
|
||||
|
||||
SlideH = new QSlider(this);
|
||||
SlideH->setObjectName("spk_pg_qsstest_slider_h");
|
||||
SlideH->setOrientation(Qt::Horizontal);
|
||||
SlideH->setMaximum(1000);
|
||||
SlideH->setMinimum(0);
|
||||
|
||||
VLayBtn = new QVBoxLayout;
|
||||
VLayBtn->setObjectName("spk_pg_qsstest_vlay_btn");
|
||||
VLayBtn->addWidget(Btn);
|
||||
VLayBtn->addWidget(Chk);
|
||||
VLayBtn->addWidget(Rad);
|
||||
|
||||
Group = new QGroupBox(this);
|
||||
Group->setObjectName("spk_pg_qsstest_groupbox");
|
||||
Group->setTitle("GroupBox");
|
||||
Group->setLayout(VLayBtn);
|
||||
|
||||
VLayInput = new QVBoxLayout;
|
||||
VLayInput->setObjectName("spk_pg_qsstest_inputlay");
|
||||
VLayInput->addWidget(TextStylesheet);
|
||||
VLayInput->addLayout(HLayInputBtns);
|
||||
|
||||
VLayWidgets = new QVBoxLayout;
|
||||
VLayWidgets->setObjectName("spk_pg_qsstest_widgetlay");
|
||||
VLayWidgets->addWidget(Group);
|
||||
VLayWidgets->addWidget(SlideH);
|
||||
|
||||
HLay4Slider = new QHBoxLayout;
|
||||
HLay4Slider->setObjectName("spk_pg_qsstest_hlay_for_slider");
|
||||
HLay4Slider->addLayout(VLayWidgets);
|
||||
HLay4Slider->addWidget(SlideV);
|
||||
|
||||
WidL = new QWidget(this);
|
||||
WidL->setObjectName("spk_pg_qsstest_widleft");
|
||||
WidL->setLayout(HLay4Slider);
|
||||
|
||||
WidR = new QWidget(this);
|
||||
WidR->setObjectName("spk_pg_qsstest_widright");
|
||||
WidR->setLayout(VLayInput);
|
||||
|
||||
addWidget(WidL);
|
||||
addWidget(WidR);
|
||||
}
|
||||
|
||||
void SpkUi::SpkPageQssTest::SetStylesheet()
|
||||
{
|
||||
qApp->setStyleSheet(TextStylesheet->toPlainText());
|
||||
}
|
||||
|
||||
void SpkUi::SpkPageQssTest::FetchStylesheet()
|
||||
{
|
||||
TextStylesheet->setPlainText(*SpkUi::CurrentStylesheet);
|
||||
}
|
||||
141
gui/spktitlebar.cpp
Normal file
141
gui/spktitlebar.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
|
||||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
#include "spkui_general.h"
|
||||
#include "spktitlebar.h"
|
||||
|
||||
SpkTitleBar::SpkTitleBar(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
mLinkedWindow = nullptr;
|
||||
|
||||
setMinimumHeight(48);
|
||||
setMaximumHeight(48);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
mIcon.setFixedSize(32, 32);
|
||||
|
||||
mMainLayout.addSpacing(8);
|
||||
mMainLayout.addWidget(&mIcon);
|
||||
mMainLayout.addSpacing(8);
|
||||
mMainLayout.addWidget(&mTitle);
|
||||
mMainLayout.addSpacing(8);
|
||||
mMainLayout.addLayout(&mUserSpaceL);
|
||||
mMainLayout.addStretch();
|
||||
mMainLayout.addLayout(&mUserSpaceR);
|
||||
mMainLayout.addSpacing(8);
|
||||
mMainLayout.addWidget(&mBtnMin);
|
||||
mMainLayout.addWidget(&mBtnMaxRestore);
|
||||
mMainLayout.addWidget(&mBtnClose);
|
||||
|
||||
mBtnMin.SetRole(OperationButton::Minimize);
|
||||
mBtnMaxRestore.SetRole(OperationButton::MaximizeRestore);
|
||||
mBtnClose.SetRole(OperationButton::Close);
|
||||
|
||||
mMainLayout.setSpacing(0);
|
||||
mMainLayout.setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
setLayout(&mMainLayout);
|
||||
|
||||
connect(&mBtnClose, &QPushButton::clicked, this, &SpkTitleBar::CloseWindow);
|
||||
connect(&mBtnMin, &QPushButton::clicked, this, &SpkTitleBar::MinimizeWindow);
|
||||
connect(&mBtnMaxRestore, &QPushButton::clicked, this, &SpkTitleBar::MaximizeRestoreWindow);
|
||||
}
|
||||
|
||||
SpkTitleBar::~SpkTitleBar()
|
||||
{
|
||||
//qDebug() << "Freed title bar!";
|
||||
}
|
||||
|
||||
void SpkTitleBar::SetOperationButton(OperationButton type)
|
||||
{
|
||||
mBtnClose.setVisible(type & OperationButton::Close);
|
||||
mBtnMaxRestore.setVisible(type & OperationButton::MaximizeRestore);
|
||||
mBtnMin.setVisible(type & OperationButton::Minimize);
|
||||
}
|
||||
|
||||
bool SpkTitleBar::event(QEvent *evt)
|
||||
{
|
||||
switch(evt->type())
|
||||
{
|
||||
case QEvent::MouseButtonDblClick:
|
||||
{
|
||||
if(static_cast<QMouseEvent*>(evt)->button())
|
||||
emit mBtnMaxRestore.clicked();
|
||||
break;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
return QWidget::event(evt);
|
||||
}
|
||||
|
||||
void SpkTitleBar::CloseWindow()
|
||||
{
|
||||
if(mLinkedWindow)
|
||||
mLinkedWindow->close();
|
||||
}
|
||||
|
||||
void SpkTitleBar::MinimizeWindow()
|
||||
{
|
||||
if(mLinkedWindow)
|
||||
mLinkedWindow->setWindowState(Qt::WindowMinimized);
|
||||
}
|
||||
|
||||
void SpkTitleBar::MaximizeRestoreWindow()
|
||||
{
|
||||
if(mLinkedWindow)
|
||||
{
|
||||
if(mLinkedWindow->windowState().testFlag(Qt::WindowMaximized))
|
||||
mLinkedWindow->setWindowState(mLinkedWindow->windowState() & ~Qt::WindowMaximized);
|
||||
else
|
||||
mLinkedWindow->setWindowState(Qt::WindowMaximized);
|
||||
}
|
||||
}
|
||||
|
||||
SpkTitleBarDefaultButton::SpkTitleBarDefaultButton()
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||
setMaximumWidth(ButtonWidth);
|
||||
setMinimumWidth(ButtonWidth);
|
||||
}
|
||||
|
||||
void SpkTitleBarDefaultButton::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
QPushButton::paintEvent(e);
|
||||
QPainter painter;
|
||||
painter.begin(this);
|
||||
PaintSymbol(painter);
|
||||
painter.end();
|
||||
}
|
||||
|
||||
void SpkTitleBarDefaultButton::PaintSymbol(QPainter &p)
|
||||
{
|
||||
QPen pen(SpkUi::ColorLine);
|
||||
p.setPen(pen);
|
||||
auto mh = height() / 2, mw = width() / 2, h = height(), w = width();
|
||||
constexpr int fr = 10;
|
||||
switch(Role)
|
||||
{
|
||||
case Minimize:
|
||||
p.drawLine(mw - w / fr, mh, mw + w / fr, mh);
|
||||
break;
|
||||
case MaximizeRestore:
|
||||
p.drawRect(mw - w / fr, mh - h / fr,
|
||||
w / fr * 2, h / fr * 2);
|
||||
break;
|
||||
case Restore:
|
||||
p.drawRect(mw - w / fr - 2, mh - w / fr + 2, w / fr * 2, h / fr * 2);
|
||||
p.drawLine(mw - w / fr, mh - h / fr - 2, mw + w / fr, mh - h / fr - 2);
|
||||
p.drawLine(mw + w / fr, mh - h / fr - 2, mw + w / fr, mh + h / fr - 2);
|
||||
break;
|
||||
case Close:
|
||||
p.drawLine(mw - h / fr * 1.3, mh - h / fr * 1.3,
|
||||
mw + h / fr * 1.3, mh + h / fr * 1.3);
|
||||
p.drawLine(mw - h / fr * 1.3, mh + h / fr * 1.3,
|
||||
mw + h / fr * 1.3, mh - h / fr * 1.3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SpkTitleBarDefaultButton::SetRole(OperationButton role)
|
||||
{
|
||||
Role = role;
|
||||
}
|
||||
167
gui/spkui_general.cpp
Normal file
167
gui/spkui_general.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// Created by rigoligo on 2021/5/8.
|
||||
//
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QLibrary>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QScreen>
|
||||
#include <csignal>
|
||||
#include <dlfcn.h>
|
||||
#include <execinfo.h>
|
||||
#include "deepinplatform.h"
|
||||
#include "spkui_general.h"
|
||||
#include "spkmsgbox.h"
|
||||
#include "spklogging.h"
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
QString StylesheetLight, StylesheetDark, *CurrentStylesheet = &StylesheetLight;
|
||||
QColor ColorLine, ColorBack;
|
||||
QSize PrimaryScreenSize;
|
||||
namespace Priv
|
||||
{
|
||||
bool CrashHandlerActivated;
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
// Obtain global stylesheets
|
||||
QFile ObtainStylesheet;
|
||||
ObtainStylesheet.setFileName(":/stylesheets/stylesheets/mainwindow.css");
|
||||
ObtainStylesheet.open(QIODevice::ReadOnly);
|
||||
StylesheetLight = ObtainStylesheet.readAll();
|
||||
ObtainStylesheet.close();
|
||||
ObtainStylesheet.setFileName(":/stylesheets/stylesheets/mainwindow_dark.css");
|
||||
ObtainStylesheet.open(QIODevice::ReadOnly);
|
||||
StylesheetDark = ObtainStylesheet.readAll();
|
||||
ObtainStylesheet.close();
|
||||
|
||||
SetGlobalStyle(Dark);
|
||||
|
||||
// Initalize crash handler
|
||||
signal(SIGSEGV, SpkUi::CrashSignalHandler);
|
||||
signal(SIGABRT, SpkUi::CrashSignalHandler);
|
||||
signal(SIGFPE, SpkUi::CrashSignalHandler);
|
||||
|
||||
// Prepare theme following for DDE
|
||||
PrepareForDeepinDesktop();
|
||||
|
||||
// Data initialization
|
||||
PrimaryScreenSize = QGuiApplication::primaryScreen()->size();
|
||||
}
|
||||
|
||||
void GuessAppropriateTheme()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool CheckIsDeepinDesktop()
|
||||
{
|
||||
QString Desktop(getenv("XDG_CURRENT_DESKTOP"));
|
||||
if(Desktop.contains("deepin", Qt::CaseInsensitive) ||
|
||||
Desktop.contains("tablet", Qt::CaseInsensitive))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void PrepareForDeepinDesktop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SetGlobalStyle(const SpkUiStyle aStyle)
|
||||
{
|
||||
switch(aStyle)
|
||||
{
|
||||
case Light:
|
||||
qApp->setStyleSheet(StylesheetLight);
|
||||
CurrentStylesheet = &StylesheetLight;
|
||||
ColorLine = Qt::black;
|
||||
break;
|
||||
case Dark:
|
||||
qApp->setStyleSheet(StylesheetDark);
|
||||
CurrentStylesheet = &StylesheetDark;
|
||||
ColorLine = Qt::white;
|
||||
break;
|
||||
default:
|
||||
sWarn(QObject::tr("SetGlobalStyle invoked with unknown style %1.")
|
||||
.arg(static_cast<int>(aStyle)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString WriteStackTrace(const QString &aStackTrace)
|
||||
{
|
||||
QString path = QDir::homePath() + "/.local/share/spark-store/crash/";
|
||||
QFile StackTraceFile;
|
||||
if(!QDir().exists(path))
|
||||
if(!QDir().mkpath(path))
|
||||
return QObject::tr("Stack trace directory %1 cannot be created. "
|
||||
"Stack trace wasn't saved.").arg(path);
|
||||
path += QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
|
||||
while(QFile::exists(path))
|
||||
path += "_";
|
||||
StackTraceFile.setFileName(path);
|
||||
StackTraceFile.open(QIODevice::WriteOnly);
|
||||
if(StackTraceFile.isOpen() && StackTraceFile.isWritable())
|
||||
{
|
||||
QTextStream StackTraceWriter;
|
||||
StackTraceWriter.setDevice(&StackTraceFile);
|
||||
StackTraceWriter << QDateTime::currentDateTime().toLocalTime().toString() << "\n\n";
|
||||
StackTraceWriter << aStackTrace;
|
||||
StackTraceFile.close();
|
||||
return QObject::tr("Stack trace written to \"%1\".").arg(path);
|
||||
}
|
||||
return QObject::tr("Stack trace file %1 cannot be opened. "
|
||||
"Stack trace wasn't saved.").arg(path);
|
||||
}
|
||||
|
||||
void CrashSignalHandler(int sig)
|
||||
{
|
||||
QString msg(QObject::tr("Program has received signal %1 during normal execution.\n\n")),
|
||||
trace;
|
||||
switch(sig)
|
||||
{
|
||||
case SIGSEGV:
|
||||
msg = msg.arg(QObject::tr("\"SIGSEGV\" (Segmentation fault)"));
|
||||
goto CRASH;
|
||||
case SIGFPE:
|
||||
msg = msg.arg(QObject::tr("\"SIGFPE\" (Arithmetic exception)"));
|
||||
goto CRASH;
|
||||
case SIGABRT:
|
||||
msg = msg.arg(QObject::tr("\"SIGABRT\" (Abort)"));
|
||||
CRASH:
|
||||
{
|
||||
if(Priv::CrashHandlerActivated) // If error occured in the handler...
|
||||
{
|
||||
signal(SIGABRT, SIG_DFL); // Return control flow to OS and give up
|
||||
raise(SIGABRT);
|
||||
exit(2);
|
||||
}
|
||||
Priv::CrashHandlerActivated = true;
|
||||
void* TraceStack[StackTraceArraySize];
|
||||
int StackTraceSize = backtrace(TraceStack, StackTraceArraySize);
|
||||
auto TraceTextArray = backtrace_symbols(TraceStack, StackTraceArraySize);
|
||||
trace = QString(QObject::tr("Stack trace:\n"));
|
||||
for(int i = 0; i < StackTraceSize; i++)
|
||||
trace += QString::number(i) + "> " + QString(TraceTextArray[i]) + '\n';
|
||||
msg += QObject::tr("Spark Store cannot continue.\n\n");
|
||||
msg += WriteStackTrace(trace);
|
||||
SpkMsgBox::StaticExec(msg, QObject::tr("Spark Store Crashed"), QMessageBox::Critical,
|
||||
QMessageBox::Ok, trace);
|
||||
exit(2);
|
||||
}
|
||||
default:
|
||||
sErrPop(QObject::tr("Unknown signal %1 received in crash handler. "
|
||||
"Program internals may be corrupted. Please decide if you want "
|
||||
"to continue execution.").arg(sig));
|
||||
}
|
||||
}
|
||||
}
|
||||
297
gui/spkwindow.cpp
Normal file
297
gui/spkwindow.cpp
Normal file
@@ -0,0 +1,297 @@
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QApplication>
|
||||
#include <QStyleHints>
|
||||
#include <QPainterPath>
|
||||
#include <QFile>
|
||||
#include <QPushButton>
|
||||
#include <QMouseEvent>
|
||||
#include "spklogging.h"
|
||||
#include "spkwindow.h"
|
||||
#include "spkui_general.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
SpkWindow::SpkWindow(QWidget *parent) : QMainWindow(parent)
|
||||
{
|
||||
setWindowFlags(Qt::FramelessWindowHint); // Remove default title bar, we'll have custom title bar
|
||||
mCornerRadius = 5;
|
||||
mUserCentralWidget = nullptr;
|
||||
mResizable = true;
|
||||
mResizing = false;
|
||||
mCloseHook = nullptr;
|
||||
mMaximized = windowState().testFlag(Qt::WindowMaximized);
|
||||
|
||||
PopulateUi();
|
||||
}
|
||||
|
||||
SpkWindow::~SpkWindow()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool SpkWindow::event(QEvent *evt)
|
||||
{
|
||||
switch(evt->type())
|
||||
{
|
||||
case QEvent::WindowStateChange:
|
||||
{
|
||||
mMaximized = windowState().testFlag(Qt::WindowMaximized);
|
||||
if(mMaximized)
|
||||
mTitleBarComponent->mBtnMaxRestore.SetRole(SpkTitleBarDefaultButton::Restore);
|
||||
else
|
||||
mTitleBarComponent->mBtnMaxRestore.SetRole(SpkTitleBarDefaultButton::MaximizeRestore);
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
if(!mResizable) break;
|
||||
auto e = static_cast<QMouseEvent*>(evt);
|
||||
if(e->button() != Qt::LeftButton) break;
|
||||
auto edge = DetectEdgeOnThis(e->pos());
|
||||
if(edge)
|
||||
{
|
||||
mResizing = true;
|
||||
mEdgesBeingResized = edge;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonRelease:
|
||||
{
|
||||
if(!mResizable) break;
|
||||
auto e = static_cast<QMouseEvent*>(evt);
|
||||
if(e->button() != Qt::LeftButton) break;
|
||||
mResizing = false;
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case QEvent::HoverMove:
|
||||
{
|
||||
if(mResizing || !mResizable) break;
|
||||
if(mMaximized)
|
||||
{
|
||||
unsetCursor();
|
||||
break;
|
||||
}
|
||||
auto e = static_cast<QHoverEvent*>(evt);
|
||||
auto edge = DetectEdgeOnThis(e->pos());
|
||||
SetMouseCursor(edge);
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseMove:
|
||||
{
|
||||
if(!mResizable) break;
|
||||
auto e = static_cast<QMouseEvent*>(evt);
|
||||
if(mResizing && !mMaximized)
|
||||
{
|
||||
ResizeWindowByCursor(e->globalPos());
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
;
|
||||
}
|
||||
return QMainWindow::event(evt);
|
||||
}
|
||||
|
||||
Qt::Edges SpkWindow::DetectEdgeOnThis(QPoint p)
|
||||
{
|
||||
Qt::Edges edge;
|
||||
if(p.x() < BorderWidth) edge |= Qt::LeftEdge;
|
||||
if(p.x() > width() - BorderWidth) edge |= Qt::RightEdge;
|
||||
if(p.y() < BorderWidth) edge |= Qt::TopEdge;
|
||||
if(p.y() > height() - BorderWidth) edge |= Qt::BottomEdge;
|
||||
return edge;
|
||||
}
|
||||
|
||||
void SpkWindow::SetMouseCursor(Qt::Edges e)
|
||||
{
|
||||
switch(e)
|
||||
{
|
||||
case Qt::TopEdge:
|
||||
case Qt::BottomEdge:
|
||||
setCursor(Qt::SizeVerCursor);
|
||||
break;
|
||||
case Qt::LeftEdge:
|
||||
case Qt::RightEdge:
|
||||
setCursor(Qt::SizeHorCursor);
|
||||
break;
|
||||
case Qt::TopEdge | Qt::LeftEdge:
|
||||
case Qt::BottomEdge | Qt::RightEdge:
|
||||
setCursor(Qt::SizeFDiagCursor);
|
||||
break;
|
||||
case Qt::TopEdge | Qt::RightEdge:
|
||||
case Qt::BottomEdge | Qt::LeftEdge:
|
||||
setCursor(Qt::SizeBDiagCursor);
|
||||
break;
|
||||
default:
|
||||
unsetCursor();
|
||||
}
|
||||
}
|
||||
|
||||
void SpkWindow::ResizeWindowByCursor(QPoint p)
|
||||
{
|
||||
auto r_ = geometry(), r = r_;
|
||||
switch(mEdgesBeingResized)
|
||||
{
|
||||
case Qt::TopEdge | Qt::LeftEdge:
|
||||
r.setLeft(p.x());
|
||||
if(r.width() < minimumWidth()) // If smaller than minimum the window moves, so we stop it
|
||||
r.setLeft(r_.left());
|
||||
case Qt::TopEdge:
|
||||
r.setTop(p.y());
|
||||
if(r.height() < minimumHeight()) // Same
|
||||
r.setTop(r_.top());
|
||||
break;
|
||||
case Qt::BottomEdge | Qt::LeftEdge:
|
||||
r.setLeft(p.x());
|
||||
if(r.width() < minimumWidth())
|
||||
r.setLeft(r_.left());
|
||||
case Qt::BottomEdge:
|
||||
r.setBottom(p.y());
|
||||
if(r.height() < minimumHeight())
|
||||
r.setBottom(r_.bottom());
|
||||
break;
|
||||
case Qt::TopEdge | Qt::RightEdge:
|
||||
r.setTop(p.y());
|
||||
r.setRight(p.x());
|
||||
if(r.height() < minimumHeight())
|
||||
r.setTop(r_.top());
|
||||
if(r.width() < minimumWidth())
|
||||
r.setRight(r_.right());
|
||||
break;
|
||||
case Qt::BottomEdge | Qt::RightEdge:
|
||||
r.setBottom(p.y());
|
||||
if(r.height() < minimumHeight())
|
||||
r.setBottom(r_.bottom());
|
||||
case Qt::RightEdge:
|
||||
r.setRight(p.x());
|
||||
if(r.width() < minimumWidth())
|
||||
r.setRight(r_.right());
|
||||
break;
|
||||
case Qt::LeftEdge:
|
||||
r.setLeft(p.x());
|
||||
if(r.width() < minimumWidth())
|
||||
r.setLeft(r_.left());
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
setGeometry(r);
|
||||
}
|
||||
|
||||
void SpkWindow::closeEvent(QCloseEvent *e)
|
||||
{
|
||||
if(mCloseHook)
|
||||
{
|
||||
if(mCloseHook())
|
||||
e->accept();
|
||||
else
|
||||
e->ignore();
|
||||
emit Closed();
|
||||
return;
|
||||
}
|
||||
e->accept();
|
||||
emit Closed();
|
||||
}
|
||||
|
||||
void SpkWindow::SetCornerRadius(int radius)
|
||||
{
|
||||
mCornerRadius = radius;
|
||||
}
|
||||
|
||||
void SpkWindow::SetWindowTheme(SpkWindow::SpkWindowStyle style)
|
||||
{
|
||||
switch(style)
|
||||
{
|
||||
case Light:
|
||||
this->setStyleSheet(SpkUi::StylesheetLight);
|
||||
break;
|
||||
case Dark:
|
||||
this->setStyleSheet(SpkUi::StylesheetDark);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void SpkWindow::PopulateUi()
|
||||
{
|
||||
mCentralWidget = new QWidget(this);
|
||||
mMainVLayout = new QVBoxLayout;
|
||||
mTitleBarComponent = new SpkTitleBar(this);
|
||||
|
||||
mCentralWidget->setLayout(mMainVLayout);
|
||||
|
||||
mMainVLayout->addWidget(mTitleBarComponent);
|
||||
mMainVLayout->setAlignment(Qt::AlignTop);
|
||||
mMainVLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mMainVLayout->setSpacing(0);
|
||||
|
||||
mTitleBarComponent->SetTitle(qAppName());
|
||||
mTitleBarComponent->SetUseIcon(false);
|
||||
mTitleBarComponent->SetLinkedWindow(this);
|
||||
|
||||
setCentralWidget(mCentralWidget);
|
||||
setWindowFlag(Qt::NoDropShadowWindowHint, false);
|
||||
}
|
||||
|
||||
void SpkWindow::SetCentralWidget(QWidget *widget)
|
||||
{
|
||||
if(mUserCentralWidget)
|
||||
mMainVLayout->removeWidget(mUserCentralWidget);
|
||||
mUserCentralWidget = widget;
|
||||
mMainVLayout->addWidget(widget);
|
||||
}
|
||||
|
||||
void SpkWindow::SetUseTitleBar(bool x)
|
||||
{
|
||||
mTitleBarComponent->setVisible(x);
|
||||
}
|
||||
|
||||
void SpkWindow::SetCentralMargin(int a, int b, int c, int d)
|
||||
{
|
||||
if(mUserCentralWidget)
|
||||
mUserCentralWidget->setContentsMargins(a, b, c, d);
|
||||
}
|
||||
|
||||
void SpkWindow::SetCloseHook(bool (*f)())
|
||||
{
|
||||
mCloseHook = f;
|
||||
}
|
||||
|
||||
void SpkWindow::ClearCloseHook()
|
||||
{
|
||||
mCloseHook = nullptr;
|
||||
}
|
||||
|
||||
void SpkWindow::RecalculateSize()
|
||||
{
|
||||
mMainVLayout->activate();
|
||||
}
|
||||
|
||||
bool SpkWindow::GetUseTitleBar()
|
||||
{
|
||||
return mTitleBarComponent->isVisible();
|
||||
}
|
||||
|
||||
SpkTitleBar *SpkWindow::GetTitleBar()
|
||||
{
|
||||
return mTitleBarComponent;
|
||||
}
|
||||
|
||||
SpkTitleBar *SpkWindow::SetTitleBar(SpkTitleBar *bar, bool replace)
|
||||
{
|
||||
if(!bar)
|
||||
return nullptr;
|
||||
auto ret = mTitleBarComponent;
|
||||
mMainVLayout->removeWidget(mTitleBarComponent);
|
||||
if(replace)
|
||||
mMainVLayout->insertWidget(0, bar);
|
||||
mTitleBarComponent = bar;
|
||||
bar->SetLinkedWindow(this);
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user