Initial commit

This commit is contained in:
Linloir 2021-12-05 09:05:54 +08:00
commit ba9e5b2944
29 changed files with 5921 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

43
.gitignore vendored Normal file
View File

@ -0,0 +1,43 @@
# C++ objects and libs
*.slo
*.lo
*.o
*.a
*.la
*.lai
*.so
*.dll
*.dylib
# Qt-es
object_script.*.Release
object_script.*.Debug
*_plugin_import.cpp
/.qmake.cache
/.qmake.stash
*.pro.user
*.pro.user.*
*.qbs.user
*.qbs.user.*
*.moc
moc_*.cpp
moc_*.h
qrc_*.cpp
ui_*.h
*.qmlc
*.jsc
Makefile*
*build-*
# Qt unit tests
target_wrapper.*
# QtCreator
*.autosave
# QtCreator Qml
*.qmlproject.user
*.qmlproject.user.*
# QtCreator CMake
CMakeLists.txt.user*

42
GraphBuilder.pro Normal file
View File

@ -0,0 +1,42 @@
QT += core gui
QT += svg
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
customScrollContainer.cpp \
customWidgets.cpp \
graph_implement.cpp \
graph_view.cpp \
main.cpp \
mainwindow.cpp \
mycanvas.cpp \
slidepage.cpp
HEADERS += \
customScrollContainer.h \
customWidgets.h \
graph_implement.h \
graph_view.h \
mainwindow.h \
mycanvas.h \
slidepage.h
FORMS += \
mainwindow.ui
RC_ICONS = logo.ico
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
RESOURCES += \
icons.qrc

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Linloir
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

410
customScrollContainer.cpp Normal file
View File

@ -0,0 +1,410 @@
#include "customScrollContainer.h"
ScrollAreaCustom::ScrollAreaCustom(QWidget *parent) : QWidget(parent)
{
//initialize list container and timer
container = new ScrollListContainer(this);
container->move(0, 0);
container->resize(this->width(), 3);
getCord = new QTimer;
getCord->setSingleShot(true);
rfrshView = new QTimer;
getCord->setSingleShot(true);
indicator = new ScrollIndicator(this);
indicator->resize(indicator->width(), (int)((double)this->height() * this->height() / (double)container->height()));
indicator->move(this->width() - indicator->width() - 3, 0);
this->setMouseTracking(true);
container->setMouseTracking(true);
indicator->setMouseTracking(true);
bounce = new QPropertyAnimation(container, "pos");
QObject::connect(getCord, SIGNAL(timeout()), this, SLOT(updateSpd()));
QObject::connect(rfrshView, SIGNAL(timeout()), this, SLOT(scrollContainer()));
QObject::connect(indicator, SIGNAL(scrollPage(int)), this, SLOT(scrollIndicator(int)));
}
void ScrollAreaCustom::paintEvent(QPaintEvent *event){
container->resize(this->width(), container->height());
if(container->height() > this->height() && container->y() < this->height() - container->height() && curSpd == 0 && bounce->state() == QAbstractAnimation::Stopped)
container->move(container->x(), this->height() - container->height());
if(container->height() <= this->height()){
container->move(container->x(), 0);
indicator->hide();
}
else{
indicator->show();
}
indicator->resize(indicator->width(), (int)((double)this->height() * this->height() / (double)container->height()));
indicator->move(this->width() - indicator->width() - 3, -container->y() * this->height() / container->height());
}
void ScrollAreaCustom::mousePressEvent(QMouseEvent *event){
if(container->height() > this->height()){
if(container->y() <= 0 && container->y() + container->height() >= this->height())
pressed = true;
lastY = event->pos().y();
}
getCord->stop();
rfrshView->stop();
curSpd = 0;
outOfEdge = false;
moveStored = 0;
nextMove = 1;
}
void ScrollAreaCustom::mouseMoveEvent(QMouseEvent *event){
setCursor(Qt::ArrowCursor);
if(pressed){
//start scroll
if(!getCord->isActive() && event->pos().y() - lastY != 0){
//start 30ms timer
getCord->start(30);
strtY = event->pos().y();
}
if(container->y() <= 0 && container->y() + container->height() >= this->height())
container->move(container->x(), container->y() + event->pos().y() - lastY);
else{
if(!outOfEdge){
bfEdgeY = event->pos().y();
container->move(container->x(), container->y() + event->pos().y() - lastY);
outOfEdge = true;
}
else{
int pos = container->y() >= 0 ? 1 : -1;
int dp = event->pos().y() - bfEdgeY;
if(dp == 0){
outOfEdge = false;
nextMove = 1;
moveStored = 0;
if(container->y() >= 0)
container->move(container->x(), 0);
else
container->move(container->x(), this->height() - container->height());
}
else if(dp / abs(dp) != pos){
outOfEdge = false;
container->move(container->x(), this->y() + event->pos().y() - bfEdgeY);
nextMove = 1;
moveStored = 0;
}
else{
while(abs(moveStored) + nextMove <= abs(event->pos().y() - bfEdgeY)){
moveStored += nextMove * pos;
container->move(container->x(), container->y() + pos);
nextMove++;
}
while(nextMove > 1 && abs(moveStored) > abs(event->pos().y() - bfEdgeY)){
nextMove--;
moveStored -= nextMove * pos;
container->move(container->x(), container->y() - pos);
}
if(moveStored == 0){
outOfEdge = false;
if(container->y() >= 0)
container->move(container->x(), 0);
else
container->move(container->x(), this->height() - container->height());
nextMove = 1;
moveStored = 0;
}
}
}
}
lastY = event->pos().y();
}
}
void ScrollAreaCustom::mouseReleaseEvent(QMouseEvent *event){
//start scrolling
if(container->y() > 0 || container->y() + container->height() < this->height())
bounceBack();
else
rfrshView->start(30);
pressed = false;
}
void ScrollAreaCustom::bounceBack(){
rfrshView->stop();
getCord->stop();
bounce->setDuration(500);
bounce->setStartValue(container->pos());
if(container->y() > 0)
bounce->setEndValue(QPoint(container->x(), 0));
else
bounce->setEndValue(QPoint(container->x(), this->height() - container->height()));
bounce->setEasingCurve(QEasingCurve::OutQuad);
bounce->start();
}
void ScrollAreaCustom::scrollContainer(){
//scroll
if(curSpd > 0){
if(curSpd > MAXSPEED && !ignoreMaxSpeed)
curSpd = MAXSPEED;
else if(curSpd <= MAXSPEED) ignoreMaxSpeed = false;
int dp = scrollDown ? curSpd : -curSpd;
container->move(container->x(), container->y() + dp);
}
else
return;
if(container->y() <= 0 && container->y() + container->height() >= this->height()){
curSpd -= damp;
curSpd = curSpd < 0 ? 0 : curSpd;
}
else
curSpd /= 2;
if(curSpd == 0 && (container->y() > 0 || container->y() + container->height() < this->height()))
bounceBack();
else
rfrshView->start(30);
}
void ScrollAreaCustom::updateSpd(){
int spd = lastY - strtY;
scrollDown = spd >= 0;
strtY = lastY;
curSpd = abs(spd);
}
void ScrollAreaCustom::addWidget(QWidget *newWidget, bool setAnimation){
newWidget->setParent(container);
container->AddWidget(newWidget, setAnimation);
}
void ScrollAreaCustom::removeWidget(QWidget *w){
container->RemoveWidget(w);
}
void ScrollAreaCustom::scrollToTop(){
curSpd = sqrt(8 * (- container->pos().y()) + 2) / 2;
scrollDown = true;
getCord->stop();
rfrshView->stop();
outOfEdge = false;
moveStored = 0;
nextMove = 1;
ignoreMaxSpeed = true;
rfrshView->start(30);
}
void ScrollAreaCustom::updateHeight(){
container->updateHeight();
}
void ScrollAreaCustom::clear(){
container->clear();
}
void ScrollAreaCustom::scrollIndicator(int dp){
int newY = container->y() - dp * container->height() / this->height();
if(newY > 0)
newY = 0;
else if(newY < this->height() - container->height())
newY = this->height() - container->height();
container->move(container->x(), newY);
update();
}
void ScrollAreaCustom::wheelEvent(QWheelEvent *event){
if(container->y() > 0 || container->y() + container->height() < this->height())
return;
curSpd += 5;
bool newDirection = event->angleDelta().y() > 0;
if(newDirection != scrollDown)
curSpd = 5;
if(curSpd > MAXSPEED)
curSpd = MAXSPEED;
scrollDown = newDirection;
if(!rfrshView->isActive())
rfrshView->start(30);
update();
}
ScrollListContainer::ScrollListContainer(QWidget *parent) : QWidget(parent){}
void ScrollListContainer::paintEvent(QPaintEvent *event){
for(int i = 0; i < widgets.size(); i++){
widgets[i]->resize(this->width(), widgets[i]->height());
}
}
void ScrollListContainer::AddWidget(QWidget *widget, bool setAnimation){
//Add animation for all widgets current
this->resize(this->width(), this->height() + widget->height() + spacing);
widgets.push_back(widget);
size++;
ys.push_back(0);
widget->resize(this->width(), widget->height());
widget->show();
if(setAnimation){
QGraphicsOpacityEffect* widgetOpac = new QGraphicsOpacityEffect(widget);
widgetOpac->setOpacity(0);
widget->setGraphicsEffect(widgetOpac);
QParallelAnimationGroup* dpGroup = new QParallelAnimationGroup;
QSequentialAnimationGroup* newWidgetFadeIn = new QSequentialAnimationGroup;
for(int i = 0; i < size - 1; i++){
ys[i] += widget->height() + spacing;
QPropertyAnimation* move = new QPropertyAnimation(widgets[i], "pos");
move->setDuration(750);
move->setStartValue(widgets[i]->pos());
move->setEndValue(QPoint(widgets[i]->x(), ys[i]));
move->setEasingCurve(QEasingCurve::InOutQuart);
dpGroup->addAnimation(move);
}
newWidgetFadeIn->addPause(300);
QPropertyAnimation* fade = new QPropertyAnimation(widgetOpac, "opacity", widget);
fade->setDuration(300);
fade->setStartValue(0);
fade->setEndValue(0.99);
newWidgetFadeIn->addAnimation(fade);
dpGroup->addAnimation(newWidgetFadeIn);
dpGroup->start();
connect(dpGroup, &QPropertyAnimation::stateChanged, [=](){
if(dpGroup->state() == QAbstractAnimation::Stopped){
if(widgetOpac->opacity() != 0.99){
fade->start(QAbstractAnimation::DeleteWhenStopped);
connect(fade,&QPropertyAnimation::finished,[=](){widgetOpac->deleteLater();});
}
else{
dpGroup->deleteLater();
widgetOpac->deleteLater();
}
}
});
}
else{
for(int i = 0; i < size - 1; i++){
ys[i] += widget->height() + spacing;
widgets[i]->move(QPoint(widgets[i]->pos().x(), ys[i]));
}
}
}
void ScrollListContainer::RemoveWidget(QWidget *widget){
int index;
if(widget == nullptr){
index = size - 1;
if(index != -1)
widget = widgets[index];
}
else
index = widgets.indexOf(widget);
if(index == -1 || widget == nullptr){
return;
}
this->resize(this->width(), this->height() - widget->height() - spacing);
this->parentWidget()->update();
widget->hide();
widget->setParent(nullptr);
QParallelAnimationGroup* dpGroup = new QParallelAnimationGroup;
for(int i = index - 1; i >= 0; i--){
ys[i] -= (widget->height() + spacing);
QPropertyAnimation* move = new QPropertyAnimation(widgets[i], "pos");
move->setDuration(750);
move->setStartValue(widgets[i]->pos());
move->setEndValue(QPoint(widgets[i]->x(), ys[i]));
move->setEasingCurve(QEasingCurve::InOutQuart);
dpGroup->addAnimation(move);
}
dpGroup->start(QAbstractAnimation::DeleteWhenStopped);
widgets.remove(index);
size--;
ys.remove(index);
}
void ScrollListContainer::updateHeight(){
for(int i = size - 2; i >= 0; i--){
ys[i] = ys[i + 1] + widgets[i + 1]->height() + spacing;
widgets[i]->move(widgets[i]->pos().x(), ys[i]);
}
this->resize(this->width(), ys[0] + widgets[0]->height() + 3);
}
void ScrollListContainer::clear(){
int n = size;
for(int i = 0; i < n; i++)
RemoveWidget();
}
ScrollIndicator::ScrollIndicator(QWidget *parent) : QWidget(parent)
{
this->resize(defaultWidth, 0);
hovTimer = new QTimer(this);
hovTimer->setSingleShot(true);
aniPause = new QTimer(this);
aniPause->setSingleShot(true);
QObject::connect(hovTimer, SIGNAL(timeout()), this, SLOT(setHoverActive()));
this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
this->curColor = defaultColor;
this->setMouseTracking(true);
}
void ScrollIndicator::paintEvent(QPaintEvent *event){
QPainter painter(this);
painter.setPen(Qt::NoPen);
painter.setBrush(curColor);
painter.drawRect(this->rect());
}
void ScrollIndicator::enterEvent(QEnterEvent *event){
if(!pressed){
hovTimer->start(100);
curColor = hoverColor;
update();
}
}
void ScrollIndicator::leaveEvent(QEvent *event){
hovTimer->stop();
curColor = defaultColor;
QPropertyAnimation* narrow = new QPropertyAnimation(this, "geometry");
narrow->setDuration(300);
narrow->setStartValue(QRect(this->x(), this->y(), this->width(), this->height()));
narrow->setEndValue(QRect(this->parentWidget()->width() - margin - defaultWidth, this->y(), defaultWidth, this->height()));
narrow->setEasingCurve(QEasingCurve::InOutQuad);
narrow->start(QAbstractAnimation::DeleteWhenStopped);
aniPause->start(300);
update();
}
void ScrollIndicator::mousePressEvent(QMouseEvent *event){
curColor = pressColor;
pressed = true;
//>note: globalPos -> globalPosition here due to deprecation
//> may cause issues
lastY = event->globalPosition().y();
update();
}
void ScrollIndicator::mouseMoveEvent(QMouseEvent *event){
if(pressed && !aniPause->isActive()){
//>note: globalPos -> globalPosition here due to deprecation
//> may cause issues
int dp = event->globalPosition().y() - lastY;
emit scrollPage(dp);
//>note: globalPos -> globalPosition here due to deprecation
//> may cause issues
lastY = event->globalPosition().y();
}
}
void ScrollIndicator::mouseReleaseEvent(QMouseEvent *event){
pressed = false;
curColor = hoverColor;
update();
}
void ScrollIndicator::setHoverActive(){
QPropertyAnimation* widen = new QPropertyAnimation(this, "geometry");
widen->setDuration(300);
widen->setStartValue(QRect(this->x(), this->y(), this->width(), this->height()));
widen->setEndValue(QRect(this->parentWidget()->width() - margin - defaultWidthAtFocus, this->y(), defaultWidthAtFocus, this->height()));
widen->setEasingCurve(QEasingCurve::InOutQuad);
widen->start(QAbstractAnimation::DeleteWhenStopped);
aniPause->start(300);
}

144
customScrollContainer.h Normal file
View File

@ -0,0 +1,144 @@
#ifndef CUSTOMSCROLLCONTAINER_H
#define CUSTOMSCROLLCONTAINER_H
#include <QWidget>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPainter>
#include <QPropertyAnimation>
#include <QParallelAnimationGroup>
#include <QSequentialAnimationGroup>
#include <QGraphicsOpacityEffect>
#include <QVector>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QTimer>
#define MAXSPEED 70
class ScrollAreaCustom;
class ScrollListContainer;
class ScrollIndicator;
class ScrollAreaCustom : public QWidget
{
Q_OBJECT
private:
QTimer* getCord;
QTimer* rfrshView;
ScrollListContainer* container;
ScrollIndicator* indicator;
QPropertyAnimation* bounce;
bool pressed = false;
bool scrollDown = true;
bool outOfEdge = false;
bool ignoreMaxSpeed = false;
int strtY;
int lastY;
int bfEdgeY; //last y value before out of edge
int curSpd = 0;
int damp = 1;
int moveStored = 0;
int nextMove = 1;
void paintEvent(QPaintEvent* event);
void mousePressEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
void wheelEvent(QWheelEvent* event);
void bounceBack();
public:
explicit ScrollAreaCustom(QWidget *parent = nullptr);
void addWidget(QWidget* newWidget, bool setAnimation = true);
void addWidgets(QVector<QWidget*> widgets){for(int i = 0; i < widgets.size(); i++)addWidget(widgets[i], false);}
void removeWidget(QWidget* w = nullptr);
void scrollToTop();
void updateHeight();
void clear();
signals:
private slots:
void scrollContainer();
void updateSpd();
void scrollIndicator(int dp);
};
class ScrollListContainer : public QWidget
{
Q_OBJECT
public:
explicit ScrollListContainer(QWidget *parent = nullptr);
void AddWidget(QWidget* widget, bool setAnimation = true);
void RemoveWidget(QWidget* widget = nullptr);
void updateHeight();
void clear();
//void RemoveWidget(QWidget* widget);
private:
//QTimer* newWidgetFade;
int spacing = 3;
QVector<QWidget*> widgets;
int size = 0;
QVector<int> ys;
void paintEvent(QPaintEvent* event);
signals:
private slots:
};
class ScrollIndicator : public QWidget
{
Q_OBJECT
private:
QColor curColor;
QColor defaultColor = QColor(100, 100, 100, 130);
QColor hoverColor = QColor(70, 70, 70, 150);
QColor pressColor = QColor(50, 50, 50, 170);
QTimer* hovTimer;
QTimer* aniPause;
int lastY;
int defaultWidth = 2;
int defaultWidthAtFocus = 9;
int margin = 3;
bool pressed = false;
public:
explicit ScrollIndicator(QWidget *parent = nullptr);
private:
void paintEvent(QPaintEvent* event);
void enterEvent(QEnterEvent* event);
void leaveEvent(QEvent* event);
void mousePressEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
signals:
void scrollPage(int);
private slots:
void setHoverActive();
};
#endif // CUSTOMSCROLLCONTAINER_H

828
customWidgets.cpp Normal file
View File

@ -0,0 +1,828 @@
#include "customWidgets.h"
//*********************************************************//
//CustomIcon class implementation
//*********************************************************//
customIcon::customIcon(QString iconPath, QString hint, int r, QWidget *parent):
QPushButton(parent),
radius(r),
iconHint(hint){
QSvgRenderer renderer;
renderer.load(iconPath);
QSize size = renderer.defaultSize();
iconImg = new QPixmap(size);
iconImg->fill(Qt::transparent);
QPainter painter(iconImg);
painter.setRenderHints(QPainter::Antialiasing);
renderer.render(&painter);
widgetRatio = iconImg->height() / iconImg->width();
bgColor = defaultColor;
}
customIcon::customIcon(const QPixmap &icon, QString hint, int r, QWidget *parent):
QPushButton(parent),
radius(r),
iconHint(hint){
iconImg = new QPixmap(icon);
widgetRatio = iconImg->height() / iconImg->width();
bgColor = defaultColor;
}
void customIcon::paintEvent(QPaintEvent *event){
resize(height() / widgetRatio, height());
QPainter bgPainter(this);
bgPainter.setRenderHints(QPainter::Antialiasing);
bgPainter.setPen(Qt::NoPen);
bgPainter.setBrush(bgColor);
bgPainter.drawRoundedRect(this->rect(), radius, radius);
QPainter pixmapPainter(this);
pixmapPainter.setRenderHints(QPainter::Antialiasing);
pixmapPainter.translate(width() / 2, height() / 2);
pixmapPainter.rotate(rotation);
pixmapPainter.translate(-width() / 2, -height() / 2);
int w = iconSizeRate * width();
int h = iconSizeRate * height();
pixmapPainter.drawPixmap(width() / 2 - w / 2, height() / 2 - h / 2, w, h, *iconImg);
}
void customIcon::enterEvent(QEnterEvent *event){
bgColor = hoverColor;
update();
}
void customIcon::leaveEvent(QEvent *event){
bgColor = defaultColor;
update();
}
void customIcon::mousePressEvent(QMouseEvent *event){
emit clicked();
setFocus();
iconSizeRate -= 0.1;
update();
}
void customIcon::mouseReleaseEvent(QMouseEvent *event){
iconSizeRate += 0.1;
update();
}
//*********************************************************//
//selectionItem class implementation
//*********************************************************//
selectionItem::selectionItem(QString name, QString info, QWidget *parent) :
QWidget(parent){
/* set labels */
QFont titleFont = QFont("Corbel", 13);
QFontMetrics fm(titleFont);
qreal height = fm.lineSpacing();
title = new QLabel(this);
title->setText(name);
title->setFont(titleFont);
title->setMinimumHeight(height);
title->setStyleSheet("color:#2c2c2c");
title->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
QFont descFont = QFont("Corbel Light", 11);
fm = QFontMetrics(descFont);
height = fm.lineSpacing();
description = new QLabel(this);
description->setText(info);
description->setFont(descFont);
description->setMinimumHeight(height);
description->setAlignment(Qt::AlignLeft | Qt::AlignTop);
description->setStyleSheet("color:#707070");
indicator = new QWidget(this);
/* set minimum height and layout */
setFixedHeight(title->height() + (info == "" ? 0 : description->height() + 5));
indicator->resize(6, 0.4 * this->height());
indicator->move(4, 0.3 * this->height());
indicator->setStyleSheet("border-radius:3px;background-color:#0078D4");
opac = new QGraphicsOpacityEffect(indicator);
opac->setOpacity(0);
indicator->setGraphicsEffect(opac);
QVBoxLayout *contentLayout = new QVBoxLayout(this);
contentLayout->setContentsMargins(20, 0, 0, 0);
contentLayout->setSpacing(2);
this->setLayout(contentLayout);
contentLayout->addWidget(title);
if(info != "")
contentLayout->addWidget(description);
contentLayout->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
/* set background widget */
bgWidget = new QWidget(this);
bgWidget->resize(this->size());
bgWidget->setStyleSheet("border-radius:5px;background-color:#00000000");
bgWidget->lower();
bgWidget->show();
this->setMouseTracking(true);
}
void selectionItem::enterEvent(QEnterEvent *event){
bgWidget->setStyleSheet("border-radius:5px;background-color:#0a000000");
QParallelAnimationGroup *enter = new QParallelAnimationGroup(this);
QPropertyAnimation *longer = new QPropertyAnimation(indicator, "geometry", this);
longer->setStartValue(indicator->geometry());
longer->setEndValue(QRectF(4, 0.25 * this->height(), 6, this->height() * 0.5));
longer->setDuration(150);
longer->setEasingCurve(QEasingCurve::OutBack);
QPropertyAnimation *fadeIn = new QPropertyAnimation(opac, "opacity", this);
fadeIn->setStartValue(opac->opacity());
fadeIn->setEndValue(0.99);
fadeIn->setDuration(100);
enter->addAnimation(longer);
enter->addAnimation(fadeIn);
enter->start();
}
void selectionItem::leaveEvent(QEvent *event){
bgWidget->setStyleSheet("border-radius:5px;background-color:#00000000");
QParallelAnimationGroup *leave = new QParallelAnimationGroup(this);
QPropertyAnimation *shorter = new QPropertyAnimation(indicator, "geometry", this);
shorter->setStartValue(indicator->geometry());
shorter->setEndValue(QRectF(4, 0.3 * this->height(), 6, this->height() * 0.4));
shorter->setDuration(150);
shorter->setEasingCurve(QEasingCurve::OutBack);
QPropertyAnimation *fadeOut = new QPropertyAnimation(opac, "opacity", this);
fadeOut->setStartValue(opac->opacity());
fadeOut->setEndValue(onSelected ? 0.99 : 0);
fadeOut->setDuration(100);
leave->addAnimation(shorter);
leave->addAnimation(fadeOut);
leave->start();
if(mousePressed)
mousePressed = false;
}
void selectionItem::mousePressEvent(QMouseEvent *event){
bgWidget->setStyleSheet("border-radius:5px;background-color:#1a000000");
QPropertyAnimation *shorter = new QPropertyAnimation(indicator, "geometry", this);
shorter->setStartValue(indicator->geometry());
shorter->setEndValue(QRectF(4, 0.4 * this->height(), 6, this->height() * 0.2));
shorter->setDuration(100);
shorter->setEasingCurve(QEasingCurve::OutBack);
shorter->start();
mousePressed = true;
}
void selectionItem::mouseReleaseEvent(QMouseEvent *event){
if(mousePressed){
bgWidget->setStyleSheet("border-radius:5px;background-color:#0a000000");
QPropertyAnimation *longer = new QPropertyAnimation(indicator, "geometry", this);
longer->setStartValue(indicator->geometry());
longer->setEndValue(QRectF(4, 0.25 * this->height(), 6, this->height() * 0.5));
longer->setDuration(150);
longer->setEasingCurve(QEasingCurve::OutBack);
longer->start();
if(!onSelected){
onSelected = true;
title->setStyleSheet("color:#005FB8");
description->setStyleSheet("color:#3a8fb7");
emit selected(this);
setFocus();
}
mousePressed = false;
}
}
void selectionItem::resizeEvent(QResizeEvent *event){
bgWidget->resize(this->size());
}
void selectionItem::Select(){
if(!onSelected){
onSelected = true;
title->setStyleSheet("color:#005FB8");
description->setStyleSheet("color:#3a8fb7");
indicator->setGeometry(4, 0.5 * this->height(), 6, 0);
QParallelAnimationGroup *sel = new QParallelAnimationGroup(this);
QPropertyAnimation *longer = new QPropertyAnimation(indicator, "geometry", this);
longer->setStartValue(indicator->geometry());
longer->setEndValue(QRectF(4, 0.3 * this->height(), 6, this->height() * 0.4));
longer->setDuration(150);
longer->setEasingCurve(QEasingCurve::OutBack);
QPropertyAnimation *fadeIn = new QPropertyAnimation(opac, "opacity", this);
fadeIn->setStartValue(opac->opacity());
fadeIn->setEndValue(0.99);
fadeIn->setDuration(100);
sel->addAnimation(longer);
sel->addAnimation(fadeIn);
sel->start();
emit selected(this);
}
}
void selectionItem::Deselect(){
if(onSelected){
onSelected = false;
title->setStyleSheet("color:#2c2c2c");
description->setStyleSheet("color:#707070");
QPropertyAnimation *fadeOut = new QPropertyAnimation(opac, "opacity", this);
fadeOut->setStartValue(opac->opacity());
fadeOut->setEndValue(0);
fadeOut->setDuration(100);
fadeOut->start();
}
}
singleSelectGroup::singleSelectGroup(QString name, QWidget *parent) :
QWidget(parent){
QFont titleFont = QFont("Corbel", 16);
QFontMetrics fm(titleFont);
qreal height = fm.lineSpacing();
groupName = new QLabel(this);
groupName->setMinimumHeight(height);
groupName->setFont(titleFont);
groupName->setText(name);
QWidget *spacingLine = new QWidget(this);
spacingLine->setFixedHeight(1);
spacingLine->setStyleSheet("background-color:#0a000000");
this->setFixedHeight(groupName->height() + middleSpacing + 1 + bottomSpacing);
mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(10, 0, 10, bottomSpacing);
mainLayout->setSpacing(middleSpacing);
mainLayout->addWidget(groupName);
mainLayout->addWidget(spacingLine);
}
void singleSelectGroup::AddItem(selectionItem *item){
selections.push_back(item);
this->setFixedHeight(this->height() + middleSpacing + item->height());
mainLayout->addWidget(item);
if(selectedID == -1){
item->Select();
selectedID = 0;
}
connect(item, SIGNAL(selected(selectionItem*)), this, SLOT(changeSelection(selectionItem*)));
emit itemChange();
}
void singleSelectGroup::RemoveItem(selectionItem *item){
int id = selections.indexOf(item);
if(id < 0) return;
selections.erase(selections.begin() + id);
mainLayout->removeWidget(item);
item->setParent(nullptr);
item->deleteLater();
this->setFixedHeight(this->height() - middleSpacing - item->height());
if(selections.size() == 0)
selectedID = -1;
else{
selectedID = id < selections.size() ? id : id - 1;
selections[selectedID]->Select();
}
emit selectedItemChange(selectedID);
emit itemChange();
}
void singleSelectGroup::SetSelection(selectionItem *item){
int id = selections.indexOf(item);
selections[id]->Select();
}
void singleSelectGroup::changeSelection(selectionItem *item){
int id = selections.indexOf(item);
for(int i = 0; i < selections.size(); i++){
if(i == id) continue;
selections[i]->Deselect();
}
selectedID = id;
emit selectedItemChange(id);
}
horizontalValueAdjuster::horizontalValueAdjuster(QString name, qreal min, qreal max, qreal step, QWidget *parent) :
QWidget(parent),
curValue(min),
minValue(min),
maxValue(max),
stepValue(step)
{
QFont titleFont = QFont("Corbel", 16);
QFontMetrics fm(titleFont);
qreal height = fm.lineSpacing();
title = new QLabel(this);
title->setMinimumHeight(height);
title->setFont(titleFont);
title->setText(name);
QWidget *spacingLine = new QWidget(this);
spacingLine->setFixedHeight(1);
spacingLine->setStyleSheet("background-color:#0a000000");
slider = new QSlider(Qt::Horizontal, this);
slider->setMinimum(0);
slider->setMaximum((max - min) / step + 1);
slider->setPageStep(1);
QString grooveStyle = "QSlider::groove:horizontal{height:6px; border-radius:3px;} ";
QString sliderStyle = "QSlider::handle:horizontal{width:12px; margin-bottom:-3px; margin-top:-3px; background:#c2c2c2; border-radius:6px;} ";
QString sliderHStyle = "QSlider::handle:horizontal:hover{width:12px; margin-bottom:-3px; margin-top:-3px; background:#3a8fb7; border-radius:6px;} ";
QString sliderPStyle = "QSlider::handle:horizontal:pressed{width:12px; margin-bottom:-3px; margin-top:-3px; background:#005fb8; border-radius:6px;} ";
QString subStyle = "QSlider::sub-page:horizontal{background:#0078D4; border-radius:3px} ";
QString addStyle = "QSlider::add-page:horizontal{background:#1a000000; border-radius:3px} ";
slider->setStyleSheet(grooveStyle+sliderStyle+sliderHStyle+sliderPStyle+subStyle+addStyle);
QFont valueFont = QFont("Corbel", 13);
fm = QFontMetrics(titleFont);
height = fm.lineSpacing();
valueLabel = new QLabel(this);
valueLabel->setMinimumHeight(height);
valueLabel->setFont(valueFont);
valueLabel->setText(QString::asprintf("%g", min));
valueLabel->setMinimumWidth(30);
valueLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
valueLabel->setStyleSheet("margin-bottom:5px");
QWidget *content = new QWidget(this);
content->setMinimumHeight(valueLabel->height() < slider->height() ? valueLabel->height() : slider->height());
QHBoxLayout *contentLayout = new QHBoxLayout(content);
contentLayout->setAlignment(Qt::AlignVCenter);
content->setLayout(contentLayout);
contentLayout->setContentsMargins(0, 0, 0, 0);
contentLayout->setSpacing(10);
contentLayout->addWidget(valueLabel);
contentLayout->addWidget(slider);
this->setMinimumHeight(title->height() + 2 * middleSpacing + 1 + content->height() + bottomSpacing);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
this->setLayout(mainLayout);
mainLayout->setContentsMargins(10, 0, 10, bottomSpacing);
mainLayout->setSpacing(middleSpacing);
mainLayout->addWidget(title);
mainLayout->addWidget(spacingLine);
mainLayout->addWidget(content);
connect(slider, &QSlider::valueChanged, this, [=](qreal value){
valueLabel->setText(QString::asprintf("%g", value * stepValue + minValue));
curValue = value * stepValue + minValue;
emit valueChanged(curValue);
});
}
void horizontalValueAdjuster::setValue(qreal value){
valueLabel->setText(QString::asprintf("%g", value));
slider->setValue((value - minValue) / stepValue);
curValue = value;
emit valueChanged(value);
}
//********************
//itemGroup::itemGroup(const QString &name, QWidget *parent){
// QFont titleFont = QFont("DengXian", 16, QFont::DemiBold);
// QFontMetrics fm(titleFont);
// qreal height = fm.lineSpacing();
// groupName = new QLabel(this);
// groupName->setFixedHeight(height);
// groupName->setFont(titleFont);
// groupName->setText(name);
//
// QWidget *spacingLine = new QWidget(this);
// spacingLine->setFixedHeight(1);
// spacingLine->setStyleSheet("background-color:#0a000000");
//
// this->setFixedHeight(groupName->height() + middleSpacing + 1 + bottomSpacing);
//
// mainLayout = new QVBoxLayout(this);
// mainLayout->setContentsMargins(10, 0, 10, bottomSpacing);
// mainLayout->setSpacing(middleSpacing);
// mainLayout->addWidget(groupName);
// mainLayout->addWidget(spacingLine);
//}
//
//void itemGroup::AddItem(QWidget *item){
// items.push_back(item);
// this->setFixedHeight(this->height() + middleSpacing + item->height());
// mainLayout->addWidget(item);
//}
//
//void itemGroup::RemoveItem(QWidget *item){
// items.erase(items.begin() + items.indexOf(item));
// mainLayout->removeWidget(item);
// this->setFixedHeight(this->height() - middleSpacing - item->height());
//}
//*****************
bigIconButton::bigIconButton(const QString &iconPath, const QString &description, int radius, QWidget *parent) :
QWidget(parent),
cornerRadius(radius)
{
iconImg = new QPixmap(iconPath);
/* set icon label and text label */
icon = new QLabel(this);
icon->setPixmap(*iconImg);
icon->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
icon->setAlignment(Qt::AlignCenter);
QFont textFont = QFont("Corbel", 13);
QFontMetrics fm(textFont);
text = new QLabel(this);
text->setFont(textFont);
text->setText(description);
text->setWordWrap(true);
text->setMinimumHeight(fm.lineSpacing());
text->setAlignment(Qt::AlignCenter);
/* set indicator */
indicator = new QWidget(this);
indicator->resize(6, 6);
indicator->move(this->width() - 3, this->height() - 21);
indicator->setStyleSheet("border-radius:3px;background-color:#afafaf");
/* set background */
bgWidget = new QWidget(this);
bgWidget->resize(this->size());
radiusStyle = QString::asprintf("border-radius:%dpx;", cornerRadius);
bgWidget->setStyleSheet(radiusStyle + "background-color:#00000000");
bgWidget->lower();
bgWidget->show();
/* set layout */
QVBoxLayout *layout = new QVBoxLayout(this);
this->setLayout(layout);
layout->setContentsMargins(15, 35, 15, 35);
layout->setSpacing(15);
layout->addWidget(icon);
layout->addWidget(text);
layout->setAlignment(Qt::AlignCenter);
this->setMinimumHeight(200);
}
void bigIconButton::resizeEvent(QResizeEvent *event){
bgWidget->setFixedSize(this->size());
if(onSelected){
indicator->resize(this->width() * 0.1, 6);
indicator->move(this->width() * 0.45, this->height() - 21);
}
else{
indicator->resize(this->width() * 0.4, 6);
indicator->move(this->width() * 0.3, this->height() - 21);
}
}
void bigIconButton::enterEvent(QEnterEvent *event){
bgWidget->setStyleSheet(radiusStyle + "background-color:#0a0078D4");
QPropertyAnimation *longer = new QPropertyAnimation(indicator, "geometry", this);
longer->setStartValue(indicator->geometry());
longer->setEndValue(QRectF(this->width() * 0.2, this->height() - 21, this->width() * 0.6, 6));
longer->setDuration(150);
longer->setEasingCurve(QEasingCurve::OutBack);
longer->start();
indicator->setStyleSheet("border-radius:3px;background-color:#0078d4");
}
void bigIconButton::leaveEvent(QEvent *event){
bgWidget->setStyleSheet(radiusStyle + "background-color:#00000000");
QPropertyAnimation *shorter = new QPropertyAnimation(indicator, "geometry", this);
shorter->setStartValue(indicator->geometry());
if(!onSelected)
shorter->setEndValue(QRectF(this->width() * 0.45, this->height() - 21, this->width() * 0.1, 6));
else
shorter->setEndValue(QRectF(this->width() * 0.3, this->height() - 21, this->width() * 0.4, 6));
shorter->setDuration(250);
shorter->setEasingCurve(QEasingCurve::OutBack);
shorter->start();
if(!onSelected)
indicator->setStyleSheet("border-radius:3px;background-color:#afafaf");
if(mousePressed)
mousePressed = false;
}
void bigIconButton::mousePressEvent(QMouseEvent *event){
bgWidget->setStyleSheet(radiusStyle + "background-color:#1a0078D4");
QPropertyAnimation *shorter = new QPropertyAnimation(indicator, "geometry", this);
shorter->setStartValue(indicator->geometry());
shorter->setEndValue(QRectF(this->width() * 0.4, this->height() - 21, this->width() * 0.2, 6));
shorter->setDuration(100);
shorter->setEasingCurve(QEasingCurve::OutBack);
shorter->start();
mousePressed = true;
}
void bigIconButton::mouseReleaseEvent(QMouseEvent *event){
if(mousePressed){
bgWidget->setStyleSheet(radiusStyle + "background-color:#0a0078D4");
QPropertyAnimation *longer = new QPropertyAnimation(indicator, "geometry", this);
longer->setStartValue(indicator->geometry());
longer->setEndValue(QRectF(this->width() * 0.2, this->height() - 21, this->width() * 0.6, 6));
longer->setDuration(150);
longer->setEasingCurve(QEasingCurve::OutBack);
longer->start();
mousePressed = false;
emit clicked();
if(selectable){
emit selected();
onSelected = true;
}
}
}
void bigIconButton::setScale(qreal scale){
iconImg = new QPixmap(iconImg->scaled(iconImg->size() * scale, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
icon->setPixmap(*iconImg);
}
textInputItem::textInputItem(const QString &name, QWidget *parent) :
QWidget(parent)
{
QFont nameFont = QFont("Corbel", 12);
QFontMetrics fm(nameFont);
qreal height = fm.lineSpacing();
itemName = new QLabel(this);
itemName->setText(name);
itemName->setFont(nameFont);
itemName->setFixedHeight(height);
itemName->setStyleSheet("color:#1c1c1c");
QFont textFont = QFont("Corbel", 12);
fm = QFontMetrics(textFont);
editor = new QLineEdit(this);
editor->setText("");
editor->setFixedHeight(fm.lineSpacing());
editor->setStyleSheet("color:#5c5c5c;background-color:#00000000;border-style:none;");
editor->setReadOnly(true);
editor->setFont(textFont);
bgWidget = new QWidget(this);
bgWidget->setStyleSheet("background-color:#00000000;border-radius:5px;");
bgWidget->lower();
bgWidget->show();
indicator = new QWidget(this);
indicator->setFixedHeight(4);
indicator->setStyleSheet("background-color:#0078d4;border-radius:2px");
opac = new QGraphicsOpacityEffect(this);
opac->setOpacity(0);
indicator->setGraphicsEffect(opac);
this->setFixedHeight(itemName->height() + 10);
connect(editor, &QLineEdit::returnPressed, this, [=](){
leaveEditEffect();
onEditing = false;
editor->setReadOnly(true);
curText = editor->text();
});
connect(editor, &QLineEdit::editingFinished, this, [=](){
leaveEditEffect();
onEditing = false;
editor->setReadOnly(true);
curText = editor->text();
QTimer *delay = new QTimer(this);
connect(delay, &QTimer::timeout, this, [=](){mousePressed = false;});
delay->setSingleShot(true);
delay->start(10);
mousePressed = false;
emit textEdited(curText);
});
}
void textInputItem::resizeEvent(QResizeEvent *event){
itemName->move(margin, this->height() / 2 - itemName->height() / 2);
itemName->setFixedWidth(this->width() * 0.3 - margin - spacing);
int width = QFontMetrics(editor->font()).size(Qt::TextSingleLine, editor->text()).width() + 3;
if(!onEditing){
if(width > this->width() * 0.7 - margin)
editor->resize(this->width() * 0.7 - margin, editor->height());
else
editor->resize(width, editor->height());
editor->move(this->width() - margin - editor->width(), this->height() / 2 - editor->height() / 2);
indicator->move(this->width() - margin, this->height() - 7);
}
else{
editor->resize(this->width() * 0.7 - margin, editor->height());
editor->move(this->width() * 0.3, this->height() / 2 - editor->height() / 2 - 2);
indicator->move(this->width() * 0.3, this->height() - 7);
}
bgWidget->setFixedSize(this->size());
}
void textInputItem::enterEditEffect(){
editor->setCursorPosition(editor->text().length());
editor->setStyleSheet("color:#1c1c1c;background-color:#00000000;border-style:none;");
QParallelAnimationGroup *group = new QParallelAnimationGroup(this);
QPropertyAnimation *longer = new QPropertyAnimation(indicator, "geometry", this);
longer->setStartValue(indicator->geometry());
longer->setEndValue(QRectF(this->width() * 0.3, this->height() - 7, this->width() * 0.7 - margin, 4));
longer->setDuration(500);
longer->setEasingCurve(QEasingCurve::InOutExpo);
QPropertyAnimation *fade = new QPropertyAnimation(opac, "opacity", this);
fade->setStartValue(opac->opacity());
fade->setEndValue(0.99);
fade->setDuration(150);
QPropertyAnimation *move = new QPropertyAnimation(editor, "geometry", this);
move->setStartValue(editor->geometry());
move->setEndValue(QRectF(this->width() * 0.3, this->height() / 2 - editor->height() / 2 - 2, this->width() * 0.7 - margin, editor->height()));
move->setDuration(500);
move->setEasingCurve(QEasingCurve::InOutExpo);
group->addAnimation(longer);
group->addAnimation(fade);
group->addAnimation(move);
group->start();
}
void textInputItem::leaveEditEffect(){
editor->setCursorPosition(0);
editor->setStyleSheet("color:#5c5c5c;background-color:#00000000;border-style:none;");
QParallelAnimationGroup *group = new QParallelAnimationGroup(this);
QPropertyAnimation *shorter = new QPropertyAnimation(indicator, "geometry", this);
shorter->setStartValue(indicator->geometry());
shorter->setEndValue(QRectF(this->width() - margin - 4, this->height() - 7, 4, 4));
shorter->setDuration(500);
shorter->setEasingCurve(QEasingCurve::InOutExpo);
QPropertyAnimation *fade = new QPropertyAnimation(opac, "opacity", this);
fade->setStartValue(opac->opacity());
fade->setEndValue(0);
fade->setDuration(350);
QPropertyAnimation *move = new QPropertyAnimation(editor, "geometry", this);
move->setStartValue(editor->geometry());
int width = QFontMetrics(editor->font()).size(Qt::TextSingleLine, editor->text()).width() + 3;
if(width > this->width() * 0.7 - margin)
move->setEndValue(QRectF(this->width() * 0.3, this->height() / 2 - editor->height() / 2, this->width() * 0.7 - margin, editor->height()));
else
move->setEndValue(QRectF(this->width() - width - margin, this->height() / 2 - editor->height() / 2, width, editor->height()));
move->setDuration(500);
move->setEasingCurve(QEasingCurve::InOutExpo);
group->addAnimation(shorter);
group->addAnimation(fade);
group->addAnimation(move);
group->start();
}
void textInputItem::enterEvent(QEnterEvent *event){
bgWidget->setStyleSheet("border-radius:5px;background-color:#0a000000");
}
void textInputItem::leaveEvent(QEvent *event){
bgWidget->setStyleSheet("border-radius:5px;background-color:#00000000");
}
void textInputItem::mousePressEvent(QMouseEvent *event){
bgWidget->setStyleSheet("border-radius:5px;background-color:#1a000000");
mousePressed = true;
}
void textInputItem::mouseReleaseEvent(QMouseEvent *event){
if(mousePressed){
bgWidget->setStyleSheet("border-radius:5px;background-color:#0a000000");
if(onEditing){
leaveEditEffect();
onEditing = false;
curText = editor->text();
editor->setReadOnly(true);
emit textEdited(curText);
}
else{
if(enabled){
enterEditEffect();
editor->raise();
onEditing = true;
editor->setReadOnly(false);
editor->setText(curText + "");
editor->setFocus();
}
}
mousePressed = false;
}
}
void textInputItem::setValue(const QString &text){
editor->setText(text);
editor->setCursorPosition(0);
curText = text;
int width = QFontMetrics(editor->font()).size(Qt::TextSingleLine, editor->text()).width() + 3;
if(!onEditing){
if(width > this->width() * 0.7 - margin)
editor->resize(this->width() * 0.7 - margin, editor->height());
else
editor->resize(width, editor->height());
editor->move(this->width() - margin - editor->width(), this->height() / 2 - editor->height() / 2);
}
else{
editor->resize(this->width() * 0.7 - margin, editor->height());
editor->move(this->width() * 0.3, this->height() / 2 - editor->height() / 2 - 2);
}
}
textButton::textButton(QString text, QWidget *parent, qreal ratio) :
QWidget(parent)
{
QFont textFont = QFont("Corbel", 10);
QFontMetrics fm(textFont);
qreal height = fm.lineSpacing();
btnText = new QLabel(this);
btnText->setText(text);
btnText->setFont(textFont);
btnText->setFixedHeight(height);
btnText->setFixedWidth(fm.size(Qt::TextSingleLine, text).width() + 2);
btnText->setStyleSheet("color:#1c1c1c");
btnText->setAlignment(Qt::AlignCenter);
bgWidget = new QWidget(this);
bgWidget->setStyleSheet("background-color:"+defaultColor+";border-radius:5px;");
this->setFixedHeight(btnText->height() / ratio);
}
textButton::textButton(QString text, QString defC, QString hoverC, QString pressedC, QWidget *parent, qreal ratio):
QWidget(parent),
defaultColor(defC),
hoverColor(hoverC),
pressedColor(pressedC)
{
QFont textFont = QFont("Corbel", 10);
QFontMetrics fm(textFont);
qreal height = fm.lineSpacing();
btnText = new QLabel(this);
btnText->setText(text);
btnText->setFont(textFont);
btnText->setFixedHeight(height);
btnText->setFixedWidth(fm.size(Qt::TextSingleLine, text).width() + 2);
btnText->setStyleSheet("color:#1c1c1c");
btnText->setAlignment(Qt::AlignCenter);
bgWidget = new QWidget(this);
bgWidget->setStyleSheet("background-color:"+defaultColor+";border-radius:5px;");
this->setFixedHeight(btnText->height() / ratio);
}
void textButton::resizeEvent(QResizeEvent *event){
bgWidget->resize(this->size());
btnText->move(this->width() / 2 - btnText->width() / 2, this->height() / 2 - btnText->height() / 2);
}
void textButton::enterEvent(QEnterEvent *event){
bgWidget->setStyleSheet("background-color:"+hoverColor+";border-radius:5px;");
}
void textButton::leaveEvent(QEvent *event){
bgWidget->setStyleSheet("background-color:"+defaultColor+";border-radius:5px;");
if(mousePressed){
bgWidget->setStyleSheet("background-color:"+pressedColor+";border-radius:5px;");
QPropertyAnimation *enlarge = new QPropertyAnimation(bgWidget, "geometry", this);
enlarge->setStartValue(bgWidget->geometry());
enlarge->setEndValue(QRect(0, 0, this->width(), this->height()));
enlarge->setDuration(150);
enlarge->setEasingCurve(QEasingCurve::OutBounce);
enlarge->start();
mousePressed = false;
}
}
void textButton::mousePressEvent(QMouseEvent *event){
bgWidget->setStyleSheet("background-color:"+pressedColor+";border-radius:5px;");
QPropertyAnimation *shrink = new QPropertyAnimation(bgWidget, "geometry", this);
shrink->setStartValue(bgWidget->geometry());
shrink->setEndValue(QRect(0.05 * this->width(), 0.05 * this->height(), this->width() * 0.9, this->height() * 0.9));
shrink->setDuration(100);
shrink->setEasingCurve(QEasingCurve::OutBack);
shrink->start();
mousePressed = true;
setFocus();
}
void textButton::mouseReleaseEvent(QMouseEvent *event){
if(mousePressed){
bgWidget->setStyleSheet("background-color:"+hoverColor+";border-radius:5px;");
QPropertyAnimation *enlarge = new QPropertyAnimation(bgWidget, "geometry", this);
enlarge->setStartValue(bgWidget->geometry());
enlarge->setEndValue(QRect(0, 0, this->width(), this->height()));
enlarge->setDuration(150);
enlarge->setEasingCurve(QEasingCurve::OutBounce);
enlarge->start();
mousePressed = false;
emit clicked();
}
}

258
customWidgets.h Normal file
View File

@ -0,0 +1,258 @@
#ifndef CUSTOMWIDGETS_H
#define CUSTOMWIDGETS_H
#include <QPushButton>
#include <QLineEdit>
#include <QRegularExpression>
#include <QRegularExpressionValidator>
#include <QSlider>
#include <QString>
#include <QtSvg>
#include <QPixmap>
#include <QPainter>
#include <QPaintEvent>
#include <QMouseEvent>
#include <QResizeEvent>
#include <QFocusEvent>
class customIcon : public QPushButton{
Q_OBJECT
Q_PROPERTY(qreal rotationAngle READ rotationAngle WRITE setRotationAngle NOTIFY rotationAngleChanged)
private:
int radius;
qreal widgetRatio;
qreal iconSizeRate = 0.8;
qreal rotation = 0;
QPixmap *iconImg;
QString iconHint;
/* for hover and click effects */
QColor bgColor;
QColor defaultColor = QColor(0, 0, 0, 0);
QColor hoverColor = QColor(241, 241, 241, 200);
protected:
void paintEvent(QPaintEvent* event);
void enterEvent(QEnterEvent *event);
void leaveEvent(QEvent* event);
void mousePressEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
protected:
qreal rotationAngle() const {return rotation;}
public:
customIcon(QString iconPath, QString hint = "", int r = 0, QWidget *parent = nullptr);
customIcon(const QPixmap &icon, QString hint = "", int r = 0, QWidget *parent = nullptr);
void setRotationAngle(qreal angle = 0){rotation = angle;update();}
signals:
void rotationAngleChanged();
};
class selectionItem : public QWidget{
Q_OBJECT
private:
QLabel *title;
QLabel *description;
QWidget *indicator;
QWidget *mainContent;
QWidget *bgWidget;
QGraphicsOpacityEffect *opac;
bool onSelected = false;
bool mousePressed = false;
void enterEvent(QEnterEvent *event);
void leaveEvent(QEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void resizeEvent(QResizeEvent *event);
public:
selectionItem(QString name, QString info = "", QWidget *parent = nullptr);
void Select();
void Deselect();
void setTitle(QString titleText){title->setText(titleText);}
void setDescription(QString descText){description->setText(descText);}
signals:
void selected(selectionItem *item);
//void heightChange();
};
class singleSelectGroup : public QWidget{
Q_OBJECT
private:
const int middleSpacing = 5;
const int bottomSpacing = 30;
QLabel *groupName;
QVBoxLayout *mainLayout;
int selectedID = -1;
QVector<selectionItem*> selections;
public:
singleSelectGroup(QString name = "", QWidget *parent = nullptr);
void AddItem(selectionItem *item);
void RemoveItem(selectionItem *item);
void SetSelection(selectionItem *item);
qreal value(){return selectedID;}
signals:
void selectedItemChange(int selectID);
void itemChange();
private slots:
void changeSelection(selectionItem *item);
};
class horizontalValueAdjuster : public QWidget{
Q_OBJECT
private:
const int middleSpacing = 5;
const int bottomSpacing = 30;
QLabel *title;
qreal curValue;
qreal minValue;
qreal maxValue;
qreal stepValue;
QWidget *editArea;
QLabel *valueLabel;
//QDoubleSpinBox *editLabel;
customIcon *decreaseBtn;
customIcon *increaseBtn;
QSlider *slider;
public:
horizontalValueAdjuster(QString name, qreal min, qreal max, qreal step, QWidget *parent = nullptr);
void setValue(qreal value);
qreal value(){return curValue;}
signals:
void valueChanged(qreal value);
};
//class itemGroup : public QWidget{
// Q_OBJECT
//
//private:
// const int middleSpacing = 5;
// const int bottomSpacing = 30;
// QLabel *groupName;
// QVBoxLayout *mainLayout;
// QVector<QWidget*> items;
//
//public:
// itemGroup(const QString &name, QWidget *parent = nullptr);
// void AddItem(QWidget *item);
// void RemoveItem(QWidget *item);
//};
class bigIconButton : public QWidget{
Q_OBJECT
private:
QPixmap *iconImg;
QLabel *text;
QLabel *icon;
QWidget *bgWidget;
QWidget *indicator;
int cornerRadius;
QString radiusStyle;
bool selectable = false;
bool mousePressed = false;
bool onSelected = false;
void enterEvent(QEnterEvent *event);
void leaveEvent(QEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void resizeEvent(QResizeEvent *event);
public:
bigIconButton(const QString &iconPath, const QString &description, int radius, QWidget *parent = nullptr);
void setSelectable(bool sel = true){selectable = sel;}
void setScale(qreal scale);
signals:
void clicked();
void selected();
};
class textInputItem : public QWidget{
Q_OBJECT
private:
const int margin = 10;
const int spacing = 10;
QLabel *itemName;
QLineEdit *editor;
QWidget *bgWidget;
QWidget *indicator;
QGraphicsOpacityEffect *opac;
QString curText = "";
bool mousePressed = false;
bool onEditing = false;
bool enabled = true;
void enterEditEffect();
void leaveEditEffect();
void enterEvent(QEnterEvent *event);
void leaveEvent(QEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void resizeEvent(QResizeEvent *event);
//void focusOutEvent(QFocusEvent *event);
public:
textInputItem(const QString &name, QWidget *parent = nullptr);
QLineEdit* lineEditor(){return editor;}
QString value(){return editor->text();}
void setValue(const QString &text);
void setValidator(QValidator *vali){editor->setValidator(vali);}
void setEnabled(bool enable = true){enabled = enable;}
signals:
void textEdited(QString text);
};
class textButton : public QWidget{
Q_OBJECT
private:
QLabel *btnText;
QWidget *bgWidget;
QString defaultColor = "#0a0078d4";
QString hoverColor = "#1a0078d4";
QString pressedColor = "#2a0078d4";
bool mousePressed;
void enterEvent(QEnterEvent *event);
void leaveEvent(QEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void resizeEvent(QResizeEvent *event);
public:
textButton(QString text, QWidget *parent = nullptr, qreal ratio = 0.5);
textButton(QString text, QString defC, QString hoverC, QString pressedC, QWidget *parent = nullptr, qreal ratio = 0.5);
signals:
void clicked();
};
#endif // CUSTOMWIDGETS_H

882
graph_implement.cpp Normal file
View File

@ -0,0 +1,882 @@
#include "graph_implement.h"
#include <QDebug>
AbstractGraph::~AbstractGraph(){}
void ALVex::visit(){
if(visited)
return;
info->gVex->visit(true);
visited = true;
}
void ALVex::access(const QString &hint){
info->gVex->access(hint);
}
void ALArc::visit(){
gArc->visit(true);
}
void ALArc::access(){
gArc->access();
}
ALGraph::~ALGraph(){
int i = vexList.size() - 1;
while(i >= 0)
DelVex(i--);
vexList.clear();
}
void ALGraph::AddVex(MyGraphicsVexItem *gvex){
ALVex newVex(gvex);
vexList.push_back(newVex);
}
void ALGraph::AddVex(VexInfo *info){
ALVex newVex(info);
vexList.push_back(newVex);
}
void ALGraph::AddArc(MyGraphicsLineItem *garc, int weight){
int strtVex = GetIdOf(garc->stVex());
int endVex = GetIdOf(garc->edVex());
ALArc *temp = vexList[strtVex].firstArc;
ALArc *newArc = new ALArc(garc, endVex, temp);
newArc->weight = weight;
vexList[strtVex].firstArc = newArc;
if(type == UDG){
temp = vexList[endVex].firstArc;
newArc = new ALArc(garc, strtVex, temp);
vexList[endVex].firstArc = newArc;
}
}
void ALGraph::DelVex(MyGraphicsVexItem *gvex){
int vexID = GetIdOf(gvex);
DelVex(vexID);
}
void ALGraph::DelVex(int vexID){
//Delete out arc
ALArc *curArc = vexList[vexID].firstArc;
while(curArc != nullptr){
ALArc *next = curArc->nextArc;
delete curArc;
curArc = next;
}
//Delete in arc and adjust arcs
for(int i = 0; i < vexList.size(); i++){
if(i == vexID) continue;
ALArc *dummyHead = new ALArc(nullptr, 0, vexList[i].firstArc);
ALArc *preArc = dummyHead;
while(preArc->nextArc != nullptr){
if(preArc->nextArc->eVexID == vexID){
ALArc *next = preArc->nextArc;
preArc->nextArc = next->nextArc;
delete next;
continue;
}
if(preArc->nextArc->eVexID > vexID)
preArc->nextArc->eVexID--;
preArc = preArc->nextArc;
}
vexList[i].firstArc = dummyHead->nextArc;
delete dummyHead;
}
vexList.erase(vexList.begin() + vexID);
}
void ALGraph::DelArc(MyGraphicsLineItem *garc){
int sVex = GetIdOf(garc->stVex());
int eVex = GetIdOf(garc->edVex());
DelArc(sVex, eVex);
}
void ALGraph::DelArc(int sVexID, int eVexID){
//Delete sVex -> eVex
if(vexList[sVexID].firstArc != nullptr){
if(vexList[sVexID].firstArc->eVexID == eVexID){
ALArc *awaitDel = vexList[sVexID].firstArc;
vexList[sVexID].firstArc = awaitDel->nextArc;
delete awaitDel;
}
else{
ALArc *preArc = vexList[sVexID].firstArc;
while(preArc->nextArc != nullptr && preArc->nextArc->eVexID != eVexID)
preArc = preArc->nextArc;
if(preArc->nextArc != nullptr){
ALArc *awaitDel = preArc->nextArc;
preArc->nextArc = awaitDel->nextArc;
delete awaitDel;
}
}
}
//Delete eVex -> sVex
if(type == UDG && vexList[eVexID].firstArc != nullptr){
if(vexList[eVexID].firstArc->eVexID == sVexID){
ALArc *awaitDel = vexList[eVexID].firstArc;
vexList[eVexID].firstArc = awaitDel->nextArc;
delete awaitDel;
}
else{
ALArc *preArc = vexList[eVexID].firstArc;
while(preArc->nextArc != nullptr && preArc->nextArc->eVexID != sVexID)
preArc = preArc->nextArc;
if(preArc->nextArc != nullptr){
ALArc *awaitDel = preArc->nextArc;
preArc->nextArc = awaitDel->nextArc;
delete awaitDel;
}
}
}
}
int ALGraph::GetIdOf(MyGraphicsVexItem *gvex){
int i = 0;
while(i < vexList.size() && !vexList[i].info->gVex->equalTo(gvex))
i++;
return i == vexList.size() ? -1 : i;
}
ALArc* ALGraph::FindArc(int sID, int eID){
if(sID < 0 || sID >= vexList.size())
return nullptr;
ALArc *p = vexList[sID].firstArc;
while(p != nullptr){
if(p->eVexID == eID)
return p;
p = p->nextArc;
}
return nullptr;
}
void ALGraph::SetWeight(MyGraphicsLineItem *garc, int weight){
int strtVex = GetIdOf(garc->stVex());
int endVex = GetIdOf(garc->edVex());
ALArc *p = vexList[strtVex].firstArc;
while(p != nullptr){
if(p->eVexID == endVex){
p->weight = weight;
p->gArc->setText(QString::asprintf("%d", weight));
}
p = p->nextArc;
}
if(type == UDG){
p = vexList[endVex].firstArc;
while(p != nullptr){
if(p->eVexID == strtVex){
p->weight = weight;
}
p = p->nextArc;
}
}
}
void ALGraph::ConvertType(int _type){
if(_type == type) return;
type = _type;
if(type == UDG){
for(int i = 0; i < vexList.size(); i++){
ALArc *dummyHead = new ALArc(nullptr, i, vexList[i].firstArc);
ALArc *pre = dummyHead;
while(pre->nextArc != nullptr){
if(pre->nextArc->eVexID == GetIdOf(pre->nextArc->gArc->edVex())){
ALArc *temp = vexList[pre->nextArc->eVexID].firstArc;
vexList[pre->nextArc->eVexID].firstArc = new ALArc(pre->nextArc->gArc, i, temp);
pre->nextArc->gArc->setDirection(false);
}
pre = pre->nextArc;
}
delete dummyHead;
}
}
else{
for(int i = 0; i < vexList.size(); i++){
ALArc *dummyHead = new ALArc(nullptr, i, vexList[i].firstArc);
ALArc *pre = dummyHead;
while(pre->nextArc != nullptr){
if(pre->nextArc->eVexID != GetIdOf(pre->nextArc->gArc->edVex())){
ALArc *temp = pre->nextArc;
pre->nextArc = temp->nextArc;
temp->gArc->setDirection(true);
delete temp;
continue;
}
pre = pre->nextArc;
}
vexList[i].firstArc = dummyHead->nextArc;
delete dummyHead;
}
}
}
void ALGraph::ClearVisit(){
for(int i = 0; i < vexList.size(); i++){
vexList[i].visited = false;
vexList[i].info->gVex->visit(false);
}
}
void ALGraph::ResetDistance(){
for(int i = 0; i < vexList.size(); i++){
vexList[i].info->strtVexInfo = nullptr;
vexList[i].info->distance = VexInfo::INF;
vexList[i].info->preVexID = -1;
vexList[i].info->gVex->access("", false);
}
}
void ALGraph::DFS(int strtID){
if(strtID == -1)
return;
vector<int> awaitVexList;
vector<ALArc*> awaitArcList;
awaitVexList.push_back(strtID);
while(awaitVexList.size() > 0){
int nextVex = awaitVexList.back();
ALArc *nextArc = awaitArcList.size() > 0 ? awaitArcList.back() : nullptr;
awaitVexList.pop_back();
if(nextArc)
awaitArcList.pop_back();
for(ALArc *p = vexList[nextVex].firstArc; p != nullptr; p = p->nextArc){
if(vexList[p->eVexID].visited == false){
awaitVexList.push_back(p->eVexID);
awaitArcList.push_back(p);
if(type == UDG && GetIdOf(p->gArc->edVex()) != p->eVexID)
p->gArc->reverseDirection();
}
}
if(nextArc && !vexList[nextArc->eVexID].visited)
nextArc->visit();
vexList[nextVex].visit();
}
}
void ALGraph::BFS(int strtID){
if(strtID == -1)
return;
vector<int> awaitVexList;
vector<ALArc*> awaitArcList;
awaitVexList.push_back(strtID);
while(awaitVexList.size() > 0){
int nextVex = awaitVexList[0];
ALArc *nextArc = awaitArcList.size() > 0 ? awaitArcList[0] : nullptr;
awaitVexList.erase(awaitVexList.begin());
if(nextArc)
awaitArcList.erase(awaitArcList.begin());
for(ALArc *p = vexList[nextVex].firstArc; p != nullptr; p = p->nextArc){
if(vexList[p->eVexID].visited == false){
awaitVexList.push_back(p->eVexID);
awaitArcList.push_back(p);
if(type == UDG && GetIdOf(p->gArc->edVex()) != p->eVexID)
p->gArc->reverseDirection();
}
}
if(nextArc && !vexList[nextArc->eVexID].visited)
nextArc->visit();
vexList[nextVex].visit();
}
}
void ALGraph::Dijkstra(int strtID){
//Clear previous result
ClearVisit();
ResetDistance();
//Set start vex info to all vertexes
for(int i = 0; i < vexList.size(); i++)
vexList[i].info->strtVexInfo = vexList[strtID].info;
//Start dijkstra
vexList[strtID].info->distance = 0;
vexList[strtID].access("strt");
while(true){
//Find next
int minVexID = -1;
for(int i = 0; i < vexList.size(); i++){
if(vexList[i].visited || vexList[i].info->distance == VexInfo::INF)
continue;
if(minVexID == -1)
minVexID = i;
else if(vexList[i].info->distance < vexList[minVexID].info->distance)
minVexID = i;
}
if(minVexID == -1)
break;
//Set visit to edge and vex
ALArc *edge = FindArc(vexList[minVexID].info->preVexID, minVexID);
if(edge){
if(type == UDG && GetIdOf(edge->gArc->edVex()) != minVexID)
edge->gArc->reverseDirection();
edge->visit();
}
vexList[minVexID].visit();
//Find adjacent
for(ALArc *p = vexList[minVexID].firstArc; p != nullptr; p = p->nextArc){
if(!vexList[p->eVexID].visited){
if(GetIdOf(p->gArc->edVex()) != p->eVexID)
p->gArc->reverseDirection();
p->access();
if(vexList[p->eVexID].info->distance == VexInfo::INF ||
vexList[p->eVexID].info->distance > vexList[minVexID].info->distance + p->weight){
vexList[p->eVexID].info->preVexID = minVexID;
vexList[p->eVexID].info->distance = vexList[minVexID].info->distance + p->weight;
vexList[p->eVexID].access(QString::asprintf("%d", vexList[p->eVexID].info->distance));
}
}
}
}
}
AMLGraph* ALGraph::ConvertToAML(){
AMLGraph *converted = new AMLGraph(type);
for(int i = 0; i < vexList.size(); i++){
converted->AddVex(vexList[i].info);
}
for(int i = 0; i < vexList.size(); i++){
ALArc *p = vexList[i].firstArc;
while(p != nullptr){
if(type == DG || (type == UDG && i == GetIdOf(p->gArc->edVex())))
converted->AddArc(p->gArc, p->weight);
p = p->nextArc;
}
}
return converted;
}
/**************************************************************************************/
void AMLVex::visit(){
if(visited)
return;
info->gVex->visit(true);
visited = true;
}
void AMLVex::access(const QString &hint){
info->gVex->access(hint);
}
void AMLArc::visit(){
gArc->visit(true);
}
void AMLArc::access(){
gArc->access();
}
AMLGraph::~AMLGraph(){
int i = outVexList.size() - 1;
while(i >= 0){
DelVex(i--);
}
outVexList.clear();
if(type == DG)
inVexList.clear();
}
void AMLGraph::AddVex(MyGraphicsVexItem *gvex){
AMLVex newVex(gvex);
outVexList.push_back(newVex);
if(type == DG){
inVexList.push_back(newVex);
}
}
void AMLGraph::AddVex(VexInfo *info){
AMLVex newVex(info);
outVexList.push_back(newVex);
if(type == DG){
inVexList.push_back(newVex);
}
}
void AMLGraph::AddArc(MyGraphicsLineItem *garc, int weight){
int strtVex = GetIdOf(garc->stVex());
int endVex = GetIdOf(garc->edVex());
AMLArc *nextOutArc = outVexList[strtVex].firstArc;
AMLArc *nextInArc = type == DG ? inVexList[endVex].firstArc : outVexList[endVex].firstArc;
AMLArc *newArc = new AMLArc(garc, strtVex, endVex, nextOutArc, nextInArc);
newArc->weight = weight;
outVexList[strtVex].firstArc = newArc;
if(type == DG)
inVexList[endVex].firstArc = newArc;
else
outVexList[endVex].firstArc = newArc;
}
void AMLGraph::DelVex(MyGraphicsVexItem *gvex){
int vexID = GetIdOf(gvex);
DelVex(vexID);
}
void AMLGraph::DelVex(int vexID){
if(type == DG){
//Delete out arc
AMLArc *outArc = outVexList[vexID].firstArc;
while(outArc != nullptr){
AMLArc *dummyHead = new AMLArc(nullptr, 0, 0, nullptr, inVexList[outArc->inVexID].firstArc);
AMLArc *preInArc = dummyHead;
while(preInArc->nextInArc != nullptr){
if(preInArc->nextInArc->outVexID == vexID){
AMLArc *next = preInArc->nextInArc;
preInArc->nextInArc = next->nextInArc;
delete next;
}
else
preInArc = preInArc->nextInArc;
}
inVexList[outArc->inVexID].firstArc = dummyHead->nextInArc;
delete dummyHead;
outArc = outArc->nextOutArc;
}
//Delete in arc and adjust ID
for(int i = 0; i < outVexList.size(); i++){
if(i == vexID) continue;
AMLArc *dummyHead = new AMLArc(nullptr, 0, 0, outVexList[i].firstArc, nullptr);
AMLArc *preOutArc = dummyHead;
while(preOutArc->nextOutArc != nullptr){
if(preOutArc->nextOutArc->inVexID == vexID){
AMLArc *next = preOutArc->nextOutArc;
preOutArc->nextOutArc = next->nextOutArc;
delete next;
continue;
}
if(preOutArc->nextOutArc->inVexID > vexID)
preOutArc->nextOutArc->inVexID--;
if(preOutArc->nextOutArc->outVexID > vexID)
preOutArc->nextOutArc->outVexID--;
preOutArc = preOutArc->nextOutArc;
}
outVexList[i].firstArc = dummyHead->nextOutArc;
delete dummyHead;
}
outVexList.erase(outVexList.begin() + vexID);
inVexList.erase(inVexList.begin() + vexID);
}
else{
//Traverse all and adjust ID
AMLArc *p = outVexList[vexID].firstArc;
while(p != nullptr){
if(p->outVexID == vexID){
AMLArc *temp = p->nextOutArc;
p->nextOutArc = nullptr;
p = temp;
}
else{
AMLArc *temp = p->nextInArc;
p->nextInArc = nullptr;
p = temp;
}
}
outVexList[vexID].firstArc = nullptr;
for(int i = 0; i < outVexList.size(); i++){
if(i == vexID) continue;
AMLArc *dummyHead = new AMLArc(nullptr, i, -1, outVexList[i].firstArc, nullptr);
AMLArc *preArc = dummyHead;
AMLArc *nextArc = preArc->nextOutArc;
while(nextArc != nullptr){
if(nextArc->inVexID == vexID || nextArc->outVexID == vexID){
if(preArc->outVexID == i){
if(nextArc->outVexID == i){
preArc->nextOutArc = nextArc->nextOutArc;
nextArc->nextOutArc = nullptr;
delete nextArc;
}
else{
preArc->nextOutArc = nextArc->nextInArc;
nextArc->nextInArc = nullptr;
delete nextArc;
}
}
else{
if(nextArc->outVexID == i){
preArc->nextInArc = nextArc->nextOutArc;
nextArc->nextOutArc = nullptr;
delete nextArc;
}
else{
preArc->nextInArc = nextArc->nextInArc;
nextArc->nextInArc = nullptr;
delete nextArc;
}
}
nextArc = preArc->outVexID == i ? preArc->nextOutArc : preArc->nextInArc;
continue;
}
preArc = nextArc;
nextArc = preArc->outVexID == i ? preArc->nextOutArc : preArc->nextInArc;
if(preArc->inVexID > vexID)
preArc->inVexID = - preArc->inVexID;
else if(preArc->inVexID < 0)
preArc->inVexID = - preArc->inVexID;
if(preArc->outVexID > vexID)
preArc->outVexID = - preArc->outVexID;
else if(preArc->outVexID < 0)
preArc->outVexID = - preArc->outVexID;
}
outVexList[i].firstArc = dummyHead->nextOutArc;
delete dummyHead;
}
//Delete vexID
outVexList.erase(outVexList.begin() + vexID);
}
}
void AMLGraph::DelArc(MyGraphicsLineItem *garc){
int sVex = GetIdOf(garc->stVex());
int eVex = GetIdOf(garc->edVex());
DelArc(sVex, eVex);
}
void AMLGraph::DelArc(int sVexID, int eVexID){
if(type == DG){
AMLArc *dummyHead;
AMLArc *preArc;
//Delete sVex -> eVex
dummyHead = new AMLArc(nullptr, sVexID, -1, outVexList[sVexID].firstArc, nullptr);
preArc = dummyHead;
while(preArc->nextOutArc != nullptr){
if(preArc->nextOutArc->inVexID == eVexID){
preArc->nextOutArc = preArc->nextOutArc->nextOutArc;
continue;
}
else
preArc = preArc->nextOutArc;
}
outVexList[sVexID].firstArc = dummyHead->nextOutArc;
delete dummyHead;
//Delete eVex -> sVex
dummyHead = new AMLArc(nullptr, -1, eVexID, nullptr, inVexList[eVexID].firstArc);
preArc = dummyHead;
while(preArc->nextInArc != nullptr){
if(preArc->nextInArc->outVexID == sVexID){
AMLArc *awaitDel = preArc->nextInArc;
preArc->nextInArc = preArc->nextInArc->nextInArc;
delete awaitDel;
continue;
}
else
preArc = preArc->nextInArc;
}
inVexList[eVexID].firstArc = dummyHead->nextInArc;
delete dummyHead;
}
else{
AMLArc *dummyHead;
AMLArc *preArc;
AMLArc *nextArc;
//Delete sVex -> eVex
dummyHead = new AMLArc(nullptr, sVexID, -1, outVexList[sVexID].firstArc, nullptr);
preArc = dummyHead;
nextArc = outVexList[sVexID].firstArc;
while(nextArc != nullptr){
if(nextArc->inVexID == eVexID || nextArc->outVexID == eVexID){
if(preArc->outVexID == sVexID){
if(nextArc->outVexID == sVexID){
preArc->nextOutArc = nextArc->nextOutArc;
nextArc->nextOutArc = nullptr;
}
else{
preArc->nextOutArc = nextArc->nextInArc;
nextArc->nextInArc = nullptr;
}
}
else{
if(nextArc->outVexID == sVexID){
preArc->nextInArc = nextArc->nextOutArc;
nextArc->nextOutArc = nullptr;
}
else{
preArc->nextInArc = nextArc->nextInArc;
nextArc->nextInArc = nullptr;
}
}
nextArc = preArc->outVexID == sVexID ? preArc->nextOutArc : preArc->nextInArc;
continue;
}
else{
preArc = nextArc;
nextArc = preArc->outVexID == sVexID ? preArc->nextOutArc : preArc->nextInArc;
}
}
outVexList[sVexID].firstArc = dummyHead->nextOutArc;
delete dummyHead;
//Delete eVex -> sVex and release arc
dummyHead = new AMLArc(nullptr, -1, eVexID, nullptr, outVexList[eVexID].firstArc);
preArc = dummyHead;
nextArc = outVexList[eVexID].firstArc;
while(nextArc != nullptr){
if(nextArc->inVexID == sVexID || nextArc->outVexID == sVexID){
if(preArc->outVexID == eVexID){
if(nextArc->outVexID == eVexID){
preArc->nextOutArc = nextArc->nextOutArc;
delete nextArc;
}
else{
preArc->nextOutArc = nextArc->nextInArc;
delete nextArc;
}
}
else{
if(nextArc->outVexID == eVexID){
preArc->nextInArc = nextArc->nextOutArc;
delete nextArc;
}
else{
preArc->nextInArc = nextArc->nextInArc;
delete nextArc;
}
}
nextArc = preArc->outVexID == eVexID ? preArc->nextOutArc : preArc->nextInArc;
continue;
}
else{
preArc = nextArc;
nextArc = preArc->outVexID == eVexID ? preArc->nextOutArc : preArc->nextInArc;
}
}
outVexList[eVexID].firstArc = dummyHead->nextInArc;
delete dummyHead;
}
}
int AMLGraph::GetIdOf(MyGraphicsVexItem *gvex){
int i = 0;
while(i < outVexList.size() && outVexList[i].info->gVex != gvex)
i++;
return i == outVexList.size() ? -1 : i;
}
AMLArc* AMLGraph::FindArc(int strtID, int endID){
if(strtID < 0 || strtID >= outVexList.size())
return nullptr;
AMLArc *p = outVexList[strtID].firstArc;
while(p != nullptr){
if(p->outVexID == endID || p->inVexID == endID)
return p;
p = p->outVexID == strtID ? p->nextOutArc : p->nextInArc;
}
return nullptr;
}
void AMLGraph::SetWeight(MyGraphicsLineItem *garc, int weight){
int strtVex = GetIdOf(garc->stVex());
int endVex = GetIdOf(garc->edVex());
AMLArc *p = outVexList[strtVex].firstArc;
while(p != nullptr){
if(p->inVexID == endVex || p->outVexID == endVex){
p->weight = weight;
p->gArc->setText(QString::asprintf("%d", weight));
}
p = p->inVexID == strtVex ? p->nextInArc : p->nextOutArc;
}
if(type == DG){
p = inVexList[endVex].firstArc;
while(p != nullptr){
if(p->inVexID == strtVex || p->outVexID == strtVex){
p->weight = weight;
p->gArc->setText(QString::asprintf("%d", weight));
}
p = p->inVexID == endVex ? p->nextInArc : p->nextOutArc;
}
}
}
void AMLGraph::ConvertType(int _type){
if(_type == type) return;
type = _type;
if(type == UDG){
for(int i = 0; i < inVexList.size(); i++){
AMLArc *p = inVexList[i].firstArc;
while(p != nullptr && p->nextInArc != nullptr){
p->gArc->setDirection(false);
p = p->nextInArc;
}
AMLArc *temp = outVexList[i].firstArc;
if(p){
outVexList[i].firstArc = inVexList[i].firstArc;
p->nextInArc = temp;
}
while(temp != nullptr){
temp->gArc->setDirection(false);
temp = temp->nextOutArc;
}
}
}
else{
inVexList.clear();
inVexList.assign(outVexList.begin(), outVexList.end());
for(int i = 0; i < inVexList.size(); i++)
inVexList[i].firstArc = nullptr;
for(int i = 0; i < outVexList.size(); i++){
AMLArc *dummyHead = new AMLArc(nullptr, i, -1, outVexList[i].firstArc, nullptr);
AMLArc *pre = dummyHead;
AMLArc *next = outVexList[i].firstArc;
while(next != nullptr){
next->gArc->setDirection(true);
if(next->outVexID != i){
//A reversed edge
pre->nextOutArc = next->nextInArc;
AMLArc *temp = inVexList[next->inVexID].firstArc;
inVexList[next->inVexID].firstArc = next;
next->nextInArc = temp;
next = pre->nextOutArc;
continue;
}
pre = next;
next = pre->nextOutArc;
}
outVexList[i].firstArc = dummyHead->nextOutArc;
delete dummyHead;
}
}
}
void AMLGraph::ClearVisit(){
for(int i = 0; i < outVexList.size(); i++){
outVexList[i].visited = false;
outVexList[i].info->gVex->visit(false);
}
if(type == DG)
for(int i = 0; i < inVexList.size(); i++)
inVexList[i].visited = false;
}
void AMLGraph::ResetDistance(){
for(int i = 0; i < outVexList.size(); i++){
outVexList[i].info->strtVexInfo = nullptr;
outVexList[i].info->distance = VexInfo::INF;
outVexList[i].info->preVexID = -1;
outVexList[i].info->gVex->access("", false);
}
if(type == DG)
for(int i = 0; i < outVexList.size(); i++){
inVexList[i].info->strtVexInfo = nullptr;
inVexList[i].info->distance = VexInfo::INF;
inVexList[i].info->preVexID = -1;
}
}
void AMLGraph::DFS(int strtID){
if(strtID == -1)
return;
vector<int> awaitVexList;
vector<AMLArc*>awaitArcList;
awaitVexList.push_back(strtID);
while(awaitVexList.size() > 0){
int nextVex = awaitVexList.back();
AMLArc *nextArc = awaitArcList.size() > 0 ? awaitArcList.back() : nullptr;
awaitVexList.pop_back();
if(nextArc)
awaitArcList.pop_back();
for(AMLArc *p = outVexList[nextVex].firstArc; p != nullptr; p = p->outVexID == strtID ? p->nextOutArc : p->nextInArc){
int endID = p->outVexID == nextVex ? p->inVexID : p->outVexID;
if(outVexList[endID].visited == false){
awaitVexList.push_back(endID);
awaitArcList.push_back(p);
if(type == UDG && GetIdOf(p->gArc->edVex()) != endID)
p->gArc->reverseDirection();
}
}
if(nextArc && !outVexList[nextVex].visited)
nextArc->visit();
outVexList[nextVex].visit();
}
}
void AMLGraph::BFS(int strtID){
if(strtID == -1)
return;
vector<int> awaitVexList;
vector<AMLArc*> awaitArcList;
awaitVexList.push_back(strtID);
while(awaitVexList.size() > 0){
int nextVex = awaitVexList[0];
AMLArc *nextArc = awaitArcList.size() > 0 ? awaitArcList[0] : nullptr;
awaitVexList.erase(awaitVexList.begin());
if(nextArc)
awaitArcList.erase(awaitArcList.begin());
for(AMLArc *p = outVexList[nextVex].firstArc; p != nullptr; p = p->outVexID == strtID ? p->nextOutArc : p->nextInArc){
int endID = p->outVexID == nextVex ? p->inVexID : p->outVexID;
if(outVexList[endID].visited == false){
awaitVexList.push_back(endID);
awaitArcList.push_back(p);
if(type == UDG && GetIdOf(p->gArc->edVex()) != endID)
p->gArc->reverseDirection();
}
}
if(nextArc && !outVexList[nextVex].visited)
nextArc->visit();
outVexList[nextVex].visit();
}
}
void AMLGraph::Dijkstra(int strtID){
//Clear previous result
ClearVisit();
ResetDistance();
//Set start vex info to all vertexes
for(int i = 0; i < outVexList.size(); i++)
outVexList[i].info->strtVexInfo = outVexList[strtID].info;
//Start dijkstra
outVexList[strtID].info->distance = 0;
outVexList[strtID].access("strt");
while(true){
//Find next
int minVexID = -1;
for(int i = 0; i < outVexList.size(); i++){
if(outVexList[i].visited || outVexList[i].info->distance == VexInfo::INF)
continue;
if(minVexID == -1)
minVexID = i;
else if(outVexList[i].info->distance < outVexList[minVexID].info->distance)
minVexID = i;
}
if(minVexID == -1)
break;
//Set visit to edge and vex
AMLArc *edge = FindArc(outVexList[minVexID].info->preVexID, minVexID);
if(edge){
if(type == UDG && GetIdOf(edge->gArc->edVex()) != minVexID)
edge->gArc->reverseDirection();
edge->visit();
}
outVexList[minVexID].visit();
//Find adjacent
for(AMLArc *p = outVexList[minVexID].firstArc; p != nullptr; p = p->outVexID == strtID ? p->nextOutArc : p->nextInArc){
int endID = p->outVexID == minVexID ? p->inVexID : p->outVexID;
if(!outVexList[endID].visited){
if(GetIdOf(p->gArc->edVex()) != endID)
p->gArc->reverseDirection();
p->access();
if(outVexList[endID].info->distance == VexInfo::INF ||
outVexList[endID].info->distance > outVexList[minVexID].info->distance + p->weight){
outVexList[endID].info->preVexID = minVexID;
outVexList[endID].info->distance = outVexList[minVexID].info->distance + p->weight;
outVexList[endID].access(QString::asprintf("%d", outVexList[endID].info->distance));
}
}
}
}
}
ALGraph* AMLGraph::ConvertToAL(){
ALGraph *converted = new ALGraph(type);
for(int i = 0; i < outVexList.size(); i++)
converted->AddVex(outVexList[i].info);
for(int i = 0; i < outVexList.size(); i++){
AMLArc *p = outVexList[i].firstArc;
while(p != nullptr){
if(p->outVexID == i)
converted->AddArc(p->gArc);
p = p->outVexID == i ? p->nextOutArc : p->nextInArc;
}
}
return converted;
}

216
graph_implement.h Normal file
View File

@ -0,0 +1,216 @@
#ifndef GRAPH_IMPLEMENT_H
#define GRAPH_IMPLEMENT_H
#include "graph_view.h"
using namespace std;
class VexInfo{
public:
enum { INF = 2147483647 };
MyGraphicsVexItem *gVex;
VexInfo *strtVexInfo = nullptr;
int preVexID = -1;
int distance = INF;
VexInfo(MyGraphicsVexItem *vex) : gVex(vex){}
};
class AbstractGraph{
protected:
int type;
int vexNum = 0;
public:
enum { UDG = 1, DG = 2 };
AbstractGraph(int _type = DG) : type(_type){}
virtual ~AbstractGraph() = 0;
/* Insert */
virtual void AddVex(MyGraphicsVexItem *gvex) = 0;
virtual void AddVex(VexInfo *info) = 0;
virtual void AddArc(MyGraphicsLineItem *garc, int weight = 1) = 0;
/* Delete */
virtual void DelVex(MyGraphicsVexItem *gvex) = 0;
virtual void DelVex(int vexID) = 0;
virtual void DelArc(MyGraphicsLineItem *garc) = 0;
virtual void DelArc(int sVexID, int eVexID) = 0;
/* Find */
virtual int GetIdOf(MyGraphicsVexItem *gvex) = 0;
virtual VexInfo* GetInfoOf(int id) = 0;
virtual VexInfo* GetInfoOf(MyGraphicsVexItem *gvex) = 0;
/* Modify */
//virtual void SetText(MyGraphicsVexItem *gvex);
virtual void SetWeight(MyGraphicsLineItem *garc, int weight) = 0;
virtual void ConvertType(int _type) = 0;
/* Other Function */
virtual void ClearVisit() = 0;
virtual void ResetDistance() = 0;
virtual void DFS(int strtID) = 0;
virtual void DFS(MyGraphicsVexItem *strtVex) = 0;
virtual void BFS(int strtID) = 0;
virtual void BFS(MyGraphicsVexItem *strtVex) = 0;
virtual void Dijkstra(int strtID) = 0;
virtual void Dijkstra(MyGraphicsVexItem *strtVex) = 0;
virtual int Type() const = 0;
};
class ALVex;
class ALArc;
class ALGraph;
class AMLVex;
class AMLArc;
class AMLGraph;
/* Classes of ALGraph */
class ALVex{
public:
bool visited = false;
VexInfo *info = nullptr;
ALArc *firstArc = nullptr;
ALVex(MyGraphicsVexItem *vex){info = new VexInfo(vex);}
ALVex(VexInfo *_info){info = _info;}
bool equalTo(const ALVex &v){return info == v.info;}
void visit();
void access(const QString &hint = "");
};
class ALArc{
public:
MyGraphicsLineItem *gArc;
int weight = 1;
int eVexID;
ALArc *nextArc = nullptr;
ALArc(MyGraphicsLineItem *garc, int eVex, ALArc *next = nullptr) : gArc(garc), eVexID(eVex), nextArc(next){}
void visit();
void access();
};
class ALGraph : public AbstractGraph{
private:
vector<ALVex> vexList;
public:
ALGraph(int _type = DG) : AbstractGraph(_type){}
~ALGraph();
/* Insert */
void AddVex(MyGraphicsVexItem *gvex);
void AddVex(VexInfo *info);
void AddArc(MyGraphicsLineItem *garc, int weight = 1);
/* Delete */
void DelVex(MyGraphicsVexItem *gvex);
void DelVex(int vexID);
void DelArc(MyGraphicsLineItem *garc);
void DelArc(int sVexID, int eVexID);
/* Find */
int GetIdOf(MyGraphicsVexItem *gvex);
VexInfo* GetInfoOf(int id){return vexList[id].info;}
VexInfo* GetInfoOf(MyGraphicsVexItem *gvex){return vexList[GetIdOf(gvex)].info;}
ALArc* FindArc(int sID, int eID);
/* Modify */
void SetWeight(MyGraphicsLineItem *garc, int weight);
void ConvertType(int _type);
/* Other Function */
void ClearVisit();
void ResetDistance();
void DFS(int strtID);
void DFS(MyGraphicsVexItem *strtVex){DFS(GetIdOf(strtVex));}
void BFS(int strtID);
void BFS(MyGraphicsVexItem *strtVex){BFS(GetIdOf(strtVex));}
void Dijkstra(int strtID);
void Dijkstra(MyGraphicsVexItem *strtVex){Dijkstra(GetIdOf(strtVex));}
AMLGraph* ConvertToAML();
int Type() const { return type; }
};
/* Classes of AMLGraph */
class AMLVex{
public:
bool visited = false;
VexInfo *info = nullptr;
AMLArc *firstArc = nullptr;
AMLVex(MyGraphicsVexItem *gvex){info = new VexInfo(gvex);}
AMLVex(VexInfo *_info){info = _info;}
bool equalTo(const AMLVex &v){return info == v.info;}
void visit();
void access(const QString &hint = "");
};
class AMLArc{
public:
MyGraphicsLineItem *gArc;
int weight = 1;
int outVexID;
AMLArc *nextOutArc = nullptr;
int inVexID;
AMLArc *nextInArc = nullptr;
AMLArc(MyGraphicsLineItem *garc, int sVex, int eVex) : gArc(garc), outVexID(sVex), inVexID(eVex){}
AMLArc(MyGraphicsLineItem *garc, int sVex, int eVex, AMLArc *nextOut, AMLArc *nextIn) :
gArc(garc), outVexID(sVex), nextOutArc(nextOut), inVexID(eVex), nextInArc(nextIn){}
void visit();
void access();
};
class AMLGraph : public AbstractGraph{
private:
vector<AMLVex> outVexList;
vector<AMLVex> inVexList;
public:
AMLGraph(int _type = DG) : AbstractGraph(_type){}
~AMLGraph();
/* Insert */
void AddVex(MyGraphicsVexItem *gvex);
void AddVex(VexInfo *info);
void AddArc(MyGraphicsLineItem *garc, int weight = 1);
/* Delete */
void DelVex(MyGraphicsVexItem *gvex);
void DelVex(int vexID);
void DelArc(MyGraphicsLineItem *garc);
void DelArc(int sVexID, int eVexID);
/* Find */
int GetIdOf(MyGraphicsVexItem *gvex);
VexInfo* GetInfoOf(int id){return outVexList[id].info;}
VexInfo* GetInfoOf(MyGraphicsVexItem *gvex){return outVexList[GetIdOf(gvex)].info;}
AMLArc* FindArc(int strtID, int endID);
/* Modify */
void SetWeight(MyGraphicsLineItem *garc, int weight);
void ConvertType(int _type);
/* Other Function */
void ClearVisit();
void ResetDistance();
void DFS(int strtID);
void DFS(MyGraphicsVexItem *strtVex){DFS(GetIdOf(strtVex));}
void BFS(int strtID);
void BFS(MyGraphicsVexItem *strtVex){BFS(GetIdOf(strtVex));}
void Dijkstra(int strtID);
void Dijkstra(MyGraphicsVexItem *strtVex){Dijkstra(GetIdOf(strtVex));}
ALGraph* ConvertToAL();
int Type() const { return type; }
};
#endif // GRAPH_IMPLEMENT_H

1085
graph_view.cpp Normal file

File diff suppressed because it is too large Load Diff

371
graph_view.h Normal file
View File

@ -0,0 +1,371 @@
#ifndef GRAPH_VIEW_H
#define GRAPH_VIEW_H
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QResizeEvent>
#include <QQueue>
#include <QFile>
#include <QTextStream>
#include <QScrollBar>
#include <QLabel>
//Header for MyVex class
#include <QGraphicsEllipseItem>
#include <QVector>
//Headers for lines
#include <QPainter>
#include <QColor>
#include <QGraphicsPathItem>
#include <QTimeLine>
#include <QEasingCurve>
class viewLog : public QLabel{
Q_OBJECT
private:
QFont logFont = QFont("Corbel", 12);
QString logText;
void resizeEvent(QResizeEvent *event);
public:
viewLog(QString log, QWidget *parent = nullptr);
};
class MyGraphicsView;
class MyGraphicsVexItem;
class MyGraphicsLineItem;
// Summary:
// MyGraphicsView class is customized for visualizing graph
//
// Functions:
// -Left click to add vex
// -Left click on vex to add arc
// -Right click on vex or arc to view information
// -Drag vex to adjust place (adjust connected arcs either)
class MyGraphicsView : public QGraphicsView{
Q_OBJECT
private:
enum mouseStates{
NORMAL = 0b00000000,
ON_HOVER = 0b00010000,
ON_SELECTED = 0b00100000,
ON_MOVING = 0b01000000
};
enum itemStates{
NON = 0b00000000,
SEL = 0b00010000,
ADD = 0b00100000,
VEX = 0b00000001,
LINE = 0b00000010
};
QGraphicsScene* myGraphicsScene;
int type;
int vexID = 0;
int getIdOf(MyGraphicsVexItem* vex){return vexes.indexOf(vex);}
int mouseState = NORMAL;
int itemState = NON;
bool onRightPress = false;
//For dragging and scaling
bool onMiddlePress = false;
QPointF lastPos;
QGraphicsItem *selItem = nullptr;
MyGraphicsVexItem *strtVex = nullptr;
QGraphicsItem *sketchItem = nullptr;
qreal zValue = -1;
/* Animation loop */
QQueue<QTimeLine*> aniQueue;
bool onAni = false;
QTimeLine *curAni = nullptr;
qreal speedRate = 1;
void nextAni();
void mousePressEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
void wheelEvent(QWheelEvent *event);
void resizeEvent(QResizeEvent *event){this->setSceneRect(this->rect());}
void changeCursor();
MyGraphicsVexItem* addVex(QPointF center, qreal radius = 10);
void clearSketch();
void sketchLine(QPointF start, QPointF end);
void addLine(MyGraphicsVexItem* start, MyGraphicsVexItem* end);
public:
enum { UDG = 128, DG = 256 };
int vexNum = 0;
int arcNum = 0;
/* For Saving */
QVector<MyGraphicsVexItem*> vexes;
QVector<MyGraphicsLineItem*> lines;
/* for visit flag */
bool hasVisitedItem = false;
MyGraphicsView(int _type = UDG, QWidget *parent = nullptr);
MyGraphicsVexItem* selectedVex();
MyGraphicsLineItem* selectedArc();
void RemoveVex(MyGraphicsVexItem *vex);
void RemoveArc(MyGraphicsLineItem *line);
void setAniRate(qreal rate){speedRate = rate;}
void setType(int _type){type = _type;}
void unSelect(){itemState = NON;selItem = nullptr;emit unselected();}
void SaveToFile(QTextStream &ts);
void ReadFromFile(QTextStream &ts);
signals:
void mouseMoved(QPointF position);
void mouseLeftClicked(QPointF position);
void mouseRightClicked(QPointF position);
void mouseReleased();
void vexAdded(MyGraphicsVexItem *vex);
void arcAdded(MyGraphicsLineItem *arc);
void logAdded(viewLog *log);
void selected(QGraphicsItem *item);
void unselected();
void visitClear();
public slots:
void setHover(bool in = true);
void setSel(QGraphicsItem *sel);
void startLine(MyGraphicsVexItem* startVex);
void setMenu(QGraphicsItem *target, bool display = true);
void addLog(viewLog *log){emit logAdded(log);}
void vexRemoved(MyGraphicsVexItem* vex){vexes.erase(vexes.begin() + vexes.indexOf(vex));vexNum--;}
void arcRemoved(MyGraphicsLineItem* line){lines.erase(lines.begin() + lines.indexOf(line));arcNum--;}
void addAnimation(QTimeLine *ani);
};
// Summary:
// MyGraphicsVexItem realize the interactions with vex
class MyGraphicsVexItem : public QObject, public QGraphicsEllipseItem{
Q_OBJECT
private:
enum {
PREPARING = 0b10000000,
UNDEFINED = 0b00000000,
ON_HOVER = 0b00000001,
ON_LEFT_CLICK = 0b00000010,
ON_RIGHT_CLICK = 0b00000100,
ON_SELECTED = 0b00001000,
ON_LINING = 0b00010000,
ON_MENU = 0b00100000,
ON_VISIT = 0b01000000,
ON_ACCESS = 0b10000000
};
private:
static unsigned int internalID;
QBrush regBrush = QBrush(QColor(58, 143, 192));
QBrush selBrush = QBrush(QColor(208, 90, 110));
QBrush visitedBrush = QBrush(QColor(93, 172, 129));
QBrush accessBrush = QBrush(QColor(152, 109, 178));
QPointF center;
qreal radius;
int state = UNDEFINED;
QTimeLine* curAnimation = nullptr;
QVector<MyGraphicsLineItem*> linesStartWith;
QVector<MyGraphicsLineItem*> linesEndWith;
/* For display temporary tag */
QGraphicsSimpleTextItem *nameTag = nullptr;
QString nameText = "";
QFont nameFont = QFont("Corbel", 13, QFont::Normal, true);
QGraphicsSimpleTextItem *tag = nullptr;
QString hintText = "";
QFont hintFont = QFont("Corbel", 12);
void displayText();
void hoverInEffect();
void hoverOutEffect();
void onClickEffect();
void onReleaseEffect();
void startAnimation();
void stopAnimation();
void move(QPointF position);
public:
enum { Type = UserType + 1 };
int id;
MyGraphicsVexItem(QPointF _center, qreal _r, int nameID = 0, QGraphicsItem *parent = nullptr);
/* initializing */
void estConnection(MyGraphicsView* view);
void showAnimation();
void select();
void visit(bool visited = true);
void access(const QString &hint = "", bool isAccess = true);
QString Text(){return nameText;}
void setText(const QString & text){nameTag->setText(text);nameText = text;}
void addStartLine(MyGraphicsLineItem *line){linesStartWith.push_back(line);}
void removeStartLine(MyGraphicsLineItem *line){linesStartWith.remove(linesStartWith.indexOf(line));}
void addEndLine(MyGraphicsLineItem *line){linesEndWith.push_back(line);}
void removeEndLine(MyGraphicsLineItem *line){linesEndWith.remove(linesEndWith.indexOf(line));}
void remove();
bool equalTo(MyGraphicsVexItem *v){return id == v->id;}
int type() const override {return Type;}
qreal getRadius() {return radius;}
QString getData(){return QString::asprintf("%g %g %g\n", center.x(), center.y(), radius)+nameText;}
signals:
void setHover(bool in = true);
void selected(QGraphicsItem *sel);
void lineFrom(MyGraphicsVexItem *start);
void menuStateChanged(QGraphicsItem *item, bool display = true);
void logAdded(viewLog *log);
void removed(MyGraphicsVexItem *vex);
void addAnimation(QTimeLine *ani);
public slots:
void onMouseMove(QPointF position);
void onLeftClick(QPointF position);
void onRightClick(QPointF position);
void onMouseRelease();
};
class MyGraphicsLineItem : public QObject, public QGraphicsLineItem{
Q_OBJECT
private:
enum {
UNDEFINED = 0b00000000,
ON_HOVER = 0b00000001,
ON_LEFT_CLICK = 0b00000010,
ON_RIGHT_CLICK = 0b00000100,
ON_SELECTED = 0b00001000,
ON_MENU = 0b00100000,
ON_VISIT = 0b01000000
};
/* basic data */
bool hasDirection;
MyGraphicsVexItem *startVex;
MyGraphicsVexItem *endVex;
QGraphicsLineItem *line1 = nullptr;
QGraphicsLineItem *line2 = nullptr;
QGraphicsPathItem *arrow = nullptr;
QGraphicsSimpleTextItem *textItem = nullptr;
QString text = "";
int state = UNDEFINED;
/* about animation */
QTimeLine *curAnimation;
/* detail of the line */
qreal lineWidth = 3;
qreal arrowLength = 10;
Qt::PenStyle lineStyle = Qt::SolidLine;
Qt::PenCapStyle capStyle = Qt::RoundCap;
QColor defaultColor = QColor(125, 185, 222);
QColor hoverColor = QColor(0, 98, 132);
QColor selColor = QColor(208, 90, 110);
QColor visitColor = QColor(93, 172, 129);
QColor accessColor = QColor(178, 143, 206);
QPen defaultPen;
QPen curPen;
QFont textFont = QFont("Corbel", 12);
QColor textColor = QColor(0, 0, 0);
/* for calculation and line rendering */
qreal angle = 0;
QPointF center;
QPointF sP, eP, dP;
void setLengthRate(qreal r=1);
void drawLine();
void drawText();
void drawArrow();
void delArrow();
/* effects */
void hoverInEffect();
void hoverOutEffect();
void onClickEffect();
void onReleaseEffect();
void onSelectEffect();
void deSelectEffect();
public:
enum { Type = UserType + 2 };
MyGraphicsLineItem(MyGraphicsVexItem *start, MyGraphicsVexItem *end, bool hasDir = false, QGraphicsItem *parent = nullptr);
/* initialize functions */
void estConnection(MyGraphicsView *view);
void refrshLine();
/* adjust functions */
void reverseDirection();
void moveStart(MyGraphicsVexItem *start);
void moveEnd(MyGraphicsVexItem *end);
void setText(const QString & _text);
void setDirection(bool hasDir = true);
/* effects */
//void startAnimation(){}
//void stopAnimation(){}
/* retrieve */
MyGraphicsVexItem* stVex(){return startVex;}
MyGraphicsVexItem* edVex(){return endVex;}
QString weightText(){return text;}
void visit(bool visited = true);
void remove();
void access();
int type() const override {return Type;}
signals:
void setHover(bool in = true);
void selected(QGraphicsItem *sel);
void menuStateChanged(QGraphicsItem *item, bool display = true);
void logAdded(viewLog *log);
void removed(MyGraphicsLineItem *line);
void addAnimation(QTimeLine *ani);
private slots:
void onMouseMove(QPointF position);
void onLeftClick(QPointF position);
void onRightClick(QPointF position);
void onMouseRelease();
};
#endif // GRAPH_VIEW_H

10
icons.qrc Normal file
View File

@ -0,0 +1,10 @@
<RCC>
<qresource prefix="/icons">
<file>icons/back.svg</file>
<file>icons/settings.svg</file>
<file>icons/open.svg</file>
<file>icons/open.png</file>
<file>icons/create.png</file>
<file>icons/layers.svg</file>
</qresource>
</RCC>

1
icons/back.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1638198774644" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1975" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M916.3 466.3H218.1l288.4-288.4c17.8-17.8 17.8-46.9 0-64.7-17.8-17.8-46.9-17.8-64.7 0L75.3 479.7c-17.8 17.8-17.8 46.9 0 64.7l366.5 366.5c17.8 17.8 46.9 17.8 64.7 0 17.8-17.8 17.8-46.9 0-64.7L218.1 557.7h698.2c25.2 0 45.7-20.6 45.7-45.7 0-25.2-20.6-45.7-45.7-45.7z" fill="#2c2c2c" p-id="1976"></path></svg>

After

Width:  |  Height:  |  Size: 681 B

BIN
icons/create.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

1
icons/create.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1638343049872" class="icon" viewBox="0 0 1026 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8600" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.390625" height="200"><defs><style type="text/css"></style></defs><path d="M992 799.232h-192v191.808a32 32 0 1 1-64 0v-191.808h-192a32 32 0 1 1 0-63.936h192V543.488a32 32 0 0 1 64 0v191.808h192a32 32 0 1 1 0 63.936zM832 283.136C832 153.472 752.64 64 612.608 64H283.456C143.296 64 63.936 148.288 63.936 283.136v328.832c0 129.728 86.208 219.264 219.52 219.264h116.48v63.872H256C114.688 895.104 0 780.672 0 639.424V255.808A255.872 255.872 0 0 1 256 0h384c141.376 0 256 114.56 256 255.808v143.808h-64v-116.48z" p-id="8601"></path></svg>

After

Width:  |  Height:  |  Size: 841 B

1
icons/layers.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1638411977810" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2957" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M938.633323 570.21589 554.672082 742.800573c-36.761735 15.990183-51.399706 15.990183-85.329837 0L85.366677 570.21589c-20.383048-10.82658-25.879451-50.886971-25.879451-72.745814 25.630777 14.637372 61.674122 30.959106 60.334559 30.131251l392.178726 180.787506 392.19203-180.787506c0.662106-0.165776 35.628888-17.786085 60.320232-30.131251C964.512773 519.839549 957.57959 561.377594 938.633323 570.21589zM938.633323 389.413034 554.672082 562.012044c-36.761735 15.991206-51.399706 15.991206-85.329837 0L85.366677 389.413034c-30.160116-16.004509-29.221706-66.407456 0-85.229127L469.342245 101.453646c33.930131-16.943904 55.155394-17.882276 85.329837 0l383.961241 202.730261C967.854005 320.188416 966.887964 376.225687 938.633323 389.413034zM511.999488 135.865387 119.820762 346.798471l392.178726 165.252695L904.192541 346.798471 511.999488 135.865387zM511.999488 135.865387M511.999488 889.202944l392.19203-180.815135c0.662106-0.165776 35.628888-17.786085 60.320232-30.130228 0 22.369473-6.93216 63.907519-25.879451 72.745814L554.672082 923.615709c-36.761735 15.990183-51.399706 15.990183-85.329837 0L85.366677 751.002372c-20.383048-10.82658-25.879451-50.872644-25.879451-72.745814 25.630777 14.637372 61.674122 30.959106 60.334559 30.130228L511.999488 889.202944z" p-id="2958"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
icons/open.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

1
icons/open.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1638343089361" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11202" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M928.426667 458.453333a61.013333 61.013333 0 0 0-51.626667-27.733333h-59.52v-58.666667a100.053333 100.053333 0 0 0-98.346667-101.333333H498.133333L344.106667 170.666667H183.68A100.053333 100.053333 0 0 0 85.333333 272v539.946667A42.666667 42.666667 0 0 0 128 853.333333h620.8a62.08 62.08 0 0 0 56.96-37.333333l128-300.16a59.946667 59.946667 0 0 0-5.333333-57.386667zM128 713.813333V272A57.173333 57.173333 0 0 1 183.68 213.333333h147.84l154.026667 100.053334H718.933333a57.173333 57.173333 0 0 1 55.68 58.666666v58.666667H277.333333a62.08 62.08 0 0 0-58.026666 39.893333zM894.506667 499.2l-77.226667 180.906667-50.773333 119.04a19.2 19.2 0 0 1-17.706667 11.52l-612.053333 1.92 121.813333-326.4a19.413333 19.413333 0 0 1 18.133333-12.16H876.8a18.986667 18.986667 0 0 1 16.213333 8.533333 18.346667 18.346667 0 0 1 1.493334 16.64z" p-id="11203"></path></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

1
icons/settings.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1638334169417" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2957" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M878.08 466.944l-129.3824-253.0816a98.8672 98.8672 0 0 0-88.064-53.8624H366.08c-36.864 0-70.656 20.48-87.6544 53.1456l-132.096 253.0816a98.8672 98.8672 0 0 0 0 91.5456l132.096 253.0816a98.8672 98.8672 0 0 0 87.6544 53.1456h294.5536c37.1712 0 71.168-20.7872 88.064-53.8624l129.3824-253.1328a98.8672 98.8672 0 0 0 0-90.0096z m-72.3968 372.3264a162.8672 162.8672 0 0 1-145.0496 88.7296H366.08a162.8672 162.8672 0 0 1-144.384-87.552l-132.096-253.0816a162.8672 162.8672 0 0 1 0-150.7328l132.096-253.1328a162.8672 162.8672 0 0 1 144.384-87.5008h294.5536c61.184 0 117.1968 34.304 145.0496 88.7296l129.3824 253.1328c23.808 46.592 23.808 101.7344 0 148.2752l-129.3824 253.1328z" p-id="2958"></path><path d="M512 697.6a185.6 185.6 0 1 1 0-371.2 185.6 185.6 0 0 1 0 371.2z m0-64a121.6 121.6 0 1 0 0-243.2 121.6 121.6 0 0 0 0 243.2z" p-id="2959"></path></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
logo.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

14
main.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.setWindowFlag(Qt::FramelessWindowHint);
w.setAttribute(Qt::WA_TranslucentBackground);
w.show();
return a.exec();
}

449
mainwindow.cpp Normal file
View File

@ -0,0 +1,449 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPainterPath>
#include <QRegion>
#include <QTimer>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->centralwidget->setMouseTracking(true);
QTimer *t = new QTimer(this);
connect(t, &QTimer::timeout, this, [=](){Init();});
t->setSingleShot(true);
t->start(10);
connect(ui->adjSizeBtn, &QPushButton::clicked, this, [=](){controlWindowScale();});
}
void MainWindow::Init(){
/* Create main widget and set mask, style sheet and shadow */
QPainterPath path;
path.addRoundedRect(ui->mainWidget->rect(), cornerRadius - 1, cornerRadius - 1);
QRegion mask(path.toFillPolygon().toPolygon());
ui->mainWidget->setMask(mask);
QString mainStyle;
ui->mainWidget->setObjectName("mainWidget");
mainStyle = "QWidget#mainWidget{background-color:" + mainBackGround.name() + QString::asprintf(";border-radius:%dpx", cornerRadius) + "}";
ui->mainWidget->setStyleSheet(mainStyle);
windowShadow = new QGraphicsDropShadowEffect(this);
windowShadow->setBlurRadius(30);
windowShadow->setColor(QColor(0, 0, 0));
windowShadow->setOffset(0, 0);
ui->mainWidget->setGraphicsEffect(windowShadow);
/**********************************************************/
/* Create border in order to cover the zigzag edge of the region */
border = new QWidget(this);
border->move(ui->mainWidget->pos() - QPoint(1, 1));
border->resize(ui->mainWidget->size() + QSize(2, 2));
QString borderStyle;
borderStyle = "background-color:#00FFFFFF;border:1.5px solid #686868; border-radius:" + QString::asprintf("%d",cornerRadius) + "px";
border->setStyleSheet(borderStyle);
border->setAttribute(Qt::WA_TransparentForMouseEvents);
border->show();
/*****************************************************************/
/* Create settings page */
defaultSettingsPage = new SlidePage(cornerRadius, "ABOUT", ui->mainWidget);
textInputItem *version = new textInputItem("version", defaultSettingsPage);
version->setValue("1.0");
version->setEnabled(false);
textInputItem *updateDate = new textInputItem("last-upd", defaultSettingsPage);
updateDate->setValue("2021/12/4");
updateDate->setEnabled(false);
textInputItem *Author = new textInputItem("author", defaultSettingsPage);
Author->setValue("Linloir | Made with love");
Author->setEnabled(false);
defaultSettingsPage->AddContent(Author);
defaultSettingsPage->AddContent(updateDate);
defaultSettingsPage->AddContent(version);
curSettingsPage = defaultSettingsPage;
defaultSettingsPage->show();
pageList.push_back(defaultSettingsPage);
/************************/
/* Initialize display area */
QFont titleFont = QFont("Corbel Light", 24);
QFontMetrics titleFm(titleFont);
canvasTitle = new QLineEdit(this);
canvasTitle->setFont(titleFont);
canvasTitle->setText("START");
canvasTitle->setMaxLength(20);
canvasTitle->setReadOnly(true);
canvasTitle->setMinimumHeight(titleFm.height());
canvasTitle->setMaximumWidth(titleFm.size(Qt::TextSingleLine, "START").width() + 10);
canvasTitle->setStyleSheet("background-color:#00000000;border-style:none;border-width:0px;margin-left:1px;");
connect(canvasTitle, &QLineEdit::textEdited, canvasTitle, [=](QString text){canvasTitle->setMaximumWidth(titleFm.size(Qt::TextSingleLine, text).width());});
QFont descFont = QFont("Corbel Light", 12);
QFontMetrics descFm(descFont);
canvasDesc = new QLineEdit(this);
canvasDesc->setFont(descFont);
canvasDesc->setText("Add your first canvas to start");
canvasDesc->setMaxLength(128);
canvasDesc->setReadOnly(true);
canvasDesc->setMinimumHeight(descFm.lineSpacing());
canvasDesc->setStyleSheet("background-color:#00000000;border-style:none;border-width:0px;");
settingsIcon = new customIcon(":/icons/icons/settings.svg", "settings", 5, this);
settingsIcon->setMinimumHeight(canvasTitle->height() * 0.7);
settingsIcon->setMaximumWidth(canvasTitle->height() * 0.7);
connect(settingsIcon, &customIcon::clicked, this, [=](){
QPropertyAnimation *rotate = new QPropertyAnimation(settingsIcon, "rotationAngle", this);
rotate->setDuration(750);
rotate->setStartValue(0);
rotate->setEndValue(90);
rotate->setEasingCurve(QEasingCurve::InOutExpo);
rotate->start();
curSettingsPage->slideIn();
});
layersIcon = new customIcon(":/icons/icons/layers.svg", "layers", 5, this);
layersIcon->setMinimumHeight(canvasTitle->height() * 0.7);
layersIcon->setMaximumWidth(canvasTitle->height() * 0.7);
/* create title */
QWidget *titleInnerWidget = new QWidget(this);
titleInnerWidget->setFixedHeight(canvasTitle->height());
QHBoxLayout *innerLayout = new QHBoxLayout(titleInnerWidget);
titleInnerWidget->setLayout(innerLayout);
innerLayout->setContentsMargins(0, 0, 0, 0);
innerLayout->setSpacing(10);
innerLayout->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
innerLayout->addWidget(canvasTitle);
innerLayout->addWidget(settingsIcon);
innerLayout->addWidget(layersIcon);
QWidget *titleWidget = new QWidget(this);
titleWidget->setMaximumHeight(canvasTitle->height() + canvasDesc->height());
QVBoxLayout *outerLayout = new QVBoxLayout(titleWidget);
titleWidget->setLayout(outerLayout);
outerLayout->setContentsMargins(0, 0, 0, 0);
outerLayout->setSpacing(0);
outerLayout->addWidget(titleInnerWidget);
outerLayout->addWidget(canvasDesc);
/* create default page */
defaultPage = new QWidget(ui->mainWidget);
defaultPage->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
bigIconButton *createNew = new bigIconButton(":/icons/icons/create.png", "Create new", 10, this);
createNew->setScale(0.9);
bigIconButton *openFile = new bigIconButton(":/icons/icons/open.png", "Open from file", 10, this);
connect(openFile, &bigIconButton::clicked, this, [=](){
QString inputPath = QFileDialog::getOpenFileName(this, tr("Open map"), " ", tr("Map File(*.map)"));
if(!inputPath.isEmpty()){
MyCanvas *newCanvas = loadCanvas(inputPath);
if(newCanvas != nullptr){
canvasList.push_back(newCanvas);
selectionItem *newLayer = new selectionItem(newCanvas->name(), newCanvas->description(), layersPage);
layerSel->AddItem(newLayer);
layerSel->SetSelection(newLayer);
pageList.push_back(newCanvas->settingPage());
connect(newLayer, &selectionItem::selected, this, [=](){selectCanvas(newCanvas);});
selectCanvas(newCanvas);
connect(newCanvas, &MyCanvas::nameChanged, this, [=](QString text){
canvasTitle->setText(text);
canvasTitle->setMaximumWidth(QFontMetrics(QFont("Corbel Light", 24)).size(Qt::TextSingleLine, canvasTitle->text()).width() + 10);
newLayer->setTitle(text);
});
connect(newCanvas, &MyCanvas::descChanged, this, [=](QString text){this->canvasDesc->setText(text);newLayer->setDescription(text);});
connect(newCanvas, &MyCanvas::setDel, this, [=](MyCanvas *c){curSettingsPage->slideOut();deleteCanvas(c);layerSel->RemoveItem(newLayer);});
createNewPage->slideOut();
}
}
});
QHBoxLayout *defaultPageLayout = new QHBoxLayout(defaultPage);
defaultPage->setLayout(defaultPageLayout);
defaultPageLayout->setContentsMargins(50, 30, 50, 80);
defaultPageLayout->setSpacing(20);
defaultPageLayout->addWidget(createNew);
defaultPageLayout->addWidget(openFile);
/* create layers page */
//for add new page
textInputItem *rename = new textInputItem("Name:",createNewPage);
rename->setValue("Layer_" + QString::asprintf("%d", canvasList.size()));
textInputItem *redescribe = new textInputItem("Detail:",createNewPage);
redescribe->setValue("No description");
layersPage = new SlidePage(cornerRadius, "LAYERS", ui->mainWidget);
layersPage->stackUnder(createNewPage);
connect(layersIcon, &customIcon::clicked, layersPage, &SlidePage::slideIn);
layerSel = new singleSelectGroup("Layers", layersPage);
connect(layerSel, &singleSelectGroup::itemChange, layersPage, [=](){layersPage->UpdateContents();});
textButton *openFileBtn = new textButton("Open file", layersPage);
connect(openFileBtn, &textButton::clicked, this, [=](){
QString inputPath = QFileDialog::getOpenFileName(this, tr("Open map"), " ", tr("Map File(*.map)"));
if(!inputPath.isEmpty()){
MyCanvas *newCanvas = loadCanvas(inputPath);
if(newCanvas != nullptr){
canvasList.push_back(newCanvas);
selectionItem *newLayer = new selectionItem(newCanvas->name(), newCanvas->description(), layersPage);
layerSel->AddItem(newLayer);
layerSel->SetSelection(newLayer);
pageList.push_back(newCanvas->settingPage());
connect(newLayer, &selectionItem::selected, this, [=](){selectCanvas(newCanvas);});
selectCanvas(newCanvas);
connect(newCanvas, &MyCanvas::nameChanged, this, [=](QString text){
canvasTitle->setText(text);
canvasTitle->setMaximumWidth(QFontMetrics(QFont("Corbel Light", 24)).size(Qt::TextSingleLine, canvasTitle->text()).width() + 10);
newLayer->setTitle(text);
});
connect(newCanvas, &MyCanvas::descChanged, this, [=](QString text){this->canvasDesc->setText(text);newLayer->setDescription(text);});
connect(newCanvas, &MyCanvas::setDel, this, [=](MyCanvas *c){curSettingsPage->slideOut();deleteCanvas(c);layerSel->RemoveItem(newLayer);});
createNewPage->slideOut();
}
}
});
textButton *addNewBtn = new textButton("Create new", layersPage);
layersPage->AddContent(addNewBtn);
layersPage->AddContent(openFileBtn);
layersPage->AddContent(layerSel);
connect(addNewBtn, &textButton::clicked, this, [=](){rename->setValue("Layer_" + QString::asprintf("%d", canvasList.size()));redescribe->setValue("No description");createNewPage->slideIn();});
layersPage->show();
pageList.push_back(layersPage);
/* create add new slide page */
createNewPage = new SlidePage(cornerRadius, "CREATE CANVAS", ui->mainWidget);
QLineEdit *canvasName = new QLineEdit(this);
canvasName->setMaximumHeight(20);
QLineEdit *canvasDesc = new QLineEdit(this);
canvasDesc->setMaximumHeight(20);
QWidget *whiteSpace = new QWidget(createNewPage);
whiteSpace->setFixedHeight(30);
singleSelectGroup *structureSel = new singleSelectGroup("Structure",createNewPage);
selectionItem *item_1 = new selectionItem("AL", "Use adjacent list for canvas", createNewPage);
selectionItem *item_2 = new selectionItem("AML", "Use multiple adjacent list for canvas", createNewPage);
structureSel->AddItem(item_1);
structureSel->AddItem(item_2);
singleSelectGroup *dirSel = new singleSelectGroup("Mode", createNewPage);
selectionItem *item_3 = new selectionItem("DG", "Directed graph", createNewPage);
selectionItem *item_4 = new selectionItem("UDG", "Undirected graph", createNewPage);
dirSel->AddItem(item_3);
dirSel->AddItem(item_4);
textButton *submit = new textButton("Create!", createNewPage);
connect(submit, &textButton::clicked, this, [=](){
MyCanvas *newCanvas = new MyCanvas(cornerRadius,
rename->value(),
redescribe->value(),
structureSel->value() == 0 ? MyCanvas::AL : MyCanvas::AML,
dirSel->value() == 0 ? MyCanvas::DG : MyCanvas::UDG, ui->mainWidget);
canvasList.push_back(newCanvas);
selectionItem *newLayer = new selectionItem(newCanvas->name(), newCanvas->description(), layersPage);
layerSel->AddItem(newLayer);
layerSel->SetSelection(newLayer);
pageList.push_back(newCanvas->settingPage());
connect(newLayer, &selectionItem::selected, this, [=](){selectCanvas(newCanvas);});
selectCanvas(newCanvas);
connect(newCanvas, &MyCanvas::nameChanged, this, [=](QString text){
canvasTitle->setText(text);
canvasTitle->setMaximumWidth(QFontMetrics(QFont("Corbel Light", 24)).size(Qt::TextSingleLine, canvasTitle->text()).width() + 10);
newLayer->setTitle(text);
});
connect(newCanvas, &MyCanvas::descChanged, this, [=](QString text){this->canvasDesc->setText(text);newLayer->setDescription(text);});
connect(newCanvas, &MyCanvas::setDel, this, [=](MyCanvas *c){curSettingsPage->slideOut();deleteCanvas(c);layerSel->RemoveItem(newLayer);});
createNewPage->slideOut();
});
createNewPage->AddContent(submit);
createNewPage->AddContent(dirSel);
createNewPage->AddContent(structureSel);
createNewPage->AddContent(whiteSpace);
createNewPage->AddContent(redescribe);
createNewPage->AddContent(rename);
connect(createNew, &bigIconButton::clicked, createNewPage, [=](){rename->setValue("Layer_" + QString::asprintf("%d", canvasList.size()));redescribe->setValue("No description");createNewPage->slideIn();});
createNewPage->show();
pageList.push_back(createNewPage);
ui->displayLayout->addWidget(titleWidget);
ui->displayLayout->addWidget(defaultPage);
ui->displayLayout->setAlignment(Qt::AlignTop);
}
void MainWindow::selectCanvas(MyCanvas *canvas){
if(!curCanvas){
ui->displayLayout->removeWidget(defaultPage);
defaultPage->hide();
ui->displayLayout->addWidget(canvas);
canvas->show();
}
else{
ui->displayLayout->removeWidget(curCanvas);
curCanvas->hide();
ui->displayLayout->addWidget(canvas);
canvas->show();
}
curCanvas = canvas;
canvas->settingPage()->setParent(ui->mainWidget);
curSettingsPage = canvas->settingPage();
canvasTitle->setText(curCanvas->name());
canvasTitle->setMaximumWidth(QFontMetrics(QFont("Corbel Light", 24)).size(Qt::TextSingleLine, canvasTitle->text()).width() + 10);
canvasDesc->setText(curCanvas->description());
}
void MainWindow::deleteCanvas(MyCanvas *canvas){
int index = canvasList.indexOf(canvas);
if(index < 0)
return;
canvasList.erase(canvasList.begin() + index);
ui->displayLayout->removeWidget(curCanvas);
curCanvas->hide();
if(canvasList.size() > 0){
selectCanvas(canvasList[0]);
}
else{
ui->displayLayout->addWidget(defaultPage);
defaultPage->show();
curCanvas = nullptr;
canvasTitle->setText("START");
canvasTitle->setMaximumWidth(QFontMetrics(QFont("Corbel Light", 24)).size(Qt::TextSingleLine, "START").width() + 10);
canvasDesc->setText("Add your first canvas to start");
curSettingsPage = defaultSettingsPage;
}
pageList.erase(pageList.begin() + pageList.indexOf(canvas->settingPage()));
delete canvas;
ui->mainWidget->update();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::mousePressEvent(QMouseEvent *event){
if(event->button() == Qt::LeftButton){
mousePressed = true;
lastPos = event->globalPosition().toPoint() - this->frameGeometry().topLeft();
}
}
void MainWindow::mouseMoveEvent(QMouseEvent *event){
if(event->buttons() == Qt::NoButton)
mousePressed = false;
if(!mousePressed){
mouseState = 0;
if(!maximized && abs(event->pos().x() - ui->mainWidget->pos().x()) < 5)
mouseState |= AT_LEFT;
if(!maximized && abs(event->pos().y() - ui->mainWidget->pos().y()) < 5)
mouseState |= AT_TOP;
if(!maximized && abs(event->pos().x() - ui->mainWidget->pos().x() - ui->mainWidget->width()) < 5)
mouseState |= AT_RIGHT;
if(!maximized && abs(event->pos().y() - ui->mainWidget->pos().y() - ui->mainWidget->height()) < 5)
mouseState |= AT_BOTTOM;
if(mouseState == AT_TOP_LEFT || mouseState == AT_BOTTOM_RIGHT)
setCursor(Qt::SizeFDiagCursor);
else if(mouseState == AT_TOP_RIGHT || mouseState == AT_BOTTOM_LEFT)
setCursor(Qt::SizeBDiagCursor);
else if(mouseState & (AT_LEFT | AT_RIGHT))
setCursor(Qt::SizeHorCursor);
else if(mouseState & (AT_TOP | AT_BOTTOM))
setCursor(Qt::SizeVerCursor);
else
unsetCursor();
}
else{
if(mouseState == 0){
if(maximized){
qDebug() << event->pos() << ui->mainWidget->width();
qreal wRatio = (double)event->pos().x() / (double)ui->mainWidget->width();
qDebug() << wRatio;
controlWindowScale();
qDebug() << ui->mainWidget->width();
qDebug() << QPoint(event->globalPosition().x() - ui->mainWidget->width() * wRatio, event->globalPosition().y());
qDebug() << this->frameGeometry().topLeft();
this->move(QPoint(event->globalPosition().x() - ui->mainWidget->width() * wRatio, -30));
qDebug() << this->frameGeometry().topLeft();
lastPos = QPoint(ui->mainWidget->width() * wRatio, event->pos().y());
}
else
this->move(event->globalPosition().toPoint() - lastPos);
}
else{
QPoint d = event->globalPosition().toPoint() - frameGeometry().topLeft() - lastPos;
if(mouseState & AT_LEFT){
this->move(this->frameGeometry().x() + d.x(), this->frameGeometry().y());
this->resize(this->width() - d.x(), this->height());
}
if(mouseState & AT_RIGHT){
this->resize(this->width() + d.x(), this->height());
}
if(mouseState & AT_TOP){
this->move(this->frameGeometry().x(), this->frameGeometry().y() + d.y());
this->resize(this->width(), this->height() - d.y());
}
if(mouseState & AT_BOTTOM){
this->resize(this->width(), this->height() + d.y());
}
}
lastPos = event->globalPosition().toPoint() - this->frameGeometry().topLeft();
}
}
void MainWindow::resizeEvent(QResizeEvent *event){
//Resize border
if(border)
border->resize(ui->mainWidget->size() + QSize(2, 2));
//Resize mask
QPainterPath path;
path.addRoundedRect(ui->mainWidget->rect(), cornerRadius - 1, cornerRadius - 1);
QRegion mask(path.toFillPolygon().toPolygon());
ui->mainWidget->setMask(mask);
//Resize all pages
for(int i = 0; i < pageList.size(); i++){
pageList[i]->resize(ui->mainWidget->width() * 0.3 < pageList[i]->preferWidth ? pageList[i]->preferWidth - 1 : ui->mainWidget->width() * 0.3 - 1, ui->mainWidget->height());
pageList[i]->resize(pageList[i]->width() + 1, pageList[i]->height());
}
}
void MainWindow::controlWindowScale(){
if(!maximized){
lastGeometry = this->frameGeometry();
windowShadow->setEnabled(false);
ui->verticalLayout->setContentsMargins(0, 0, 0, 0);
border->hide();
QString mainStyle = "QWidget#mainWidget{background-color:" + mainBackGround.name() + ";border-radius:0px;}";
ui->mainWidget->setStyleSheet(mainStyle);
this->showMaximized();
maximized = true;
QPainterPath path;
path.addRect(ui->mainWidget->rect());
QRegion mask(path.toFillPolygon().toPolygon());
ui->mainWidget->setMask(mask);
}
else{
ui->verticalLayout->setContentsMargins(30, 30, 30, 30);
this->showNormal();
QString mainStyle = "QWidget#mainWidget{background-color:" + mainBackGround.name() + QString::asprintf(";border-radius:%dpx", cornerRadius) + "}";
ui->mainWidget->setStyleSheet(mainStyle);
QPainterPath path;
path.addRoundedRect(ui->mainWidget->rect(), cornerRadius - 1, cornerRadius - 1);
QRegion mask(path.toFillPolygon().toPolygon());
ui->mainWidget->setMask(mask);
border->show();
windowShadow->setEnabled(true);
this->resize(lastGeometry.width(), lastGeometry.height());
this->move(lastGeometry.x(), lastGeometry.y());
maximized = false;
}
}
MyCanvas* MainWindow::loadCanvas(const QString &path){
QFile input(path);
input.open(QIODevice::ReadOnly);
QTextStream ts(&input);
QString magicString = ts.readLine();
if(magicString != "VFdGeWFXUnZaekl3TURJd05ESTE=") return nullptr;
MyCanvas *newCanvas = new MyCanvas(ts, cornerRadius, ui->mainWidget);
input.close();
return newCanvas;
}

67
mainwindow.h Normal file
View File

@ -0,0 +1,67 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QVector>
#include <QGraphicsDropShadowEffect>
#include "slidepage.h"
#include "mycanvas.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
int cornerRadius = 20;
QWidget *border = nullptr;
QWidget *defaultPage;
QGraphicsDropShadowEffect *windowShadow;
QColor mainBackGround = QColor(251, 251, 251);
QLineEdit *canvasTitle = nullptr;
QLineEdit *canvasDesc = nullptr;
customIcon *settingsIcon = nullptr;
customIcon *layersIcon = nullptr;
QWidget *canvasDisplay = nullptr;
QVector<SlidePage*> pageList;
SlidePage *createNewPage = nullptr;
SlidePage *defaultSettingsPage = nullptr;
SlidePage *curSettingsPage = nullptr;
SlidePage *layersPage = nullptr;
singleSelectGroup *layerSel = nullptr;
QVector<MyCanvas*> canvasList;
MyCanvas *curCanvas = nullptr;
void selectCanvas(MyCanvas *canvas);
void deleteCanvas(MyCanvas *canvas);
void Init();
enum {AT_LEFT = 1, AT_TOP = 2, AT_RIGHT = 4, AT_BOTTOM = 8,
AT_TOP_LEFT = 3, AT_TOP_RIGHT = 6, AT_BOTTOM_LEFT = 9, AT_BOTTOM_RIGHT = 12};
bool mousePressed = false;
int mouseState;
QPoint lastPos;
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event){mousePressed = false;}
void resizeEvent(QResizeEvent *event);
bool maximized = false;
QRect lastGeometry;
void controlWindowScale();
MyCanvas* loadCanvas(const QString &path);
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

307
mainwindow.ui Normal file
View File

@ -0,0 +1,307 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>900</width>
<height>650</height>
</rect>
</property>
<property name="mouseTracking">
<bool>true</bool>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<property name="mouseTracking">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>30</number>
</property>
<property name="topMargin">
<number>30</number>
</property>
<property name="rightMargin">
<number>30</number>
</property>
<property name="bottomMargin">
<number>30</number>
</property>
<item>
<widget class="QWidget" name="mainWidget" native="true">
<property name="mouseTracking">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="mainLayout">
<property name="spacing">
<number>5</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="titleBar" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>30</height>
</size>
</property>
<property name="mouseTracking">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>13</number>
</property>
<property name="topMargin">
<number>15</number>
</property>
<property name="rightMargin">
<number>20</number>
</property>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="minimumBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>12</width>
<height>12</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>12</width>
<height>12</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QPushButton{background-color:#c2c2c2;border-radius:6px}
QPushButton:hover {background-color:#f9bf45;border-radius:6px;}
QPushButton:pressed {background-color:#ffb11b;border-radius:6px;}</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="adjSizeBtn">
<property name="minimumSize">
<size>
<width>12</width>
<height>12</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>12</width>
<height>12</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QPushButton{background-color:#c2c2c2;border-radius:6px}
QPushButton:hover {background-color:#227d51;border-radius:6px;}
QPushButton:pressed {background-color:#2d6d4b;border-radius:6px;}</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="closeBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>12</width>
<height>12</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>12</width>
<height>12</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QPushButton{background-color:#c2c2c2;border-radius:6px}
QPushButton:hover {background-color:#cb4042;border-radius:6px;}
QPushButton:pressed {background-color:#ab3b3a;border-radius:6px;}</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="mainDisplayWidget" native="true">
<property name="mouseTracking">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="displayLayout">
<property name="leftMargin">
<number>30</number>
</property>
<property name="topMargin">
<number>15</number>
</property>
<property name="rightMargin">
<number>30</number>
</property>
<property name="bottomMargin">
<number>30</number>
</property>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>minimumBtn</sender>
<signal>clicked()</signal>
<receiver>MainWindow</receiver>
<slot>showMinimized()</slot>
<hints>
<hint type="sourcelabel">
<x>688</x>
<y>54</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>closeBtn</sender>
<signal>clicked()</signal>
<receiver>MainWindow</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>742</x>
<y>54</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
</connections>
</ui>

462
mycanvas.cpp Normal file
View File

@ -0,0 +1,462 @@
#include "mycanvas.h"
MyCanvas::MyCanvas(int radius, QString name, QString desc, int structure, int _type, QWidget *parent) :
QWidget(parent),
canvasName(name),
canvasDescription(desc),
structure_type(structure),
type(_type)
{
/* create canvas */
mainLayout = new QHBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
this->setLayout(mainLayout);
view = new MyGraphicsView(type == UDG ? MyGraphicsView::UDG : MyGraphicsView::DG);
view->setSceneRect(view->rect());
view->setStyleSheet("background-color: #FFFFFF;border:1px solid #cfcfcf;border-radius:10px;");
mainLayout->addWidget(view);
g = structure == AL ? (AbstractGraph*)(new ALGraph(type)) : (AbstractGraph*)(new AMLGraph(type));
connect(view, SIGNAL(vexAdded(MyGraphicsVexItem*)), this, SLOT(addVex(MyGraphicsVexItem*)));
connect(view, SIGNAL(arcAdded(MyGraphicsLineItem*)), this, SLOT(addArc(MyGraphicsLineItem*)));
connect(view, &MyGraphicsView::visitClear, this, [=](){g->ClearVisit();});
this->setFocusPolicy(Qt::ClickFocus);
CreateSettings(radius);
}
MyCanvas::MyCanvas(QTextStream &ts, int radius, QWidget *parent) :
QWidget(parent)
{
canvasName = ts.readLine();
canvasDescription = ts.readLine();
ts >> structure_type >> type;
/* create canvas */
mainLayout = new QHBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
this->setLayout(mainLayout);
view = new MyGraphicsView(type == UDG ? MyGraphicsView::UDG : MyGraphicsView::DG);
view->setSceneRect(view->rect());
view->setStyleSheet("background-color: #FFFFFF;border:1px solid #cfcfcf;border-radius:10px;");
mainLayout->addWidget(view);
g = structure_type == AL ? (AbstractGraph*)(new ALGraph(type)) : (AbstractGraph*)(new AMLGraph(type));
connect(view, SIGNAL(vexAdded(MyGraphicsVexItem*)), this, SLOT(addVex(MyGraphicsVexItem*)));
connect(view, SIGNAL(arcAdded(MyGraphicsLineItem*)), this, SLOT(addArc(MyGraphicsLineItem*)));
connect(view, &MyGraphicsView::visitClear, this, [=](){g->ClearVisit();});
view->ReadFromFile(ts);
for(int i = 0; i < view->arcNum; i++){
int w;
ts >> w;
if(w != 0)
g->SetWeight(view->lines[i], w);
}
this->setFocusPolicy(Qt::ClickFocus);
CreateSettings(radius);
}
void MyCanvas::CreateSettings(int radius){
/* create settings page */
settings = new SlidePage(radius, "SETTINGS", this->parentWidget());
singleSelectGroup *structureSetting = new singleSelectGroup("Structure", this);
selectionItem *setAL = new selectionItem("AL", "Adjacent list structure", this);
selectionItem *setAML = new selectionItem("AML", "Adjacent multiple list", this);
structureSetting->AddItem(setAL);
structureSetting->AddItem(setAML);
structureSetting->SetSelection(structure_type == AL ? setAL : setAML);
connect(structureSetting, &singleSelectGroup::selectedItemChange, this, [=](int id){
if(id == 1){
ALGraph *old = (ALGraph*)g;
g = old->ConvertToAML();
old->~ALGraph();
structure_type = AML;
}
else{
AMLGraph *old = (AMLGraph*)g;
g = old->ConvertToAL();
old->~AMLGraph();
structure_type = AL;
}
});
singleSelectGroup *dirSetting = new singleSelectGroup("Mode", this);
selectionItem *setDG = new selectionItem("DG", "Directed graph", this);
selectionItem *setUDG = new selectionItem("UDG", "Undirected graph", this);
dirSetting->AddItem(setDG);
dirSetting->AddItem(setUDG);
dirSetting->SetSelection(type == DG ? setDG : setUDG);
connect(dirSetting, &singleSelectGroup::selectedItemChange, this, [=](int id){
g->ConvertType(id == 0 ? AbstractGraph::DG : AbstractGraph::UDG);
view->setType(id == 0 ? MyGraphicsView::DG : MyGraphicsView::UDG);
type = id == 0 ? DG : UDG;
});
QWidget *whiteSpace = new QWidget(this);
whiteSpace->setFixedHeight(30);
horizontalValueAdjuster *aniSpeed = new horizontalValueAdjuster("Animation speed", 0.1, 20, 0.1, this);
aniSpeed->setValue(1.0);
connect(aniSpeed, &horizontalValueAdjuster::valueChanged, view, [=](qreal value){view->setAniRate(value);});
textInputItem *rename = new textInputItem("Name", this);
rename->setValue(canvasName);
connect(rename, &textInputItem::textEdited, this, [=](QString text){canvasName = text; emit nameChanged(text);});
textInputItem *redesc = new textInputItem("Detail", this);
redesc->setValue(canvasDescription);
connect(redesc, &textInputItem::textEdited, this, [=](QString text){canvasDescription = text; emit descChanged(text);});
textButton *saveBtn = new textButton("Save to file", this);
connect(saveBtn, &textButton::clicked, this, [=](){
QString savePath = QFileDialog::getSaveFileName(this, tr("Save map"), " ", tr("Map file(*.map)"));
if(!savePath.isEmpty())
SaveToFile(savePath);
});
textButton *delBtn = new textButton("Delete", "#0acb1b45","#1acb1b45","#2acb1b45",this);
connect(delBtn, &textButton::clicked, this, [=](){emit setDel(this);});
settings->AddContent(delBtn);
settings->AddContent(saveBtn);
settings->AddContent(dirSetting);
settings->AddContent(structureSetting);
settings->AddContent(aniSpeed);
settings->AddContent(whiteSpace);
settings->AddContent(redesc);
settings->AddContent(rename);
settings->show();
QTimer *delay = new QTimer(this);
connect(delay, &QTimer::timeout, this, [=](){Init();});
delay->setSingleShot(true);
delay->start(10);
}
void MyCanvas::Init(){
/* Create info widget */
infoWidget = new QWidget(this);
mainLayout->addWidget(infoWidget);
mainLayout->setStretch(0, 7);
mainLayout->setStretch(1, 3);
infoWidget->setMinimumWidth(250);
infoWidget->setMaximumWidth(500);
//Set basic layout
QVBoxLayout *infoLayout = new QVBoxLayout(infoWidget);
infoWidget->setLayout(infoLayout);
infoLayout->setContentsMargins(10, 0, 0, 0);
infoLayout->setAlignment(Qt::AlignTop);
QFont titleFont = QFont("Corbel", 20);
QWidget *upper = new QWidget(infoWidget);
QVBoxLayout *upperLayout = new QVBoxLayout(upper);
upper->setLayout(upperLayout);
upperLayout->setContentsMargins(0, 0, 0, 0);
upper->setContentsMargins(0, 0, 0, 0);
pageName = new QLabel(infoWidget);
pageName->setText("INFO");
pageName->setFont(titleFont);
pageName->setAlignment(Qt::AlignLeft | Qt::AlignTop);
pageName->setStyleSheet("color:#2c2c2c");
QWidget *upperSplitter = new QWidget(upper);
upperSplitter->setFixedSize(30, 6);
upperSplitter->setStyleSheet("background-color:#3c3c3c;border-radius:3px;");
upperLayout->addWidget(pageName);
upperLayout->addWidget(upperSplitter);
QWidget *lower = new QWidget(infoWidget);
QVBoxLayout *lowerLayout = new QVBoxLayout(lower);
lower->setLayout(lowerLayout);
lowerLayout->setContentsMargins(0, 0, 0, 0);
QLabel *logLabel = new QLabel(lower);
logLabel->setText("LOG");
logLabel->setFont(titleFont);
logLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
logLabel->setStyleSheet("color:#2c2c2c");
QWidget *lowerSplitter = new QWidget(lower);
lowerSplitter->setFixedSize(30, 6);
lowerSplitter->setStyleSheet("background-color:#3c3c3c;border-radius:3px;");
ScrollAreaCustom *logDisplay = new ScrollAreaCustom(lower);
logDisplay->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
lowerLayout->addWidget(logLabel);
lowerLayout->addWidget(lowerSplitter);
lowerLayout->addWidget(logDisplay);
infoLayout->addWidget(upper);
infoLayout->addWidget(lower);
//Add specific items and connections
//Default page
QWidget *defInfoPage = new QWidget(infoWidget);
QVBoxLayout *defInfoLayout = new QVBoxLayout(defInfoPage);
defInfoPage->setLayout(defInfoLayout);
defInfoLayout->setContentsMargins(0, 0, 0, 0);
defInfoLayout->setAlignment(Qt::AlignTop);
QWidget *defTextItems = new QWidget(defInfoPage);
defTextItems->setObjectName("DefTextItems");
defTextItems->setStyleSheet("QWidget#DefTextItems{border:1px solid #cfcfcf;border-radius:5px;}");
QVBoxLayout *defTextLayout = new QVBoxLayout(defTextItems);
defTextItems->setLayout(defTextLayout);
defTextLayout->setContentsMargins(0, 5, 0, 5);
textInputItem *textName = new textInputItem("Name", defInfoPage);
textName->setValue(canvasName);
connect(this, &MyCanvas::nameChanged, this, [=](){textName->setValue(canvasName);});
textName->setEnabled(false);
defTextLayout->addWidget(textName);
textInputItem *textDesc = new textInputItem("Detail", defInfoPage);
textDesc->setValue(canvasDescription);
connect(this, &MyCanvas::descChanged, this, [=](){textDesc->setValue(canvasDescription);});
textDesc->setEnabled(false);
defTextLayout->addWidget(textDesc);
textInputItem *vexNumText = new textInputItem("Vex", defInfoPage);
vexNumText->setValue(QString::asprintf("%d", view->vexNum));
vexNumText->setEnabled(false);
defTextLayout->addWidget(vexNumText);
textInputItem *arcNumText = new textInputItem("Arc", defInfoPage);
arcNumText->setValue(QString::asprintf("%d", view->arcNum));
arcNumText->setEnabled(false);
defTextLayout->addWidget(arcNumText);
defInfoLayout->addWidget(defTextItems);
upperLayout->addWidget(defInfoPage);
defInfoPage->show();
//VexPage
QWidget *vexInfoPage = new QWidget(infoWidget);
QVBoxLayout *vexInfoLayout = new QVBoxLayout(vexInfoPage);
vexInfoLayout->setContentsMargins(0, 0, 0, 0);
vexInfoLayout->setAlignment(Qt::AlignTop);
vexInfoPage->setLayout(vexInfoLayout);
QWidget *vexTextItems = new QWidget(vexInfoPage);
vexTextItems->setObjectName("VexTextItems");
vexTextItems->setStyleSheet("QWidget#VexTextItems{border:1px solid #cfcfcf;border-radius:5px;}");
QVBoxLayout *vexTextLayout = new QVBoxLayout(vexTextItems);
vexTextItems->setLayout(vexTextLayout);
vexTextLayout->setContentsMargins(0, 5, 0, 5);
textInputItem *textTag = new textInputItem("Tag", vexInfoPage);
vexTextLayout->addWidget(textTag);
textInputItem *dijStart = new textInputItem("Start", vexInfoPage);
dijStart->setValue("Run dijkstra first");
dijStart->setEnabled(false);
vexTextLayout->addWidget(dijStart);
textInputItem *dijDistance = new textInputItem("Dist", vexInfoPage);
dijDistance->setValue("Infinite");
dijDistance->setEnabled(false);
vexTextLayout->addWidget(dijDistance);
textInputItem *dijPrev = new textInputItem("Prev", vexInfoPage);
dijPrev->setValue("Run dijkstra first");
dijPrev->setEnabled(false);
vexTextLayout->addWidget(dijPrev);
vexInfoLayout->addWidget(vexTextItems);
QWidget *traverseBar = new QWidget(vexInfoPage);
QHBoxLayout *traverseLayout = new QHBoxLayout(traverseBar);
traverseBar->setLayout(traverseLayout);
traverseLayout->setContentsMargins(0, 0, 0, 0);
textButton *startBfs = new textButton("BFS", vexInfoPage);
traverseLayout->addWidget(startBfs);
textButton *startDfs = new textButton("DFS", vexInfoPage);
traverseLayout->addWidget(startDfs);
vexInfoLayout->addWidget(traverseBar);
textButton *startDij = new textButton("Start Dijkstra", vexInfoPage);
startDij->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
vexInfoLayout->addWidget(startDij);
textButton *delVex = new textButton("Delete", "#1acb1b45","#2acb1b45","#3acb1b45", vexInfoPage);
vexInfoLayout->addWidget(delVex);
upperLayout->addWidget(vexInfoPage);
vexInfoPage->hide();
//ArcPage
QWidget *arcInfoPage = new QWidget(infoWidget);
QVBoxLayout *arcInfoLayout = new QVBoxLayout(arcInfoPage);
arcInfoLayout->setContentsMargins(0, 0, 0, 0);
arcInfoLayout->setAlignment(Qt::AlignTop);
arcInfoPage->setLayout(arcInfoLayout);
QWidget *arcTextItems = new QWidget(arcInfoPage);
arcTextItems->setObjectName("VexTextItems");
arcTextItems->setStyleSheet("QWidget#VexTextItems{border:1px solid #cfcfcf;border-radius:5px;}");
QVBoxLayout *arcTextLayout = new QVBoxLayout(arcTextItems);
arcTextItems->setLayout(arcTextLayout);
arcTextLayout->setContentsMargins(0, 5, 0, 5);
textInputItem *arcWeight = new textInputItem("Pow", arcInfoPage);
arcTextLayout->addWidget(arcWeight);
QRegularExpression re("^[1-9]\\d*$");
arcWeight->setValidator(new QRegularExpressionValidator(re));
textInputItem *arcStart = new textInputItem("Start", arcInfoPage);
arcStart->setValue("NA");
arcStart->setEnabled(false);
arcTextLayout->addWidget(arcStart);
textInputItem *arcEnd = new textInputItem("End", arcInfoPage);
arcEnd->setValue("NA");
arcEnd->setEnabled(false);
arcTextLayout->addWidget(arcEnd);
arcInfoLayout->addWidget(arcTextItems);
textButton *reverseBtn = new textButton("Reverse", arcInfoPage);
arcInfoLayout->addWidget(reverseBtn);
textButton *delArc = new textButton("Delete", "#1acb1b45","#2acb1b45","#3acb1b45", arcInfoPage);
arcInfoLayout->addWidget(delArc);
upperLayout->addWidget(arcInfoPage);
arcInfoPage->hide();
connect(view, &MyGraphicsView::vexAdded, this, [=](){vexNumText->setValue(QString::asprintf("%d",view->vexNum));});
connect(view, &MyGraphicsView::arcAdded, this, [=](){arcNumText->setValue(QString::asprintf("%d",view->arcNum));});
connect(view, &MyGraphicsView::selected, this, [=](QGraphicsItem *item){
int type = item->type();
if(type == MyGraphicsVexItem::Type){
defInfoPage->hide();
arcInfoPage->hide();
vexInfoPage->show();
textTag->setValue(view->selectedVex()->Text());
if(g->GetInfoOf(view->selectedVex())->strtVexInfo == nullptr){
dijStart->setValue("Run dijkstra first");
dijPrev->setValue("Run dijkstra first");
dijDistance->setValue("Infinite");
}
else{
dijStart->setValue(g->GetInfoOf(view->selectedVex())->strtVexInfo->gVex->Text());
if(g->GetInfoOf(view->selectedVex())->preVexID == -1)
dijPrev->setValue("This vex");
else
dijPrev->setValue(g->GetInfoOf(g->GetInfoOf(view->selectedVex())->preVexID)->gVex->Text());
dijDistance->setValue(g->GetInfoOf(view->selectedVex())->distance == 2147483647 ? "Infinite" : QString::asprintf("%d", g->GetInfoOf(view->selectedVex())->distance));
}
}
else if(type == MyGraphicsLineItem::Type){
defInfoPage->hide();
vexInfoPage->hide();
arcInfoPage->show();
arcWeight->setValue(view->selectedArc()->weightText() == "" ? "1" : view->selectedArc()->weightText());
arcStart->setValue(view->selectedArc()->stVex()->Text());
arcEnd->setValue(view->selectedArc()->edVex()->Text());
}
else{
vexInfoPage->hide();
arcInfoPage->hide();
defInfoPage->show();
vexNumText->setValue(QString::asprintf("%d",view->vexNum));
arcNumText->setValue(QString::asprintf("%d",view->arcNum));
}
});
connect(textTag, &textInputItem::textEdited, this, [=](QString text){
logDisplay->addWidget(new viewLog("[Vex] | Rename \""+view->selectedVex()->Text()+"\" to \""+text+"\""));
if(view->selectedVex() != nullptr)
view->selectedVex()->setText(text);
if(g->GetInfoOf(view->selectedVex())->strtVexInfo != nullptr){
dijStart->setValue(g->GetInfoOf(view->selectedVex())->strtVexInfo->gVex->Text());
if(g->GetInfoOf(view->selectedVex())->preVexID != -1)
dijPrev->setValue(g->GetInfoOf(g->GetInfoOf(view->selectedVex())->preVexID)->gVex->Text());
}
});
connect(arcWeight, &textInputItem::textEdited, this, [=](QString text){
logDisplay->addWidget(new viewLog("[Arc] | \""+view->selectedArc()->stVex()->Text()+"\" -> \""+view->selectedArc()->edVex()->Text()+"\" set to "+text));
g->SetWeight(view->selectedArc(), text.toDouble());
});
connect(view, &MyGraphicsView::unselected, this, [=](){
vexInfoPage->hide();
arcInfoPage->hide();
defInfoPage->show();
vexNumText->setValue(QString::asprintf("%d",view->vexNum));
arcNumText->setValue(QString::asprintf("%d",view->arcNum));
});
connect(startBfs, &textButton::clicked, this, [=](){
viewLog *newLog = new viewLog("[BFS] | --- BFS start ---");
newLog->setStyleSheet("color:#0078d4");
logDisplay->addWidget(newLog);
bfs();
});
connect(startDfs, &textButton::clicked, this, [=](){
viewLog *newLog = new viewLog("[DFS] | --- DFS start ---");
newLog->setStyleSheet("color:#0078d4");
logDisplay->addWidget(newLog);
dfs();
});
connect(startDij, &textButton::clicked, this, [=](){
viewLog *newLog = new viewLog("[Dij] | --- Dijkstra start ---");
newLog->setStyleSheet("color:#0078d4");
logDisplay->addWidget(newLog);
dijkstra();
if(g->GetInfoOf(view->selectedVex())->strtVexInfo == nullptr){
dijStart->setValue("Run dijkstra first");
dijPrev->setValue("Run dijkstra first");
dijDistance->setValue("Infinite");
}
else{
dijStart->setValue(g->GetInfoOf(view->selectedVex())->strtVexInfo->gVex->Text());
if(g->GetInfoOf(view->selectedVex())->preVexID == -1)
dijPrev->setValue("This vex");
else
dijPrev->setValue(g->GetInfoOf(g->GetInfoOf(view->selectedVex())->preVexID)->gVex->Text());
dijDistance->setValue(g->GetInfoOf(view->selectedVex())->distance == 2147483647 ? "Infinite" : QString::asprintf("%d", g->GetInfoOf(view->selectedVex())->distance));
}
});
connect(reverseBtn, &textButton::clicked, this, [=](){
if(g->Type() == AbstractGraph::UDG)
view->selectedArc()->reverseDirection();
else{
g->DelArc(view->selectedArc());
view->selectedArc()->reverseDirection();
g->AddArc(view->selectedArc());
}
});
connect(delVex, &textButton::clicked, this, [=](){
logDisplay->addWidget(new viewLog("[Vex] | Delete vex \""+view->selectedVex()->Text()+"\""));
g->DelVex(view->selectedVex());
view->selectedVex()->remove();
g->ResetDistance();
g->ClearVisit();
view->unSelect();
});
connect(delArc, &textButton::clicked, this, [=](){
logDisplay->addWidget(new viewLog("[Arc] | Delete arc \""+view->selectedArc()->stVex()->Text()+"\" -> \""+view->selectedArc()->edVex()->Text()+"\""));
g->DelArc(view->selectedArc());
view->selectedArc()->remove();
g->ResetDistance();
g->ClearVisit();
view->unSelect();
});
connect(view, &MyGraphicsView::logAdded, this, [=](viewLog* log){logDisplay->addWidget(log);});
}
void MyCanvas::SaveToFile(const QString &path){
QFile output(path);
output.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream ts(&output);
ts << "VFdGeWFXUnZaekl3TURJd05ESTE=\n";
ts << canvasName << "\n";
ts << canvasDescription << "\n";
ts << structure_type << " " << type << "\n";
view->SaveToFile(ts);
output.close();
}
void MyCanvas::addVex(MyGraphicsVexItem *vex){
g->AddVex(vex);
}
void MyCanvas::addArc(MyGraphicsLineItem *arc){
g->AddArc(arc);
}
void MyCanvas::dfs(){
MyGraphicsVexItem *strtVex = view->selectedVex();
if(strtVex != nullptr){
g->DFS(strtVex);
view->hasVisitedItem = true;
}
}
void MyCanvas::bfs(){
MyGraphicsVexItem *strtVex = view->selectedVex();
if(strtVex != nullptr){
g->BFS(strtVex);
view->hasVisitedItem = true;
}
}
void MyCanvas::dijkstra(){
MyGraphicsVexItem *strtVex = view->selectedVex();
if(strtVex){
g->Dijkstra(strtVex);
view->hasVisitedItem = true;
}
}
void MyCanvas::setWeight(int w){
MyGraphicsLineItem *arc = view->selectedArc();
if(arc){
g->SetWeight(arc, w);
}
}

61
mycanvas.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef MYCANVAS_H
#define MYCANVAS_H
#include <QWidget>
#include <QGridLayout>
#include "slidepage.h"
#include "graph_view.h"
#include "graph_implement.h"
class MyCanvas : public QWidget
{
Q_OBJECT
private:
QString canvasName;
QString canvasDescription;
SlidePage *settings;
//For display
MyGraphicsView *view;
QHBoxLayout *mainLayout;
QWidget *infoWidget;
QLabel *pageName;
AbstractGraph *g;
int structure_type;
int type;
void CreateSettings(int r);
void Init();
void SaveToFile(const QString &path);
public:
enum { UDG = AbstractGraph::UDG, DG = AbstractGraph::DG };
enum { AL = 128, AML = 256 };
explicit MyCanvas(int radius, QString name = "", QString desc = "", int structure = AL, int _type = UDG, QWidget *parent = nullptr);
MyCanvas(QTextStream &ts, int radius, QWidget *parent = nullptr);
QString name(){return canvasName;}
QString description(){return canvasDescription;}
SlidePage *settingPage(){return settings;}
signals:
void nameChanged(QString name);
void descChanged(QString desc);
void setDel(MyCanvas* target);
private slots:
void addVex(MyGraphicsVexItem*);
void addArc(MyGraphicsLineItem*);
//void delVex(MyGraphicsVexItem*);
//void delArc(MyGraphicsLineItem*);
void dfs();
void bfs();
void dijkstra();
void setWeight(int w);
void setAniRate(int step){view->setAniRate(step / 100.0);}
};
#endif // MYCANVAS_H

164
slidepage.cpp Normal file
View File

@ -0,0 +1,164 @@
#include "slidepage.h"
SlidePage::SlidePage(int radius, QString name, QWidget *parent) :
QWidget(parent),
cornerRadius(radius),
pageName(name)
{
//if(parent)
// resize(parent->width() * 0.8 <= preferWidth ? parent->width() * 0.8 : preferWidth, parent->height());
resize(parent->width() * 0.3 <= preferWidth ? preferWidth : parent->width() * 0.3, parent->height());
this->move(QPoint(-this->width() - 30, 0));
pageContentContainer = new ScrollAreaCustom(this);
//> note: Important!!!
pageContentContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
nameLabel = new QLabel(pageName, this);
textFont.setStyleStrategy(QFont::PreferAntialias);
nameLabel->setFont(textFont);
backIcon = new customIcon(":/icons/icons/back.svg", "", 5, this);
opacity = new QGraphicsOpacityEffect(this);
opacity->setOpacity(0);
pageContentContainer->setGraphicsEffect(opacity);
nameLabel->setGraphicsEffect(opacity);
QString style;
style = "background-color:white;border-radius:" + QString::asprintf("%d", cornerRadius) + "px";
bgWidget = new QWidget(this);
bgWidget->lower();
bgWidget->resize(this->size());
bgWidget->setStyleSheet(style);
bgWidget->show();
/* Intialize layout */
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(20, 40, 20, 20);
QWidget *titleBar = new QWidget(this);
QHBoxLayout *titleLayout = new QHBoxLayout(titleBar);
titleLayout->setAlignment(Qt::AlignLeft);
titleBar->setLayout(titleLayout);
titleLayout->addWidget(backIcon);
titleLayout->addWidget(nameLabel);
mainLayout->addWidget(titleBar);
mainLayout->addWidget(pageContentContainer);
mainLayout->setAlignment(Qt::AlignTop);
this->setLayout(mainLayout);
sheildLayer = new SheildLayer(this->parentWidget());
sheildLayer->resize(this->parentWidget()->size());
sheildLayer->setGraphicsEffect(opacity);
sheildLayer->setMouseTracking(true);
connect(sheildLayer, &SheildLayer::clicked, this, [=](){slideOut();setFocus();});
/* Set shadow */
QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(this);
shadow->setBlurRadius(30);
shadow->setColor(QColor(0, 0, 0));
shadow->setOffset(0, 0);
this->setGraphicsEffect(shadow);
/* set policies */
this->setFocusPolicy(Qt::ClickFocus);
this->setMouseTracking(true);
bgWidget->setMouseTracking(true);
sheildLayer->setMouseTracking(true);
/* connect */
connect(backIcon, &QPushButton::clicked, this, [=](){slideOut();});
}
void SlidePage::resizeEvent(QResizeEvent *event){
bgWidget->resize(this->size());
sheildLayer->resize(this->parentWidget()->size());
if(!onShown && !curAni)
this->move(QPoint(-this->width() - 30, 0));
else if(!onShown && curAni)
emit sizeChange();
}
void SlidePage::SetRadius(int radius){
cornerRadius = radius;
QString style;
style = "background-color:white;border-radius:" + QString::asprintf("%d", cornerRadius) + "px";
this->setStyleSheet(style);
}
void SlidePage::SetName(QString name){
pageName = name;
nameLabel->setText(pageName);
}
void SlidePage::slideIn(){
if(curAni){
curAni->stop();
curAni->deleteLater();
curAni = nullptr;
}
onShown = true;
sheildLayer->raise();
sheildLayer->setEnabled(true);
this->raise();
sheildLayer->show();
QParallelAnimationGroup *inGroup = new QParallelAnimationGroup(this);
QPropertyAnimation *slideInAni = new QPropertyAnimation(this, "pos", this);
slideInAni->setStartValue(this->pos());
slideInAni->setEndValue(QPoint(0, 0));
slideInAni->setDuration(1000);
slideInAni->setEasingCurve(QEasingCurve::InOutExpo);
QPropertyAnimation *fadeInAni = new QPropertyAnimation(opacity, "opacity", this);
fadeInAni->setStartValue(opacity->opacity());
//> note: DO NOT CHANGE 0.99 TO 1!!!!!
//> Will cause unexpected position shift (maybe qt's bug)
fadeInAni->setEndValue(0.99);
fadeInAni->setDuration(750);
QSequentialAnimationGroup *rotate = new QSequentialAnimationGroup(this);
QPropertyAnimation *rotateAni = new QPropertyAnimation(backIcon, "rotationAngle", this);
rotateAni->setStartValue(180);
rotateAni->setEndValue(360);
rotateAni->setDuration(750);
rotateAni->setEasingCurve(QEasingCurve::InOutExpo);
rotate->addPause(250);
rotate->addAnimation(rotateAni);
inGroup->addAnimation(slideInAni);
inGroup->addAnimation(fadeInAni);
inGroup->addAnimation(rotate);
connect(inGroup, &QParallelAnimationGroup::finished, this, [=](){this->curAni = nullptr;});
inGroup->start();
curAni = inGroup;
}
void SlidePage::slideOut(){
if(curAni){
curAni->stop();
curAni->deleteLater();
curAni = nullptr;
}
onShown = false;
sheildLayer->setEnabled(false);
QParallelAnimationGroup *outGroup = new QParallelAnimationGroup(this);
QPropertyAnimation *slideOutAni = new QPropertyAnimation(this, "pos", this);
slideOutAni->setStartValue(this->pos());
slideOutAni->setEndValue(QPoint(-this->width() - 30, 0));
slideOutAni->setDuration(1000);
slideOutAni->setEasingCurve(QEasingCurve::InOutExpo);
QPropertyAnimation *fadeOutAni = new QPropertyAnimation(opacity, "opacity", this);
fadeOutAni->setStartValue(opacity->opacity());
fadeOutAni->setEndValue(0);
fadeOutAni->setDuration(750);
QPropertyAnimation *rotateAni = new QPropertyAnimation(backIcon, "rotationAngle", this);
rotateAni->setStartValue(360);
rotateAni->setEndValue(180);
rotateAni->setDuration(750);
rotateAni->setEasingCurve(QEasingCurve::InOutExpo);
outGroup->addAnimation(slideOutAni);
outGroup->addAnimation(fadeOutAni);
outGroup->addAnimation(rotateAni);
connect(outGroup, &QPropertyAnimation::finished, this, [=](){this->curAni = nullptr;pageContentContainer->scrollToTop();sheildLayer->hide();});
connect(this, &SlidePage::sizeChange, slideOutAni, [=](){slideOutAni->setEndValue(QPoint(-this->width() - 30, 0));});
outGroup->start();
curAni = outGroup;
}

80
slidepage.h Normal file
View File

@ -0,0 +1,80 @@
#ifndef SLIDEPAGE_H
#define SLIDEPAGE_H
#include <QWidget>
#include <QLabel>
#include <QPaintEvent>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGraphicsDropShadowEffect>
#include <QGraphicsOpacityEffect>
#include <QGraphicsEffect>
#include <QPropertyAnimation>
#include <QParallelAnimationGroup>
#include <QSequentialAnimationGroup>
#include "customScrollContainer.h"
#include "customWidgets.h"
class SheildLayer : public QWidget{
Q_OBJECT
private:
bool pressed = false;
bool enabled = true;
QWidget *bg;
void mousePressEvent(QMouseEvent *event){if(enabled)pressed = true;}
void mouseReleaseEvent(QMouseEvent *event){if(enabled && pressed)emit clicked();pressed = false;}
void resizeEvent(QResizeEvent *event){bg->resize(this->parentWidget()->size());}
public:
SheildLayer(QWidget *parent = nullptr) : QWidget(parent){
bg = new QWidget(this);
bg->resize(parent->size());
bg->setStyleSheet("background-color:#5a000000");
bg->setAttribute(Qt::WA_TransparentForMouseEvents);
bg->show();
}
void setEnabled(bool e){enabled = e;}
signals:
void clicked();
};
class SlidePage : public QWidget
{
Q_OBJECT
private:
int cornerRadius;
QString pageName;
ScrollAreaCustom *pageContentContainer;
QLabel *nameLabel;
customIcon *backIcon;
SheildLayer *sheildLayer;
QWidget *bgWidget;
QFont textFont = QFont("Corbel Light", 24);
bool onShown = false;
QParallelAnimationGroup *curAni = nullptr;
QGraphicsOpacityEffect *opacity;
void resizeEvent(QResizeEvent *event);
public:
const int preferWidth = 350;
explicit SlidePage(int radius, QString name, QWidget *parent = nullptr);
void SetRadius(int radius);
void SetName(QString name);
void AddContent(QWidget* widget){widget->setParent(this);pageContentContainer->addWidget(widget, false);}
void AddContents(QVector<QWidget*> widgets){pageContentContainer->addWidgets(widgets);}
void RemoveContents(QVector<QWidget*> widgets){for(int i = 0; i < widgets.size(); i++)pageContentContainer->removeWidget(widgets[i]);}
void UpdateContents(){pageContentContainer->updateHeight();}
void ScrollToTop(){pageContentContainer->scrollToTop();}
signals:
void sizeChange();
public slots:
void slideIn();
void slideOut();
};
#endif // SLIDEPAGE_H