#include "richtexteditor.h" #include #include #include #include #include #include #include #include #include #include "../../thirdparty/tags/include/tags_line_edit.hpp" #include #include #include #include #include #include #include #include #include #include #include // ===================== RichTextEditor ===================== RichTextEditor::RichTextEditor(QWidget *parent) : QTextEdit(parent) { setAcceptRichText(true); setPlaceholderText(\"Write your message here...\"); } void RichTextEditor::setupToolbar(QVBoxLayout *layout) { m_toolbar = new QToolBar(\"Formatting\"); m_toolbar->setIconSize(QSize(16, 16)); m_toolbar->setStyleSheet( \"QToolBar { background: #f5f5f7; border: 1px solid #d1d1d6; border-radius: 4px; spacing: 2px; padding: 2px; }\"\n \"QToolButton { padding: 4px 6px; border-radius: 3px; }\"\n \"QToolButton:hover { background: #e0e0e0; }\"\n \"QToolButton:checked { background: #bbdefb; }\"\n ); // Font family combo m_fontCombo = new QFontComboBox(); m_fontCombo->setFixedWidth(150); connect(m_fontCombo, &QFontComboBox::currentFontChanged, this, &RichTextEditor::onFontChanged); m_toolbar->addWidget(m_fontCombo); // Font size spin m_fontSizeSpin = new QSpinBox(); m_fontSizeSpin->setRange(8, 72); m_fontSizeSpin->setValue(11); m_fontSizeSpin->setFixedWidth(70); m_fontSizeSpin->setFixedHeight(24); connect(m_fontSizeSpin, QOverload::of(&QSpinBox::valueChanged), this, &RichTextEditor::onFontSizeChanged); m_toolbar->addWidget(m_fontSizeSpin); m_toolbar->addSeparator(); // Bold / Italic / QAction *boldAct = m_toolbar->addAction(\"B\"); boldAct->setCheckable(true); boldAct->setIcon(QIcon(QStringLiteral(\":/icons/resources/icons/SVG/Bold/Text Formatting/Text Bold.svg\"))); QFont boldFont = boldAct->font(); boldFont.setBold(true); boldAct->setFont(boldFont); connect(boldAct, &QAction::triggered, this, &RichTextEditor::onBold); QAction *italicAct = m_toolbar->addAction(\"I\"); italicAct->setCheckable(true); italicAct->setIcon(QIcon(QStringLiteral(\":/icons/resources/icons/SVG/Outline/Text Formatting/Text Italic.svg\"))); QFont italicFont = italicAct->font(); italicFont.setItalic(true); italicAct->setFont(italicFont); connect(italicAct, &QAction::triggered, this, &RichTextEditor::onItalic); QAction *underlineAct = m_toolbar->addAction(\"U\"); underlineAct->setCheckable(true); underlineAct->setIcon(QIcon(QStringLiteral(\":/icons/resources/icons/SVG/Outline/Text Formatting/Text Underline.svg\"))); QFont uFont = underlineAct->font(); uFont.setUnderline(true); underlineAct->setFont(uFont); connect(underlineAct, &QAction::triggered, this, &RichTextEditor::onUnderline); m_toolbar->addSeparator(); // Alignment QAction *alignLeft = m_toolbar->addAction(\"L\"); connect(alignLeft, &QAction::triggered, this, &RichTextEditor::onAlignLeft); QAction *alignCenter = m_toolbar->addAction(\"C\"); connect(alignCenter, &QAction::triggered, this, &RichTextEditor::onAlignCenter); QAction *alignRight = m_toolbar->addAction(\"R\"); connect(alignRight, &QAction::triggered, this, &RichTextEditor::onAlignRight); QAction *alignJustify = m_toolbar->addAction(\"J\"); connect(alignJustify, &QAction::triggered, this, &RichTextEditor::onAlignJustify); m_toolbar->addSeparator(); // Lists QAction *bulletAct = m_toolbar->addAction(\"Bullets\"); connect(bulletAct, &QAction::triggered, this, &RichTextEditor::onBulletList); QAction *numAct = m_toolbar->addAction(\"1. List\"); connect(numAct, &QAction::triggered, this, &RichTextEditor::onNumberedList); m_toolbar->addSeparator(); // Indent / Outdent QAction *indentAct = m_toolbar->addAction(\"Indent\"); connect(indentAct, &QAction::triggered, this, &RichTextEditor::onIndent); QAction *outdentAct = m_toolbar->addAction(\"Outdent\"); connect(outdentAct, &QAction::triggered, this, &RichTextEditor::onOutdent); m_toolbar->addSeparator(); // Insert image QAction *imgAct = m_toolbar->addAction(\"Img\"); connect(imgAct, &QAction::triggered, this, &RichTextEditor::onInsertImage); // Insert table QAction *tableAct = m_toolbar->addAction(\"Tbl\"); connect(tableAct, &QAction::triggered, this, &RichTextEditor::onInsertTable); // Signature button m_signatureButton = new QToolButton(); m_signatureButton->setText(\"Signature\"); m_signatureButton->setToolButtonStyle(Qt::ToolButtonTextOnly); m_signatureButton->setPopupMode(QToolButton::MenuButtonPopup); m_signatureMenu = new QMenu(m_signatureButton); m_signatureButton->setMenu(m_signatureMenu); m_signatureButton->setStyleSheet( \"QToolButton { background: #f5f5f7; border: 1px solid #d1d1d6; border-radius: 3px; padding: 4px 6px; }\"\n \"QToolButton:hover { background: #e0e0e0; }\"\n \"QToolButton::menu-button { border-left: 1px solid rgba(0,0,0,0.1); width: 12px; }\"\n ); connect(m_signatureButton, &QToolButton::clicked, this, &RichTextEditor::signatureClicked); m_toolbar->addWidget(m_signatureButton); QAction *editSigAct = m_signatureMenu->addAction(tr(\"Editar firmas\")); connect(editSigAct, &QAction::triggered, this, &RichTextEditor::signatureEditRequested); m_toolbar->addSeparator(); layout->addWidget(m_toolbar); } void RichTextEditor::onBold() { QTextCharFormat fmt; fmt.setFontWeight(textCursor().charFormat().fontWeight() == QFont::Bold ? QFont::Normal : QFont::Bold); mergeCurrentCharFormat(fmt); setFocus(); } void RichTextEditor::onItalic() { QTextCharFormat fmt; fmt.setFontItalic(!textCursor().charFormat().fontItalic()); mergeCurrentCharFormat(fmt); setFocus(); } void RichTextEditor::onUnderline() { QTextCharFormat fmt; fmt.setFontUnderline(!textCursor().charFormat().fontUnderline()); mergeCurrentCharFormat(fmt); setFocus(); } void RichTextEditor::onBulletList() { QTextCursor cursor = textCursor(); QTextList *list = cursor.currentList(); if (list && list->format().style() == QTextListFormat::ListDisc) { // Remove list QTextBlockFormat bfmt; bfmt.setIndent(0); cursor.setBlockFormat(bfmt); list->remove(cursor.block()); } else { QTextListFormat listFormat; listFormat.setStyle(QTextListFormat::ListDisc); cursor.createList(listFormat); } } void RichTextEditor::onNumberedList() { QTextCursor cursor = textCursor(); QTextList *list = cursor.currentList(); if (list && list->format().style() == QTextListFormat::ListDecimal) { QTextBlockFormat bfmt; bfmt.setIndent(0); cursor.setBlockFormat(bfmt); list->remove(cursor.block()); } else { QTextListFormat listFormat; listFormat.setStyle(QTextListFormat::ListDecimal); cursor.createList(listFormat); } } void RichTextEditor::onIndent() { QTextCursor cursor = textCursor(); QTextBlockFormat bfmt = cursor.blockFormat(); bfmt.setIndent(bfmt.indent() + 1); cursor.setBlockFormat(bfmt); } void RichTextEditor::onOutdent() { QTextCursor cursor = textCursor(); QTextBlockFormat bfmt = cursor.blockFormat(); int indent = bfmt.indent(); if (indent > 0) { bfmt.setIndent(indent - 1); cursor.setBlockFormat(bfmt); } } void RichTextEditor::onAlignLeft() { QTextCursor cursor = textCursor(); QTextBlockFormat bfmt = cursor.blockFormat(); bfmt.setAlignment(Qt::AlignLeft); cursor.setBlockFormat(bfmt); } void RichTextEditor::onAlignCenter() { QTextCursor cursor = textCursor(); QTextBlockFormat bfmt = cursor.blockFormat(); bfmt.setAlignment(Qt::AlignCenter); cursor.setBlockFormat(bfmt); } void RichTextEditor::onAlignRight() { QTextCursor cursor = textCursor(); QTextBlockFormat bfmt = cursor.blockFormat(); bfmt.setAlignment(Qt::AlignRight); cursor.setBlockFormat(bfmt); } void RichTextEditor::onAlignJustify() { QTextCursor cursor = textCursor(); QTextBlockFormat bfmt = cursor.blockFormat(); bfmt.setAlignment(Qt::AlignJustify); cursor.setBlockFormat(bfmt); } void RichTextEditor::onFontChanged(const QFont &font) { QTextCharFormat fmt; fmt.setFontFamilies({font.family()}); mergeCurrentCharFormat(fmt); } void RichTextEditor::onFontSizeChanged(int size) { QTextCharFormat fmt; fmt.setFontPointSize(size); mergeCurrentCharFormat(fmt); } void RichTextEditor::onInsertImage() { QString filePath = QFileDialog::getOpenFileName(this, \"Insert Image\", QString(), \"Images (*.png *.jpg *.jpeg *.gif *.bmp)\"); if (filePath.isEmpty()) return; QTextCursor cursor = textCursor(); QTextImageFormat imgFmt; imgFmt.setName(filePath); // Scale down if too large QPixmap pm(filePath); if (pm.width() > 600) { imgFmt.setWidth(600); imgFmt.setHeight(pm.height() * 600 / pm.width()); } cursor.insertImage(imgFmt); } void RichTextEditor::onInsertTable() { bool ok; int rows = QInputDialog::getInt(this, \"Table Rows\", \"Rows:\", 3, 1, 50, 1, &ok); if (!ok) return; int cols = QInputDialog::getInt(this, \"Table Columns\", \"Columns:\", 3, 1, 20, 1, &ok); if (!ok) return; QTextCursor cursor = textCursor(); QTextTableFormat tableFmt; tableFmt.setBorder(1); tableFmt.setBorderStyle(QTextFrameFormat::BorderStyle_Solid); tableFmt.setCellPadding(4); tableFmt.setCellSpacing(0); tableFmt.setWidth(QTextLength(QTextLength::PercentageLength, 100)); cursor.insertTable(rows, cols, tableFmt); }