/* * Copyright (C) Ascensio System SIA, 2009-2026 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation, together with the * additional terms provided in the LICENSE file. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: https://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA by email at info@onlyoffice.com * or by postal mail at 20A-6 Ernesta Birznieka-Upisha Street, Riga, * LV-1050, Latvia, European Union. * * The interactive user interfaces in modified versions of the Program * are required to display Appropriate Legal Notices in accordance with * Section 5 of the GNU AGPL version 3. * * No trademark rights are granted under this License. * * All non-code elements of the Product, including illustrations, * icon sets, and technical writing content, are licensed under the * Creative Commons Attribution-ShareAlike 4.0 International License: * https://creativecommons.org/licenses/by-sa/4.0/legalcode * * This license applies only to such non-code elements and does not * modify or replace the licensing terms applicable to the Program's * source code, which remains licensed under the GNU Affero General * Public License v3. * * SPDX-License-Identifier: AGPL-3.0-only */ #include "mainwindow.h" #include "ui_mainwindow.h" #include CustomLabel::CustomLabel(QWidget *parent) : QLabel(parent) { setMouseTracking(true); } QPointF CustomLabel::GetStartPoint() const noexcept { return StartP; } double CustomLabel::GetDifferenceX() const noexcept { return CurrP.x() - StartP.x(); } double CustomLabel::GetDifferenceY() const noexcept { return CurrP.y() - StartP.y(); } bool CustomLabel::GetMovable() const noexcept { return Movable; } void CustomLabel::mousePressEvent(QMouseEvent *event) { StartP = event->pos(); Movable = true; emit mousePress(); } void CustomLabel::mouseReleaseEvent(QMouseEvent *event) { CurrP = event->pos(); Movable = false; emit mousePress(); } void CustomLabel::mouseMoveEvent(QMouseEvent *event) { CurrP = event->pos(); emit mouseMove(); } CustomButton::CustomButton(QWidget *parent) : QPushButton(parent) { } BooleanButton::BooleanButton(QWidget *parent) : QPushButton(parent) { } std::vector GetChildsByClassName(QObject* parent, const QString& name) { std::vector res; foreach (QObject* child, parent->children()) { if (QString(child->metaObject()->className()) == name) res.push_back(child); else { if (!child->children().empty()) { std::vector resChilds = GetChildsByClassName(child, name); res.insert(res.end(), resChilds.begin(), resChilds.end()); } } } return res; } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); Figure1 = ""; Figure2 = ""; Op = Aggplus::Intersection; std::vector arrPathButtons = GetChildsByClassName(this, "CustomButton"); std::vector arrBooleanButtons = GetChildsByClassName(this, "BooleanButton"); for (std::vector::iterator i = arrPathButtons.begin(); i != arrPathButtons.end(); i++) connect((QPushButton*)(*i), &QPushButton::clicked, this, &MainWindow::SetFigure); for (std::vector::iterator i = arrBooleanButtons.begin(); i != arrBooleanButtons.end(); i++) connect((QPushButton*)(*i), &QPushButton::clicked, this, &MainWindow::SetCommand); Path1.StartFigure(); Path1.MoveTo(100.0, 100.0); Path1.LineTo(150.0, 150.0); Path1.LineTo(200.0, 150.0); Path1.LineTo(100.0, 100.0); Path1.CloseFigure(); Path1.MoveTo(300.0, 300.0); Path1.LineTo(400.0, 300.0); Path1.LineTo(400.0, 400.0); Path1.LineTo(300.0, 400.0); Path1.LineTo(300.0, 300.0); Path1.CloseFigure(); Path2.StartFigure(); Path2.MoveTo(100.0, 125.0); Path2.LineTo(100.0, 350.0); Path2.LineTo(350.0, 350.0); Path2.LineTo(350.0, 125.0); Path2.LineTo(100.0, 125.0); Path2.CloseFigure(); Result = Aggplus::CalcBooleanOperation(Path1, Path2, Aggplus::Intersection); Draw(true); } void MainWindow::SetFigure() { QPushButton* sender = (QPushButton*)this->sender(); if (((QGroupBox*)sender->parentWidget())->title() == "Path1") { Figure1 = sender->text(); DrawPath1(); } if (((QGroupBox*)sender->parentWidget())->title() == "Path2") { Figure2 = sender->text(); DrawPath2(); } } void MainWindow::SetCommand() { QString text = ((QPushButton*)sender())->text(); if (text == "Unite") Op = Aggplus::Union; else if (text == "Intersect") Op = Aggplus::Intersection; else Op = Aggplus::Subtraction; BooleanOp(); } MainWindow::~MainWindow() { delete ui; } Aggplus::CGraphicsPath MainWindow::SetPath(double scale, double offsetX, double offsetY, QString Figure) { Aggplus::CGraphicsPath path; path.StartFigure(); if (Figure == "Rectangle") { path.MoveTo(RECTANGLE[0] + offsetX, RECTANGLE[1] + offsetY); path.LineTo(RECTANGLE[0] + scale * RECTANGLE[2] + offsetX, RECTANGLE[1] + offsetY); path.LineTo(RECTANGLE[0] + scale * RECTANGLE[2] + offsetX, RECTANGLE[1] + scale * RECTANGLE[3] + offsetY); path.LineTo(RECTANGLE[0] + offsetX, RECTANGLE[1] + scale * RECTANGLE[3] + offsetY); path.LineTo(RECTANGLE[0] + offsetX, RECTANGLE[1] + offsetY); } else if (Figure == "Ellipse") { path.AddEllipse(RECTANGLE[0] + offsetX, RECTANGLE[1] + offsetY, scale * RECTANGLE[2], scale * RECTANGLE[3]); } else if (Figure == "Triangle") { path.MoveTo(TRIANGLE[0] + offsetX, TRIANGLE[1] + offsetY); for (size_t i = 2; i < std::size(TRIANGLE); i += 2) path.LineTo(TRIANGLE[0] + scale * TRIANGLE[i] + offsetX, TRIANGLE[1] + scale * TRIANGLE[i + 1] + offsetY); path.LineTo(TRIANGLE[0] + offsetX, TRIANGLE[1] + offsetY); } else if (Figure == "Cross") { path.MoveTo(CROSS[0] + offsetX, CROSS[1] + offsetY); for (size_t i = 2; i < std::size(CROSS); i += 2) path.LineTo(CROSS[0] + scale * CROSS[i] + offsetX, CROSS[1] + scale * CROSS[i + 1] + offsetY); path.LineTo(CROSS[0] + offsetX, CROSS[1] + offsetY); } path.CloseFigure(); return path; } void MainWindow::AddPath(NSGraphics::IGraphicsRenderer* pathRenderer, const Aggplus::CGraphicsPath& path, bool isResult) { if (path.GetPointCount() == 0) return; pathRenderer->PathCommandStart(); pathRenderer->BeginCommand(c_nPathType); size_t length = path.GetPointCount(), compound = path.GetCloseCount(); std::vector points = path.GetPoints(0, length + compound); for (size_t i = 0; i < length + compound; i++) { if (path.IsCurvePoint(i)) { pathRenderer->PathCommandCurveTo(points[i].X + NEGATIVE_OFFSET, points[i].Y + NEGATIVE_OFFSET, points[i + 1].X + NEGATIVE_OFFSET, points[i + 1].Y + NEGATIVE_OFFSET, points[i + 2].X + NEGATIVE_OFFSET, points[i + 2].Y + NEGATIVE_OFFSET); i += 2; } else if (path.IsMovePoint(i)) pathRenderer->PathCommandMoveTo(points[i].X + NEGATIVE_OFFSET, points[i].Y + NEGATIVE_OFFSET); else if (path.IsLinePoint(i)) pathRenderer->PathCommandLineTo(points[i].X + NEGATIVE_OFFSET, points[i].Y + NEGATIVE_OFFSET); } if (isResult) { pathRenderer->put_BrushColor1(0xFF0000); pathRenderer->Fill(); } pathRenderer->put_PenColor(!isResult ? 0x000000 : 0x0000FF); pathRenderer->DrawPath(c_nStroke); pathRenderer->EndCommand(c_nPathType); pathRenderer->PathCommandEnd(); } void MainWindow::Draw(bool drawResult) { ui->label->clear(); NSGraphics::IGraphicsRenderer* pathRenderer = NSGraphics::Create(); NSFonts::IFontManager* fmp = NSFonts::NSFontManager::Create(); pathRenderer->SetFontManager(fmp); int nW = ui->label->width(); int nH = ui->label->height(); BYTE* pData = new BYTE[4 * nW * nH]; CBgraFrame oFrame; oFrame.put_Data(pData); oFrame.put_Width(nW); oFrame.put_Height(nH); oFrame.put_Stride(4 * nW); pathRenderer->CreateFromBgraFrame(&oFrame); pathRenderer->SetSwapRGB(true); pathRenderer->put_Width(nW); pathRenderer->put_Height(nH); AddPath(pathRenderer, Path1); AddPath(pathRenderer, Path2); if (drawResult) { AddPath(pathRenderer, Result, true); } QImage img = QImage(pData, nW, nH, QImage::Format_RGBA8888, [](void *data){ delete [] (BYTE*)data; }); ui->label->setPixmap(QPixmap::fromImage(img)); } void MainWindow::SetCoords(QLabel *label, const Aggplus::CGraphicsPath& path) { size_t length = path.GetPointCount(); std::vector points = path.GetPoints(0, length); QString text = ""; for (size_t i = 0; i < length; i++) text += "(" + QString::number(points[i].X) + "; " + QString::number(points[i].Y) + "); "; label->setText(text); } void MainWindow::DrawPath1() { if (Path1.GetPointCount() > 0) Path1.Reset(); Path1 = SetPath(Scale[0], Offsets[0], Offsets[1], Figure1); Draw(); SetCoords(ui->label_4, Path1); } void MainWindow::DrawPath2() { if (Path2.GetPointCount() > 0) Path2.Reset(); Path2 = SetPath(Scale[1], Offsets[2], Offsets[3], Figure2); Draw(); SetCoords(ui->label_5, Path2); } void MainWindow::BooleanOp() { if (Path1.GetPointCount() == 0 || Path2.GetPointCount() == 0) return; Result = Aggplus::CalcBooleanOperation(Path1, Path2, Op); Draw(true); SetCoords(ui->label_7, Result); } void MainWindow::CheckMousePress() { if (!ui->label->GetMovable()) { Move1 = false; Move2 = false; disconnect(ui->label, SIGNAL(mouseMove()), this, SLOT(Move())); return; } QRectF rect1(RECTANGLE[0] + NEGATIVE_OFFSET + Offsets[0], RECTANGLE[1] + NEGATIVE_OFFSET + Offsets[1], Scale[0] * RECTANGLE[2], Scale[0] * RECTANGLE[3]), rect2(RECTANGLE[0] + NEGATIVE_OFFSET + Offsets[2], RECTANGLE[1] + NEGATIVE_OFFSET + Offsets[3], Scale[1] * RECTANGLE[2], Scale[1] * RECTANGLE[3]); Move1 = rect1.contains(ui->label->GetStartPoint()) && Path1.GetPointCount() != 0; Move2 = rect2.contains(ui->label->GetStartPoint()) && Path2.GetPointCount() != 0; if (Move2) Move1 = false; if (Move1 || Move2) { for (size_t i = 0; i < 4; i++) OldOffsets[i] = Offsets[i]; connect(ui->label, SIGNAL(mouseMove()), this, SLOT(Move())); } } inline double CheckOffset(double offset, double min, double max) { return std::max(min, std::min(max, offset)); } void MainWindow::Move() { if (Move1) { Offsets[0] = CheckOffset(OldOffsets[0] + ui->label->GetDifferenceX(), static_cast(ui->label->x()), static_cast(ui->label->width())); Offsets[1] = CheckOffset(OldOffsets[1] + ui->label->GetDifferenceY(), static_cast(ui->label->y()), static_cast(ui->label->height())); DrawPath1(); } if (Move2) { Offsets[2] = CheckOffset(OldOffsets[2] + ui->label->GetDifferenceX(), static_cast(ui->label->x()), static_cast(ui->label->width())); Offsets[3] = CheckOffset(OldOffsets[3] + ui->label->GetDifferenceY(), static_cast(ui->label->y()), static_cast(ui->label->height())); DrawPath2(); } } void MainWindow::on_horizontalSlider_sliderMoved(int position) { Scale[0] = position / 100.0; DrawPath1(); } void MainWindow::on_horizontalSlider_2_sliderMoved(int position) { Scale[1] = position / 100.0; DrawPath2(); }