QT-CART
No files matched your search
@@ -0,0 +1,35 @@
|
||||
# Qt Creator
|
||||
*.pro.user*
|
||||
.qtcreator/
|
||||
build*/
|
||||
*.o
|
||||
*.obj
|
||||
moc_*
|
||||
ui_*
|
||||
qrc_*
|
||||
Makefile*
|
||||
.qmake.stash
|
||||
QTCart
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.qtds
|
||||
|
||||
# Python
|
||||
.venv/
|
||||
venv/
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
.env
|
||||
.pytest_cache/
|
||||
|
||||
# IDE & System
|
||||
.vscode/
|
||||
.idea/
|
||||
.DS_Store
|
||||
[Tt]humbs.db
|
||||
|
||||
QT-Main/Makefile
|
||||
QT-Main/build/
|
||||
QT-Server/build/
|
||||
@@ -1,30 +1,46 @@
|
||||
QT += core gui
|
||||
QT += core gui network serialport
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
CONFIG += c++17
|
||||
|
||||
# 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 += \
|
||||
barcodescanner.cpp \
|
||||
main.cpp \
|
||||
mainwidget.cpp \
|
||||
pagecart.cpp \
|
||||
pageguide.cpp \
|
||||
pagepay.cpp \
|
||||
pagepay_card.cpp \
|
||||
pagetotalpay.cpp \
|
||||
pagewelcome.cpp
|
||||
|
||||
HEADERS += \
|
||||
barcodescanner.h \
|
||||
mainwidget.h \
|
||||
pagecart.h \
|
||||
pageguide.h \
|
||||
pagepay.h \
|
||||
pagepay_card.h \
|
||||
pagetotalpay.h \
|
||||
pagewelcome.h
|
||||
|
||||
FORMS += \
|
||||
mainwidget.ui \
|
||||
pagecart.ui \
|
||||
pageguide.ui \
|
||||
pagepay.ui \
|
||||
pagepay_card.ui \
|
||||
pagetotalpay.ui \
|
||||
pagewelcome.ui
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
DISTFILES +=
|
||||
|
||||
RESOURCES += \
|
||||
etc_image/etc_image.qrc \
|
||||
item_image/item_image.qrc
|
||||
@@ -0,0 +1,108 @@
|
||||
#include "barcodescanner.h"
|
||||
#include <QNetworkRequest>
|
||||
#include <QUrl>
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QVariant>
|
||||
|
||||
BarcodeScanner::BarcodeScanner(QObject *parent)
|
||||
: QObject(parent),
|
||||
manager(new QNetworkAccessManager(this))
|
||||
{
|
||||
connect(manager, &QNetworkAccessManager::finished,
|
||||
this, &BarcodeScanner::onNetworkReply);
|
||||
}
|
||||
|
||||
void BarcodeScanner::setApiBaseUrl(const QString &ip, int port)
|
||||
{
|
||||
m_apiBaseUrl = QString("http://%1:%2").arg(ip).arg(port);
|
||||
qDebug() << "[Scanner] API Base URL set to:" << m_apiBaseUrl;
|
||||
}
|
||||
|
||||
// 상품 추가
|
||||
void BarcodeScanner::fetchItemDetails(const QString& itemId)
|
||||
{
|
||||
QString path = QString("%1/cart/add/%2").arg(m_apiBaseUrl).arg(itemId);
|
||||
QUrl url(path);
|
||||
|
||||
QNetworkRequest request(url);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
manager->post(request, QByteArray());
|
||||
|
||||
qDebug() << "==================================================";
|
||||
qDebug() << "[Scanner] Requesting ADD -> ID:" << itemId;
|
||||
qDebug() << "[Scanner] URL:" << url.toString();
|
||||
}
|
||||
|
||||
// 상품 제거
|
||||
void BarcodeScanner::removeItem(const QString& itemId)
|
||||
{
|
||||
QString path = QString("%1/cart/remove/%2").arg(m_apiBaseUrl).arg(itemId);
|
||||
QUrl url(path);
|
||||
|
||||
QNetworkRequest request(url);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
manager->post(request, QByteArray());
|
||||
|
||||
qDebug() << "==================================================";
|
||||
qDebug() << "[Scanner] Requesting REMOVE -> ID:" << itemId;
|
||||
qDebug() << "[Scanner] URL:" << url.toString();
|
||||
}
|
||||
|
||||
void BarcodeScanner::onNetworkReply(QNetworkReply *reply)
|
||||
{
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
qDebug() << "[Scanner] Network Error:" << reply->errorString();
|
||||
emit fetchFailed(reply->errorString());
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
qDebug() << "[Scanner] Raw Response Data:" << data;
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data);
|
||||
if (!doc.isObject()) {
|
||||
qDebug() << "[Scanner] Invalid JSON response";
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject obj = doc.object();
|
||||
QString action = obj["action"].toString();
|
||||
|
||||
qDebug() << "[Scanner] Parsed Action:" << action;
|
||||
|
||||
// 데이터 유효성 검사
|
||||
if (action == "add") {
|
||||
Item item;
|
||||
|
||||
if (obj.contains("item")) item.name = obj["item"].toString();
|
||||
else if (obj.contains("name")) item.name = obj["name"].toString();
|
||||
else item.name = "알수없음";
|
||||
|
||||
if (obj.contains("id")) {
|
||||
item.id = obj["id"].toVariant().toString();
|
||||
}
|
||||
|
||||
if (obj.contains("price")) item.price = obj["price"].toDouble();
|
||||
|
||||
double expectedWeight = 0.0;
|
||||
if (obj.contains("expected_weight")) {
|
||||
expectedWeight = obj["expected_weight"].toDouble();
|
||||
item.weight = expectedWeight;
|
||||
}
|
||||
|
||||
qDebug() << "[Scanner] Item Parsed: " << item.name << ", " << item.price;
|
||||
|
||||
emit itemFetched(item, expectedWeight);
|
||||
}
|
||||
else if (action == "remove") {
|
||||
qDebug() << "[Scanner] Remove confirmed.";
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef BARCODESCANNER_H
|
||||
#define BARCODESCANNER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QString>
|
||||
|
||||
class Item {
|
||||
public:
|
||||
QString id = "";
|
||||
QString name = "";
|
||||
double price = 0.0;
|
||||
double weight = 0.0;
|
||||
int stock = 0;
|
||||
};
|
||||
|
||||
class BarcodeScanner : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit BarcodeScanner(QObject *parent = nullptr);
|
||||
|
||||
void setApiBaseUrl(const QString &ip, int port);
|
||||
void fetchItemDetails(const QString& itemId);
|
||||
void removeItem(const QString& itemId);
|
||||
|
||||
signals:
|
||||
void itemFetched(const Item &item, double cartWeight);
|
||||
void fetchFailed(const QString &error);
|
||||
|
||||
private slots:
|
||||
void onNetworkReply(QNetworkReply *reply);
|
||||
|
||||
private:
|
||||
QNetworkAccessManager *manager;
|
||||
QString m_apiBaseUrl;
|
||||
};
|
||||
|
||||
#endif // BARCODESCANNER_H
|
||||
@@ -0,0 +1 @@
|
||||
<RCC/>
|
||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 1021 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 447 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 213 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 347 KiB |
@@ -0,0 +1,37 @@
|
||||
<RCC>
|
||||
<qresource prefix="/etc">
|
||||
<file>card.png</file>
|
||||
<file>cart.png</file>
|
||||
<file>counter.png</file>
|
||||
<file>food.png</file>
|
||||
<file>home.png</file>
|
||||
<file>kitty.jpg</file>
|
||||
<file>search.png</file>
|
||||
<file>wind.png</file>
|
||||
<file>map.pgm</file>
|
||||
<file>guide_map.png</file>
|
||||
<file>map_handcream.png</file>
|
||||
<file>map_phone.png</file>
|
||||
<file>mappin.png</file>
|
||||
<file>map_snack.png</file>
|
||||
<file>map_toy.png</file>
|
||||
<file>map_pay.png</file>
|
||||
<file>map_cream.png</file>
|
||||
<file>map_toy_2.png</file>
|
||||
<file>map_phone_1.png</file>
|
||||
<file>map_door.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/">
|
||||
<file>cart_puzzle.png</file>
|
||||
<file>cart_snack(1).jpg</file>
|
||||
<file>cart_snack(2).png</file>
|
||||
<file>cart_snack(3).jpg</file>
|
||||
<file>cart_snack(4).jpg</file>
|
||||
<file>cart_snack(5).jpg</file>
|
||||
<file>cart_snack(6).jpg</file>
|
||||
<file>cart_snack(7).jpg</file>
|
||||
<file>cart_snack(8).jpg</file>
|
||||
<file>cart_handcream.jpg</file>
|
||||
<file>cart_iphone.jpg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 2.1 MiB |
@@ -0,0 +1,10 @@
|
||||
<RCC>
|
||||
<qresource prefix="/item">
|
||||
<file>apple.jpg</file>
|
||||
<file>banana.jpg</file>
|
||||
<file>cart_handcream.jpg</file>
|
||||
<file>cart_iphone.jpg</file>
|
||||
<file>cart_snack.jpg</file>
|
||||
<file>fire.jpg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "mainwidget.h"
|
||||
#include <QApplication>
|
||||
#include <QScreen>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// (선택) DPI 흔들림 줄이기 — QApplication 생성 전에
|
||||
QCoreApplication::setAttribute(Qt::AA_Use96Dpi);
|
||||
|
||||
QApplication a(argc, argv);
|
||||
|
||||
// (선택) 스타일/폰트 통일
|
||||
QApplication::setStyle("Fusion");
|
||||
// QApplication::setFont(QFont("Noto Sans CJK KR", 10));
|
||||
|
||||
MainWidget w;
|
||||
|
||||
// ✅ 800x480 고정
|
||||
w.setFixedSize(800, 480);
|
||||
|
||||
// ✅ 타이틀바까지 꽉 채우고 싶으면 FullScreen
|
||||
w.showFullScreen();
|
||||
|
||||
// (대안) 창모드로 크게만: w.show();
|
||||
// (대안) 최대화: w.showMaximized();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
#include "mainwidget.h"
|
||||
#include "ui_mainwidget.h"
|
||||
#include <QDebug>
|
||||
#include <QtNetwork/QHostAddress>
|
||||
#include <QtNetwork/QNetworkDatagram>
|
||||
#include <QApplication>
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QMessageBox>
|
||||
#include <QUrl>
|
||||
|
||||
MainWidget::MainWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::MainWidget)
|
||||
, m_isCheckingWeight(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
qApp->installEventFilter(this);
|
||||
|
||||
m_udpSocket = new QUdpSocket(this);
|
||||
m_udpSocket->bind(QHostAddress::Any, QT_LISTEN_PORT, QUdpSocket::ShareAddress);
|
||||
connect(m_udpSocket, &QUdpSocket::readyRead, this, &MainWidget::onUdpReadyRead);
|
||||
|
||||
m_networkManager = new QNetworkAccessManager(this);
|
||||
connect(m_networkManager, &QNetworkAccessManager::finished, this, &MainWidget::onCheckWeightResponse);
|
||||
|
||||
pPageWelcome = new PageWelcome(this);
|
||||
pPageCart = new PageCart(this);
|
||||
pPageCart->setApiConfig(API_SERVER_IP, API_SERVER_PORT);
|
||||
pPageGuide = new PageGuide(this);
|
||||
pPagePay = new PagePay(this);
|
||||
pPageCard = new pagepay_card(this);
|
||||
pPageTotalPay= new PageTotalPay(this);
|
||||
|
||||
ui->pstackedWidget->addWidget(pPageWelcome);
|
||||
ui->pstackedWidget->addWidget(pPageCart);
|
||||
ui->pstackedWidget->addWidget(pPageGuide);
|
||||
ui->pstackedWidget->addWidget(pPagePay);
|
||||
ui->pstackedWidget->addWidget(pPageCard);
|
||||
ui->pstackedWidget->addWidget(pPageTotalPay);
|
||||
ui->pstackedWidget->setCurrentWidget(pPageWelcome);
|
||||
|
||||
connect(pPageWelcome, &PageWelcome::startRequested, this, &MainWidget::slotShowCartPage);
|
||||
|
||||
connect(pPageGuide, &PageGuide::requestGoal, this, &MainWidget::onGoalRequestReceived);
|
||||
connect(pPageGuide, &PageGuide::requestStop, this, &MainWidget::onStopRequestReceived);
|
||||
connect(this, SIGNAL(robotArrivedSignal()), pPageGuide, SLOT(onRobotArrived()));
|
||||
connect(pPageGuide, SIGNAL(backToCartClicked()), this, SLOT(slotShowCartPage()));
|
||||
|
||||
connect(pPageCart, SIGNAL(guideModeClicked()), this, SLOT(slotShowGuidePage()));
|
||||
connect(pPageCart, &PageCart::requestCheckout, this, &MainWidget::onCheckoutRequested);
|
||||
connect(pPageCart, SIGNAL(goWelcome()), this, SLOT(slotShowWelcomePage()));
|
||||
|
||||
connect(pPagePay, SIGNAL(creditCardClicked()), this, SLOT(slotShowPayCardPage()));
|
||||
connect(pPagePay, SIGNAL(backCartClicked()), this, SLOT(slotShowCartPage()));
|
||||
|
||||
connect(pPageCard, SIGNAL(goTotalPayClicked()), this, SLOT(slotShowTotalPayPage_2()));
|
||||
connect(pPageTotalPay, &PageTotalPay::backToStartClicked, this, &MainWidget::slotShowWelcomePage);
|
||||
|
||||
connect(ui->pstackedWidget, &QStackedWidget::currentChanged, this, &MainWidget::onPageChanged);
|
||||
onPageChanged(ui->pstackedWidget->currentIndex());
|
||||
}
|
||||
|
||||
MainWidget::~MainWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWidget::sendUdpData(const QString &cmd)
|
||||
{
|
||||
QByteArray data = cmd.toUtf8();
|
||||
m_udpSocket->writeDatagram(data, QHostAddress(ROS_SERVER_IP), ROS_SERVER_PORT);
|
||||
qDebug() << "[UDP Send]" << cmd << "to" << ROS_SERVER_IP;
|
||||
}
|
||||
|
||||
void MainWidget::onCheckoutRequested(double expectedWeight)
|
||||
{
|
||||
if (m_isCheckingWeight) {
|
||||
qDebug() << "Check skipped: Already verifying weight...";
|
||||
return;
|
||||
}
|
||||
m_isCheckingWeight = true; // Lock 설정
|
||||
|
||||
QString urlStr = QString("http://%1:%2/cart/check_weight")
|
||||
.arg(API_SERVER_IP)
|
||||
.arg(API_SERVER_PORT);
|
||||
|
||||
QUrl url(urlStr);
|
||||
QNetworkRequest request(url);
|
||||
|
||||
// GET 요청 전송 (응답은 onCheckWeightResponse 에서 처리)
|
||||
m_networkManager->get(request);
|
||||
|
||||
qDebug() << "[API Request] Check Weight ->" << urlStr;
|
||||
}
|
||||
|
||||
// ROS에서 온 UDP 수신
|
||||
void MainWidget::onUdpReadyRead()
|
||||
{
|
||||
while (m_udpSocket->hasPendingDatagrams()) {
|
||||
QNetworkDatagram datagram = m_udpSocket->receiveDatagram();
|
||||
QString msg = QString::fromUtf8(datagram.data()).trimmed();
|
||||
|
||||
qDebug() << "[UDP Recv]" << msg;
|
||||
|
||||
if (msg == "STATUS:ARRIVED") {
|
||||
emit robotArrivedSignal();
|
||||
}
|
||||
else if (msg == "STATUS:WEIGHT_OK") {
|
||||
// [성공] 무게가 일치함 -> 결제 페이지로 이동
|
||||
proceedToPayPage();
|
||||
}
|
||||
else if (msg == "ERROR:WEIGHT_MISMATCH") { // 데이터 파싱 (콜론 : 으로 나눔)
|
||||
QStringList parts = msg.split(":");
|
||||
|
||||
double expected = 0.0;
|
||||
double real = 0.0;
|
||||
double diff = 0.0;
|
||||
|
||||
// 데이터가 같이 왔는지 확인 (안 왔으면 0.0으로 표시됨)
|
||||
if (parts.size() >= 5) {
|
||||
expected = parts[2].toDouble();
|
||||
real = parts[3].toDouble();
|
||||
diff = parts[4].toDouble();
|
||||
}
|
||||
|
||||
// 요청하신 팝업 코드 적용
|
||||
QString alertMsg = QString("상품 무게가 일치하지 않습니다.\n\n"
|
||||
"예상 무게: %1 g\n"
|
||||
"실제 무게: %2 g\n"
|
||||
"차이: %3 g\n\n"
|
||||
"카트의 물건을 확인해주세요.")
|
||||
.arg(expected, 0, 'f', 1)
|
||||
.arg(real, 0, 'f', 1)
|
||||
.arg(diff, 0, 'f', 1);
|
||||
|
||||
QMessageBox::warning(this, "출발 불가", alertMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::proceedToPayPage()
|
||||
{
|
||||
auto cartLines = pPageCart->getCartLines();
|
||||
QVector<PagePay::PayLine> payLines;
|
||||
payLines.reserve(cartLines.size());
|
||||
|
||||
for (const auto &c : cartLines) {
|
||||
PagePay::PayLine p;
|
||||
p.name = c.name;
|
||||
p.qty = c.qty;
|
||||
p.unitPrice = c.unitPrice;
|
||||
payLines.push_back(p);
|
||||
}
|
||||
|
||||
pPagePay->setPayItems(payLines);
|
||||
ui->pstackedWidget->setCurrentWidget(pPagePay);
|
||||
}
|
||||
|
||||
void MainWidget::onGoalRequestReceived(double x, double y)
|
||||
{
|
||||
QString cmd = QString("GOAL:%1,%2").arg(x).arg(y);
|
||||
sendUdpData(cmd);
|
||||
}
|
||||
|
||||
void MainWidget::onStopRequestReceived()
|
||||
{
|
||||
sendUdpData("STOP");
|
||||
}
|
||||
|
||||
// 페이지 변경 시 모드 변경
|
||||
void MainWidget::onPageChanged(int index)
|
||||
{
|
||||
QWidget *currentWidget = ui->pstackedWidget->widget(index);
|
||||
int mode = 0;
|
||||
|
||||
if (currentWidget == pPageWelcome) mode = 0; // 정지
|
||||
else if (currentWidget == pPageCart) mode = 1; // 따라가기
|
||||
else if (currentWidget == pPageGuide) mode = 2; // 안내모드
|
||||
else if (currentWidget == pPagePay) mode = 0; // 결제 중 정지
|
||||
else mode = 0;
|
||||
|
||||
sendRobotMode(mode);
|
||||
}
|
||||
|
||||
void MainWidget::sendRobotMode(int mode)
|
||||
{
|
||||
sendUdpData(QString("MODE:%1").arg(mode));
|
||||
}
|
||||
|
||||
void MainWidget::on_pPBStartClicked() { ui->pstackedWidget->setCurrentWidget(pPageCart); }
|
||||
void MainWidget::slotShowCartPage() { ui->pstackedWidget->setCurrentWidget(pPageCart); }
|
||||
void MainWidget::slotShowGuidePage() { ui->pstackedWidget->setCurrentWidget(pPageGuide); }
|
||||
void MainWidget::slotShowPayCardPage(){ ui->pstackedWidget->setCurrentWidget(pPageCard); }
|
||||
void MainWidget::slotShowTotalPayPage_2() { ui->pstackedWidget->setCurrentWidget(pPageTotalPay); }
|
||||
|
||||
void MainWidget::slotShowWelcomePage()
|
||||
{
|
||||
ui->pstackedWidget->setCurrentWidget(pPageWelcome);
|
||||
pPageCart->resetCart();
|
||||
}
|
||||
|
||||
void MainWidget::slotShowPayPage()
|
||||
{
|
||||
auto cartLines = pPageCart->getCartLines();
|
||||
QVector<PagePay::PayLine> payLines;
|
||||
payLines.reserve(cartLines.size());
|
||||
|
||||
for (const auto &c : cartLines) {
|
||||
PagePay::PayLine p;
|
||||
p.name = c.name;
|
||||
p.qty = c.qty;
|
||||
p.unitPrice = c.unitPrice;
|
||||
payLines.push_back(p);
|
||||
}
|
||||
|
||||
pPagePay->setPayItems(payLines);
|
||||
ui->pstackedWidget->setCurrentWidget(pPagePay);
|
||||
}
|
||||
|
||||
bool MainWidget::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
auto *ke = static_cast<QKeyEvent*>(event);
|
||||
if (ke->key() == Qt::Key_F12) {
|
||||
qApp->quit();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QWidget::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void MainWidget::onCheckWeightResponse(QNetworkReply *reply)
|
||||
{
|
||||
// 요청한 URL이 check_weight 인지 확인 (다른 API 요청과 섞이지 않게)
|
||||
if (!reply->request().url().toString().contains("/cart/check_weight")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (reply->error()) {
|
||||
qDebug() << "API Error:" << reply->errorString();
|
||||
QMessageBox::critical(this, "통신 오류", "서버와 통신할 수 없습니다.\n" + reply->errorString());
|
||||
reply->deleteLater();
|
||||
m_isCheckingWeight = false;
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data);
|
||||
QJsonObject obj = doc.object();
|
||||
|
||||
// Python 서버 응답 필드: expected_weight, real_weight, diff, movable
|
||||
bool movable = obj["movable"].toBool();
|
||||
double expected = obj["expected_weight"].toDouble();
|
||||
double real = obj["real_weight"].toDouble();
|
||||
double diff = obj["diff"].toDouble();
|
||||
|
||||
qDebug() << "[API Response] Movable:" << movable << "Diff:" << diff;
|
||||
|
||||
if (movable) {
|
||||
// [성공] 오차 범위 내 -> 결제 페이지로 이동
|
||||
proceedToPayPage();
|
||||
} else {
|
||||
// [실패] 오차 범위 초과 -> 팝업 띄우기
|
||||
QString msg = QString("상품 무게가 일치하지 않습니다.\n\n"
|
||||
"예상 무게: %1 g\n"
|
||||
"실제 무게: %2 g\n"
|
||||
"차이: %3 g\n\n"
|
||||
"카트의 물건을 확인해주세요.")
|
||||
.arg(expected, 0, 'f', 1)
|
||||
.arg(real, 0, 'f', 1)
|
||||
.arg(diff, 0, 'f', 1);
|
||||
|
||||
QMessageBox::warning(this, "출발 불가", msg);
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
m_isCheckingWeight = false;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
#ifndef MAINWIDGET_H
|
||||
#define MAINWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QtNetwork/QUdpSocket>
|
||||
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
#define ROS_SERVER_IP "192.168.123.42"
|
||||
#define ROS_SERVER_PORT 55555
|
||||
|
||||
#define API_SERVER_IP "192.168.123.43"
|
||||
#define API_SERVER_PORT 8000
|
||||
|
||||
#define QT_LISTEN_PORT 55555
|
||||
|
||||
#include "pagewelcome.h"
|
||||
#include "pagecart.h"
|
||||
#include "pageguide.h"
|
||||
#include "pagepay.h"
|
||||
#include "pagepay_card.h"
|
||||
#include "pagetotalpay.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class MainWidget; }
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWidget(QWidget *parent = nullptr);
|
||||
~MainWidget();
|
||||
|
||||
signals:
|
||||
void robotArrivedSignal();
|
||||
|
||||
private:
|
||||
Ui::MainWidget *ui;
|
||||
QUdpSocket *m_udpSocket;
|
||||
|
||||
QNetworkAccessManager *m_networkManager;
|
||||
|
||||
PageWelcome *pPageWelcome;
|
||||
PageCart *pPageCart;
|
||||
PageGuide *pPageGuide;
|
||||
PagePay *pPagePay;
|
||||
pagepay_card *pPageCard;
|
||||
PageTotalPay *pPageTotalPay;
|
||||
|
||||
bool m_isCheckingWeight;
|
||||
|
||||
void sendUdpData(const QString &cmd);
|
||||
void sendRobotMode(int mode); // 모드 전송 (0:정지, 1:따라가기, 2:안내)
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void onUdpReadyRead(); // UDP 수신부 (무게 검증 결과 처리)
|
||||
|
||||
void onCheckWeightResponse(QNetworkReply *reply);
|
||||
|
||||
void on_pPBStartClicked();
|
||||
void slotShowPayPage();
|
||||
|
||||
void slotShowCartPage();
|
||||
void slotShowGuidePage();
|
||||
void slotShowPayCardPage();
|
||||
void slotShowTotalPayPage_2();
|
||||
void slotShowWelcomePage();
|
||||
|
||||
void onCheckoutRequested(double expectedWeight);
|
||||
|
||||
void proceedToPayPage();
|
||||
|
||||
void onGoalRequestReceived(double x, double y);
|
||||
void onStopRequestReceived();
|
||||
void onPageChanged(int index);
|
||||
};
|
||||
|
||||
#endif // MAINWIDGET_H
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>685</width>
|
||||
<height>463</height>
|
||||
<width>565</width>
|
||||
<height>348</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -0,0 +1,408 @@
|
||||
#include "pagecart.h"
|
||||
#include "ui_pagecart.h"
|
||||
|
||||
#include <QGraphicsDropShadowEffect>
|
||||
#include <QPushButton>
|
||||
#include <QTableWidgetItem>
|
||||
#include <QDebug>
|
||||
#include <QMessageBox>
|
||||
#include <QKeyEvent>
|
||||
#include <QApplication>
|
||||
#include <QHeaderView>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPixmap>
|
||||
#include <cmath>
|
||||
|
||||
static QString moneyKR(qint64 v)
|
||||
{
|
||||
const QLocale loc(QLocale::Korean, QLocale::SouthKorea);
|
||||
return loc.toString(v) + "원";
|
||||
}
|
||||
|
||||
static QString imageForName(const QString& name)
|
||||
{
|
||||
if(name=="홈런볼 초코맛") return ":/cart_snack(1).jpg";
|
||||
if(name=="허니버터칩") return ":/cart_snack(2).png";
|
||||
if(name=="오레오 초콜릿크림") return ":/cart_snack(3).jpg";
|
||||
if(name=="빼빼로 아몬드") return ":/cart_snack(4).jpg";
|
||||
if(name=="빈츠") return ":/cart_snack(5).jpg";
|
||||
if(name=="예감 치즈그르탕") return ":/cart_snack(6).jpg";
|
||||
if(name=="오!감자 감자그라탕") return ":/cart_snack(7).jpg";
|
||||
if(name=="포카칩 오리지널") return ":/cart_snack(8).jpg";
|
||||
if(name=="아이폰 15 프로") return ":/cart_iphone.jpg";
|
||||
if(name=="핸드크림") return ":/cart_handcream.jpg";
|
||||
if(name=="크리스마스 퍼즐") return ":/cart_puzzle.png";
|
||||
return "";
|
||||
}
|
||||
|
||||
PageCart::PageCart(QWidget *parent)
|
||||
: QWidget(parent),
|
||||
ui(new Ui::PageCart)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// 그림자 효과
|
||||
auto makeShadow = [](QObject *parent){
|
||||
auto *s = new QGraphicsDropShadowEffect(parent);
|
||||
s->setBlurRadius(18);
|
||||
s->setOffset(0, 4);
|
||||
s->setColor(QColor(0, 0, 0, 60));
|
||||
return s;
|
||||
};
|
||||
ui->tableCart->setStyleSheet(
|
||||
"QTableWidget::item { padding: 0px; margin: 0px; }"
|
||||
"QTableWidget { border: none; }"
|
||||
);
|
||||
|
||||
if (ui->widget_2) ui->widget_2->setGraphicsEffect(makeShadow(ui->widget_2));
|
||||
if (ui->widget) ui->widget->setGraphicsEffect(makeShadow(ui->widget));
|
||||
|
||||
ui->tableCart->setSelectionMode(QAbstractItemView::NoSelection);
|
||||
ui->tableCart->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
ui->tableCart->setShowGrid(false);
|
||||
|
||||
// 바코드 입력용 숨김 QLineEdit
|
||||
m_editBarcode = new QLineEdit(this);
|
||||
m_editBarcode->setVisible(false);
|
||||
m_editBarcode->setFocusPolicy(Qt::StrongFocus);
|
||||
m_editBarcode->setFocus();
|
||||
connect(m_editBarcode, SIGNAL(returnPressed()), this, SLOT(onBarcodeEntered()));
|
||||
|
||||
qApp->installEventFilter(this);
|
||||
|
||||
m_scanner = new BarcodeScanner(this);
|
||||
connect(m_scanner, &BarcodeScanner::itemFetched, this, &PageCart::handleItemFetched);
|
||||
connect(m_scanner, &BarcodeScanner::fetchFailed, this, &PageCart::handleFetchFailed);
|
||||
|
||||
// 테이블 컬럼 설정
|
||||
ui->tableCart->setColumnCount(7);
|
||||
ui->tableCart->horizontalHeader()->setVisible(false);
|
||||
ui->tableCart->verticalHeader()->setVisible(false);
|
||||
ui->tableCart->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
||||
ui->tableCart->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
|
||||
|
||||
ui->tableCart->setColumnWidth(0, 54);
|
||||
ui->tableCart->setColumnWidth(2, 52);
|
||||
ui->tableCart->setColumnWidth(3, 42);
|
||||
ui->tableCart->setColumnWidth(5, 76);
|
||||
ui->tableCart->setColumnWidth(6, 46);
|
||||
|
||||
updateTotal();
|
||||
|
||||
if (ui->btnHome) {
|
||||
connect(ui->btnHome, &QPushButton::clicked, this, [this](){
|
||||
emit goWelcome();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
PageCart::~PageCart()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
// MainWidget으로부터 API 설정 주입
|
||||
void PageCart::setApiConfig(const QString &ip, int port)
|
||||
{
|
||||
if (m_scanner) {
|
||||
m_scanner->setApiBaseUrl(ip, port);
|
||||
}
|
||||
resetCart();
|
||||
}
|
||||
|
||||
// 카트 행 추가
|
||||
void PageCart::addRowForItem(const QString& id, const QString& name, int unitPrice, int qty, double weight)
|
||||
{
|
||||
int row = ui->tableCart->rowCount();
|
||||
ui->tableCart->insertRow(row);
|
||||
ui->tableCart->setRowHeight(row, 60);
|
||||
|
||||
m_unitPrice.append(unitPrice);
|
||||
|
||||
ItemInfo info;
|
||||
info.id = id;
|
||||
info.name = name;
|
||||
info.price = unitPrice;
|
||||
info.weight = weight;
|
||||
m_items.append(info);
|
||||
|
||||
auto makeCenterCell = [&](QWidget *child) -> QWidget* {
|
||||
QWidget *w = new QWidget(ui->tableCart);
|
||||
auto *lay = new QHBoxLayout(w);
|
||||
lay->setContentsMargins(0, 0, 0, 0);
|
||||
lay->setSpacing(0);
|
||||
lay->setAlignment(Qt::AlignCenter);
|
||||
lay->addWidget(child);
|
||||
return w;
|
||||
};
|
||||
auto makeRightCell = [&](QWidget *child) -> QWidget* {
|
||||
QWidget *w = new QWidget(ui->tableCart);
|
||||
auto *lay = new QHBoxLayout(w);
|
||||
lay->setContentsMargins(0, 0, 0, 0);
|
||||
lay->setSpacing(0);
|
||||
lay->addStretch();
|
||||
lay->addWidget(child);
|
||||
return w;
|
||||
};
|
||||
|
||||
// 이미지
|
||||
QLabel *img = new QLabel(ui->tableCart);
|
||||
img->setFixedSize(44, 44);
|
||||
img->setAlignment(Qt::AlignCenter);
|
||||
QPixmap px(imageForName(name));
|
||||
if (!px.isNull()) {
|
||||
img->setPixmap(px.scaled(44, 44, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation));
|
||||
}
|
||||
ui->tableCart->setCellWidget(row, 0, makeCenterCell(img));
|
||||
ui->tableCart->setItem(row, 1, new QTableWidgetItem(name));
|
||||
|
||||
QPushButton *btnPlus = new QPushButton("+", ui->tableCart);
|
||||
btnPlus->setFixedSize(26, 30);
|
||||
btnPlus->setStyleSheet("QPushButton { background-color: rgb(37,99,235); color: white; border-radius: 10px; font-weight: bold; }");
|
||||
ui->tableCart->setCellWidget(row, 2, makeCenterCell(btnPlus));
|
||||
connect(btnPlus, &QPushButton::clicked, this, &PageCart::onPlusClicked);
|
||||
|
||||
QTableWidgetItem *qtyItem = new QTableWidgetItem(QString::number(qty));
|
||||
qtyItem->setTextAlignment(Qt::AlignCenter);
|
||||
ui->tableCart->setItem(row, 3, qtyItem);
|
||||
|
||||
QPushButton *btnMinus = new QPushButton("-", ui->tableCart);
|
||||
btnMinus->setFixedSize(30, 30);
|
||||
btnMinus->setStyleSheet("QPushButton { background-color: rgb(154,153,150); color: white; border-radius: 10px; font-weight: bold; }");
|
||||
ui->tableCart->setCellWidget(row, 4, makeCenterCell(btnMinus));
|
||||
connect(btnMinus, &QPushButton::clicked, this, &PageCart::onMinusClicked);
|
||||
|
||||
QTableWidgetItem *priceItem = new QTableWidgetItem(moneyKR(0));
|
||||
priceItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
ui->tableCart->setItem(row, 5, priceItem);
|
||||
|
||||
// 삭제 버튼
|
||||
QPushButton *btnDelete = new QPushButton("X", ui->tableCart);
|
||||
btnDelete->setFixedSize(30, 30);
|
||||
btnDelete->setStyleSheet("QPushButton { background-color: rgb(224,27,36); color: white; border-radius: 10px; font-weight: bold; }");
|
||||
ui->tableCart->setCellWidget(row, 6, makeRightCell(btnDelete));
|
||||
connect(btnDelete, &QPushButton::clicked, this, &PageCart::onDeleteClicked);
|
||||
|
||||
updateRowAmount(row);
|
||||
}
|
||||
|
||||
void PageCart::onPlusClicked()
|
||||
{
|
||||
QPushButton *btn = qobject_cast<QPushButton*>(sender());
|
||||
if (!btn) return;
|
||||
|
||||
int row = getRowFromButton(btn);
|
||||
if (row < 0 || row >= m_items.size()) return;
|
||||
|
||||
QString itemId = m_items[row].id;
|
||||
m_scanner->fetchItemDetails(itemId);
|
||||
}
|
||||
|
||||
void PageCart::onMinusClicked()
|
||||
{
|
||||
QPushButton *btn = qobject_cast<QPushButton*>(sender());
|
||||
if (!btn) return;
|
||||
|
||||
int row = getRowFromButton(btn);
|
||||
if (row < 0 || row >= m_items.size()) return;
|
||||
|
||||
QString itemId = m_items[row].id;
|
||||
m_scanner->removeItem(itemId);
|
||||
|
||||
int currentQty = ui->tableCart->item(row, 3)->text().toInt();
|
||||
int newQty = currentQty - 1;
|
||||
|
||||
if (newQty <= 0) {
|
||||
m_unitPrice.removeAt(row);
|
||||
m_items.removeAt(row);
|
||||
ui->tableCart->removeRow(row);
|
||||
} else {
|
||||
ui->tableCart->item(row, 3)->setText(QString::number(newQty));
|
||||
updateRowAmount(row);
|
||||
}
|
||||
updateTotal();
|
||||
}
|
||||
|
||||
void PageCart::onDeleteClicked()
|
||||
{
|
||||
QPushButton *btn = qobject_cast<QPushButton*>(sender());
|
||||
if (!btn) return;
|
||||
|
||||
int row = getRowFromButton(btn);
|
||||
if (row < 0 || row >= m_items.size()) return;
|
||||
|
||||
QString itemId = m_items[row].id;
|
||||
int qty = ui->tableCart->item(row, 3)->text().toInt();
|
||||
|
||||
for (int i = 0; i < qty; ++i) {
|
||||
m_scanner->removeItem(itemId);
|
||||
}
|
||||
|
||||
m_unitPrice.removeAt(row);
|
||||
m_items.removeAt(row);
|
||||
ui->tableCart->removeRow(row);
|
||||
updateTotal();
|
||||
}
|
||||
|
||||
void PageCart::updateRowAmount(int row)
|
||||
{
|
||||
if (row < 0 || row >= m_unitPrice.size()) return;
|
||||
int qty = ui->tableCart->item(row, 3)->text().toInt();
|
||||
int amount = m_unitPrice[row] * qty;
|
||||
ui->tableCart->item(row, 5)->setText(moneyKR(amount));
|
||||
}
|
||||
|
||||
void PageCart::updateTotal()
|
||||
{
|
||||
int totalCount = 0;
|
||||
int totalPrice = 0;
|
||||
|
||||
for (int r = 0; r < ui->tableCart->rowCount(); ++r) {
|
||||
auto *qtyItem = ui->tableCart->item(r, 3);
|
||||
if (!qtyItem) continue;
|
||||
int qty = qtyItem->text().toInt();
|
||||
totalCount += qty;
|
||||
int unit = (r < m_unitPrice.size()) ? m_unitPrice[r] : 0;
|
||||
totalPrice += unit * qty;
|
||||
}
|
||||
|
||||
if (ui->lblTotalPrice_2)
|
||||
ui->lblTotalPrice_2->setText(moneyKR(totalPrice));
|
||||
if (ui->lblCartTitle)
|
||||
ui->lblCartTitle->setText(QString("Cart (%1 products)").arg(totalCount));
|
||||
}
|
||||
|
||||
void PageCart::onBarcodeEntered()
|
||||
{
|
||||
QString code = m_editBarcode->text().trimmed();
|
||||
m_editBarcode->clear();
|
||||
if (code.isEmpty()) return;
|
||||
m_scanner->fetchItemDetails(code);
|
||||
}
|
||||
|
||||
bool PageCart::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
Q_UNUSED(obj);
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||
if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
|
||||
if (!m_barcodeData.isEmpty()) {
|
||||
m_scanner->fetchItemDetails(m_barcodeData);
|
||||
m_barcodeData.clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (!keyEvent->text().isEmpty() &&
|
||||
!(keyEvent->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier))) {
|
||||
m_barcodeData.append(keyEvent->text());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QWidget::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void PageCart::handleItemFetched(const Item &item)
|
||||
{
|
||||
QString strId = item.id;
|
||||
|
||||
int rowFound = -1;
|
||||
for (int r = 0; r < ui->tableCart->rowCount(); ++r) {
|
||||
if (m_items[r].id == strId || m_items[r].name == item.name) {
|
||||
rowFound = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rowFound == -1) {
|
||||
int unit = static_cast<int>(std::lround(item.price));
|
||||
addRowForItem(strId, item.name, unit, 1, item.weight);
|
||||
} else {
|
||||
int qty = ui->tableCart->item(rowFound, 3)->text().toInt();
|
||||
ui->tableCart->item(rowFound, 3)->setText(QString::number(qty + 1));
|
||||
|
||||
m_items[rowFound].id = strId;
|
||||
m_items[rowFound].weight = item.weight;
|
||||
|
||||
updateRowAmount(rowFound);
|
||||
}
|
||||
updateTotal();
|
||||
}
|
||||
|
||||
void PageCart::handleFetchFailed(const QString &err)
|
||||
{
|
||||
qDebug() << "Barcode fetch failed:" << err;
|
||||
QMessageBox::warning(this, "스캔 실패", "상품 정보를 불러오지 못했습니다.\n" + err);
|
||||
}
|
||||
|
||||
void PageCart::on_btnGuide_clicked() { emit guideModeClicked(); }
|
||||
|
||||
void PageCart::on_pushButton_clicked() { resetCart(); }
|
||||
|
||||
QVector<PageCart::CartLine> PageCart::getCartLines() const
|
||||
{
|
||||
QVector<CartLine> out;
|
||||
for (int r = 0; r < ui->tableCart->rowCount(); ++r) {
|
||||
auto *nameItem = ui->tableCart->item(r, 1);
|
||||
auto *qtyItem = ui->tableCart->item(r, 3);
|
||||
if (!nameItem || !qtyItem) continue;
|
||||
int qty = qtyItem->text().toInt();
|
||||
if (qty <= 0) continue;
|
||||
int unitPrice = (r < m_unitPrice.size()) ? m_unitPrice[r] : 0;
|
||||
out.push_back({ nameItem->text(), qty, unitPrice });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void PageCart::resetCart()
|
||||
{
|
||||
ui->tableCart->setRowCount(0);
|
||||
m_unitPrice.clear();
|
||||
m_items.clear();
|
||||
updateTotal();
|
||||
}
|
||||
|
||||
int PageCart::getRowFromButton(QWidget *btn)
|
||||
{
|
||||
if (!btn) return -1;
|
||||
int rowCount = ui->tableCart->rowCount();
|
||||
for (int r = 0; r < rowCount; ++r) {
|
||||
int targetCols[] = {2, 4, 6};
|
||||
for (int c : targetCols) {
|
||||
QWidget *cellWidget = ui->tableCart->cellWidget(r, c);
|
||||
if (cellWidget && (cellWidget == btn || cellWidget->isAncestorOf(btn))) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
double PageCart::getTotalWeight() const
|
||||
{
|
||||
double totalWeight = 0.0;
|
||||
// m_items와 테이블의 행은 동기화되어 있다고 가정
|
||||
for(int i = 0; i < m_items.size(); ++i) {
|
||||
if (i >= ui->tableCart->rowCount()) break;
|
||||
|
||||
QTableWidgetItem *itemQty = ui->tableCart->item(i, 3);
|
||||
if (itemQty) {
|
||||
int qty = itemQty->text().toInt();
|
||||
totalWeight += (m_items[i].weight * qty);
|
||||
}
|
||||
}
|
||||
return totalWeight;
|
||||
}
|
||||
|
||||
void PageCart::on_btnCheckout_clicked()
|
||||
{
|
||||
if (ui->tableCart->rowCount() == 0) {
|
||||
QMessageBox::information(this, "알림", "장바구니가 비어있습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
// [수정] 예상 무게를 계산하여 MainWidget으로 전달
|
||||
double expected = getTotalWeight();
|
||||
qDebug() << "Request Checkout - Expected Weight:" << expected;
|
||||
emit requestCheckout(expected);
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#ifndef PAGECART_H
|
||||
#define PAGECART_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVector>
|
||||
#include <QLineEdit>
|
||||
#include <QString>
|
||||
|
||||
#include "barcodescanner.h"
|
||||
|
||||
namespace Ui { class PageCart; }
|
||||
|
||||
struct ItemInfo {
|
||||
QString id;
|
||||
QString name;
|
||||
int price;
|
||||
double weight;
|
||||
};
|
||||
|
||||
class PageCart : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PageCart(QWidget *parent = nullptr);
|
||||
~PageCart();
|
||||
|
||||
struct CartLine {
|
||||
QString name;
|
||||
int qty;
|
||||
int unitPrice;
|
||||
};
|
||||
|
||||
QVector<CartLine> getCartLines() const;
|
||||
|
||||
// MainWidget에서 API 설정 받기
|
||||
void setApiConfig(const QString &ip, int port);
|
||||
|
||||
double getTotalWeight() const;
|
||||
|
||||
public slots:
|
||||
void resetCart();
|
||||
|
||||
signals:
|
||||
void guideModeClicked();
|
||||
void goWelcome();
|
||||
void requestCheckout(double totalWeight);
|
||||
|
||||
private slots:
|
||||
void onPlusClicked();
|
||||
void onMinusClicked();
|
||||
void onDeleteClicked();
|
||||
void onBarcodeEntered();
|
||||
|
||||
void handleItemFetched(const Item &item);
|
||||
void handleFetchFailed(const QString &err);
|
||||
|
||||
void on_pushButton_clicked(); // 카트 비우기
|
||||
void on_btnCheckout_clicked(); // 결제 버튼
|
||||
void on_btnGuide_clicked(); // 안내 버튼
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
|
||||
private:
|
||||
Ui::PageCart *ui;
|
||||
|
||||
QVector<ItemInfo> m_items;
|
||||
QVector<int> m_unitPrice;
|
||||
|
||||
QLineEdit *m_editBarcode = nullptr;
|
||||
QString m_barcodeData;
|
||||
BarcodeScanner *m_scanner = nullptr;
|
||||
|
||||
void addRowForItem(const QString& id, const QString& name, int unitPrice, int qty, double weight);
|
||||
void updateRowAmount(int row);
|
||||
void updateTotal();
|
||||
int getRowFromButton(QWidget *btn);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // PAGECART_H
|
||||
@@ -0,0 +1,478 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PageCart</class>
|
||||
<widget class="QWidget" name="PageCart">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>480</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(242, 244, 245);
|
||||
</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>60</y>
|
||||
<width>531</width>
|
||||
<height>371</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);
|
||||
border-radius: 16px;
|
||||
</string>
|
||||
</property>
|
||||
<widget class="QTableWidget" name="tableCart">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>120</y>
|
||||
<width>511</width>
|
||||
<height>241</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>50</x>
|
||||
<y>70</y>
|
||||
<width>71</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 14pt "Ubuntu Mono";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Product</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>230</x>
|
||||
<y>70</y>
|
||||
<width>71</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 14pt "Ubuntu Mono";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Count</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>415</x>
|
||||
<y>70</y>
|
||||
<width>71</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 14pt "Ubuntu Mono";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Price</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QFrame" name="frame_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>531</width>
|
||||
<height>61</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);
|
||||
|
||||
border-style: solid;
|
||||
border-top: 1px solid rgb(255, 255, 255);
|
||||
border-left: 1px solid rgb(255, 255, 255);
|
||||
border-right: 1px solid rgb(255, 255, 255);
|
||||
border-bottom: 1px solid rgb(200, 200, 200);
|
||||
|
||||
border-radius: 0px;
|
||||
</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>81</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 700 23pt "Umpush";
|
||||
|
||||
|
||||
border-style: solid;
|
||||
border-top: 1px solid rgb(255, 255, 255);
|
||||
border-left: 1px solid rgb(255, 255, 255);
|
||||
border-right: 1px solid rgb(255, 255, 255);
|
||||
border-bottom: 1px solid rgb(255, 255, 255);
|
||||
|
||||
border-radius: 0px;
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cart</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="lblCartTitle">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>90</x>
|
||||
<y>20</y>
|
||||
<width>151</width>
|
||||
<height>17</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 13pt "Umpush";
|
||||
|
||||
|
||||
border-style: solid;
|
||||
border-top: 1px solid rgb(255, 255, 255);
|
||||
border-left: 1px solid rgb(255, 255, 255);
|
||||
border-right: 1px solid rgb(255, 255, 255);
|
||||
border-bottom: 1px solid rgb(255, 255, 255);
|
||||
|
||||
border-radius: 0px;
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>410</x>
|
||||
<y>10</y>
|
||||
<width>111</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton {
|
||||
background-color: rgb(224, 27, 36);
|
||||
font: 300 12pt "Umpush";
|
||||
color: rgb(255, 255, 255);
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
padding: 10px 18px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: rgb(192, 28, 40);
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: rgb(120, 0, 10);
|
||||
}
|
||||
QPushButton:disabled {
|
||||
background-color: rgb(120, 120, 120);
|
||||
color: rgb(230, 230, 230);
|
||||
}
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>clear cart</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>550</x>
|
||||
<y>60</y>
|
||||
<width>191</width>
|
||||
<height>261</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);</string>
|
||||
</property>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>180</y>
|
||||
<width>351</width>
|
||||
<height>81</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);
|
||||
|
||||
border-style: solid;
|
||||
border-top: 1px solid rgb(200, 200, 200);
|
||||
border-left: 1px solid rgb(255, 255, 255);
|
||||
border-right: 1px solid rgb(255, 255, 255);
|
||||
border-bottom: 1px solid rgb(255, 255, 255);
|
||||
|
||||
border-radius: 0px;
|
||||
</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<widget class="QPushButton" name="btnCheckout">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>3</x>
|
||||
<y>21</y>
|
||||
<width>181</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(53, 132, 228);
|
||||
color: rgb(255, 255, 255);
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
padding: 10px 18px;
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>결제하기</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>30</y>
|
||||
<width>321</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">image: url(:/new/prefix1/Gemini_Generated_Image_u34sf6u34sf6u34s.png);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>20</y>
|
||||
<width>111</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 700 18pt "Umpush";
|
||||
background-color: rgb(255, 255, 255);
|
||||
border: none;
|
||||
border-radius: 16px;
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>총 금액</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="lblTotalPrice_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>100</y>
|
||||
<width>161</width>
|
||||
<height>51</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 700 21pt "Umpush";
|
||||
background-color: rgb(255, 255, 255);
|
||||
border: none;
|
||||
border-radius: 16px;
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnGuide">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>640</x>
|
||||
<y>10</y>
|
||||
<width>41</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 23pt "Ria Sans";
|
||||
image: url(:/etc/search.png);
|
||||
border-radius: 0px;
|
||||
background-color: rgb(242, 244, 245);
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>28</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnHome">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>700</x>
|
||||
<y>10</y>
|
||||
<width>41</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 23pt "Ria Sans";
|
||||
image: url(:/etc/home.png);
|
||||
border-radius: 0px;
|
||||
padding: 0px 0px;
|
||||
background-color: rgb(242, 244, 245);
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>28</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>330</x>
|
||||
<y>20</y>
|
||||
<width>121</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 13pt "Ubuntu Condensed";
|
||||
color: rgb(0, 0, 0);
|
||||
|
||||
color: rgb(154, 153, 150);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>O Checkout </string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>470</x>
|
||||
<y>19</y>
|
||||
<width>111</width>
|
||||
<height>17</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 13pt "Ubuntu Condensed";
|
||||
color: rgb(154, 153, 150);
|
||||
background-color: #F2F4F7;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>O Payment </string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>220</x>
|
||||
<y>19</y>
|
||||
<width>111</width>
|
||||
<height>17</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 13pt "Ubuntu Condensed";
|
||||
background-color: #F2F4F7;
|
||||
background-color: #F2F4F7;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>O Cart </string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>550</x>
|
||||
<y>330</y>
|
||||
<width>191</width>
|
||||
<height>101</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">image: url(:/etc/counter.png);
|
||||
border-radius: 16px;
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,180 @@
|
||||
#include "pageguide.h"
|
||||
#include "ui_pageguide.h"
|
||||
#include <QPixmap>
|
||||
#include <QDebug>
|
||||
#include <QPushButton>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QResizeEvent>
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QGraphicsDropShadowEffect>
|
||||
|
||||
PageGuide::PageGuide(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::PageGuide)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
QPixmap pm(":/etc/guide_map.png");
|
||||
if(!pm.isNull()) {
|
||||
m_treePixmap = pm;
|
||||
ui->lblmap->setPixmap(pm);
|
||||
ui->lblmap->setScaledContents(true);
|
||||
}
|
||||
ui->lblmap->setStyleSheet("border-radius:14px; background:#ffffff; border: none;");
|
||||
|
||||
// 버튼 연결
|
||||
connect(ui->btnBackToCart, &QPushButton::clicked, this, &PageGuide::onBackToCartClicked);
|
||||
connect(ui->btnpuzzle, &QPushButton::clicked, this, &PageGuide::onPuzzleClicked);
|
||||
connect(ui->btncream, &QPushButton::clicked, this, &PageGuide::onCreamClicked);
|
||||
connect(ui->btnsnack, &QPushButton::clicked, this, &PageGuide::onSnackClicked);
|
||||
connect(ui->btnpay, &QPushButton::clicked, this, &PageGuide::onPayClicked);
|
||||
connect(ui->btnphone, &QPushButton::clicked, this, &PageGuide::onbtnphoneClicked);
|
||||
}
|
||||
|
||||
PageGuide::~PageGuide()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void PageGuide::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
QWidget::resizeEvent(e);
|
||||
applyTreePixmap();
|
||||
}
|
||||
|
||||
void PageGuide::applyTreePixmap()
|
||||
{
|
||||
if (m_treePixmap.isNull() || !ui->lblmap) return;
|
||||
QSize target = ui->lblmap->size();
|
||||
QPixmap scaled = m_treePixmap.scaled(target, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
ui->lblmap->setPixmap(scaled);
|
||||
}
|
||||
|
||||
void PageGuide::onBackToCartClicked()
|
||||
{
|
||||
emit backToCartClicked();
|
||||
}
|
||||
|
||||
void PageGuide::onPuzzleClicked()
|
||||
{
|
||||
emit requestGoal(-0.1, -2.4);
|
||||
showMovePopup("01코너 식품");
|
||||
}
|
||||
|
||||
void PageGuide::onSnackClicked()
|
||||
{
|
||||
emit requestGoal(3.0, 0.55);
|
||||
showMovePopup("02코너 장난감");
|
||||
}
|
||||
|
||||
void PageGuide::onCreamClicked()
|
||||
{
|
||||
emit requestGoal(2.6, -6.5);
|
||||
showMovePopup("03코너 생필품");
|
||||
}
|
||||
|
||||
void PageGuide::onbtnphoneClicked()
|
||||
{
|
||||
emit requestGoal(-0.1, -5.0);
|
||||
showMovePopup("04코너 전자제품");
|
||||
}
|
||||
|
||||
void PageGuide::onPayClicked()
|
||||
{
|
||||
emit requestGoal(-0.07, -6.7);
|
||||
showMovePopup("결제 구역");
|
||||
}
|
||||
|
||||
void PageGuide::showMovePopup(const QString &zoneText)
|
||||
{
|
||||
// 이미 떠있는 팝업이 있다면 닫기
|
||||
if (m_currentPopup) {
|
||||
m_currentPopup->close();
|
||||
delete m_currentPopup;
|
||||
m_currentPopup = nullptr;
|
||||
}
|
||||
|
||||
QWidget *parentW = this->window();
|
||||
m_currentPopup = new QDialog(parentW);
|
||||
QDialog &dlg = *m_currentPopup;
|
||||
|
||||
dlg.setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
|
||||
dlg.setModal(true);
|
||||
dlg.setAttribute(Qt::WA_DeleteOnClose);
|
||||
dlg.setStyleSheet("QDialog { background: transparent; }");
|
||||
dlg.setFixedSize(520, 260);
|
||||
|
||||
// 팝업이 닫힐 때 포인터 초기화
|
||||
connect(&dlg, &QDialog::destroyed, this, [this](){
|
||||
m_currentPopup = nullptr;
|
||||
});
|
||||
|
||||
// 중앙 정렬
|
||||
const QPoint parentTopLeft = parentW->mapToGlobal(QPoint(0, 0));
|
||||
const int x = parentTopLeft.x() + (parentW->width() - dlg.width()) / 2;
|
||||
const int y = parentTopLeft.y() + (parentW->height() - dlg.height()) / 2;
|
||||
dlg.move(x, y);
|
||||
|
||||
// 카드 스타일 UI 구성
|
||||
QFrame *card = new QFrame(&dlg);
|
||||
card->setObjectName("popupCard");
|
||||
card->setStyleSheet("#popupCard { background: rgb(246, 245, 244); border-radius: 16px; }");
|
||||
|
||||
auto *shadow = new QGraphicsDropShadowEffect(card);
|
||||
shadow->setBlurRadius(30);
|
||||
shadow->setOffset(0, 8);
|
||||
shadow->setColor(QColor(0, 0, 0, 80));
|
||||
card->setGraphicsEffect(shadow);
|
||||
|
||||
QVBoxLayout *root = new QVBoxLayout(&dlg);
|
||||
root->setContentsMargins(0, 0, 0, 0);
|
||||
root->addWidget(card);
|
||||
|
||||
QVBoxLayout *lay = new QVBoxLayout(card);
|
||||
lay->setContentsMargins(28, 24, 28, 24);
|
||||
lay->setSpacing(14);
|
||||
|
||||
QLabel *title = new QLabel(QString("%1로 이동 중입니다").arg(zoneText), card);
|
||||
title->setAlignment(Qt::AlignCenter);
|
||||
title->setStyleSheet("font-size:24px; font-weight:900; color:#111827;");
|
||||
|
||||
QLabel *desc = new QLabel("확인을 누르면 이동을 중단합니다.", card);
|
||||
desc->setAlignment(Qt::AlignCenter);
|
||||
desc->setStyleSheet("font-size:16px; font-weight:700; color:#6B7280;");
|
||||
|
||||
QPushButton *stopBtn = new QPushButton("확인(이동 중단)", card);
|
||||
stopBtn->setFixedHeight(48);
|
||||
stopBtn->setMinimumWidth(220);
|
||||
stopBtn->setStyleSheet(
|
||||
"QPushButton{ background:#EF4444; color:white; border:none; border-radius:12px; "
|
||||
"font-size:18px; font-weight:900; padding:8px 18px; }"
|
||||
"QPushButton:hover{ background:#DC2626; }"
|
||||
"QPushButton:pressed{ background:#B91C1C; }"
|
||||
);
|
||||
|
||||
lay->addStretch();
|
||||
lay->addWidget(title);
|
||||
lay->addWidget(desc);
|
||||
lay->addSpacing(8);
|
||||
lay->addWidget(stopBtn, 0, Qt::AlignHCenter);
|
||||
lay->addStretch();
|
||||
|
||||
// 안내 중지 버튼 -> MainWidget에 신호
|
||||
connect(stopBtn, &QPushButton::clicked, this, [this, &dlg](){
|
||||
emit requestStop();
|
||||
dlg.accept();
|
||||
});
|
||||
|
||||
dlg.show();
|
||||
}
|
||||
|
||||
// 도착 알림 -> 팝업 끄기
|
||||
void PageGuide::onRobotArrived()
|
||||
{
|
||||
if (m_currentPopup) {
|
||||
qDebug() << "PageGuide: Robot Arrived! Closing popup.";
|
||||
m_currentPopup->accept();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef PAGEGUIDE_H
|
||||
#define PAGEGUIDE_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPixmap>
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui { class PageGuide; }
|
||||
|
||||
class PageGuide : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PageGuide(QWidget *parent = nullptr);
|
||||
~PageGuide();
|
||||
|
||||
public slots:
|
||||
void onRobotArrived();
|
||||
|
||||
signals:
|
||||
void backToCartClicked();
|
||||
void requestGoal(double x, double y);
|
||||
void requestStop();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private slots:
|
||||
void onBackToCartClicked();
|
||||
void onPuzzleClicked();
|
||||
void onCreamClicked();
|
||||
void onSnackClicked();
|
||||
void onPayClicked();
|
||||
void onbtnphoneClicked();
|
||||
|
||||
private:
|
||||
Ui::PageGuide *ui;
|
||||
QPixmap m_treePixmap;
|
||||
QDialog *m_currentPopup = nullptr;
|
||||
|
||||
void applyTreePixmap();
|
||||
void showMovePopup(const QString &zoneText);
|
||||
};
|
||||
|
||||
#endif // PAGEGUIDE_H
|
||||
@@ -0,0 +1,438 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PageGuide</class>
|
||||
<widget class="QWidget" name="PageGuide">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>480</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">/* ===== 카드(프레임) ===== */
|
||||
QFrame#frameCornerList {
|
||||
background-color: rgb(255, 255, 255);
|
||||
border-radius: 16px;
|
||||
border: 1px solid rgb(229, 231, 235); /* 연회색 */
|
||||
}
|
||||
|
||||
/* 제목 라벨 */
|
||||
QLabel#lblCornerTitle {
|
||||
background: transparent;
|
||||
color: rgb(17, 24, 39); /* 진한 글씨 */
|
||||
font-size: 20px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
/* ===== 리스트 위젯 ===== */
|
||||
QListWidget#listCorners {
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: 0;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
/* 스크롤바 깔끔하게 (선택) */
|
||||
QListWidget#listCorners QScrollBar:vertical {
|
||||
width: 10px;
|
||||
background: transparent;
|
||||
}
|
||||
QListWidget#listCorners QScrollBar::handle:vertical {
|
||||
background: rgb(209, 213, 219);
|
||||
border-radius: 5px;
|
||||
min-height: 20px;
|
||||
}
|
||||
QListWidget#listCorners QScrollBar::add-line:vertical,
|
||||
QListWidget#listCorners QScrollBar::sub-line:vertical {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
/* ===== 아이템(행) 스타일 ===== */
|
||||
QListWidget#listCorners::item {
|
||||
background-color: rgb(249, 250, 251); /* 살짝 회색 */
|
||||
border: 1px solid rgb(229, 231, 235);
|
||||
border-radius: 12px;
|
||||
|
||||
padding: 14px 16px; /* 안쪽 여백 */
|
||||
margin: 6px 4px; /* 아이템 간 간격 */
|
||||
|
||||
color: rgb(17, 24, 39);
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
|
||||
</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<widget class="QPushButton" name="btnpay">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>90</x>
|
||||
<y>350</y>
|
||||
<width>61</width>
|
||||
<height>51</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border-image: url(:/etc/map_pay.png);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnpuzzle">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>390</x>
|
||||
<y>150</y>
|
||||
<width>61</width>
|
||||
<height>61</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border-image: url(:/etc/map_toy_2.png);
|
||||
|
||||
QPushButton#Region1:hover{
|
||||
background-color: rgb(222, 221, 218);
|
||||
};
|
||||
QPushButton#Region1:pressed{
|
||||
background-color: rgb(222, 221, 218);
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnsnack">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>190</x>
|
||||
<y>170</y>
|
||||
<width>61</width>
|
||||
<height>71</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border-image: url(:/etc/map_snack.png);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnBackToCart">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>550</x>
|
||||
<y>10</y>
|
||||
<width>201</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(53, 132, 228);
|
||||
color: rgb(255, 255, 255);
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
padding: 10px 18px;
|
||||
font: 14pt "Ubuntu";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>장바구니로 돌아가기</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>121</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 700 22pt "Ubuntu";
|
||||
color: rgb(46, 194, 126);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>안내 지도</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="lblmap">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>70</y>
|
||||
<width>521</width>
|
||||
<height>341</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>780</width>
|
||||
<height>800</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border-image: url(:/etc/guide_map.png);
|
||||
|
||||
border-style: solid;
|
||||
border-top: 3px solid rgb(200, 200, 200);
|
||||
border-left: 3px solid rgb(200, 200, 200);
|
||||
border-right: 3px solid rgb(200, 200, 200);
|
||||
border-bottom: 3px solid rgb(200, 200, 200);
|
||||
|
||||
|
||||
|
||||
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>140</x>
|
||||
<y>20</y>
|
||||
<width>391</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 300 italic 11pt "Ubuntu";
|
||||
color: rgb(224, 27, 36);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>**지도의 아이콘을 터치하면 해당 구역으로 안내가 시작됩니다</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnphone">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>100</x>
|
||||
<y>290</y>
|
||||
<width>51</width>
|
||||
<height>51</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border-image: url(:/etc/map_phone_1.png);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btncream">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>390</x>
|
||||
<y>350</y>
|
||||
<width>51</width>
|
||||
<height>51</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border-image: url(:/etc/map_cream.png);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>180</x>
|
||||
<y>180</y>
|
||||
<width>21</width>
|
||||
<height>17</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 700 14pt "Ubuntu";
|
||||
color: rgb(255, 255, 255);
|
||||
background-color: rgb(224, 27, 36);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>01</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>380</x>
|
||||
<y>140</y>
|
||||
<width>21</width>
|
||||
<height>17</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 700 14pt "Ubuntu";
|
||||
color: rgb(255, 255, 255);
|
||||
background-color: rgb(224, 27, 36);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>02</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>370</x>
|
||||
<y>350</y>
|
||||
<width>21</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 700 14pt "Ubuntu";
|
||||
color: rgb(255, 255, 255);
|
||||
background-color: rgb(224, 27, 36);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>03</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>80</x>
|
||||
<y>290</y>
|
||||
<width>21</width>
|
||||
<height>17</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 700 14pt "Ubuntu";
|
||||
color: rgb(255, 255, 255);
|
||||
background-color: rgb(224, 27, 36);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>04</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QFrame" name="frameCornerList">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>560</x>
|
||||
<y>60</y>
|
||||
<width>191</width>
|
||||
<height>361</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<widget class="QLabel" name="lblCornerTitle">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>60</x>
|
||||
<y>0</y>
|
||||
<width>81</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">
|
||||
font: 700 16pt "Ubuntu";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>물품위치</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QListWidget" name="listCorners">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>30</y>
|
||||
<width>191</width>
|
||||
<height>341</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 11pt "Ubuntu";</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>01코너 식품</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>02코너 장난감</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>03코너 생필품</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>04코너 전자제품</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>05코너 계산대</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>70</x>
|
||||
<y>360</y>
|
||||
<width>21</width>
|
||||
<height>17</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 700 14pt "Ubuntu";
|
||||
color: rgb(255, 255, 255);
|
||||
background-color: rgb(224, 27, 36);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>05</string>
|
||||
</property>
|
||||
</widget>
|
||||
<zorder>lblmap</zorder>
|
||||
<zorder>btnpay</zorder>
|
||||
<zorder>btnpuzzle</zorder>
|
||||
<zorder>btnsnack</zorder>
|
||||
<zorder>btnBackToCart</zorder>
|
||||
<zorder>label</zorder>
|
||||
<zorder>label_3</zorder>
|
||||
<zorder>btnphone</zorder>
|
||||
<zorder>btncream</zorder>
|
||||
<zorder>label_4</zorder>
|
||||
<zorder>label_5</zorder>
|
||||
<zorder>label_6</zorder>
|
||||
<zorder>label_7</zorder>
|
||||
<zorder>frameCornerList</zorder>
|
||||
<zorder>label_8</zorder>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,179 @@
|
||||
#include "pagepay.h"
|
||||
#include "ui_pagepay.h"
|
||||
#include <QGraphicsDropShadowEffect>
|
||||
#include <QHeaderView>
|
||||
#include <QTableWidgetItem>
|
||||
#include <QPushButton>
|
||||
#include <QPixmap>
|
||||
|
||||
static QString moneyKR(qint64 v)
|
||||
{
|
||||
// ✅ 무조건 "1,234" 형식으로 나오게(환경 영향 최소화)
|
||||
const QLocale loc(QLocale::Korean, QLocale::SouthKorea);
|
||||
return loc.toString(v) + "원";
|
||||
}
|
||||
|
||||
PagePay::PagePay(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::PagePay)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
auto makeShadow = [](QObject *parent){
|
||||
auto *s = new QGraphicsDropShadowEffect(parent);
|
||||
s->setBlurRadius(18);
|
||||
s->setOffset(0, 4);
|
||||
s->setColor(QColor(0, 0, 0, 60));
|
||||
return s;
|
||||
};
|
||||
|
||||
// 그림자
|
||||
if (ui->frame_2) ui->frame_2->setGraphicsEffect(makeShadow(ui->frame_2));
|
||||
if (ui->widget) ui->widget->setGraphicsEffect(makeShadow(ui->widget));
|
||||
|
||||
// ✅ 버튼 연결 (새 UI 기준)
|
||||
if (ui->btnBack) connect(ui->btnBack, &QPushButton::clicked, this, &PagePay::onBackPressed);
|
||||
if (ui->btnNext) connect(ui->btnNext, &QPushButton::clicked, this, &PagePay::onNextPressed);
|
||||
|
||||
// 테이블 세팅
|
||||
setupUiTable();
|
||||
|
||||
// 카드 아이콘(임시 이미지)
|
||||
if (ui->lblCardIcon) {
|
||||
QPixmap px(":/etc/card.png");
|
||||
if (!px.isNull()) {
|
||||
ui->lblCardIcon->setPixmap(px.scaled(180, 180, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
ui->lblCardIcon->setAlignment(Qt::AlignCenter);
|
||||
} else {
|
||||
ui->lblCardIcon->setText("CARD");
|
||||
ui->lblCardIcon->setAlignment(Qt::AlignCenter);
|
||||
}
|
||||
}
|
||||
|
||||
// frame 스타일
|
||||
if (ui->frame_2) {
|
||||
ui->frame_2->setStyleSheet("QFrame { background: white; border-radius: 16px; }");
|
||||
}
|
||||
|
||||
// 안내 문구 (너 UI가 lblCarGuide면 그대로, lblCardGuide면 그걸로)
|
||||
if (ui->lblCarGuide) {
|
||||
ui->lblCarGuide->setText("카드를 투입구에 넣어주세요");
|
||||
}
|
||||
// 만약 실제로 lblCardGuide라면 위 대신 아래를 쓰면 됨:
|
||||
// if (ui->lblCardGuide) ui->lblCardGuide->setText("카드를 투입구에 넣어주세요");
|
||||
|
||||
// 처음엔 비어있으니 기본 표시
|
||||
refreshTableAndTotal();
|
||||
}
|
||||
|
||||
|
||||
PagePay::~PagePay()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void PagePay::setupUiTable()
|
||||
{
|
||||
ui->tablePayItems->horizontalHeader()->setVisible(false);
|
||||
ui->tablePayItems->verticalHeader()->setVisible(false);
|
||||
|
||||
ui->tablePayItems->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
ui->tablePayItems->setSelectionMode(QAbstractItemView::NoSelection);
|
||||
ui->tablePayItems->setShowGrid(false);
|
||||
|
||||
// ✅ 5컬럼: [물품][간격][갯수][간격][가격]
|
||||
ui->tablePayItems->setColumnCount(5);
|
||||
|
||||
auto *hh = ui->tablePayItems->horizontalHeader();
|
||||
hh->setSectionResizeMode(0, QHeaderView::Stretch); // 물품은 남는 폭 다 먹기
|
||||
hh->setSectionResizeMode(1, QHeaderView::Fixed); // 간격
|
||||
hh->setSectionResizeMode(2, QHeaderView::Fixed); // 갯수
|
||||
hh->setSectionResizeMode(3, QHeaderView::Fixed); // 간격
|
||||
hh->setSectionResizeMode(4, QHeaderView::Fixed); // 가격
|
||||
|
||||
// ✅ 800x480 최적값(기본)
|
||||
int gapW = 12; // 물품-갯수 / 갯수-가격 사이 간격
|
||||
int qtyW = 60; // "3개" 정도 충분
|
||||
int priceW = 110; // "13000원" 정도 충분
|
||||
|
||||
// ✅ 테이블 폭에 따라 살짝 자동 보정 (작아지면 더 줄임)
|
||||
int tableW = ui->tablePayItems->viewport()->width();
|
||||
if (tableW > 0) {
|
||||
// 물품 칼럼 최소폭을 남기기 위해, 너무 좁으면 qty/price/gap를 줄여줌
|
||||
int fixed = gapW*2 + qtyW + priceW;
|
||||
int nameMin = 160; // 물품명 최소로 확보(원하면 140~200 조절)
|
||||
|
||||
if (tableW - fixed < nameMin) {
|
||||
// 줄일 여지가 있는 것들부터 줄임
|
||||
gapW = 8;
|
||||
qtyW = 52;
|
||||
priceW = 78;
|
||||
}
|
||||
}
|
||||
|
||||
ui->tablePayItems->setColumnWidth(1, gapW);
|
||||
ui->tablePayItems->setColumnWidth(2, qtyW);
|
||||
ui->tablePayItems->setColumnWidth(3, gapW);
|
||||
ui->tablePayItems->setColumnWidth(4, priceW);
|
||||
|
||||
// (옵션) 글자와 셀 padding 조금 줄여서 7인치에 더 꽉 차게
|
||||
ui->tablePayItems->setStyleSheet(
|
||||
"QTableWidget::item { padding-left: 4px; padding-right: 4px; }"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void PagePay::setPayItems(const QVector<PayLine>& lines)
|
||||
{
|
||||
m_lines = lines;
|
||||
refreshTableAndTotal();
|
||||
}
|
||||
|
||||
void PagePay::refreshTableAndTotal()
|
||||
{
|
||||
ui->tablePayItems->setRowCount(0);
|
||||
|
||||
int totalPrice = 0;
|
||||
|
||||
for (int i = 0; i < m_lines.size(); ++i) {
|
||||
const auto &it = m_lines[i];
|
||||
|
||||
int row = ui->tablePayItems->rowCount();
|
||||
ui->tablePayItems->insertRow(row);
|
||||
ui->tablePayItems->setRowHeight(row, 40); // ✅ 7인치면 40~44 추천
|
||||
|
||||
// (0) 물품
|
||||
auto *nameItem = new QTableWidgetItem(it.name);
|
||||
nameItem->setTextAlignment(Qt::AlignVCenter | Qt::AlignLeft);
|
||||
ui->tablePayItems->setItem(row, 0, nameItem);
|
||||
|
||||
// (2) 갯수
|
||||
auto *qtyItem = new QTableWidgetItem(QString("%1개").arg(it.qty));
|
||||
qtyItem->setTextAlignment(Qt::AlignCenter);
|
||||
ui->tablePayItems->setItem(row, 2, qtyItem);
|
||||
|
||||
// (4) 가격
|
||||
int linePrice = it.unitPrice * it.qty;
|
||||
totalPrice += linePrice;
|
||||
|
||||
auto *priceItem = new QTableWidgetItem(moneyKR(linePrice));
|
||||
priceItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
ui->tablePayItems->setItem(row, 4, priceItem);
|
||||
}
|
||||
|
||||
if (ui->lblTotalPriceValue)
|
||||
ui->lblTotalPriceValue->setText(moneyKR(totalPrice));
|
||||
|
||||
ui->btnNext->setEnabled(!m_lines.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
void PagePay::onBackPressed()
|
||||
{
|
||||
emit backCartClicked(); // ✅ PageCart로
|
||||
}
|
||||
|
||||
void PagePay::onNextPressed()
|
||||
{
|
||||
emit creditCardClicked(); // ✅ pagepay_card로
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef PAGEPAY_H
|
||||
#define PAGEPAY_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVector>
|
||||
#include <QString>
|
||||
|
||||
namespace Ui { class PagePay; }
|
||||
|
||||
class PagePay : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PagePay(QWidget *parent = nullptr);
|
||||
~PagePay();
|
||||
|
||||
struct PayLine {
|
||||
QString name;
|
||||
int qty = 0;
|
||||
int unitPrice = 0;
|
||||
|
||||
};
|
||||
|
||||
void setPayItems(const QVector<PayLine>& lines);
|
||||
|
||||
signals:
|
||||
void backCartClicked(); // <- 이전 (PageCart로)
|
||||
void creditCardClicked(); // 다음 (pagepay_card로)
|
||||
|
||||
private slots:
|
||||
void onBackPressed();
|
||||
void onNextPressed();
|
||||
|
||||
private:
|
||||
void setupUiTable();
|
||||
void refreshTableAndTotal();
|
||||
|
||||
private:
|
||||
Ui::PagePay *ui;
|
||||
QVector<PayLine> m_lines;
|
||||
};
|
||||
|
||||
#endif // PAGEPAY_H
|
||||
@@ -0,0 +1,358 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PagePay</class>
|
||||
<widget class="QWidget" name="PagePay">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>480</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: #F2F4F7;</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<widget class="QPushButton" name="btnNext">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>460</x>
|
||||
<y>370</y>
|
||||
<width>281</width>
|
||||
<height>61</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(53, 132, 228);
|
||||
color: rgb(255, 255, 255);
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
padding: 10px 18px;
|
||||
font: 14pt "Ubuntu";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>다음으로 넘어가기</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnBack">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>610</x>
|
||||
<y>10</y>
|
||||
<width>95</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(154, 153, 150);
|
||||
color: rgb(255, 255, 255);
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
padding: 10px 18px;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>이전 화면</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>460</x>
|
||||
<y>90</y>
|
||||
<width>281</width>
|
||||
<height>271</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);
|
||||
border-radius: 16px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<widget class="QLabel" name="lblCardIcon">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>30</x>
|
||||
<y>-10</y>
|
||||
<width>201</width>
|
||||
<height>211</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">image: url(:/etc/card.png);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="lblCarGuide">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>50</x>
|
||||
<y>200</y>
|
||||
<width>241</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 500 12pt "Ubuntu";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>카드를 투입구에 넣어주세요</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>330</x>
|
||||
<y>19</y>
|
||||
<width>121</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 13pt "Ubuntu Condensed";
|
||||
color: rgb(0, 0, 0);
|
||||
background-color: #F2F4F7;
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>O Checkout </string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>220</x>
|
||||
<y>20</y>
|
||||
<width>111</width>
|
||||
<height>17</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 13pt "Ubuntu Condensed";
|
||||
color: rgb(154, 153, 150);
|
||||
background-color: #F2F4F7;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>O Cart </string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>50</y>
|
||||
<width>301</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 13pt "Ubuntu Condensed";
|
||||
color: rgb(0, 0, 0)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>아래 구매 내역을 확인해주세요</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>90</y>
|
||||
<width>441</width>
|
||||
<height>341</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);
|
||||
border-radius: 16px;</string>
|
||||
</property>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>141</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 500 20pt "Ubuntu";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>구매 내역</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>50</y>
|
||||
<width>91</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 15pt "Ubuntu Mono";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Prdoucts</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>230</x>
|
||||
<y>50</y>
|
||||
<width>91</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 15pt "Ubuntu Mono";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Count</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>385</x>
|
||||
<y>50</y>
|
||||
<width>91</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 15pt "Ubuntu Mono";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Price</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QTableWidget" name="tablePayItems">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>90</y>
|
||||
<width>441</width>
|
||||
<height>191</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);
|
||||
border-radius: 0px;
|
||||
font: 300 13pt "Umpush";
|
||||
border-top: 1px solid #cfcfcf;
|
||||
border-bottom: 0px;
|
||||
border-left: 0px;
|
||||
border-right: 0px;</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QFrame" name="frame_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>290</y>
|
||||
<width>451</width>
|
||||
<height>51</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);
|
||||
border-style: solid;
|
||||
border-top: 1px solid rgb(200, 200, 200);
|
||||
border-left: 1px solid rgb(255, 255, 255);
|
||||
border-right: 1px solid rgb(255, 255, 255);
|
||||
border-bottom: 1px solid rgb(255, 255, 255);
|
||||
border-radius: 0px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>10</y>
|
||||
<width>121</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 700 16pt "Umpush";
|
||||
background-color: rgb(255, 255, 255);
|
||||
border: none;
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>총 결제금액</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="lblTotalPriceValue">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>240</x>
|
||||
<y>10</y>
|
||||
<width>101</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border: none;
|
||||
font: 15pt "Umpush";
|
||||
color: rgb(28, 113, 216);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>460</x>
|
||||
<y>20</y>
|
||||
<width>111</width>
|
||||
<height>17</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 13pt "Ubuntu Condensed";
|
||||
color: rgb(154, 153, 150);
|
||||
background-color: #F2F4F7;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>O Payment </string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,213 @@
|
||||
#include "pagepay_card.h"
|
||||
#include "ui_pagepay_card.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QStackedWidget>
|
||||
#include <QTimer>
|
||||
#include <QShowEvent>
|
||||
#include <QPainter>
|
||||
#include <QFont>
|
||||
#include <QSharedPointer>
|
||||
|
||||
// ⏳ 텍스트를 Pixmap으로 렌더링
|
||||
static QPixmap textToPixmap(const QString &text, int fontPx)
|
||||
{
|
||||
QFont f;
|
||||
f.setPixelSize(fontPx);
|
||||
|
||||
const int size = fontPx * 2;
|
||||
QPixmap pm(size, size);
|
||||
pm.fill(Qt::transparent);
|
||||
|
||||
QPainter p(&pm);
|
||||
p.setRenderHint(QPainter::Antialiasing, true);
|
||||
p.setRenderHint(QPainter::TextAntialiasing, true);
|
||||
p.setFont(f);
|
||||
p.setPen(Qt::black);
|
||||
p.drawText(pm.rect(), Qt::AlignCenter, text);
|
||||
return pm;
|
||||
}
|
||||
|
||||
// Pixmap을 고정 캔버스 안에서 회전
|
||||
static QPixmap rotatedPixmap(const QPixmap &src, qreal angleDeg)
|
||||
{
|
||||
QPixmap out(src.size());
|
||||
out.fill(Qt::transparent);
|
||||
|
||||
QPainter p(&out);
|
||||
p.setRenderHint(QPainter::Antialiasing, true);
|
||||
p.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
||||
|
||||
const QPointF c(out.width() / 2.0, out.height() / 2.0);
|
||||
p.translate(c);
|
||||
p.rotate(angleDeg);
|
||||
p.translate(-c);
|
||||
p.drawPixmap(0, 0, src);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
pagepay_card::pagepay_card(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::pagepay_card)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
pagepay_card::~pagepay_card()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void pagepay_card::showEvent(QShowEvent *e)
|
||||
{
|
||||
QWidget::showEvent(e);
|
||||
|
||||
// 페이지가 뜬 뒤 모달 띄우기
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
showPaymentModal();
|
||||
});
|
||||
}
|
||||
|
||||
void pagepay_card::showPaymentModal()
|
||||
{
|
||||
QWidget *parentW = this->window();
|
||||
if (!parentW) parentW = this;
|
||||
|
||||
// ✅ 팝업 자체를 카드 크기로만 만들기 (전체 덮지 않음)
|
||||
QDialog *dlg = new QDialog(parentW);
|
||||
dlg->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);
|
||||
dlg->setModal(true);
|
||||
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dlg->setFixedSize(520, 260);
|
||||
|
||||
// ✅ 부모(800x480) 기준 "정중앙" 위치
|
||||
const int x = (parentW->width() - dlg->width()) / 2;
|
||||
const int y = (parentW->height() - dlg->height()) / 2;
|
||||
dlg->move(x, y);
|
||||
|
||||
// ===== 다이얼로그 루트 레이아웃 =====
|
||||
auto *dlgLay = new QVBoxLayout(dlg);
|
||||
dlgLay->setContentsMargins(0,0,0,0);
|
||||
dlgLay->setSpacing(0);
|
||||
|
||||
// ===== 카드 프레임 (둥근 모서리) =====
|
||||
QFrame *card = new QFrame(dlg);
|
||||
card->setObjectName("card");
|
||||
card->setStyleSheet(
|
||||
"#card { background: white; border-radius: 16px; }"
|
||||
);
|
||||
dlgLay->addWidget(card);
|
||||
|
||||
// ===== 카드 내부 스택 =====
|
||||
QStackedWidget *stack = new QStackedWidget(card);
|
||||
QVBoxLayout *cardLay = new QVBoxLayout(card);
|
||||
cardLay->setContentsMargins(24,24,24,24);
|
||||
cardLay->addWidget(stack);
|
||||
|
||||
// --- processing ---
|
||||
QWidget *wProc = new QWidget(card);
|
||||
QVBoxLayout *pLay = new QVBoxLayout(wProc);
|
||||
pLay->setContentsMargins(0,0,0,0);
|
||||
pLay->setSpacing(12);
|
||||
|
||||
QLabel *spinner = new QLabel(wProc);
|
||||
spinner->setAlignment(Qt::AlignCenter);
|
||||
spinner->setStyleSheet("background: transparent;");
|
||||
|
||||
const QPixmap baseHourglass = textToPixmap("⏳", 52);
|
||||
spinner->setPixmap(baseHourglass);
|
||||
|
||||
QLabel *title = new QLabel("카드를 뽑지말아주세요", wProc);
|
||||
title->setAlignment(Qt::AlignCenter);
|
||||
title->setStyleSheet("font-size: 22px; font-weight: 800; color: #111827;");
|
||||
|
||||
QLabel *desc = new QLabel("결제가 진행중입니다", wProc);
|
||||
desc->setAlignment(Qt::AlignCenter);
|
||||
desc->setStyleSheet("font-size: 14px; color: #6B7280;");
|
||||
|
||||
QLabel *countLbl = new QLabel("5", wProc);
|
||||
countLbl->setAlignment(Qt::AlignCenter);
|
||||
countLbl->setStyleSheet("font-size: 64px; font-weight: 900; color: #2563EB; margin-top: 6px;");
|
||||
|
||||
pLay->addStretch();
|
||||
pLay->addWidget(spinner);
|
||||
pLay->addWidget(title);
|
||||
pLay->addWidget(desc);
|
||||
pLay->addWidget(countLbl);
|
||||
pLay->addStretch();
|
||||
|
||||
// --- complete ---
|
||||
QWidget *wDone = new QWidget(card);
|
||||
QVBoxLayout *dLay = new QVBoxLayout(wDone);
|
||||
dLay->setContentsMargins(0,0,0,0);
|
||||
dLay->setSpacing(16);
|
||||
|
||||
QLabel *check = new QLabel("✓", wDone);
|
||||
check->setAlignment(Qt::AlignCenter);
|
||||
check->setStyleSheet("font-size: 72px; font-weight: 900; color: #22C55E;");
|
||||
|
||||
QLabel *doneTxt = new QLabel("결제가 완료되었습니다", wDone);
|
||||
doneTxt->setAlignment(Qt::AlignCenter);
|
||||
doneTxt->setStyleSheet("font-size: 22px; font-weight: 800; color: #111827;");
|
||||
|
||||
QPushButton *btnOk = new QPushButton("확인", wDone);
|
||||
btnOk->setFixedHeight(44);
|
||||
btnOk->setFixedWidth(180);
|
||||
btnOk->setStyleSheet(
|
||||
"QPushButton{background:#2563EB;color:white;border:none;border-radius:12px;font-size:16px;font-weight:800; padding: 0 18px;}"
|
||||
"QPushButton:hover{background:#1D4ED8;}"
|
||||
"QPushButton:pressed{background:#1E40AF;}"
|
||||
);
|
||||
|
||||
dLay->addStretch();
|
||||
dLay->addWidget(check);
|
||||
dLay->addWidget(doneTxt);
|
||||
dLay->addWidget(btnOk, 0, Qt::AlignHCenter);
|
||||
dLay->addStretch();
|
||||
|
||||
stack->addWidget(wProc);
|
||||
stack->addWidget(wDone);
|
||||
stack->setCurrentWidget(wProc);
|
||||
|
||||
// ===== (A) ⏳ 회전 타이머 (느리게) =====
|
||||
auto angle = QSharedPointer<qreal>::create(0.0);
|
||||
QTimer *spinTimer = new QTimer(dlg);
|
||||
spinTimer->setInterval(30); // ✅ 16ms(빠름) -> 30ms(느리게)
|
||||
|
||||
QObject::connect(spinTimer, &QTimer::timeout, dlg, [=]() mutable {
|
||||
*angle += 2.0; // ✅ 4.0(빠름) -> 2.0(느리게)
|
||||
if (*angle >= 360.0) *angle -= 360.0;
|
||||
spinner->setPixmap(rotatedPixmap(baseHourglass, *angle));
|
||||
});
|
||||
spinTimer->start();
|
||||
|
||||
// ===== (B) 5초 카운트다운 =====
|
||||
auto count = QSharedPointer<int>::create(5);
|
||||
QTimer *t = new QTimer(dlg);
|
||||
t->setInterval(1000);
|
||||
|
||||
QObject::connect(t, &QTimer::timeout, dlg, [=]() mutable {
|
||||
(*count)--;
|
||||
if (*count >= 0) countLbl->setText(QString::number(*count));
|
||||
|
||||
if (*count <= 0) {
|
||||
t->stop();
|
||||
spinTimer->stop();
|
||||
stack->setCurrentWidget(wDone);
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(btnOk, &QPushButton::clicked, dlg, [this, dlg]() {
|
||||
dlg->accept();
|
||||
emit goTotalPayClicked();
|
||||
});
|
||||
|
||||
t->start();
|
||||
dlg->exec();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef PAGEPAY_CARD_H
|
||||
#define PAGEPAY_CARD_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class pagepay_card;
|
||||
}
|
||||
|
||||
class QShowEvent;
|
||||
|
||||
class pagepay_card : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit pagepay_card(QWidget *parent = nullptr);
|
||||
~pagepay_card();
|
||||
|
||||
signals:
|
||||
void goTotalPayClicked();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *e) override;
|
||||
|
||||
private:
|
||||
void showPaymentModal();
|
||||
|
||||
private:
|
||||
Ui::pagepay_card *ui;
|
||||
};
|
||||
|
||||
#endif // PAGEPAY_CARD_H
|
||||
@@ -1,18 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>pPageWelcome</class>
|
||||
<widget class="QWidget" name="pPageWelcome">
|
||||
<class>pagepay_card</class>
|
||||
<widget class="QWidget" name="pagepay_card">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
<width>800</width>
|
||||
<height>480</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(36, 31, 49);</string>
|
||||
</property>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "pagepayment.h"
|
||||
#include "ui_pagepayment.h"
|
||||
|
||||
pagepayment::pagepayment(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::pagepayment)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
pagepayment::~pagepayment()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef PAGEPAYMENT_H
|
||||
#define PAGEPAYMENT_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class pagepayment;
|
||||
}
|
||||
|
||||
class pagepayment : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit pagepayment(QWidget *parent = nullptr);
|
||||
~pagepayment();
|
||||
|
||||
private:
|
||||
Ui::pagepayment *ui;
|
||||
};
|
||||
|
||||
#endif // PAGEPAYMENT_H
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PagePayment</class>
|
||||
<widget class="QWidget" name="PagePayment">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="verticalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>230</x>
|
||||
<y>140</y>
|
||||
<width>160</width>
|
||||
<height>80</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout"/>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,211 @@
|
||||
#include "pagetotalpay.h"
|
||||
#include "ui_pagetotalpay.h"
|
||||
|
||||
#include <QGraphicsView>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsProxyWidget>
|
||||
#include <QVariantAnimation>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QResizeEvent>
|
||||
#include <QTimer>
|
||||
|
||||
#include <QtMath>
|
||||
#include <QPainter>
|
||||
#include <QPen>
|
||||
#include <QEasingCurve>
|
||||
|
||||
PageTotalPay::PageTotalPay(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::PageTotalPay)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
if (objectName().isEmpty())
|
||||
setObjectName("PageTotalPay");
|
||||
|
||||
// ✅ 여기 추가
|
||||
setStyleSheet("QWidget#PageTotalPay { background-color: rgb(34,197,94); }");
|
||||
|
||||
|
||||
// ✅ Scene/View
|
||||
m_scene = new QGraphicsScene(this);
|
||||
|
||||
m_view = new QGraphicsView(this);
|
||||
m_view->setScene(m_scene);
|
||||
m_view->setFrameShape(QFrame::NoFrame);
|
||||
m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_view->setStyleSheet("background: transparent;");
|
||||
m_view->setAlignment(Qt::AlignCenter);
|
||||
|
||||
// 클릭 이벤트를 view/viewport에서도 잡기
|
||||
m_view->viewport()->installEventFilter(this);
|
||||
m_view->installEventFilter(this);
|
||||
|
||||
// ✅ content 위젯(아이콘+텍스트)
|
||||
m_content = new QWidget();
|
||||
m_content->setAttribute(Qt::WA_TranslucentBackground);
|
||||
m_content->installEventFilter(this);
|
||||
|
||||
auto *lay = new QVBoxLayout(m_content);
|
||||
lay->setContentsMargins(0, 0, 0, 0);
|
||||
lay->setSpacing(28);
|
||||
lay->setAlignment(Qt::AlignCenter);
|
||||
|
||||
QLabel *lblIcon = new QLabel(m_content);
|
||||
lblIcon->setFixedSize(140, 140);
|
||||
lblIcon->setAlignment(Qt::AlignCenter);
|
||||
lblIcon->setPixmap(makeCheckIcon(128));
|
||||
lblIcon->setStyleSheet("background: transparent;");
|
||||
|
||||
QLabel *lblTitle = new QLabel("구매해주셔서 감사합니다", m_content);
|
||||
lblTitle->setAlignment(Qt::AlignCenter);
|
||||
lblTitle->setStyleSheet(
|
||||
"background: transparent;"
|
||||
"color: rgb(0,0,0);"
|
||||
"font-weight: 900;"
|
||||
"font-size: 44px;"
|
||||
);
|
||||
|
||||
QLabel *lblSub = new QLabel("화면을 다시 눌러 시작하기", m_content);
|
||||
lblSub->setAlignment(Qt::AlignCenter);
|
||||
lblSub->setStyleSheet(
|
||||
"background: transparent;"
|
||||
"color: rgb(0,0,0);"
|
||||
"font-weight: 700;"
|
||||
"font-size: 22px;"
|
||||
);
|
||||
|
||||
lay->addWidget(lblIcon, 0, Qt::AlignCenter);
|
||||
lay->addWidget(lblTitle, 0, Qt::AlignCenter);
|
||||
lay->addWidget(lblSub, 0, Qt::AlignCenter);
|
||||
|
||||
// ✅ proxy로 올리기(스케일 애니메이션 대상)
|
||||
m_proxy = m_scene->addWidget(m_content);
|
||||
m_proxy->setTransformOriginPoint(m_proxy->boundingRect().center());
|
||||
|
||||
// ✅ 레이아웃 붙이기 (중요: 기존 레이아웃 있으면 거기에 붙임)
|
||||
if (this->layout()) {
|
||||
this->layout()->setContentsMargins(0,0,0,0);
|
||||
this->layout()->addWidget(m_view);
|
||||
} else {
|
||||
auto *root = new QVBoxLayout(this);
|
||||
root->setContentsMargins(0,0,0,0);
|
||||
root->addWidget(m_view);
|
||||
}
|
||||
|
||||
// ✅❗️여기가 너 코드에서 크래시 난 부분: m_pulseAnim을 반드시 생성해야 함
|
||||
m_pulseAnim = new QVariantAnimation(this);
|
||||
|
||||
// ✅ 코사인 루프 (자연스럽게 1.0 -> 1.15 -> 1.0, 점프 없음)
|
||||
m_pulseAnim->setStartValue(0.0);
|
||||
m_pulseAnim->setEndValue(2.0 * M_PI);
|
||||
m_pulseAnim->setDuration(2000);
|
||||
m_pulseAnim->setLoopCount(-1);
|
||||
m_pulseAnim->setEasingCurve(QEasingCurve::Linear);
|
||||
|
||||
connect(m_pulseAnim, &QVariantAnimation::valueChanged, this, [this](const QVariant &v){
|
||||
const qreal t = v.toReal();
|
||||
const qreal amp = 0.15;
|
||||
const qreal scale = 1.0 + amp * 0.5 * (1.0 - qCos(t));
|
||||
if (m_proxy) m_proxy->setScale(scale);
|
||||
});
|
||||
|
||||
m_pulseAnim->start();
|
||||
|
||||
// ✅ viewport size가 0일 수 있으니 show 이후에 중앙 정렬
|
||||
QTimer::singleShot(0, this, [this](){ centerProxy(); });
|
||||
}
|
||||
|
||||
PageTotalPay::~PageTotalPay()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
QPixmap PageTotalPay::makeCheckIcon(int sizePx) const
|
||||
{
|
||||
const int pad = 6;
|
||||
QPixmap pm(sizePx + pad*2, sizePx + pad*2);
|
||||
pm.fill(Qt::transparent);
|
||||
|
||||
QPainter p(&pm);
|
||||
p.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
// ✅ 초록색 (Tailwind green-500 비슷)
|
||||
QColor green(34, 197, 94);
|
||||
|
||||
// circle stroke
|
||||
QPen pen(green); // ✅ 여기!
|
||||
pen.setWidthF(sizePx * 0.07);
|
||||
pen.setCapStyle(Qt::RoundCap);
|
||||
pen.setJoinStyle(Qt::RoundJoin);
|
||||
p.setPen(pen);
|
||||
p.setBrush(Qt::NoBrush);
|
||||
|
||||
QRectF rc(pad, pad, sizePx, sizePx);
|
||||
p.drawEllipse(rc);
|
||||
|
||||
// check
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(green);
|
||||
p.drawEllipse(rc);
|
||||
|
||||
// 체크: 흰색
|
||||
QPen pen2(Qt::white);
|
||||
pen2.setWidthF(sizePx * 0.09);
|
||||
pen2.setCapStyle(Qt::RoundCap);
|
||||
pen2.setJoinStyle(Qt::RoundJoin);
|
||||
p.setPen(pen2);
|
||||
p.setBrush(Qt::NoBrush);
|
||||
|
||||
QPointF a(rc.left() + sizePx*0.28, rc.top() + sizePx*0.55);
|
||||
QPointF b(rc.left() + sizePx*0.46, rc.top() + sizePx*0.70);
|
||||
QPointF c(rc.left() + sizePx*0.74, rc.top() + sizePx*0.36);
|
||||
|
||||
p.drawLine(a, b);
|
||||
p.drawLine(b, c);
|
||||
|
||||
return pm;
|
||||
}
|
||||
|
||||
|
||||
void PageTotalPay::centerProxy()
|
||||
{
|
||||
if (!m_view || !m_scene || !m_proxy) return;
|
||||
|
||||
const QSize vsz = m_view->viewport()->size();
|
||||
if (vsz.width() <= 0 || vsz.height() <= 0) return; // ✅ 0이면 아직 표시 전
|
||||
|
||||
m_scene->setSceneRect(0, 0, vsz.width(), vsz.height());
|
||||
|
||||
const QPointF origin = m_proxy->boundingRect().center();
|
||||
m_proxy->setTransformOriginPoint(origin);
|
||||
|
||||
const QPointF sceneCenter = m_scene->sceneRect().center();
|
||||
m_proxy->setPos(sceneCenter - origin);
|
||||
}
|
||||
|
||||
void PageTotalPay::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
QWidget::resizeEvent(e);
|
||||
centerProxy();
|
||||
}
|
||||
|
||||
bool PageTotalPay::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::MouseButtonPress) {
|
||||
emit backToStartClicked();
|
||||
return true;
|
||||
}
|
||||
return QWidget::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void PageTotalPay::mousePressEvent(QMouseEvent *e)
|
||||
{
|
||||
emit backToStartClicked();
|
||||
QWidget::mousePressEvent(e);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef PAGETOTALPAY_H
|
||||
#define PAGETOTALPAY_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPixmap>
|
||||
|
||||
class QGraphicsView;
|
||||
class QGraphicsScene;
|
||||
class QGraphicsProxyWidget;
|
||||
class QVariantAnimation;
|
||||
|
||||
namespace Ui {
|
||||
class PageTotalPay;
|
||||
}
|
||||
|
||||
class PageTotalPay : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PageTotalPay(QWidget *parent = nullptr);
|
||||
~PageTotalPay();
|
||||
|
||||
signals:
|
||||
void backToStartClicked(); // ✅ 어디든 클릭하면 Welcome으로 돌아가기
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
|
||||
private:
|
||||
QPixmap makeCheckIcon(int sizePx) const;
|
||||
void centerProxy();
|
||||
|
||||
private:
|
||||
Ui::PageTotalPay *ui = nullptr;
|
||||
|
||||
QGraphicsView *m_view = nullptr;
|
||||
QGraphicsScene *m_scene = nullptr;
|
||||
QGraphicsProxyWidget *m_proxy = nullptr;
|
||||
|
||||
QWidget *m_content = nullptr;
|
||||
QVariantAnimation *m_pulseAnim = nullptr;
|
||||
};
|
||||
|
||||
#endif // PAGETOTALPAY_H
|
||||
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PageTotalPay</class>
|
||||
<widget class="QWidget" name="PageTotalPay">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>480</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(51, 209, 122);</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<widget class="QLabel" name="lblTitle">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>260</x>
|
||||
<y>200</y>
|
||||
<width>67</width>
|
||||
<height>17</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="lblSubTitle">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>270</x>
|
||||
<y>230</y>
|
||||
<width>67</width>
|
||||
<height>17</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="lblIcon">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>250</x>
|
||||
<y>140</y>
|
||||
<width>111</width>
|
||||
<height>17</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,223 @@
|
||||
#include "pagewelcome.h"
|
||||
#include "ui_pagewelcome.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QEasingCurve>
|
||||
#include <QTimer>
|
||||
#include <QPixmap>
|
||||
#include <QDebug>
|
||||
#include <QShowEvent>
|
||||
#include <QHideEvent>
|
||||
#include <QResizeEvent>
|
||||
|
||||
PageWelcome::PageWelcome(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::PageWelcome)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// ✅ 버튼 연결
|
||||
connect(ui->start_button, &QPushButton::clicked,
|
||||
this, &PageWelcome::onStartClicked);
|
||||
|
||||
// ✅ 이미지 로드/세팅(한 번만)
|
||||
loadPixmapsOnce();
|
||||
|
||||
// ✅ UI 레이아웃 적용된 다음 기본 Y 저장 + 중앙 정렬
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
|
||||
if (ui->start_image && m_baseYStartImage < 0)
|
||||
m_baseYStartImage = ui->start_image->y();
|
||||
|
||||
if (ui->qtcart_text && m_baseYTitle < 0)
|
||||
m_baseYTitle = ui->qtcart_text->y();
|
||||
|
||||
if (ui->start_text && m_baseYStartText < 0)
|
||||
m_baseYStartText = ui->start_text->y();
|
||||
|
||||
if (ui->start_button && m_baseYStartBtn < 0)
|
||||
m_baseYStartBtn = ui->start_button->y();
|
||||
|
||||
resetWelcome();
|
||||
});
|
||||
}
|
||||
|
||||
PageWelcome::~PageWelcome()
|
||||
{
|
||||
if (m_anim) {
|
||||
m_anim->stop();
|
||||
delete m_anim;
|
||||
m_anim = nullptr;
|
||||
}
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void PageWelcome::loadPixmapsOnce()
|
||||
{
|
||||
if (m_pixLoaded) return;
|
||||
m_pixLoaded = true;
|
||||
|
||||
QPixmap cartPx(":/etc/cart.png");
|
||||
QPixmap windPx(":/etc/wind.png");
|
||||
|
||||
if (ui->cart_image) {
|
||||
ui->cart_image->setPixmap(cartPx);
|
||||
ui->cart_image->setScaledContents(true);
|
||||
ui->cart_image->setAttribute(Qt::WA_TranslucentBackground);
|
||||
ui->cart_image->show();
|
||||
}
|
||||
|
||||
if (ui->wind_image) {
|
||||
ui->wind_image->setPixmap(windPx);
|
||||
ui->wind_image->setScaledContents(true);
|
||||
ui->wind_image->setAttribute(Qt::WA_TranslucentBackground);
|
||||
ui->wind_image->show();
|
||||
}
|
||||
|
||||
if (ui->start_image) ui->start_image->show();
|
||||
}
|
||||
|
||||
void PageWelcome::showEvent(QShowEvent *e)
|
||||
{
|
||||
QWidget::showEvent(e);
|
||||
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
resetWelcome();
|
||||
});
|
||||
}
|
||||
|
||||
void PageWelcome::hideEvent(QHideEvent *e)
|
||||
{
|
||||
QWidget::hideEvent(e);
|
||||
|
||||
// ✅ 페이지가 숨겨질 때 애니메이션 남아있으면 정리(안전)
|
||||
if (m_anim) {
|
||||
m_anim->stop();
|
||||
m_anim->deleteLater();
|
||||
m_anim = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void PageWelcome::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
QWidget::resizeEvent(e);
|
||||
|
||||
// ✅ 떠나지 않은 상태면 리사이즈 때도 가운데 유지
|
||||
if (!m_leaving) {
|
||||
centerStartImage(); // ✅ 기존 유지
|
||||
centerWelcomeWidgets(); // ✅ 추가
|
||||
}
|
||||
}
|
||||
|
||||
void PageWelcome::resetWelcome()
|
||||
{
|
||||
// ✅ 상태 초기화
|
||||
m_leaving = false;
|
||||
|
||||
// ✅ 버튼 다시 누르게
|
||||
if (ui->start_button) {
|
||||
ui->start_button->setEnabled(true);
|
||||
}
|
||||
|
||||
// ✅ 애니메이션 남아있으면 정리
|
||||
if (m_anim) {
|
||||
m_anim->stop();
|
||||
m_anim->deleteLater();
|
||||
m_anim = nullptr;
|
||||
}
|
||||
|
||||
// ✅ 위젯 다시 보이기
|
||||
if (ui->start_image) ui->start_image->show();
|
||||
if (ui->cart_image) ui->cart_image->show();
|
||||
if (ui->wind_image) ui->wind_image->show();
|
||||
|
||||
// 레이아웃 반영 후 이동
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
if (ui->start_image && m_baseYStartImage < 0) m_baseYStartImage = ui->start_image->y();
|
||||
if (ui->qtcart_text && m_baseYTitle < 0) m_baseYTitle = ui->qtcart_text->y();
|
||||
if (ui->start_text && m_baseYStartText < 0) m_baseYStartText = ui->start_text->y();
|
||||
if (ui->start_button&& m_baseYStartBtn < 0) m_baseYStartBtn = ui->start_button->y();
|
||||
|
||||
centerStartImage(); // ✅ 기존 유지
|
||||
centerWelcomeWidgets(); // ✅ 추가
|
||||
});
|
||||
}
|
||||
|
||||
// ✅ 기존 함수는 그대로: start_image만 가운데
|
||||
void PageWelcome::centerStartImage()
|
||||
{
|
||||
if (!ui->start_image) return;
|
||||
|
||||
QWidget *parentW = ui->start_image->parentWidget();
|
||||
if (!parentW) parentW = this;
|
||||
|
||||
const int pw = parentW->width();
|
||||
const int w = ui->start_image->width();
|
||||
const int x = (pw - w) / 2;
|
||||
|
||||
int y = (m_baseYStartImage >= 0) ? m_baseYStartImage : ui->start_image->y();
|
||||
|
||||
ui->start_image->move(x, y);
|
||||
}
|
||||
|
||||
// ✅ 추가: qcart_text, start_text, start_button도 “X만” 중앙정렬
|
||||
void PageWelcome::centerWelcomeWidgets()
|
||||
{
|
||||
QWidget *parentW = this; // 보통 PageWelcome 전체 기준이 가장 깔끔함
|
||||
const int pw = parentW->width();
|
||||
|
||||
auto centerXKeepY = [&](QWidget *w, int baseY){
|
||||
if (!w) return;
|
||||
const int x = (pw - w->width()) / 2;
|
||||
const int y = (baseY >= 0) ? baseY : w->y();
|
||||
w->move(x, y);
|
||||
};
|
||||
|
||||
centerXKeepY(ui->qtcart_text, m_baseYTitle);
|
||||
centerXKeepY(ui->start_text, m_baseYStartText);
|
||||
centerXKeepY(ui->start_button, m_baseYStartBtn);
|
||||
}
|
||||
|
||||
void PageWelcome::onStartClicked()
|
||||
{
|
||||
if (m_leaving) return;
|
||||
m_leaving = true;
|
||||
|
||||
if (ui->start_button)
|
||||
ui->start_button->setEnabled(false);
|
||||
|
||||
if (!ui->start_image) {
|
||||
emit startRequested();
|
||||
emit startClicked();
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget *parentW = ui->start_image->parentWidget();
|
||||
if (!parentW) parentW = this;
|
||||
|
||||
const QPoint startPos = ui->start_image->pos();
|
||||
const int y = startPos.y();
|
||||
|
||||
// ✅ 오른쪽 화면 밖으로 슈웅~
|
||||
const int endX = parentW->width() + ui->start_image->width() + 20;
|
||||
const QPoint endPos(endX, y);
|
||||
|
||||
// ✅ 멤버로 애니메이션 보관(돌아올 때 stop/정리 가능)
|
||||
m_anim = new QPropertyAnimation(ui->start_image, "pos", this);
|
||||
m_anim->setDuration(700);
|
||||
m_anim->setEasingCurve(QEasingCurve::InOutCubic);
|
||||
m_anim->setStartValue(startPos);
|
||||
m_anim->setEndValue(endPos);
|
||||
|
||||
connect(m_anim, &QPropertyAnimation::finished, this, [this]() {
|
||||
if (m_anim) {
|
||||
m_anim->deleteLater();
|
||||
m_anim = nullptr;
|
||||
}
|
||||
emit startRequested();
|
||||
emit startClicked();
|
||||
});
|
||||
|
||||
m_anim->start();
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifndef PAGEWELCOME_H
|
||||
#define PAGEWELCOME_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QPropertyAnimation;
|
||||
class QShowEvent;
|
||||
class QHideEvent;
|
||||
class QResizeEvent;
|
||||
|
||||
namespace Ui {
|
||||
class PageWelcome;
|
||||
}
|
||||
|
||||
class PageWelcome : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PageWelcome(QWidget *parent = nullptr);
|
||||
~PageWelcome();
|
||||
|
||||
signals:
|
||||
void startClicked();
|
||||
void startRequested();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *e) override;
|
||||
void hideEvent(QHideEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private slots:
|
||||
void onStartClicked();
|
||||
|
||||
private:
|
||||
void loadPixmapsOnce();
|
||||
void centerStartImage(); // ✅ 기존: start_image만 가운데
|
||||
void centerWelcomeWidgets(); // ✅ 추가: 텍스트/버튼도 가운데
|
||||
void resetWelcome();
|
||||
|
||||
private:
|
||||
Ui::PageWelcome *ui;
|
||||
|
||||
bool m_leaving = false;
|
||||
bool m_pixLoaded = false;
|
||||
|
||||
// ✅ 각 위젯의 "기본 Y"를 기억해두고 X만 중앙정렬
|
||||
int m_baseYStartImage = -1;
|
||||
int m_baseYTitle = -1; // qcart_text
|
||||
int m_baseYStartText = -1; // start_text
|
||||
int m_baseYStartBtn = -1; // start_button
|
||||
|
||||
QPropertyAnimation *m_anim = nullptr;
|
||||
};
|
||||
|
||||
#endif // PAGEWELCOME_H
|
||||
@@ -0,0 +1,163 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PageWelcome</class>
|
||||
<widget class="QWidget" name="PageWelcome">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>480</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>11</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<widget class="QLabel" name="start_text">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>340</y>
|
||||
<width>781</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>시작하기 버튼을 눌러 쇼핑을 시작하세요</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="start_image" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>300</x>
|
||||
<y>80</y>
|
||||
<width>211</width>
|
||||
<height>171</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);</string>
|
||||
</property>
|
||||
<widget class="QLabel" name="cart_image">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>90</x>
|
||||
<y>30</y>
|
||||
<width>121</width>
|
||||
<height>101</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="wind_image">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>70</y>
|
||||
<width>61</width>
|
||||
<height>71</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QLabel" name="qtcart_text">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>5</x>
|
||||
<y>250</y>
|
||||
<width>771</width>
|
||||
<height>77</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LayoutDirection::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 700 40pt "Ria Sans";
|
||||
color: rgb(87, 227, 137);
|
||||
background-color: rgb(255, 255, 255);
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>QT CART</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="start_button">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>260</x>
|
||||
<y>390</y>
|
||||
<width>261</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 700 11pt "Ria Sans";
|
||||
QPushButton {
|
||||
background-color: rgb(224, 27, 36); /* ✅ 기본 상태: 더 진한 빨강 */
|
||||
|
||||
font: 300 14pt "Umpush";
|
||||
color: rgb(255, 255, 255);
|
||||
border: none;
|
||||
border-radius: 14px; /* ✅ 동글동글 */
|
||||
padding: 10px 18px; /* 버튼 크기/여백 */
|
||||
}
|
||||
|
||||
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>시작하기</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,62 @@
|
||||
from fastapi import APIRouter
|
||||
from pydantic import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/dashboard",
|
||||
tags=["Dashboard"]
|
||||
)
|
||||
|
||||
bot_state = {
|
||||
"status": "OFFLINE",
|
||||
"last_updated": datetime.now(),
|
||||
"battery": 0.0,
|
||||
"speed": 0.0
|
||||
}
|
||||
|
||||
BOT_TIMEOUT_SEC = 5 # 5초간 보고 없으면 오프라인
|
||||
|
||||
class BotReport(BaseModel):
|
||||
status: str
|
||||
battery: float = 0.0
|
||||
speed: float = 0.0
|
||||
|
||||
class BotConnectionInfo(BaseModel):
|
||||
bot_status: str
|
||||
battery: float
|
||||
speed: float
|
||||
last_update: str
|
||||
|
||||
# 로봇 -> 서버
|
||||
@router.post("/bot/report")
|
||||
def report_bot_status(report: BotReport):
|
||||
global bot_state
|
||||
bot_state["status"] = report.status
|
||||
bot_state["last_updated"] = datetime.now()
|
||||
bot_state["battery"] = report.battery
|
||||
bot_state["speed"] = report.speed
|
||||
return {"msg": "status report received"}
|
||||
|
||||
# 서버 -> 프론트엔드
|
||||
@router.get("/bot/check", response_model=BotConnectionInfo)
|
||||
def check_bot_connection():
|
||||
global bot_state
|
||||
|
||||
elapsed = (datetime.now() - bot_state["last_updated"]).total_seconds()
|
||||
|
||||
current_status = bot_state["status"]
|
||||
if elapsed > BOT_TIMEOUT_SEC:
|
||||
current_status = "OFFLINE"
|
||||
bot_state["speed"] = 0.0
|
||||
|
||||
return {
|
||||
"bot_status": current_status,
|
||||
"battery": bot_state["battery"],
|
||||
"speed": bot_state["speed"],
|
||||
"last_update": bot_state["last_updated"].strftime("%H:%M:%S")
|
||||
}
|
||||
|
||||
# 서버 연결 확인
|
||||
@router.get("/health")
|
||||
def health_check():
|
||||
return {"status": "ok", "time": datetime.now().isoformat()}
|
||||
@@ -0,0 +1,20 @@
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
SQLALCHEMY_DATABASE_URL = "sqlite:///./shopping_cart.db"
|
||||
|
||||
engine = create_engine(
|
||||
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
|
||||
)
|
||||
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
@@ -0,0 +1,74 @@
|
||||
import lgpio
|
||||
import time
|
||||
|
||||
|
||||
class HX711:
|
||||
def __init__(self, dout, pd_sck, gain=128):
|
||||
self.DOUT = dout
|
||||
self.PD_SCK = pd_sck
|
||||
|
||||
self.chip = lgpio.gpiochip_open(0)
|
||||
|
||||
lgpio.gpio_claim_input(self.chip, self.DOUT)
|
||||
lgpio.gpio_claim_output(self.chip, self.PD_SCK)
|
||||
|
||||
self.GAIN = 1 if gain == 128 else 3 if gain == 64 else 2
|
||||
|
||||
self.OFFSET = 0
|
||||
self.REFERENCE_UNIT = 1
|
||||
|
||||
self.set_gain(gain)
|
||||
|
||||
def is_ready(self):
|
||||
return lgpio.gpio_read(self.chip, self.DOUT) == 0
|
||||
|
||||
def set_gain(self, gain):
|
||||
if gain == 128:
|
||||
self.GAIN = 1
|
||||
elif gain == 64:
|
||||
self.GAIN = 3
|
||||
elif gain == 32:
|
||||
self.GAIN = 2
|
||||
|
||||
self.read_raw()
|
||||
|
||||
def read_raw(self):
|
||||
while not self.is_ready():
|
||||
pass
|
||||
|
||||
data = 0
|
||||
for _ in range(24):
|
||||
lgpio.gpio_write(self.chip, self.PD_SCK, 1)
|
||||
data = (data << 1) | lgpio.gpio_read(self.chip, self.DOUT)
|
||||
lgpio.gpio_write(self.chip, self.PD_SCK, 0)
|
||||
|
||||
for _ in range(self.GAIN):
|
||||
lgpio.gpio_write(self.chip, self.PD_SCK, 1)
|
||||
lgpio.gpio_write(self.chip, self.PD_SCK, 0)
|
||||
|
||||
if data & 0x800000:
|
||||
data -= 0x1000000
|
||||
|
||||
return data
|
||||
|
||||
def set_offset(self, offset):
|
||||
self.OFFSET = offset
|
||||
|
||||
def set_reference_unit(self, value):
|
||||
self.REFERENCE_UNIT = value
|
||||
|
||||
def get_value(self, times=5):
|
||||
return sum(self.read_raw() for _ in range(times)) / times
|
||||
|
||||
def get_weight(self, times=5):
|
||||
value = self.get_value(times) - self.OFFSET
|
||||
return value / self.REFERENCE_UNIT
|
||||
|
||||
def power_down(self):
|
||||
lgpio.gpio_write(self.chip, self.PD_SCK, 0)
|
||||
lgpio.gpio_write(self.chip, self.PD_SCK, 1)
|
||||
time.sleep(0.0001)
|
||||
|
||||
def power_up(self):
|
||||
lgpio.gpio_write(self.chip, self.PD_SCK, 0)
|
||||
time.sleep(0.0001)
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"offset": 449326.96,
|
||||
"scale": 311.0220000000001
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
from hx711 import HX711
|
||||
import time, json
|
||||
|
||||
DT_PIN = 5
|
||||
SCK_PIN = 6
|
||||
|
||||
hx = HX711(DT_PIN, SCK_PIN)
|
||||
|
||||
print("HX711 보정 시작")
|
||||
time.sleep(2)
|
||||
|
||||
# 1) 빈 상태
|
||||
print("1️⃣ 아무것도 안 올리고 기다리세요...")
|
||||
N = 30
|
||||
empty = sum(hx.get_value(5) for _ in range(N)) / N
|
||||
print("OFFSET =", empty)
|
||||
|
||||
known = float(input("2️⃣ 기준 무게(g): "))
|
||||
|
||||
print("3️⃣ 기준 무게 올리고 기다리세요...")
|
||||
|
||||
raw = sum(hx.get_value(5) for _ in range(N)) / N
|
||||
|
||||
scale = (raw - empty) / known
|
||||
|
||||
print("\n보정 완료")
|
||||
print("offset =", empty)
|
||||
print("scale =", scale)
|
||||
|
||||
calib = {
|
||||
"offset": empty,
|
||||
"scale": scale
|
||||
}
|
||||
|
||||
with open("hx711_calib.json", "w") as f:
|
||||
json.dump(calib, f, indent=4)
|
||||
|
||||
print("✔ hx711_calib.json 저장 완료")
|
||||
@@ -0,0 +1,23 @@
|
||||
from hx711 import HX711
|
||||
import json, time
|
||||
|
||||
DT_PIN = 5
|
||||
SCK_PIN = 6
|
||||
|
||||
with open("hx711_calib.json") as f:
|
||||
calib = json.load(f)
|
||||
|
||||
OFFSET = calib["offset"]
|
||||
SCALE = calib["scale"]
|
||||
|
||||
hx = HX711(DT_PIN, SCK_PIN)
|
||||
|
||||
hx.set_offset(OFFSET)
|
||||
hx.set_reference_unit(SCALE)
|
||||
|
||||
print(" 무게 측정 시작")
|
||||
|
||||
while True:
|
||||
weight = hx.get_weight(10)
|
||||
print(f"무게: {weight:.1f} g")
|
||||
time.sleep(0.5)
|
||||
@@ -0,0 +1,200 @@
|
||||
import uvicorn
|
||||
from fastapi import FastAPI, Depends, HTTPException
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.responses import FileResponse
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
from datetime import datetime
|
||||
import models, database
|
||||
import dashboard
|
||||
import logging
|
||||
from read_weight import read_cart_weight
|
||||
|
||||
CART_ITEMS = []
|
||||
EXPECTED_WEIGHT = 0.0
|
||||
|
||||
app = FastAPI()
|
||||
models.Base.metadata.create_all(bind=database.engine)
|
||||
|
||||
# 대시보드 라우터 등록
|
||||
app.include_router(dashboard.router)
|
||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||
|
||||
def get_db():
|
||||
db = database.SessionLocal()
|
||||
try: yield db
|
||||
finally: db.close()
|
||||
|
||||
# 무게 검증 로직
|
||||
def is_movable(expected, real):
|
||||
if expected <= 0: return True
|
||||
diff_ratio = abs(real - expected) / expected
|
||||
return diff_ratio <= 0.2
|
||||
|
||||
# 페이지 라우팅
|
||||
@app.get("/dashboard")
|
||||
async def dashboard_view(): return FileResponse("templates/dashboard.html")
|
||||
|
||||
@app.get("/inventory")
|
||||
async def inventory_view(): return FileResponse("templates/inventory.html")
|
||||
|
||||
# 카트 무게 기준값 설정
|
||||
@app.post("/cart/tare")
|
||||
def tare_cart():
|
||||
global EXPECTED_WEIGHT
|
||||
EXPECTED_WEIGHT = read_cart_weight()
|
||||
return {"expected_weight": EXPECTED_WEIGHT}
|
||||
|
||||
@app.get("/items", response_model=List[models.ItemSchema])
|
||||
def read_all_items(db: Session = Depends(get_db)):
|
||||
return db.query(models.Item).all()
|
||||
|
||||
# 상품 추가
|
||||
@app.post("/cart/add/{item_id}")
|
||||
def add_item(item_id: int, db: Session = Depends(get_db)):
|
||||
global EXPECTED_WEIGHT, CART_ITEMS
|
||||
|
||||
item = db.query(models.Item).filter(models.Item.id == item_id).first()
|
||||
if not item:
|
||||
raise HTTPException(404, "Item not found")
|
||||
|
||||
CART_ITEMS.append({
|
||||
"id": item.id,
|
||||
"name": item.name,
|
||||
"price": item.price,
|
||||
"weight": item.weight
|
||||
})
|
||||
|
||||
EXPECTED_WEIGHT += item.weight
|
||||
|
||||
real = read_cart_weight()
|
||||
movable = is_movable(EXPECTED_WEIGHT, real)
|
||||
|
||||
return {
|
||||
"action": "add",
|
||||
"id": item.id,
|
||||
"item": item.name,
|
||||
"price": item.price,
|
||||
"expected_weight": EXPECTED_WEIGHT,
|
||||
"real_weight": real,
|
||||
"diff": abs(real - EXPECTED_WEIGHT),
|
||||
"movable": movable
|
||||
}
|
||||
|
||||
# 상품 제거
|
||||
@app.post("/cart/remove/{item_id}")
|
||||
def remove_item(item_id: int):
|
||||
global EXPECTED_WEIGHT, CART_ITEMS
|
||||
|
||||
for i, item in enumerate(CART_ITEMS):
|
||||
if item["id"] == item_id:
|
||||
removed = CART_ITEMS.pop(i)
|
||||
EXPECTED_WEIGHT -= removed["weight"]
|
||||
break
|
||||
else:
|
||||
raise HTTPException(404, "Item not in cart")
|
||||
|
||||
EXPECTED_WEIGHT = max(EXPECTED_WEIGHT, 0)
|
||||
|
||||
real = read_cart_weight()
|
||||
movable = is_movable(EXPECTED_WEIGHT, real)
|
||||
|
||||
return {
|
||||
"action": "remove",
|
||||
"id": removed["id"],
|
||||
"item": removed["name"],
|
||||
"price": removed["price"],
|
||||
"expected_weight": EXPECTED_WEIGHT,
|
||||
"real_weight": real,
|
||||
"movable": movable
|
||||
}
|
||||
|
||||
# 장바구니 조회
|
||||
@app.get("/cart")
|
||||
def get_cart():
|
||||
total_price = sum(item["price"] for item in CART_ITEMS)
|
||||
|
||||
return {
|
||||
"items": CART_ITEMS,
|
||||
"total_count": len(CART_ITEMS),
|
||||
"total_price": total_price,
|
||||
"expected_weight": EXPECTED_WEIGHT
|
||||
}
|
||||
|
||||
# 무게 체크
|
||||
@app.get("/cart/check_weight")
|
||||
def check_cart():
|
||||
real = read_cart_weight()
|
||||
movable = is_movable(EXPECTED_WEIGHT, real)
|
||||
|
||||
return {
|
||||
"expected_weight": EXPECTED_WEIGHT,
|
||||
"real_weight": real,
|
||||
"diff": abs(real - EXPECTED_WEIGHT),
|
||||
"movable": movable
|
||||
}
|
||||
|
||||
# 대시보드 상태 조회
|
||||
@app.get("/cart/status")
|
||||
def get_cart_status_for_dashboard():
|
||||
global EXPECTED_WEIGHT, CART_ITEMS
|
||||
|
||||
real = read_cart_weight()
|
||||
movable = is_movable(EXPECTED_WEIGHT, real)
|
||||
|
||||
system_status = "NORMAL" if movable else "WARNING_WEIGHT_MISMATCH"
|
||||
|
||||
return {
|
||||
"real_weight": real,
|
||||
"expected_weight": EXPECTED_WEIGHT,
|
||||
"cart_items": CART_ITEMS,
|
||||
"total_price": sum(item["price"] for item in CART_ITEMS),
|
||||
"total_count": len(CART_ITEMS),
|
||||
"system_status": system_status,
|
||||
"movable": movable
|
||||
}
|
||||
|
||||
# 결제
|
||||
@app.post("/cart/pay")
|
||||
def pay_cart(db: Session = Depends(get_db)):
|
||||
global CART_ITEMS, EXPECTED_WEIGHT
|
||||
|
||||
if not CART_ITEMS:
|
||||
raise HTTPException(status_code=400, detail="장바구니가 비어있습니다.")
|
||||
|
||||
total_price = sum(item["price"] for item in CART_ITEMS)
|
||||
|
||||
new_pay = models.Pay(
|
||||
total_price=total_price,
|
||||
created_at=datetime.now()
|
||||
)
|
||||
db.add(new_pay)
|
||||
db.commit()
|
||||
|
||||
reset_cart()
|
||||
|
||||
return {"msg": "결제 완료", "amount": total_price}
|
||||
|
||||
# 결제 내역 조회
|
||||
@app.get("/payments", response_model=List[models.PaySchema])
|
||||
def get_payment_history(db: Session = Depends(get_db)):
|
||||
return db.query(models.Pay).order_by(models.Pay.created_at.desc()).all()
|
||||
|
||||
# 카트 초기화
|
||||
@app.post("/cart/reset")
|
||||
def reset_cart():
|
||||
global EXPECTED_WEIGHT, CART_ITEMS
|
||||
EXPECTED_WEIGHT = 0.0
|
||||
CART_ITEMS.clear()
|
||||
return {"ok": True}
|
||||
|
||||
# 로그 필터
|
||||
class EndpointFilter(logging.Filter):
|
||||
def filter(self, record: logging.LogRecord) -> bool:
|
||||
msg = record.getMessage()
|
||||
return all(x not in msg for x in ["/bot/check", "/bot/report", "/cart/status"])
|
||||
|
||||
logging.getLogger("uvicorn.access").addFilter(EndpointFilter())
|
||||
|
||||
if __name__ == "__main__":
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
@@ -0,0 +1,74 @@
|
||||
from sqlalchemy import Column, Integer, String, Float, DateTime
|
||||
from database import Base
|
||||
from pydantic import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
# 상품 테이블
|
||||
class Item(Base):
|
||||
__tablename__ = "items"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, index=True)
|
||||
price = Column(Float)
|
||||
stock = Column(Integer)
|
||||
weight = Column(Float) # 무게 로직용
|
||||
expiry_date = Column(String) # 대시보드 유통기한 관리용
|
||||
|
||||
# 결제 내역 테이블
|
||||
class Pay(Base):
|
||||
__tablename__ = "payments"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
total_price = Column(Float)
|
||||
created_at = Column(DateTime, default=datetime.now)
|
||||
|
||||
# 상품 생성 요청
|
||||
class ItemCreate(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
stock: int
|
||||
weight: float
|
||||
expiry_date: str
|
||||
|
||||
# 상품 조회 응답
|
||||
class ItemSchema(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
price: float
|
||||
stock: int
|
||||
weight: float
|
||||
expiry_date: str
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
# 결제 내역 응답 (대시보드 차트용)
|
||||
class PaySchema(BaseModel):
|
||||
id: int
|
||||
total_price: float
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
class CartScanResponse(BaseModel):
|
||||
item: ItemSchema
|
||||
cart_weight: float
|
||||
expected_weight: float
|
||||
weight_ok: bool
|
||||
diff: float
|
||||
|
||||
allowed: float
|
||||
|
||||
# 무게 검증 응답
|
||||
class CartScanResponse(BaseModel):
|
||||
item: ItemSchema # 스캔된 상품 정보
|
||||
cart_weight: float # 현재 실제 무게
|
||||
expected_weight: float # 예상 무게
|
||||
weight_ok: bool # 무게 일치 여부
|
||||
diff: float # 오차
|
||||
allowed: float # 허용 오차 범위
|
||||
|
||||
# 무게 포함 아이템 정보
|
||||
class ItemWithWeight(ItemSchema):
|
||||
cart_weight: float
|
||||
@@ -0,0 +1,33 @@
|
||||
from hx711 import HX711
|
||||
import json, time, threading
|
||||
|
||||
# --- 보정값 로드 ---
|
||||
with open("hx711_calib.json", "r") as f:
|
||||
calib = json.load(f)
|
||||
|
||||
OFFSET = calib["offset"]
|
||||
SCALE = calib["scale"]
|
||||
|
||||
hx = HX711(5, 6)
|
||||
|
||||
hx_lock = threading.Lock()
|
||||
|
||||
def read_cart_weight():
|
||||
"""현재 카트 무게(g)를 반환"""
|
||||
with hx_lock:
|
||||
# 여러 번 평균 내서 노이즈 줄이기
|
||||
samples = 10
|
||||
total = 0
|
||||
|
||||
for _ in range(samples):
|
||||
total += hx.read_raw()
|
||||
time.sleep(0.02)
|
||||
|
||||
raw = total / samples
|
||||
weight = (raw - OFFSET) / SCALE
|
||||
|
||||
# 음수/미세값 보호
|
||||
if weight < 0:
|
||||
weight = 0
|
||||
|
||||
return round(weight, 2)
|
||||
@@ -0,0 +1,4 @@
|
||||
fastapi
|
||||
uvicorn[standard]
|
||||
SQLAlchemy
|
||||
pydantic
|
||||
@@ -0,0 +1,310 @@
|
||||
import rclpy
|
||||
from rclpy.node import Node
|
||||
from rclpy.action import ActionClient
|
||||
from geometry_msgs.msg import TwistStamped, PoseWithCovarianceStamped
|
||||
from nav2_msgs.action import NavigateToPose
|
||||
from sensor_msgs.msg import BatteryState
|
||||
from nav_msgs.msg import Odometry
|
||||
from rclpy.qos import QoSProfile, ReliabilityPolicy, DurabilityPolicy, HistoryPolicy
|
||||
|
||||
import socket
|
||||
import time
|
||||
import math
|
||||
import requests
|
||||
import threading
|
||||
from collections import deque
|
||||
|
||||
UDP_PORT_UWB = 44444
|
||||
UDP_PORT_QT = 55555
|
||||
BUFFER_SIZE = 1024
|
||||
SERVER_IP = "192.168.123.43"
|
||||
API_REPORT_URL = f"http://{SERVER_IP}:8000/dashboard/bot/report"
|
||||
API_WEIGHT_URL = f"http://{SERVER_IP}:8000/cart/check_weight"
|
||||
|
||||
TAG_HEIGHT = 1.85
|
||||
ANCHOR_Z = 2.37
|
||||
H_DIFF = abs(ANCHOR_Z - TAG_HEIGHT)
|
||||
|
||||
# 고정 오프셋 보정값
|
||||
FIXED_OFFSETS = {0: -7.00, 1: -7.00, 2: -7.50}
|
||||
# 앵커 절대 좌표
|
||||
ANCHORS_POS = {
|
||||
0: {'x': 0.00, 'y': 0.00},
|
||||
1: {'x': 6.00, 'y': 0.00},
|
||||
2: {'x': 3.00, 'y': 15.00}
|
||||
}
|
||||
MIN_UPDATE_DIST = 1.2
|
||||
NAV_UPDATE_INTERVAL = 2.0
|
||||
|
||||
class IntegratedRosController(Node):
|
||||
def __init__(self):
|
||||
super().__init__('integrated_ros_controller_node')
|
||||
|
||||
amcl_qos = QoSProfile(
|
||||
depth=1,
|
||||
reliability=ReliabilityPolicy.RELIABLE,
|
||||
durability=DurabilityPolicy.TRANSIENT_LOCAL,
|
||||
history=HistoryPolicy.KEEP_LAST
|
||||
)
|
||||
|
||||
self.cmd_vel_pub = self.create_publisher(TwistStamped, '/cmd_vel', 10)
|
||||
self.battery_sub = self.create_subscription(BatteryState, '/battery_state', self.battery_callback, 10)
|
||||
self.odom_sub = self.create_subscription(Odometry, '/odom', self.odom_callback, 10)
|
||||
self.amcl_sub = self.create_subscription(
|
||||
PoseWithCovarianceStamped,
|
||||
'/amcl_pose',
|
||||
self.amcl_callback,
|
||||
amcl_qos
|
||||
)
|
||||
|
||||
self.nav_to_pose_client = ActionClient(self, NavigateToPose, 'navigate_to_pose')
|
||||
|
||||
self.sock_uwb = self.create_udp_socket(UDP_PORT_UWB)
|
||||
self.sock_qt = self.create_udp_socket(UDP_PORT_QT)
|
||||
|
||||
self.current_mode = 0
|
||||
self.battery_level = 0.0
|
||||
self.current_speed = 0.0
|
||||
self.qt_addr = None
|
||||
|
||||
self.robot_x = 0.0
|
||||
self.robot_y = 0.0
|
||||
self.human_x = 0.0
|
||||
self.human_y = 0.0
|
||||
|
||||
self.x_his = deque(maxlen=15)
|
||||
self.y_his = deque(maxlen=5)
|
||||
self.uwb_dists = [0.0, 0.0, 0.0]
|
||||
self.uwb_last_update = [0.0, 0.0, 0.0]
|
||||
|
||||
self.nav_goal_handle = None
|
||||
self.last_goal_time = 0.0
|
||||
self.last_target_pos = [0.0, 0.0]
|
||||
|
||||
self.is_weight_ok = True
|
||||
self.last_weight_check_time = 0.0
|
||||
self.weight_check_interval = 3.0
|
||||
|
||||
self.get_logger().info("Waiting for Nav2 Server...")
|
||||
if not self.nav_to_pose_client.wait_for_server(timeout_sec=5.0):
|
||||
self.get_logger().warn("Nav2 Server not ready yet.")
|
||||
|
||||
self.create_timer(0.05, self.control_loop)
|
||||
self.create_timer(1.0, self.send_bot_status)
|
||||
|
||||
self.get_logger().info("ROS Controller Started")
|
||||
|
||||
def create_udp_socket(self, port):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.bind(('0.0.0.0', port))
|
||||
sock.setblocking(False)
|
||||
return sock
|
||||
|
||||
# 무게 체크
|
||||
def trigger_async_weight_check(self):
|
||||
def _check():
|
||||
try:
|
||||
response = requests.get(API_WEIGHT_URL, timeout=0.5)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
movable = data.get("movable", True)
|
||||
self.is_weight_ok = movable
|
||||
|
||||
if not movable:
|
||||
self.send_udp_to_qt("ERROR:WEIGHT_MISMATCH")
|
||||
except: pass
|
||||
|
||||
threading.Thread(target=_check, daemon=True).start()
|
||||
|
||||
def send_udp_to_qt(self, message):
|
||||
if self.qt_addr:
|
||||
try: self.sock_qt.sendto(message.encode(), self.qt_addr)
|
||||
except: pass
|
||||
|
||||
def battery_callback(self, msg):
|
||||
self.battery_level = int(msg.percentage) if msg.percentage >= 0 else 0.0
|
||||
|
||||
def odom_callback(self, msg):
|
||||
self.current_speed = msg.twist.twist.linear.x
|
||||
|
||||
def amcl_callback(self, msg):
|
||||
self.robot_x = msg.pose.pose.position.x
|
||||
self.robot_y = msg.pose.pose.position.y
|
||||
|
||||
# 로봇 상태 전송
|
||||
def send_bot_status(self):
|
||||
def _post():
|
||||
try:
|
||||
payload = {
|
||||
"status": "ONLINE",
|
||||
"mode": self.current_mode,
|
||||
"battery": round(self.battery_level, 1),
|
||||
"speed": round(self.current_speed, 2),
|
||||
"x": self.robot_x,
|
||||
"y": self.robot_y,
|
||||
"human_x": self.human_x,
|
||||
"human_y": self.human_y
|
||||
}
|
||||
requests.post(API_REPORT_URL, json=payload, timeout=2.0)
|
||||
except: pass
|
||||
|
||||
# 스레드 비동기 전송 후 종료
|
||||
threading.Thread(target=_post, daemon=True).start()
|
||||
|
||||
# 삼변측량 함수
|
||||
def calculate_trilateration(self, distances):
|
||||
try:
|
||||
x1, y1, r1 = ANCHORS_POS[0]['x'], ANCHORS_POS[0]['y'], distances[0]
|
||||
x2, y2, r2 = ANCHORS_POS[1]['x'], ANCHORS_POS[1]['y'], distances[1]
|
||||
x3, y3, r3 = ANCHORS_POS[2]['x'], ANCHORS_POS[2]['y'], distances[2]
|
||||
A, B = 2*(x2-x1), 2*(y2-y1)
|
||||
C = r1**2 - r2**2 - x1**2 + x2**2 - y1**2 + y2**2
|
||||
D, E = 2*(x3-x2), 2*(y3-y2)
|
||||
F = r2**2 - r3**2 - x2**2 + x3**2 - y2**2 + y3**2
|
||||
den = (A * E) - (B * D)
|
||||
if abs(den) < 0.0001: return None
|
||||
return ((C * E) - (B * F)) / den, ((A * F) - (C * D)) / den
|
||||
except: return None
|
||||
|
||||
def transform_to_map(self, ux, uy):
|
||||
mx = 3.25 + (ux * -0.9725)
|
||||
my = -7.35 + (uy * 0.5966)
|
||||
return mx, my
|
||||
|
||||
# UWB 데이터 수신
|
||||
def receive_uwb_data(self):
|
||||
try:
|
||||
for _ in range(10):
|
||||
data, _ = self.sock_uwb.recvfrom(BUFFER_SIZE)
|
||||
msg = data.decode('utf-8').strip()
|
||||
idx = -1
|
||||
if msg.startswith("A1:"): idx = 0
|
||||
elif msg.startswith("A2:"): idx = 1
|
||||
elif msg.startswith("A3:"): idx = 2
|
||||
|
||||
if idx != -1:
|
||||
raw_val = float(msg.split(":")[1])
|
||||
corrected_dist = raw_val - FIXED_OFFSETS[idx]
|
||||
h_dist = math.sqrt(corrected_dist**2 - H_DIFF**2) if corrected_dist > H_DIFF else 0.1
|
||||
self.uwb_dists[idx] = h_dist
|
||||
self.uwb_last_update[idx] = time.time()
|
||||
except BlockingIOError: pass
|
||||
except: pass
|
||||
|
||||
def receive_qt_command(self):
|
||||
try:
|
||||
while True:
|
||||
data, addr = self.sock_qt.recvfrom(BUFFER_SIZE)
|
||||
self.qt_addr = addr
|
||||
text = data.decode('utf-8').strip()
|
||||
if text.startswith("MODE:"): self.change_mode(int(text.split(":")[1]))
|
||||
elif text.startswith("GOAL:"):
|
||||
if self.current_mode != 2: self.change_mode(2)
|
||||
p = text.split(":")[1].split(",")
|
||||
self.start_navigation(float(p[0]), float(p[1]))
|
||||
elif text.startswith("STOP"): self.change_mode(0)
|
||||
except BlockingIOError: pass
|
||||
except: pass
|
||||
|
||||
def control_loop(self):
|
||||
self.receive_uwb_data()
|
||||
self.receive_qt_command()
|
||||
|
||||
now = time.time()
|
||||
|
||||
if now - self.last_weight_check_time > self.weight_check_interval:
|
||||
self.trigger_async_weight_check()
|
||||
self.last_weight_check_time = now
|
||||
|
||||
if all(now - self.uwb_last_update[i] < 1.0 for i in range(3)):
|
||||
pos = self.calculate_trilateration(self.uwb_dists)
|
||||
if pos:
|
||||
raw_x = max(0, min(pos[0], 6.0))
|
||||
raw_y = max(0, min(pos[1], 15.0))
|
||||
self.x_his.append(raw_x)
|
||||
self.y_his.append(raw_y)
|
||||
avg_x = sum(self.x_his) / len(self.x_his)
|
||||
avg_y = sum(self.y_his) / len(self.y_his)
|
||||
|
||||
final_uwb_x = (avg_x / 6.0) * (3.80 - 0.10) + 0.10
|
||||
final_uwb_y = avg_y
|
||||
|
||||
mx, my = self.transform_to_map(final_uwb_x, final_uwb_y)
|
||||
self.human_x = mx
|
||||
self.human_y = my
|
||||
|
||||
if self.current_mode == 1:
|
||||
dist_diff = math.sqrt((mx - self.last_target_pos[0])**2 + (my - self.last_target_pos[1])**2)
|
||||
|
||||
if self.is_weight_ok:
|
||||
if (now - self.last_goal_time > NAV_UPDATE_INTERVAL) and (dist_diff > MIN_UPDATE_DIST):
|
||||
self.get_logger().info(f"Target Moved -> Goal: ({mx:.2f}, {my:.2f})")
|
||||
self.start_navigation(mx, my)
|
||||
self.last_goal_time = now
|
||||
self.last_target_pos = [mx, my]
|
||||
|
||||
if self.current_mode == 0:
|
||||
if self.nav_goal_handle: self.cancel_navigation()
|
||||
self.stop_robot()
|
||||
|
||||
def change_mode(self, new_mode):
|
||||
if self.current_mode == new_mode: return
|
||||
self.get_logger().info(f"Mode Switching: {self.current_mode} -> {new_mode}")
|
||||
self.cancel_navigation()
|
||||
self.stop_robot()
|
||||
self.current_mode = new_mode
|
||||
self.last_target_pos = [0.0, 0.0]
|
||||
self.trigger_async_weight_check()
|
||||
|
||||
# 네비게이션 실행
|
||||
def start_navigation(self, x, y):
|
||||
if not self.is_weight_ok: return
|
||||
|
||||
if not self.nav_to_pose_client.server_is_ready():
|
||||
self.get_logger().error("Nav2 Server not ready!")
|
||||
return
|
||||
|
||||
goal_msg = NavigateToPose.Goal()
|
||||
goal_msg.pose.header.frame_id = 'map'
|
||||
goal_msg.pose.header.stamp = self.get_clock().now().to_msg()
|
||||
goal_msg.pose.pose.position.x = x
|
||||
goal_msg.pose.pose.position.y = y
|
||||
goal_msg.pose.pose.orientation.w = 1.0
|
||||
self._send_goal_future = self.nav_to_pose_client.send_goal_async(goal_msg)
|
||||
self._send_goal_future.add_done_callback(self.goal_response_callback)
|
||||
|
||||
def goal_response_callback(self, future):
|
||||
handle = future.result()
|
||||
if handle.accepted:
|
||||
self.nav_goal_handle = handle
|
||||
self._get_result_future = handle.get_result_async()
|
||||
self._get_result_future.add_done_callback(self.get_result_callback)
|
||||
|
||||
def get_result_callback(self, future):
|
||||
result = future.result()
|
||||
if result.status == 4:
|
||||
self.send_udp_to_qt("STATUS:ARRIVED")
|
||||
self.nav_goal_handle = None
|
||||
|
||||
def cancel_navigation(self):
|
||||
if self.nav_goal_handle:
|
||||
self.nav_goal_handle.cancel_goal_async()
|
||||
self.nav_goal_handle = None
|
||||
|
||||
def stop_robot(self):
|
||||
msg = TwistStamped()
|
||||
msg.header.stamp = self.get_clock().now().to_msg()
|
||||
msg.header.frame_id = 'base_link'
|
||||
self.cmd_vel_pub.publish(msg)
|
||||
|
||||
def main():
|
||||
rclpy.init()
|
||||
node = IntegratedRosController()
|
||||
try: rclpy.spin(node)
|
||||
except KeyboardInterrupt: pass
|
||||
finally:
|
||||
node.destroy_node()
|
||||
rclpy.shutdown()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,253 @@
|
||||
body {
|
||||
background-color: #0f172a;
|
||||
color: #f1f5f9;
|
||||
font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 헤더 스타일 */
|
||||
header {
|
||||
background-color: #1e293b;
|
||||
border-bottom: 1px solid #334155;
|
||||
padding: 0 30px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.logo { font-weight: 800; font-size: 1.3rem; margin-right: 40px; color: #fff; }
|
||||
|
||||
nav { display: flex; gap: 10px; flex: 1; }
|
||||
|
||||
.nav-btn {
|
||||
text-decoration: none;
|
||||
color: #94a3b8;
|
||||
font-weight: 600;
|
||||
padding: 8px 16px;
|
||||
border-radius: 8px;
|
||||
transition: all 0.2s;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.nav-btn:hover { background-color: #334155; color: #fff; }
|
||||
.nav-btn.active { background-color: #3b82f6; color: #fff; box-shadow: 0 0 10px rgba(59, 130, 246, 0.3); }
|
||||
|
||||
/* 상단 상태 배지 */
|
||||
.status-group { display: flex; gap: 10px; }
|
||||
.status-badge {
|
||||
font-size: 0.8rem;
|
||||
padding: 4px 12px;
|
||||
border-radius: 99px;
|
||||
background-color: #334155;
|
||||
color: #94a3b8;
|
||||
font-weight: 700;
|
||||
display: flex; align-items: center; gap: 6px; border: 1px solid #475569;
|
||||
}
|
||||
.dot { width: 6px; height: 6px; border-radius: 50%; background-color: #94a3b8; }
|
||||
.status-badge.on { background-color: #064e3b; color: #34d399; border-color: #059669; }
|
||||
.status-badge.on .dot { background-color: #34d399; box-shadow: 0 0 4px #34d399; }
|
||||
.status-badge.off { background-color: #450a0a; color: #f87171; border-color: #b91c1c; }
|
||||
.status-badge.off .dot { background-color: #f87171; box-shadow: 0 0 4px #f87171; }
|
||||
|
||||
/* --- 메인 레이아웃 --- */
|
||||
main {
|
||||
padding: 20px;
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
overflow-y: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
/* 상단 카트 요약 그리드 */
|
||||
.cart-select-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.cart-summary-card {
|
||||
background-color: #1e293b;
|
||||
border: 2px solid #334155;
|
||||
border-radius: 12px;
|
||||
padding: 15px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.cart-summary-card:hover { transform: translateY(-2px); border-color: #64748b; }
|
||||
|
||||
.cart-summary-card.selected {
|
||||
border-color: #3b82f6;
|
||||
background-color: #1e293b;
|
||||
box-shadow: 0 0 15px rgba(59, 130, 246, 0.2);
|
||||
}
|
||||
|
||||
.summary-header { display: flex; justify-content: space-between; align-items: center; }
|
||||
.summary-name { font-weight: 700; color: #fff; font-size: 1rem; }
|
||||
.summary-status-dot { width: 8px; height: 8px; border-radius: 50%; background-color: #475569; }
|
||||
.summary-status-dot.online { background-color: #10b981; box-shadow: 0 0 5px #10b981; }
|
||||
.summary-status-dot.warning { background-color: #e45d0f; box-shadow: 0 0 5px #e45d0f; }
|
||||
.summary-status-dot.offline { background-color: #fa0303; box-shadow: 0 0 5px #e45d0f;}
|
||||
|
||||
.summary-row { display: flex; justify-content: space-between; font-size: 0.85rem; color: #94a3b8; }
|
||||
.summary-val { color: #f1f5f9; font-weight: 600; }
|
||||
|
||||
/* 하단 상세 패널 */
|
||||
.cart-panel {
|
||||
flex: 1;
|
||||
background-color: #1e293b;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
|
||||
border: 2px solid #334155;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
background-color: #0f172a;
|
||||
padding: 15px 25px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #334155;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.cart-info { display: flex; align-items: center; gap: 10px; }
|
||||
.cart-icon { font-size: 1.5rem; }
|
||||
.cart-name { font-size: 1.2rem; font-weight: 800; color: #fff; }
|
||||
.panel-status { font-weight: 700; font-size: 0.95rem; color: #64748b; }
|
||||
|
||||
/* --- 패널 내부 비율 (4:6) --- */
|
||||
.panel-body {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
/* 왼쪽 영역 (정보) */
|
||||
.panel-left {
|
||||
flex: 4;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-right: 1px solid #334155;
|
||||
min-width: 320px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* 오른쪽 영역 (지도) */
|
||||
.panel-right {
|
||||
flex: 6;
|
||||
background-color: #0f172a;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 센서 그리드 */
|
||||
.sensor-grid {
|
||||
padding: 25px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
gap: 15px;
|
||||
border-bottom: 1px solid #334155;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.data-box {
|
||||
background-color: #28364d;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
text-align: center;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
display: flex; flex-direction: column; justify-content: center;
|
||||
}
|
||||
.data-label { font-size: 0.9rem; color: #94a3b8; margin-bottom: 5px; font-weight: 600; }
|
||||
.data-value { font-size: 1.8rem; font-weight: 800; color: #fff; }
|
||||
.unit { font-size: 0.9rem; color: #64748b; font-weight: 500; margin-left: 3px; }
|
||||
|
||||
.val-normal { color: #38bdf8; }
|
||||
.val-warning { color: #f87171; }
|
||||
.val-success { color: #34d399; }
|
||||
.val-offline { color: #64748b; }
|
||||
|
||||
/* 아이템 리스트 */
|
||||
.items-section {
|
||||
padding: 25px;
|
||||
background-color: #1e293b;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.items-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; }
|
||||
.items-title { font-size: 1.1rem; font-weight: 700; color: #e2e8f0; }
|
||||
.items-summary { font-size: 0.95rem; color: #94a3b8; font-weight: 600; }
|
||||
.total-price { color: #34d399; font-weight: 800; font-size: 1.1rem; margin-left: 8px; }
|
||||
|
||||
.table-scroll-box {
|
||||
flex: 1; overflow-y: auto;
|
||||
border: 1px solid #334155; border-radius: 8px;
|
||||
background-color: #1e293b;
|
||||
min-height: 150px;
|
||||
}
|
||||
.table-scroll-box::-webkit-scrollbar { width: 8px; }
|
||||
.table-scroll-box::-webkit-scrollbar-track { background: #1e293b; }
|
||||
.table-scroll-box::-webkit-scrollbar-thumb { background: #475569; border-radius: 4px; }
|
||||
|
||||
.items-table { width: 100%; border-collapse: collapse; font-size: 0.95rem; }
|
||||
.items-table th {
|
||||
text-align: left; color: #94a3b8; padding: 12px 20px; background-color: #0f172a;
|
||||
position: sticky; top: 0; z-index: 1; border-bottom: 1px solid #334155; font-size: 0.85rem; font-weight: 700;
|
||||
}
|
||||
.items-table td { padding: 12px 20px; border-bottom: 1px solid #334155; color: #f1f5f9; }
|
||||
.items-table tr:hover td { background-color: #334155; }
|
||||
|
||||
/* 지도 헤더 */
|
||||
.map-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.map-title { font-size: 1.1rem; font-weight: 700; color: #e2e8f0; }
|
||||
.map-coords { font-family: monospace; color: #34d399; font-size: 0.9rem; }
|
||||
|
||||
/* 캔버스 컨테이너 */
|
||||
.canvas-container {
|
||||
flex: 1;
|
||||
background-color: #020617;
|
||||
border: 1px solid #334155;
|
||||
border-radius: 8px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
canvas {
|
||||
background-color: transparent;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/* --- 다크 모드 기본 스타일 --- */
|
||||
body {
|
||||
background-color: #0f172a;
|
||||
color: #f1f5f9;
|
||||
font-family: 'Pretendard', sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* --- 헤더 --- */
|
||||
header {
|
||||
background-color: #1e293b;
|
||||
color: #fff;
|
||||
border-bottom: 1px solid #334155;
|
||||
padding: 0 30px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.logo { font-weight: 800; font-size: 1.3rem; margin-right: 40px; }
|
||||
|
||||
nav { display: flex; gap: 10px; flex: 1; }
|
||||
.nav-btn { text-decoration: none; color: #94a3b8; font-weight: 600; padding: 8px 16px; border-radius: 8px; transition: all 0.2s; font-size: 0.9rem; }
|
||||
.nav-btn:hover { background-color: #334155; color: #fff; }
|
||||
.nav-btn.active { background-color: #3b82f6; color: #fff; box-shadow: 0 0 10px rgba(59, 130, 246, 0.3); }
|
||||
|
||||
.container { display: flex; flex-direction: column; flex: 1; min-height: 0; padding: 20px; gap: 20px; box-sizing: border-box; }
|
||||
|
||||
/* 다크 모드 섹션 스타일 */
|
||||
.inventory-section {
|
||||
flex: 1;
|
||||
background: #1e293b;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
border: 1px solid #334155;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #334155;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: 700;
|
||||
font-size: 1.1rem;
|
||||
color: #e2e8f0;
|
||||
background-color: #0f172a;
|
||||
}
|
||||
|
||||
.table-wrapper { flex: 1; overflow-y: auto; }
|
||||
|
||||
/* 다크 모드 테이블 */
|
||||
table { width: 100%; border-collapse: collapse; font-size: 0.95rem; }
|
||||
th {
|
||||
position: sticky; top: 0;
|
||||
background-color: #0f172a;
|
||||
color: #94a3b8;
|
||||
padding: 12px 20px;
|
||||
text-align: left;
|
||||
border-bottom: 2px solid #334155;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 700;
|
||||
z-index: 10;
|
||||
}
|
||||
td {
|
||||
padding: 12px 20px;
|
||||
border-bottom: 1px solid #334155;
|
||||
color: #f1f5f9;
|
||||
vertical-align: middle;
|
||||
}
|
||||
tr:hover td { background-color: #334155; }
|
||||
|
||||
.sortable { cursor: pointer; user-select: none; transition: color 0.2s; }
|
||||
.sortable:hover { color: #3b82f6; background-color: #1e293b; }
|
||||
|
||||
/* 다크 모드 배지 스타일 */
|
||||
.badge { padding: 4px 10px; border-radius: 6px; font-size: 0.8rem; font-weight: 700; display: inline-block; min-width: 80px; text-align: center; }
|
||||
|
||||
.expiry-expired { background-color: #450a0a; color: #f87171; border: 1px solid #b91c1c; } /* 만료 */
|
||||
.expiry-warning { background-color: #422006; color: #fbbf24; border: 1px solid #b45309; } /* 임박 */
|
||||
.expiry-good { background-color: #064e3b; color: #34d399; border: 1px solid #059669; } /* 안전 */
|
||||
|
||||
.stock-badge { padding: 4px 10px; border-radius: 6px; font-size: 0.8rem; font-weight: 700; display: inline-block; text-align: center; }
|
||||
.stock-low { background-color: #450a0a; color: #f87171; border: 1px solid #b91c1c; }
|
||||
.stock-normal { background-color: #334155; color: #94a3b8; border: 1px solid #475569; }
|
||||
|
||||
/* 매출 섹션 */
|
||||
.sales-section { flex: 1; display: flex; gap: 20px; min-height: 0; }
|
||||
.kpi-container { display: flex; flex-direction: column; gap: 15px; width: 250px; flex-shrink: 0; }
|
||||
|
||||
.kpi-card {
|
||||
background: #1e293b;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
border: 1px solid #334155;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
.kpi-title { font-size: 0.9rem; color: #94a3b8; margin-bottom: 5px; font-weight: 600; }
|
||||
.kpi-value { font-size: 1.8rem; font-weight: 800; color: #fff; }
|
||||
.kpi-icon { font-size: 2rem; margin-bottom: 10px; }
|
||||
|
||||
.chart-container {
|
||||
flex: 1;
|
||||
background: #1e293b;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #334155;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar { width: 8px; }
|
||||
::-webkit-scrollbar-track { background: #0f172a; }
|
||||
::-webkit-scrollbar-thumb { background: #475569; border-radius: 4px; }
|
||||
::-webkit-scrollbar-thumb:hover { background: #64748b; }
|
||||
@@ -0,0 +1,341 @@
|
||||
let currentCartId = 1;
|
||||
|
||||
const mapImg = new Image();
|
||||
mapImg.src = "/static/map601.png";
|
||||
|
||||
const MAP_BOUNDS = {
|
||||
LEFT_X: -0.67,
|
||||
RIGHT_X: 3.34,
|
||||
TOP_Y: 1.66,
|
||||
BOTTOM_Y: -7.4
|
||||
};
|
||||
|
||||
const allCartsData = {
|
||||
1: { id: 1, name: "QTCART 1호차", isOnline: false, battery: 0, speed: 0, weight: 0, expected: 0, items: [], status: "OFFLINE", x: 0.0, y: 0.0, human_x: 0.0, human_y: 0.0 },
|
||||
2: { id: 2, name: "QTCART 2호차", isOnline: true, battery: 92, speed: 50, weight: 710, expected: 700, items: generateMockItems(3), status: "ONLINE", x: 1.5, y: 1.0 },
|
||||
3: { id: 3, name: "QTCART 3호차", isOnline: true, battery: 34, speed: 0, weight: 0, expected: 0, items: [], status: "ONLINE", x: -0.67, y: 1.66 },
|
||||
4: { id: 4, name: "QTCART 4호차", isOnline: true, battery: 65, speed: 0, weight: 0, expected: 0, items: [], status: "ONLINE", x: 3.34, y: -7.4 }
|
||||
};
|
||||
|
||||
function generateMockItems(count) {
|
||||
const mockDb = [
|
||||
{name: "코카콜라 500ml", price: 2000, weight: 500},
|
||||
{name: "포카칩 오리지널", price: 1500, weight: 100},
|
||||
{name: "제주 삼다수 2L", price: 1000, weight: 2000},
|
||||
{name: "신라면 멀티팩", price: 4500, weight: 600}
|
||||
];
|
||||
let items = [];
|
||||
for(let i=0; i<count; i++) {
|
||||
const rand = mockDb[Math.floor(Math.random() * mockDb.length)];
|
||||
items.push({...rand, id: 100+i});
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
// 주기적으로 데이터 갱신
|
||||
async function updateDashboard() {
|
||||
const apiBadge = document.getElementById('apiBadge');
|
||||
|
||||
try {
|
||||
// 로봇 상태 조회
|
||||
const botRes = await fetch('/dashboard/bot/check');
|
||||
const botData = await botRes.json();
|
||||
|
||||
// 카트 상태 조회
|
||||
let cartData = null;
|
||||
try {
|
||||
const cRes = await fetch('/cart/status');
|
||||
if(cRes.ok) cartData = await cRes.json();
|
||||
} catch(e) {}
|
||||
|
||||
apiBadge.className = 'status-badge on';
|
||||
apiBadge.innerHTML = '<span class="dot"></span> 서버 연결됨';
|
||||
|
||||
const c1 = allCartsData[1];
|
||||
|
||||
if(botData.bot_status === 'ONLINE') {
|
||||
c1.isOnline = true;
|
||||
c1.status = "ONLINE";
|
||||
|
||||
const batVal = parseFloat(botData.battery);
|
||||
c1.battery = isNaN(batVal) ? 0 : Math.round(batVal);
|
||||
|
||||
c1.speed = Math.abs(Math.round(botData.speed * 100));
|
||||
|
||||
// 좌표 업데이트
|
||||
c1.x = botData.x !== undefined ? botData.x : 0.0;
|
||||
c1.y = botData.y !== undefined ? botData.y : 0.0;
|
||||
c1.human_x = botData.human_x !== undefined ? botData.human_x : 0.0;
|
||||
c1.human_y = botData.human_y !== undefined ? botData.human_y : 0.0;
|
||||
|
||||
// 카트 데이터 업데이트
|
||||
if(cartData) {
|
||||
c1.weight = cartData.real_weight;
|
||||
c1.expected = cartData.expected_weight;
|
||||
c1.items = cartData.cart_items || [];
|
||||
|
||||
if(cartData.system_status === "WARNING_WEIGHT_MISMATCH") {
|
||||
c1.status = "WARNING";
|
||||
} else {
|
||||
c1.status = "ONLINE";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
c1.isOnline = false;
|
||||
c1.status = "OFFLINE";
|
||||
c1.speed = 0;
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
apiBadge.className = 'status-badge off';
|
||||
apiBadge.innerHTML = '<span class="dot"></span> 서버 끊김';
|
||||
|
||||
allCartsData[1].isOnline = false;
|
||||
allCartsData[1].status = "OFFLINE";
|
||||
}
|
||||
|
||||
updateMockData(2);
|
||||
updateMockData(3);
|
||||
updateMockData(4);
|
||||
|
||||
renderGrid();
|
||||
renderDetailPanel();
|
||||
drawMap();
|
||||
}
|
||||
|
||||
function updateMockData(id) {
|
||||
const c = allCartsData[id];
|
||||
if(!c.isOnline) return;
|
||||
if(Math.random() > 0.98) c.battery = Math.max(0, c.battery - 1);
|
||||
if(Math.random() > 0.7) c.speed = Math.floor(Math.random() * 80);
|
||||
c.x += (Math.random() - 0.5) * 0.1;
|
||||
c.y += (Math.random() - 0.5) * 0.1;
|
||||
}
|
||||
|
||||
function renderGrid() {
|
||||
const grid = document.getElementById('cartGrid');
|
||||
grid.innerHTML = '';
|
||||
|
||||
for(let i=1; i<=4; i++) {
|
||||
const data = allCartsData[i];
|
||||
const isSelected = (i === currentCartId) ? 'selected' : '';
|
||||
let dotClass = 'offline';
|
||||
let statusColor = '#64748b';
|
||||
|
||||
if(data.isOnline) {
|
||||
if(data.status === 'WARNING') {
|
||||
dotClass = 'warning';
|
||||
statusColor = '#fbbf24';
|
||||
} else {
|
||||
dotClass = 'online';
|
||||
statusColor = '#34d399';
|
||||
}
|
||||
}
|
||||
|
||||
const speedDisplay = data.isOnline ? `${data.speed} cm/s` : '--';
|
||||
|
||||
const html = `
|
||||
<div class="cart-summary-card ${isSelected}" onclick="selectCart(${i})">
|
||||
<div class="summary-header">
|
||||
<div class="summary-name">${data.name}</div>
|
||||
<div class="summary-status-dot ${dotClass}" style="${dotClass === 'warning' ? 'background-color:#f97316; box-shadow:0 0 5px #f97316;' : ''}"></div>
|
||||
</div>
|
||||
<div class="summary-row" style="margin-top:5px;">
|
||||
<span>배터리</span>
|
||||
<span class="summary-val" style="color:${statusColor}">${data.isOnline ? data.battery+'%' : '-'}</span>
|
||||
</div>
|
||||
<div class="summary-row">
|
||||
<span>현재 속도</span> <span class="summary-val">${speedDisplay}</span> </div>
|
||||
</div>`;
|
||||
grid.innerHTML += html;
|
||||
}
|
||||
}
|
||||
|
||||
function renderDetailPanel() {
|
||||
const data = allCartsData[currentCartId];
|
||||
const statusText = document.getElementById('detailStatusText');
|
||||
const panel = document.getElementById('detailPanel');
|
||||
|
||||
document.getElementById('detailName').innerText = data.name;
|
||||
|
||||
if(data.isOnline) {
|
||||
if(data.status === 'WARNING') {
|
||||
statusText.innerText = '● 무게 불일치 경고';
|
||||
statusText.style.color = '#fbbf24';
|
||||
panel.style.borderColor = '#fbbf24';
|
||||
} else {
|
||||
statusText.innerText = '● 온라인';
|
||||
statusText.style.color = '#34d399';
|
||||
panel.style.borderColor = '#334155';
|
||||
}
|
||||
} else {
|
||||
statusText.innerText = '● 오프라인';
|
||||
statusText.style.color = '#f87171';
|
||||
panel.style.borderColor = '#ef4444';
|
||||
}
|
||||
|
||||
const elReal = document.getElementById('detailReal');
|
||||
const elExp = document.getElementById('detailExpected');
|
||||
const elBat = document.getElementById('detailBattery');
|
||||
const elSpd = document.getElementById('detailSpeed');
|
||||
|
||||
if(data.isOnline) {
|
||||
elReal.innerText = typeof data.weight === 'number' ? data.weight.toFixed(1) : data.weight;
|
||||
elExp.innerText = typeof data.expected === 'number' ? data.expected.toFixed(1) : data.expected;
|
||||
elBat.innerText = data.battery;
|
||||
elSpd.innerText = data.speed;
|
||||
|
||||
elBat.parentElement.className = data.battery < 20 ? "data-value val-warning" : "data-value val-success";
|
||||
if(data.status === 'WARNING') elReal.parentElement.className = "data-value val-warning";
|
||||
else elReal.parentElement.className = "data-value val-normal";
|
||||
} else {
|
||||
elReal.innerText = '--';
|
||||
elExp.innerText = '--';
|
||||
elBat.innerText = '--';
|
||||
elSpd.innerText = '--';
|
||||
elReal.parentElement.className = "data-value val-offline";
|
||||
elBat.parentElement.className = "data-value val-offline";
|
||||
}
|
||||
|
||||
const tbody = document.getElementById('detailListBody');
|
||||
const countEl = document.getElementById('detailCount');
|
||||
const priceEl = document.getElementById('detailPrice');
|
||||
|
||||
if(!data.isOnline || data.items.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="4" style="text-align: center; color: #64748b; padding: 30px;">데이터 없음</td></tr>';
|
||||
countEl.innerText = '0';
|
||||
priceEl.innerText = '0원';
|
||||
} else {
|
||||
const agg = {};
|
||||
let totalP = 0;
|
||||
let totalC = 0;
|
||||
data.items.forEach(item => {
|
||||
if(agg[item.name]) agg[item.name].qty++;
|
||||
else agg[item.name] = {...item, qty: 1};
|
||||
totalP += item.price;
|
||||
totalC++;
|
||||
});
|
||||
let html = '';
|
||||
Object.values(agg).forEach(item => {
|
||||
html += `<tr>
|
||||
<td style="font-weight:600;">${item.name}</td>
|
||||
<td style="text-align: right;">${item.price.toLocaleString()}원</td>
|
||||
<td style="text-align: right;">${item.weight}g</td>
|
||||
<td style="text-align: right; font-weight: bold; color: #38bdf8;">${item.qty}</td>
|
||||
</tr>`;
|
||||
});
|
||||
tbody.innerHTML = html;
|
||||
countEl.innerText = totalC;
|
||||
priceEl.innerText = totalP.toLocaleString() + '원';
|
||||
}
|
||||
}
|
||||
|
||||
function drawMap() {
|
||||
const canvas = document.getElementById('robotMap');
|
||||
if(!canvas) return;
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
const data = allCartsData[currentCartId];
|
||||
|
||||
const container = canvas.parentElement;
|
||||
if(canvas.width !== container.clientWidth || canvas.height !== container.clientHeight) {
|
||||
canvas.width = container.clientWidth;
|
||||
canvas.height = container.clientHeight;
|
||||
}
|
||||
const cvsW = canvas.width;
|
||||
const cvsH = canvas.height;
|
||||
ctx.clearRect(0, 0, cvsW, cvsH);
|
||||
|
||||
// 이미지 로딩 체크
|
||||
if (!mapImg.complete || mapImg.naturalWidth === 0) {
|
||||
ctx.fillStyle = '#94a3b8';
|
||||
ctx.font = '14px sans-serif';
|
||||
ctx.fillText("Loading Map...", 20, 30);
|
||||
return;
|
||||
}
|
||||
|
||||
const imgW = mapImg.naturalWidth;
|
||||
const imgH = mapImg.naturalHeight;
|
||||
const imgRatio = imgW / imgH;
|
||||
const cvsRatio = cvsW / cvsH;
|
||||
|
||||
let drawW, drawH, drawX, drawY;
|
||||
|
||||
if (cvsRatio > imgRatio) {
|
||||
drawH = cvsH;
|
||||
drawW = cvsH * imgRatio;
|
||||
drawX = (cvsW - drawW) / 2;
|
||||
drawY = 0;
|
||||
} else {
|
||||
drawW = cvsW;
|
||||
drawH = cvsW / imgRatio;
|
||||
drawX = 0;
|
||||
drawY = (cvsH - drawH) / 2;
|
||||
}
|
||||
ctx.drawImage(mapImg, drawX, drawY, drawW, drawH);
|
||||
|
||||
const toPixel = (rosX, rosY) => {
|
||||
const xRange = MAP_BOUNDS.RIGHT_X - MAP_BOUNDS.LEFT_X;
|
||||
let ratioX = (rosX - MAP_BOUNDS.LEFT_X) / xRange;
|
||||
|
||||
const yRange = MAP_BOUNDS.BOTTOM_Y - MAP_BOUNDS.TOP_Y;
|
||||
let ratioY = (rosY - MAP_BOUNDS.TOP_Y) / yRange;
|
||||
|
||||
let finalX = drawX + (ratioX * drawW);
|
||||
let finalY = drawY + (ratioY * drawH);
|
||||
return { x: finalX, y: finalY };
|
||||
};
|
||||
|
||||
if (data.isOnline) {
|
||||
console.log(`Robot(${data.x}, ${data.y})`);
|
||||
|
||||
const botPos = toPixel(data.x, data.y);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(botPos.x, botPos.y, 6, 0, Math.PI * 2);
|
||||
|
||||
let color = (currentCartId === 1) ? '#ef4444' : (data.status === 'WARNING' ? '#fbbf24' : '#34d399');
|
||||
ctx.fillStyle = color;
|
||||
ctx.fill();
|
||||
|
||||
ctx.strokeStyle = '#ffffff';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.font = 'bold 12px sans-serif';
|
||||
ctx.fillText("BOT", botPos.x + 10, botPos.y + 4);
|
||||
|
||||
if (currentCartId === 1) {
|
||||
const humanPos = toPixel(data.human_x, data.human_y);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(humanPos.x, humanPos.y, 6, 0, Math.PI * 2);
|
||||
ctx.fillStyle = '#3b82f6';
|
||||
ctx.fill();
|
||||
|
||||
ctx.strokeStyle = '#ffffff';
|
||||
ctx.stroke();
|
||||
|
||||
ctx.fillStyle = '#3b82f6';
|
||||
ctx.fillText("ME", humanPos.x + 10, humanPos.y + 4);
|
||||
}
|
||||
|
||||
const coordEl = document.getElementById('mapCoords');
|
||||
if(coordEl) coordEl.innerText = `Robot: (${data.x.toFixed(2)}, ${data.y.toFixed(2)})`;
|
||||
} else {
|
||||
const coordEl = document.getElementById('mapCoords');
|
||||
if(coordEl) coordEl.innerText = "OFFLINE";
|
||||
}
|
||||
}
|
||||
|
||||
function selectCart(id) {
|
||||
currentCartId = id;
|
||||
renderGrid();
|
||||
renderDetailPanel();
|
||||
drawMap();
|
||||
}
|
||||
|
||||
// 1초마다 갱신
|
||||
setInterval(updateDashboard, 1000);
|
||||
updateDashboard();
|
||||
@@ -0,0 +1,151 @@
|
||||
let currentItems = [];
|
||||
|
||||
function refreshAll() {
|
||||
fetchInventory();
|
||||
fetchSalesStats();
|
||||
}
|
||||
|
||||
async function fetchInventory() {
|
||||
try {
|
||||
const res = await fetch('/items');
|
||||
if (res.ok) {
|
||||
currentItems = await res.json();
|
||||
renderTable('expiry');
|
||||
}
|
||||
} catch (e) { console.error(e); }
|
||||
}
|
||||
|
||||
function renderTable(sortKey) {
|
||||
const tbody = document.getElementById('inventoryBody');
|
||||
|
||||
if (sortKey === 'expiry') {
|
||||
currentItems.sort((a, b) => new Date(a.expiry_date) - new Date(b.expiry_date));
|
||||
} else if (sortKey === 'stock') {
|
||||
currentItems.sort((a, b) => a.stock - b.stock);
|
||||
}
|
||||
|
||||
const today = new Date();
|
||||
today.setHours(0,0,0,0);
|
||||
|
||||
let html = currentItems.map(item => {
|
||||
const expiryDate = new Date(item.expiry_date);
|
||||
const diffTime = expiryDate - today;
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
|
||||
let dateClass = 'expiry-good';
|
||||
let dateText = `D-${diffDays}`;
|
||||
|
||||
if (diffDays < 0) {
|
||||
dateClass = 'expiry-expired';
|
||||
dateText = '만료됨';
|
||||
} else if (diffDays === 0) {
|
||||
dateClass = 'expiry-warning';
|
||||
dateText = '오늘 만료';
|
||||
} else if (diffDays <= 3) {
|
||||
dateClass = 'expiry-warning';
|
||||
dateText = `${diffDays}일 남음`;
|
||||
}
|
||||
|
||||
let stockHtml = '';
|
||||
if (item.stock === 0) {
|
||||
stockHtml = `<span class="stock-badge stock-low">부족 (${item.stock})</span>`;
|
||||
} else {
|
||||
stockHtml = `<span class="stock-badge stock-normal">${item.stock}개</span>`;
|
||||
}
|
||||
|
||||
return `<tr>
|
||||
<td style="color:#94a3b8;">#${item.id}</td>
|
||||
<td style="font-weight: bold;">${item.name}</td>
|
||||
<td>${item.price.toLocaleString()}원</td>
|
||||
<td>
|
||||
<span class="badge ${dateClass}">${item.expiry_date} (${dateText})</span>
|
||||
</td>
|
||||
<td>${stockHtml}</td>
|
||||
</tr>`;
|
||||
}).join('');
|
||||
|
||||
tbody.innerHTML = html || '<tr><td colspan="5" style="text-align:center; padding:30px; color:#64748b;">등록된 상품이 없습니다.</td></tr>';
|
||||
}
|
||||
|
||||
let myChart = null;
|
||||
|
||||
// ----- 결제 정보 -----
|
||||
async function fetchSalesStats() {
|
||||
try {
|
||||
const res = await fetch('/payments');
|
||||
if (!res.ok) return;
|
||||
const payments = await res.json();
|
||||
|
||||
const today = new Date();
|
||||
const thirtyDaysAgo = new Date();
|
||||
thirtyDaysAgo.setDate(today.getDate() - 30);
|
||||
|
||||
let monthTotal = 0;
|
||||
let monthCount = 0;
|
||||
const dailySales = {};
|
||||
|
||||
for (let i = 0; i < 30; i++) {
|
||||
const d = new Date();
|
||||
d.setDate(today.getDate() - i);
|
||||
dailySales[d.toISOString().split('T')[0]] = 0;
|
||||
}
|
||||
|
||||
payments.forEach(pay => {
|
||||
const payDate = new Date(pay.created_at);
|
||||
if (payDate >= thirtyDaysAgo) {
|
||||
monthTotal += pay.total_price;
|
||||
monthCount += 1;
|
||||
const dateStr = pay.created_at.split('T')[0];
|
||||
if (dailySales[dateStr] !== undefined) dailySales[dateStr] += pay.total_price;
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('monthTotal').innerText = monthTotal.toLocaleString() + '원';
|
||||
document.getElementById('monthCount').innerText = monthCount + '건';
|
||||
updateChart(dailySales);
|
||||
|
||||
} catch (e) { console.error(e); }
|
||||
}
|
||||
|
||||
function updateChart(dailyData) {
|
||||
const sortedDates = Object.keys(dailyData).sort();
|
||||
const dataValues = sortedDates.map(date => dailyData[date]);
|
||||
const labels = sortedDates.map(date => date.slice(5));
|
||||
|
||||
const ctx = document.getElementById('salesChart').getContext('2d');
|
||||
if (myChart) myChart.destroy();
|
||||
|
||||
myChart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: '매출 (원)',
|
||||
data: dataValues,
|
||||
borderColor: '#8b5cf6',
|
||||
backgroundColor: 'rgba(139, 92, 246, 0.2)',
|
||||
borderWidth: 2,
|
||||
fill: true,
|
||||
tension: 0.3
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: { legend: { display: false } },
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
grid: { borderDash: [5, 5], color: '#334155' },
|
||||
ticks: { color: '#94a3b8' }
|
||||
},
|
||||
x: {
|
||||
grid: { display: false },
|
||||
ticks: { color: '#94a3b8' }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
refreshAll();
|
||||
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,98 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>QTCART 관제 시스템</title>
|
||||
<link rel="stylesheet" href="/static/css/dashboard.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="logo">🛒 QT-CART</div>
|
||||
<nav>
|
||||
<a href="/dashboard" class="nav-btn active">관제 모니터링</a>
|
||||
<a href="/inventory" class="nav-btn">통합 관리</a>
|
||||
</nav>
|
||||
<div class="status-group">
|
||||
<div id="apiBadge" class="status-badge off"><span class="dot"></span> 서버 연결</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div class="cart-select-grid" id="cartGrid">
|
||||
</div>
|
||||
|
||||
<div id="detailPanel" class="cart-panel">
|
||||
<div class="panel-header">
|
||||
<div class="cart-info">
|
||||
<div class="cart-icon">🛒</div>
|
||||
<div class="cart-name" id="detailName">QTCART 1호차</div>
|
||||
</div>
|
||||
<div id="detailStatusText" class="panel-status">● 데이터 로딩중</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
|
||||
<div class="panel-left">
|
||||
<div class="sensor-grid">
|
||||
<div class="data-box">
|
||||
<div class="data-label">배터리 잔량</div>
|
||||
<div class="data-value"><span id="detailBattery">--</span><span class="unit">%</span></div>
|
||||
</div>
|
||||
<div class="data-box">
|
||||
<div class="data-label">현재 속도</div>
|
||||
<div class="data-value"><span id="detailSpeed">--</span><span class="unit">cm/s</span></div>
|
||||
</div>
|
||||
<div class="data-box">
|
||||
<div class="data-label">기대 무게</div>
|
||||
<div class="data-value" style="color:#fbbf24;"><span id="detailExpected">0</span><span class="unit">g</span></div>
|
||||
</div>
|
||||
<div class="data-box">
|
||||
<div class="data-label">실제 무게</div>
|
||||
<div class="data-value"><span id="detailReal">--</span><span class="unit">g</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="items-section">
|
||||
<div class="items-header">
|
||||
<div class="items-title">📦 담긴 상품 목록</div>
|
||||
<div class="items-summary">
|
||||
총 <span id="detailCount">0</span>개
|
||||
<span class="total-price" id="detailPrice">0원</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-scroll-box">
|
||||
<table class="items-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>상품명</th>
|
||||
<th style="text-align: right;">단가</th>
|
||||
<th style="text-align: right;">무게</th>
|
||||
<th style="text-align: right;">수량</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="detailListBody">
|
||||
<tr><td colspan="4" style="text-align: center; color: #64748b; padding: 30px;">데이터 없음</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-right">
|
||||
<div class="map-header">
|
||||
<div class="map-title">🗺️ 실시간 위치</div>
|
||||
<div class="map-coords" id="mapCoords">X: 0.0, Y: 0.0</div>
|
||||
</div>
|
||||
<div class="canvas-container">
|
||||
<canvas id="robotMap" width="500" height="400"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="/static/js/dashboard.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>QTCART 통합 관리</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<link rel="stylesheet" href="/static/css/inventory.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="logo">🛒 QT-CART</div>
|
||||
<nav>
|
||||
<a href="/dashboard" class="nav-btn">관제 모니터링</a>
|
||||
<a href="/inventory" class="nav-btn active">통합 관리</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
<div class="inventory-section">
|
||||
<div class="section-header">
|
||||
📦 재고 및 유통기한 관리
|
||||
<button onclick="refreshAll()" style="background:none; border:none; color:#3b82f6; cursor:pointer; font-weight:600;">🔄 새로고침</button>
|
||||
</div>
|
||||
<div class="table-wrapper">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="10%">ID</th>
|
||||
<th width="30%">상품명</th>
|
||||
<th width="20%">가격</th>
|
||||
<th width="25%" class="sortable" onclick="renderTable('expiry')">유통기한 ▼</th>
|
||||
<th width="15%" class="sortable" onclick="renderTable('stock')">재고량 ▼</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="inventoryBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sales-section">
|
||||
<div class="kpi-container">
|
||||
<div class="kpi-card">
|
||||
<div class="kpi-icon">💰</div>
|
||||
<div class="kpi-title">이번 달 총 매출</div>
|
||||
<div class="kpi-value" id="monthTotal">0원</div>
|
||||
</div>
|
||||
<div class="kpi-card">
|
||||
<div class="kpi-icon">🧾</div>
|
||||
<div class="kpi-title">이번 달 거래 수</div>
|
||||
<div class="kpi-value" id="monthCount">0건</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
<div style="font-weight:700; color:#e2e8f0; margin-bottom:10px;">📉 최근 30일 매출 추이</div>
|
||||
<div style="flex:1; position: relative;">
|
||||
<canvas id="salesChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/inventory.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,23 +0,0 @@
|
||||
QMAKE_CXX.QT_COMPILER_STDCXX = 201703L
|
||||
QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 11
|
||||
QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 4
|
||||
QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 0
|
||||
QMAKE_CXX.COMPILER_MACROS = \
|
||||
QT_COMPILER_STDCXX \
|
||||
QMAKE_GCC_MAJOR_VERSION \
|
||||
QMAKE_GCC_MINOR_VERSION \
|
||||
QMAKE_GCC_PATCH_VERSION
|
||||
QMAKE_CXX.INCDIRS = \
|
||||
/usr/include/c++/11 \
|
||||
/usr/include/x86_64-linux-gnu/c++/11 \
|
||||
/usr/include/c++/11/backward \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/11/include \
|
||||
/usr/local/include \
|
||||
/usr/include/x86_64-linux-gnu \
|
||||
/usr/include
|
||||
QMAKE_CXX.LIBDIRS = \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/11 \
|
||||
/usr/lib/x86_64-linux-gnu \
|
||||
/usr/lib \
|
||||
/lib/x86_64-linux-gnu \
|
||||
/lib
|
||||
@@ -1,346 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 18.0.0, 2025-12-08T19:19:38. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{63b9673a-654d-4546-b58a-b51c28d2b22b}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="qlonglong">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoDetect">true</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.LineEndingBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="int" key="EditorConfiguration.PreferAfterWhitespaceComments">0</value>
|
||||
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">2</value>
|
||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
||||
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
|
||||
<value type="bool" key="AutoTest.Framework.Boost">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.CTest">false</value>
|
||||
<value type="bool" key="AutoTest.Framework.Catch">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.GTest">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
|
||||
</valuemap>
|
||||
<value type="bool" key="AutoTest.ApplyFilter">false</value>
|
||||
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
|
||||
<valuelist type="QVariantList" key="AutoTest.PathFilters"/>
|
||||
<value type="int" key="AutoTest.RunAfterBuild">0</value>
|
||||
<value type="bool" key="AutoTest.UseGlobal">true</value>
|
||||
<valuemap type="QVariantMap" key="ClangTools">
|
||||
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||
<value type="int" key="ClangTools.ParallelJobs">2</value>
|
||||
<value type="bool" key="ClangTools.PreferConfigFile">true</value>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||
</valuemap>
|
||||
<value type="int" key="RcSync">0</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="DeviceType">Desktop</value>
|
||||
<value type="bool" key="HasPerBcDcs">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{69eb4bf4-1a59-4f97-a489-e2827346197c}</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="int" key="EnableQmlDebugging">0</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/ubuntu/QT/src/QTCart/build/Desktop-Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/ubuntu/QT/src/QTCart/build/Desktop-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/ubuntu/QT/src/QTCart/QTCart.pro</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/ubuntu/QT/src/QTCart/QTCart.pro</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.1</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="DeviceType">Desktop</value>
|
||||
<value type="bool" key="HasPerBcDcs">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 6.8.3</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Qt 6.8.3</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{3ff0c7d5-10d9-474f-80e6-cba74e9bcfa2}</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="int" key="EnableQmlDebugging">0</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/ubuntu/QT/src/QTCart/build/Qt_6_8_3-Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/ubuntu/QT/src/QTCart/build/Qt_6_8_3-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="qlonglong">2</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>Version</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
</qtcreator>
|
||||
@@ -1,23 +0,0 @@
|
||||
QMAKE_CXX.QT_COMPILER_STDCXX = 201703L
|
||||
QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 11
|
||||
QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 4
|
||||
QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 0
|
||||
QMAKE_CXX.COMPILER_MACROS = \
|
||||
QT_COMPILER_STDCXX \
|
||||
QMAKE_GCC_MAJOR_VERSION \
|
||||
QMAKE_GCC_MINOR_VERSION \
|
||||
QMAKE_GCC_PATCH_VERSION
|
||||
QMAKE_CXX.INCDIRS = \
|
||||
/usr/include/c++/11 \
|
||||
/usr/include/x86_64-linux-gnu/c++/11 \
|
||||
/usr/include/c++/11/backward \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/11/include \
|
||||
/usr/local/include \
|
||||
/usr/include/x86_64-linux-gnu \
|
||||
/usr/include
|
||||
QMAKE_CXX.LIBDIRS = \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/11 \
|
||||
/usr/lib/x86_64-linux-gnu \
|
||||
/usr/lib \
|
||||
/lib/x86_64-linux-gnu \
|
||||
/lib
|
||||
@@ -1,434 +0,0 @@
|
||||
#############################################################################
|
||||
# Makefile for building: QTCart
|
||||
# Generated by qmake (3.1) (Qt 6.2.4)
|
||||
# Project: ../../QTCart.pro
|
||||
# Template: app
|
||||
# Command: /usr/lib/qt6/bin/qmake -o Makefile ../../QTCart.pro -spec linux-g++ CONFIG+=debug CONFIG+=qml_debug
|
||||
#############################################################################
|
||||
|
||||
MAKEFILE = Makefile
|
||||
|
||||
EQ = =
|
||||
|
||||
####### Compiler, tools and options
|
||||
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
DEFINES = -DQT_QML_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB
|
||||
CFLAGS = -pipe -g -Wall -Wextra -D_REENTRANT -fPIC $(DEFINES)
|
||||
CXXFLAGS = -pipe -g -std=gnu++1z -Wall -Wextra -D_REENTRANT -fPIC $(DEFINES)
|
||||
INCPATH = -I../../../QTCart -I. -I/usr/include/x86_64-linux-gnu/qt6 -I/usr/include/x86_64-linux-gnu/qt6/QtWidgets -I/usr/include/x86_64-linux-gnu/qt6/QtGui -I/usr/include/x86_64-linux-gnu/qt6/QtCore -I. -I. -I/usr/lib/x86_64-linux-gnu/qt6/mkspecs/linux-g++
|
||||
QMAKE = /usr/lib/qt6/bin/qmake
|
||||
DEL_FILE = rm -f
|
||||
CHK_DIR_EXISTS= test -d
|
||||
MKDIR = mkdir -p
|
||||
COPY = cp -f
|
||||
COPY_FILE = cp -f
|
||||
COPY_DIR = cp -f -R
|
||||
INSTALL_FILE = install -m 644 -p
|
||||
INSTALL_PROGRAM = install -m 755 -p
|
||||
INSTALL_DIR = cp -f -R
|
||||
QINSTALL = /usr/lib/qt6/bin/qmake -install qinstall
|
||||
QINSTALL_PROGRAM = /usr/lib/qt6/bin/qmake -install qinstall -exe
|
||||
DEL_FILE = rm -f
|
||||
SYMLINK = ln -f -s
|
||||
DEL_DIR = rmdir
|
||||
MOVE = mv -f
|
||||
TAR = tar -cf
|
||||
COMPRESS = gzip -9f
|
||||
DISTNAME = QTCart1.0.0
|
||||
DISTDIR = /home/ubuntu/QT/src/QTCart/build/Desktop-Debug/.tmp/QTCart1.0.0
|
||||
LINK = g++
|
||||
LFLAGS = -Wl,-rpath-link,/usr/lib/x86_64-linux-gnu
|
||||
LIBS = $(SUBLIBS) /usr/lib/x86_64-linux-gnu/libQt6Widgets.so /usr/lib/x86_64-linux-gnu/libQt6Gui.so /usr/lib/x86_64-linux-gnu/libGLX.so /usr/lib/x86_64-linux-gnu/libOpenGL.so /usr/lib/x86_64-linux-gnu/libQt6Core.so -lpthread -lGLX -lOpenGL
|
||||
AR = ar cqs
|
||||
RANLIB =
|
||||
SED = sed
|
||||
STRIP = strip
|
||||
|
||||
####### Output directory
|
||||
|
||||
OBJECTS_DIR = ./
|
||||
|
||||
####### Files
|
||||
|
||||
SOURCES = ../../main.cpp \
|
||||
../../mainwidget.cpp \
|
||||
../../pagecart.cpp \
|
||||
../../pagewelcome.cpp moc_mainwidget.cpp \
|
||||
moc_pagecart.cpp \
|
||||
moc_pagewelcome.cpp
|
||||
OBJECTS = main.o \
|
||||
mainwidget.o \
|
||||
pagecart.o \
|
||||
pagewelcome.o \
|
||||
moc_mainwidget.o \
|
||||
moc_pagecart.o \
|
||||
moc_pagewelcome.o
|
||||
DIST = /usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/spec_pre.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/unix.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/linux.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/sanitize.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/gcc-base.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/gcc-base-unix.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/g++-base.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/g++-unix.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/qconfig.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_concurrent.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_concurrent_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_core.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_core_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_dbus.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_dbus_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_devicediscovery_support_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_eglfs_kms_gbm_support_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_eglfs_kms_support_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_eglfsdeviceintegration_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_fb_support_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_gui.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_gui_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_input_support_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_kms_support_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_network.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_network_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_opengl.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_opengl_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_openglwidgets.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_openglwidgets_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_printsupport.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_printsupport_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_sql.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_sql_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_testlib.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_testlib_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_widgets.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_widgets_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_xcb_qpa_lib_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_xml.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_xml_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qt_functions.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qt_config.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/linux-g++/qmake.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/spec_post.prf \
|
||||
../../.qmake.stash \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/exclusive_builds.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/toolchain.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/default_pre.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/resolve_config.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/default_post.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qml_debug.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/warn_on.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qt.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/resources_functions.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/resources.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/moc.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/unix/opengl.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/uic.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/unix/thread.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qmake_use.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/file_copies.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/testcase_targets.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/exceptions.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/yacc.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/lex.prf \
|
||||
../../../../QTCart.pro ../../mainwidget.h \
|
||||
../../pagecart.h \
|
||||
../../pagewelcome.h ../../main.cpp \
|
||||
../../mainwidget.cpp \
|
||||
../../pagecart.cpp \
|
||||
../../pagewelcome.cpp
|
||||
QMAKE_TARGET = QTCart
|
||||
DESTDIR =
|
||||
TARGET = QTCart
|
||||
|
||||
|
||||
first: all
|
||||
####### Build rules
|
||||
|
||||
QTCart: ui_mainwidget.h ui_pagecart.h ui_pagewelcome.h $(OBJECTS)
|
||||
$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)
|
||||
|
||||
Makefile: ../../QTCart.pro /usr/lib/x86_64-linux-gnu/qt6/mkspecs/linux-g++/qmake.conf /usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/spec_pre.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/unix.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/linux.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/sanitize.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/gcc-base.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/gcc-base-unix.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/g++-base.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/g++-unix.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/qconfig.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_concurrent.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_concurrent_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_core.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_core_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_dbus.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_dbus_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_devicediscovery_support_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_eglfs_kms_gbm_support_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_eglfs_kms_support_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_eglfsdeviceintegration_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_fb_support_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_gui.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_gui_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_input_support_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_kms_support_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_network.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_network_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_opengl.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_opengl_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_openglwidgets.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_openglwidgets_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_printsupport.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_printsupport_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_sql.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_sql_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_testlib.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_testlib_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_widgets.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_widgets_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_xcb_qpa_lib_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_xml.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_xml_private.pri \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qt_functions.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qt_config.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/linux-g++/qmake.conf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/spec_post.prf \
|
||||
.qmake.stash \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/exclusive_builds.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/toolchain.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/default_pre.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/resolve_config.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/default_post.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qml_debug.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/warn_on.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qt.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/resources_functions.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/resources.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/moc.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/unix/opengl.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/uic.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/unix/thread.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qmake_use.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/file_copies.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/testcase_targets.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/exceptions.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/yacc.prf \
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/lex.prf \
|
||||
../../QTCart.pro \
|
||||
/usr/lib/x86_64-linux-gnu/libQt6Widgets.prl \
|
||||
/usr/lib/x86_64-linux-gnu/libQt6Gui.prl \
|
||||
/usr/lib/x86_64-linux-gnu/libQt6Core.prl
|
||||
$(QMAKE) -o Makefile ../../QTCart.pro -spec linux-g++ CONFIG+=debug CONFIG+=qml_debug
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/spec_pre.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/unix.conf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/linux.conf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/sanitize.conf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/gcc-base.conf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/gcc-base-unix.conf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/g++-base.conf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/common/g++-unix.conf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/qconfig.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_concurrent.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_concurrent_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_core.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_core_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_dbus.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_dbus_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_devicediscovery_support_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_eglfs_kms_gbm_support_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_eglfs_kms_support_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_eglfsdeviceintegration_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_fb_support_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_gui.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_gui_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_input_support_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_kms_support_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_network.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_network_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_opengl.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_opengl_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_openglwidgets.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_openglwidgets_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_printsupport.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_printsupport_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_sql.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_sql_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_testlib.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_testlib_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_widgets.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_widgets_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_xcb_qpa_lib_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_xml.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/modules/qt_lib_xml_private.pri:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qt_functions.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qt_config.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/linux-g++/qmake.conf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/spec_post.prf:
|
||||
.qmake.stash:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/exclusive_builds.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/toolchain.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/default_pre.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/resolve_config.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/default_post.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qml_debug.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/warn_on.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qt.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/resources_functions.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/resources.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/moc.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/unix/opengl.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/uic.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/unix/thread.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/qmake_use.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/file_copies.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/testcase_targets.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/exceptions.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/yacc.prf:
|
||||
/usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/lex.prf:
|
||||
../../QTCart.pro:
|
||||
/usr/lib/x86_64-linux-gnu/libQt6Widgets.prl:
|
||||
/usr/lib/x86_64-linux-gnu/libQt6Gui.prl:
|
||||
/usr/lib/x86_64-linux-gnu/libQt6Core.prl:
|
||||
qmake: FORCE
|
||||
@$(QMAKE) -o Makefile ../../QTCart.pro -spec linux-g++ CONFIG+=debug CONFIG+=qml_debug
|
||||
|
||||
qmake_all: FORCE
|
||||
|
||||
|
||||
all: Makefile QTCart
|
||||
|
||||
dist: distdir FORCE
|
||||
(cd `dirname $(DISTDIR)` && $(TAR) $(DISTNAME).tar $(DISTNAME) && $(COMPRESS) $(DISTNAME).tar) && $(MOVE) `dirname $(DISTDIR)`/$(DISTNAME).tar.gz . && $(DEL_FILE) -r $(DISTDIR)
|
||||
|
||||
distdir: FORCE
|
||||
@test -d $(DISTDIR) || mkdir -p $(DISTDIR)
|
||||
$(COPY_FILE) --parents $(DIST) $(DISTDIR)/
|
||||
$(COPY_FILE) --parents /usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/data/dummy.cpp $(DISTDIR)/
|
||||
$(COPY_FILE) --parents ../../mainwidget.h ../../pagecart.h ../../pagewelcome.h $(DISTDIR)/
|
||||
$(COPY_FILE) --parents ../../main.cpp ../../mainwidget.cpp ../../pagecart.cpp ../../pagewelcome.cpp $(DISTDIR)/
|
||||
$(COPY_FILE) --parents ../../mainwidget.ui ../../pagecart.ui ../../pagewelcome.ui $(DISTDIR)/
|
||||
|
||||
|
||||
clean: compiler_clean
|
||||
-$(DEL_FILE) $(OBJECTS)
|
||||
-$(DEL_FILE) *~ core *.core
|
||||
|
||||
|
||||
distclean: clean
|
||||
-$(DEL_FILE) $(TARGET)
|
||||
-$(DEL_FILE) .qmake.stash
|
||||
-$(DEL_FILE) Makefile
|
||||
|
||||
|
||||
####### Sub-libraries
|
||||
|
||||
mocclean: compiler_moc_header_clean compiler_moc_objc_header_clean compiler_moc_source_clean
|
||||
|
||||
mocables: compiler_moc_header_make_all compiler_moc_objc_header_make_all compiler_moc_source_make_all
|
||||
|
||||
check: first
|
||||
|
||||
benchmark: first
|
||||
|
||||
compiler_rcc_make_all:
|
||||
compiler_rcc_clean:
|
||||
compiler_moc_predefs_make_all: moc_predefs.h
|
||||
compiler_moc_predefs_clean:
|
||||
-$(DEL_FILE) moc_predefs.h
|
||||
moc_predefs.h: /usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/data/dummy.cpp
|
||||
g++ -pipe -g -std=gnu++1z -Wall -Wextra -dM -E -o moc_predefs.h /usr/lib/x86_64-linux-gnu/qt6/mkspecs/features/data/dummy.cpp
|
||||
|
||||
compiler_moc_header_make_all: moc_mainwidget.cpp moc_pagecart.cpp moc_pagewelcome.cpp
|
||||
compiler_moc_header_clean:
|
||||
-$(DEL_FILE) moc_mainwidget.cpp moc_pagecart.cpp moc_pagewelcome.cpp
|
||||
moc_mainwidget.cpp: ../../mainwidget.h \
|
||||
../../pagewelcome.h \
|
||||
../../pagecart.h \
|
||||
moc_predefs.h \
|
||||
/usr/lib/qt6/libexec/moc
|
||||
/usr/lib/qt6/libexec/moc $(DEFINES) --include /home/ubuntu/QT/src/QTCart/build/Desktop-Debug/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt6/mkspecs/linux-g++ -I/home/ubuntu/QT/src/QTCart -I/usr/include/x86_64-linux-gnu/qt6 -I/usr/include/x86_64-linux-gnu/qt6/QtWidgets -I/usr/include/x86_64-linux-gnu/qt6/QtGui -I/usr/include/x86_64-linux-gnu/qt6/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../../mainwidget.h -o moc_mainwidget.cpp
|
||||
|
||||
moc_pagecart.cpp: ../../pagecart.h \
|
||||
moc_predefs.h \
|
||||
/usr/lib/qt6/libexec/moc
|
||||
/usr/lib/qt6/libexec/moc $(DEFINES) --include /home/ubuntu/QT/src/QTCart/build/Desktop-Debug/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt6/mkspecs/linux-g++ -I/home/ubuntu/QT/src/QTCart -I/usr/include/x86_64-linux-gnu/qt6 -I/usr/include/x86_64-linux-gnu/qt6/QtWidgets -I/usr/include/x86_64-linux-gnu/qt6/QtGui -I/usr/include/x86_64-linux-gnu/qt6/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../../pagecart.h -o moc_pagecart.cpp
|
||||
|
||||
moc_pagewelcome.cpp: ../../pagewelcome.h \
|
||||
moc_predefs.h \
|
||||
/usr/lib/qt6/libexec/moc
|
||||
/usr/lib/qt6/libexec/moc $(DEFINES) --include /home/ubuntu/QT/src/QTCart/build/Desktop-Debug/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt6/mkspecs/linux-g++ -I/home/ubuntu/QT/src/QTCart -I/usr/include/x86_64-linux-gnu/qt6 -I/usr/include/x86_64-linux-gnu/qt6/QtWidgets -I/usr/include/x86_64-linux-gnu/qt6/QtGui -I/usr/include/x86_64-linux-gnu/qt6/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../../pagewelcome.h -o moc_pagewelcome.cpp
|
||||
|
||||
compiler_moc_objc_header_make_all:
|
||||
compiler_moc_objc_header_clean:
|
||||
compiler_moc_source_make_all:
|
||||
compiler_moc_source_clean:
|
||||
compiler_uic_make_all: ui_mainwidget.h ui_pagecart.h ui_pagewelcome.h
|
||||
compiler_uic_clean:
|
||||
-$(DEL_FILE) ui_mainwidget.h ui_pagecart.h ui_pagewelcome.h
|
||||
ui_mainwidget.h: ../../mainwidget.ui \
|
||||
/usr/lib/qt6/libexec/uic
|
||||
/usr/lib/qt6/libexec/uic ../../mainwidget.ui -o ui_mainwidget.h
|
||||
|
||||
ui_pagecart.h: ../../pagecart.ui \
|
||||
/usr/lib/qt6/libexec/uic
|
||||
/usr/lib/qt6/libexec/uic ../../pagecart.ui -o ui_pagecart.h
|
||||
|
||||
ui_pagewelcome.h: ../../pagewelcome.ui \
|
||||
/usr/lib/qt6/libexec/uic
|
||||
/usr/lib/qt6/libexec/uic ../../pagewelcome.ui -o ui_pagewelcome.h
|
||||
|
||||
compiler_yacc_decl_make_all:
|
||||
compiler_yacc_decl_clean:
|
||||
compiler_yacc_impl_make_all:
|
||||
compiler_yacc_impl_clean:
|
||||
compiler_lex_make_all:
|
||||
compiler_lex_clean:
|
||||
compiler_clean: compiler_moc_predefs_clean compiler_moc_header_clean compiler_uic_clean
|
||||
|
||||
####### Compile
|
||||
|
||||
main.o: ../../main.cpp ../../mainwidget.h \
|
||||
../../pagewelcome.h \
|
||||
../../pagecart.h
|
||||
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o main.o ../../main.cpp
|
||||
|
||||
mainwidget.o: ../../mainwidget.cpp ../../mainwidget.h \
|
||||
../../pagewelcome.h \
|
||||
../../pagecart.h \
|
||||
../../ui_mainwidget.h
|
||||
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o mainwidget.o ../../mainwidget.cpp
|
||||
|
||||
pagecart.o: ../../pagecart.cpp ../../pagecart.h \
|
||||
ui_pagecart.h
|
||||
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o pagecart.o ../../pagecart.cpp
|
||||
|
||||
pagewelcome.o: ../../pagewelcome.cpp ../../pagewelcome.h \
|
||||
../../ui_pagewelcome.h
|
||||
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o pagewelcome.o ../../pagewelcome.cpp
|
||||
|
||||
moc_mainwidget.o: moc_mainwidget.cpp
|
||||
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_mainwidget.o moc_mainwidget.cpp
|
||||
|
||||
moc_pagecart.o: moc_pagecart.cpp
|
||||
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_pagecart.o moc_pagecart.cpp
|
||||
|
||||
moc_pagewelcome.o: moc_pagewelcome.cpp
|
||||
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_pagewelcome.o moc_pagewelcome.cpp
|
||||
|
||||
####### Install
|
||||
|
||||
install_target: first FORCE
|
||||
@test -d $(INSTALL_ROOT)/opt/QTCart/bin || mkdir -p $(INSTALL_ROOT)/opt/QTCart/bin
|
||||
$(QINSTALL_PROGRAM) $(QMAKE_TARGET) $(INSTALL_ROOT)/opt/QTCart/bin/$(QMAKE_TARGET)
|
||||
|
||||
uninstall_target: FORCE
|
||||
-$(DEL_FILE) $(INSTALL_ROOT)/opt/QTCart/bin/$(QMAKE_TARGET)
|
||||
-$(DEL_DIR) $(INSTALL_ROOT)/opt/QTCart/bin/
|
||||
|
||||
|
||||
install: install_target FORCE
|
||||
|
||||
uninstall: uninstall_target FORCE
|
||||
|
||||
FORCE:
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
/****************************************************************************
|
||||
** Meta object code from reading C++ file 'mainwidget.h'
|
||||
**
|
||||
** Created by: The Qt Meta Object Compiler version 68 (Qt 6.2.4)
|
||||
**
|
||||
** WARNING! All changes made in this file will be lost!
|
||||
*****************************************************************************/
|
||||
|
||||
#include <memory>
|
||||
#include "../../mainwidget.h"
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qmetatype.h>
|
||||
#if !defined(Q_MOC_OUTPUT_REVISION)
|
||||
#error "The header file 'mainwidget.h' doesn't include <QObject>."
|
||||
#elif Q_MOC_OUTPUT_REVISION != 68
|
||||
#error "This file was generated using the moc from 6.2.4. It"
|
||||
#error "cannot be used with the include files from this version of Qt."
|
||||
#error "(The moc has changed too much.)"
|
||||
#endif
|
||||
|
||||
QT_BEGIN_MOC_NAMESPACE
|
||||
QT_WARNING_PUSH
|
||||
QT_WARNING_DISABLE_DEPRECATED
|
||||
struct qt_meta_stringdata_MainWidget_t {
|
||||
const uint offsetsAndSize[6];
|
||||
char stringdata0[31];
|
||||
};
|
||||
#define QT_MOC_LITERAL(ofs, len) \
|
||||
uint(offsetof(qt_meta_stringdata_MainWidget_t, stringdata0) + ofs), len
|
||||
static const qt_meta_stringdata_MainWidget_t qt_meta_stringdata_MainWidget = {
|
||||
{
|
||||
QT_MOC_LITERAL(0, 10), // "MainWidget"
|
||||
QT_MOC_LITERAL(11, 18), // "on_pPBStartClicked"
|
||||
QT_MOC_LITERAL(30, 0) // ""
|
||||
|
||||
},
|
||||
"MainWidget\0on_pPBStartClicked\0"
|
||||
};
|
||||
#undef QT_MOC_LITERAL
|
||||
|
||||
static const uint qt_meta_data_MainWidget[] = {
|
||||
|
||||
// content:
|
||||
10, // revision
|
||||
0, // classname
|
||||
0, 0, // classinfo
|
||||
1, 14, // methods
|
||||
0, 0, // properties
|
||||
0, 0, // enums/sets
|
||||
0, 0, // constructors
|
||||
0, // flags
|
||||
0, // signalCount
|
||||
|
||||
// slots: name, argc, parameters, tag, flags, initial metatype offsets
|
||||
1, 0, 20, 2, 0x08, 1 /* Private */,
|
||||
|
||||
// slots: parameters
|
||||
QMetaType::Void,
|
||||
|
||||
0 // eod
|
||||
};
|
||||
|
||||
void MainWidget::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
|
||||
{
|
||||
if (_c == QMetaObject::InvokeMetaMethod) {
|
||||
auto *_t = static_cast<MainWidget *>(_o);
|
||||
(void)_t;
|
||||
switch (_id) {
|
||||
case 0: _t->on_pPBStartClicked(); break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
(void)_a;
|
||||
}
|
||||
|
||||
const QMetaObject MainWidget::staticMetaObject = { {
|
||||
QMetaObject::SuperData::link<QWidget::staticMetaObject>(),
|
||||
qt_meta_stringdata_MainWidget.offsetsAndSize,
|
||||
qt_meta_data_MainWidget,
|
||||
qt_static_metacall,
|
||||
nullptr,
|
||||
qt_incomplete_metaTypeArray<qt_meta_stringdata_MainWidget_t
|
||||
, QtPrivate::TypeAndForceComplete<MainWidget, std::true_type>
|
||||
, QtPrivate::TypeAndForceComplete<void, std::false_type>
|
||||
|
||||
|
||||
>,
|
||||
nullptr
|
||||
} };
|
||||
|
||||
|
||||
const QMetaObject *MainWidget::metaObject() const
|
||||
{
|
||||
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
|
||||
}
|
||||
|
||||
void *MainWidget::qt_metacast(const char *_clname)
|
||||
{
|
||||
if (!_clname) return nullptr;
|
||||
if (!strcmp(_clname, qt_meta_stringdata_MainWidget.stringdata0))
|
||||
return static_cast<void*>(this);
|
||||
return QWidget::qt_metacast(_clname);
|
||||
}
|
||||
|
||||
int MainWidget::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
||||
{
|
||||
_id = QWidget::qt_metacall(_c, _id, _a);
|
||||
if (_id < 0)
|
||||
return _id;
|
||||
if (_c == QMetaObject::InvokeMetaMethod) {
|
||||
if (_id < 1)
|
||||
qt_static_metacall(this, _c, _id, _a);
|
||||
_id -= 1;
|
||||
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
|
||||
if (_id < 1)
|
||||
*reinterpret_cast<QMetaType *>(_a[0]) = QMetaType();
|
||||
_id -= 1;
|
||||
}
|
||||
return _id;
|
||||
}
|
||||
QT_WARNING_POP
|
||||
QT_END_MOC_NAMESPACE
|
||||