Initial commit
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
43
.gitignore
vendored
Normal 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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
371
graph_view.h
Normal 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
@ -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
@ -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
|
After Width: | Height: | Size: 2.1 KiB |
1
icons/create.svg
Normal 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
@ -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
|
After Width: | Height: | Size: 2.1 KiB |
1
icons/open.svg
Normal 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
@ -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 |
14
main.cpp
Normal 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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
|
||||