File indexing completed on 2024-05-05 08:41:18
0001 /* 0002 * Copyright (C) 2010-2015 by Stephen Allewell 0003 * steve.allewell@gmail.com 0004 * 0005 * This program is free software; you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation; either version 2 of the License, or 0008 * (at your option) any later version. 0009 */ 0010 0011 #include "PageLayoutEditor.h" 0012 0013 #include <QMenu> 0014 #include <QMouseEvent> 0015 #include <QPainter> 0016 #include <QPointer> 0017 #include <QRubberBand> 0018 #include <QToolTip> 0019 0020 #include <KLocalizedString> 0021 0022 #include <math.h> 0023 0024 #include "Document.h" 0025 #include "Element.h" 0026 #include "KeyElementDlg.h" 0027 #include "Page.h" 0028 #include "PagePreviewListWidgetItem.h" 0029 #include "PagePropertiesDlg.h" 0030 #include "TextElementDlg.h" 0031 #include "configuration.h" 0032 0033 PageLayoutEditor::PageLayoutEditor(QWidget *parent, Document *document) 0034 : QWidget(parent) 0035 , m_document(document) 0036 , m_pagePreview(nullptr) 0037 , m_elementUnderCursor(nullptr) 0038 , m_selecting(false) 0039 , m_resizing(false) 0040 , m_moved(false) 0041 , m_node(nullptr) 0042 , m_showGrid(Configuration::page_ShowGrid()) 0043 , m_gridSize(Configuration::page_GridSize()) 0044 , m_zoomFactor(1.0) 0045 { 0046 setContextMenuPolicy(Qt::CustomContextMenu); 0047 setPagePreview(nullptr); 0048 setMouseTracking(true); 0049 0050 connect(this, &PageLayoutEditor::customContextMenuRequested, this, &PageLayoutEditor::contextMenuRequestedOn); 0051 } 0052 0053 double PageLayoutEditor::zoomFactor() const 0054 { 0055 return m_zoomFactor; 0056 } 0057 0058 int PageLayoutEditor::gridSize() const 0059 { 0060 return m_gridSize; 0061 } 0062 0063 bool PageLayoutEditor::showGrid() const 0064 { 0065 return m_showGrid; 0066 } 0067 0068 void PageLayoutEditor::setPagePreview(PagePreviewListWidgetItem *pagePreview) 0069 { 0070 if ((m_pagePreview = pagePreview)) { 0071 m_boundary.setElement(nullptr); 0072 show(); 0073 updatePagePreview(); 0074 } else { 0075 hide(); 0076 } 0077 } 0078 0079 void PageLayoutEditor::updatePagePreview() 0080 { 0081 if (m_pagePreview) { 0082 m_paperWidth = m_pagePreview->paperWidth(); 0083 m_paperHeight = m_pagePreview->paperHeight(); 0084 setMinimumSize(scale(m_paperWidth), scale(m_paperHeight)); 0085 resize(minimumSize()); 0086 update(); 0087 } 0088 } 0089 0090 void PageLayoutEditor::setZoomFactor(double zoomFactor) 0091 { 0092 m_zoomFactor = zoomFactor; 0093 0094 if (m_pagePreview) { 0095 setMinimumSize(scale(m_paperWidth), scale(m_paperHeight)); 0096 resize(minimumSize()); 0097 } 0098 0099 repaint(); 0100 } 0101 0102 void PageLayoutEditor::setGridSize(int size) 0103 { 0104 m_gridSize = size; 0105 repaint(); 0106 } 0107 0108 void PageLayoutEditor::setShowGrid(bool show) 0109 { 0110 m_showGrid = show; 0111 repaint(); 0112 } 0113 0114 void PageLayoutEditor::setSelecting(bool selecting) 0115 { 0116 m_selecting = selecting; 0117 0118 if (!selecting) { 0119 m_boundary.setElement(nullptr); 0120 } 0121 } 0122 0123 void PageLayoutEditor::mousePressEvent(QMouseEvent *event) 0124 { 0125 m_moved = false; 0126 m_start = m_end = toSnap(event->pos()); 0127 0128 if (event->buttons() & Qt::LeftButton) { 0129 if (m_selecting) { 0130 if (!m_node) { 0131 m_boundary.setElement(m_pagePreview->page()->itemAt(unscale(event->pos()))); 0132 } 0133 } else { 0134 m_rubberBand = QRect(m_start, m_end).normalized(); 0135 } 0136 0137 update(); 0138 } 0139 } 0140 0141 void PageLayoutEditor::mouseMoveEvent(QMouseEvent *event) 0142 { 0143 m_end = toSnap(event->pos()); 0144 0145 if (event->buttons() & Qt::LeftButton) { 0146 if (m_selecting) { 0147 QPoint offset = m_end - m_start; 0148 0149 if (offset != QPoint(0, 0) && m_boundary.element()) { 0150 if (m_node) { 0151 m_boundary.moveNode(m_node, m_end); 0152 } else { 0153 m_boundary.element()->move(offset); 0154 m_boundary.setRectangle(m_boundary.rectangle().translated(offset)); 0155 } 0156 0157 QToolTip::showText(QCursor::pos(), 0158 QString::fromLatin1("%1,%2 %3 x %4") 0159 .arg(m_boundary.rectangle().left()) 0160 .arg(m_boundary.rectangle().top()) 0161 .arg(m_boundary.rectangle().width()) 0162 .arg(m_boundary.rectangle().height())); 0163 m_moved = true; 0164 m_start = m_end; 0165 update(); 0166 } 0167 } else { 0168 m_rubberBand = QRect(m_start, m_end).normalized(); 0169 update(); 0170 0171 QToolTip::showText( 0172 QCursor::pos(), 0173 QString::fromLatin1("%1,%2 %3 x %4").arg(m_rubberBand.left()).arg(m_rubberBand.top()).arg(m_rubberBand.width()).arg(m_rubberBand.height())); 0174 } 0175 } else { 0176 if (m_boundary.element() && (m_node = m_boundary.node(unscale(event->pos())))) { 0177 setCursor(m_boundary.cursor(m_node)); 0178 } else { 0179 setCursor(Qt::ArrowCursor); 0180 } 0181 } 0182 } 0183 0184 void PageLayoutEditor::mouseReleaseEvent(QMouseEvent *event) 0185 { 0186 if (!m_selecting) { 0187 if (m_rubberBand.isValid()) { 0188 m_end = toSnap(event->pos()); 0189 QRect selection = QRect(m_start, m_end).normalized(); 0190 m_rubberBand = QRect(); 0191 0192 if (selection.isValid()) { 0193 emit selectionMade(selection.adjusted(0, 0, -1, -1)); 0194 } 0195 } 0196 } else if (m_boundary.element() && m_moved) { 0197 emit elementGeometryChanged(); 0198 } 0199 0200 m_moved = false; 0201 update(); 0202 } 0203 0204 void PageLayoutEditor::paintEvent(QPaintEvent *event) 0205 { 0206 QPainter painter; 0207 QRect updateRect = event->rect(); // in device coordinates 0208 0209 painter.begin(this); 0210 painter.fillRect(updateRect, Qt::white); 0211 painter.setRenderHint(QPainter::Antialiasing, true); 0212 painter.setWindow(0, 0, m_paperWidth, m_paperHeight); 0213 0214 m_pagePreview->page()->render(m_document, &painter); 0215 0216 // draw snap grid 0217 if (m_showGrid) { 0218 int xOffset = (m_paperWidth / 2) % m_gridSize; 0219 int yOffset = (m_paperHeight / 2) % m_gridSize; 0220 0221 for (int y = yOffset; y < m_paperHeight; y += m_gridSize) { 0222 for (int x = xOffset; x < m_paperWidth; x += m_gridSize) { 0223 painter.setPen(QPen(Qt::black, 0.2)); 0224 painter.drawPoint(x, y); 0225 } 0226 } 0227 } 0228 0229 if (m_rubberBand.isValid()) { 0230 bool qt4CompatiblePainting = painter.renderHints() & QPainter::Qt4CompatiblePainting; 0231 painter.setRenderHint(QPainter::Qt4CompatiblePainting, true); 0232 QStyleOptionRubberBand opt; 0233 opt.initFrom(this); 0234 opt.shape = QRubberBand::Rectangle; 0235 opt.opaque = false; 0236 opt.rect = m_rubberBand; 0237 style()->drawControl(QStyle::CE_RubberBand, &opt, &painter); 0238 painter.setRenderHint(QPainter::Qt4CompatiblePainting, qt4CompatiblePainting); 0239 } 0240 0241 if (m_boundary.isValid()) { 0242 if (m_pagePreview->page()->elements().contains(m_boundary.element())) { 0243 m_boundary.render(&painter); 0244 } else { 0245 m_boundary.setElement(nullptr); 0246 } 0247 } 0248 0249 painter.end(); 0250 } 0251 0252 void PageLayoutEditor::contextMenuRequestedOn(const QPoint &pos) 0253 { 0254 Element *element = m_pagePreview->page()->itemAt(unscale(pos)); 0255 0256 if (element) { 0257 if (m_boundary.element() != element) { 0258 m_boundary.setElement(element); 0259 } 0260 } else { 0261 m_boundary.setElement(nullptr); 0262 } 0263 0264 update(); 0265 } 0266 0267 QPoint PageLayoutEditor::toSnap(const QPoint &pos) const 0268 { 0269 int scaledGridSize = scale(m_gridSize); 0270 int xOffset = (width() / 2) % scaledGridSize; 0271 int yOffset = (height() / 2) % scaledGridSize; 0272 int xSnap = unscale((((pos.x() - xOffset + 5) / scaledGridSize) * scaledGridSize) + xOffset); 0273 int ySnap = unscale((((pos.y() - yOffset + 5) / scaledGridSize) * scaledGridSize) + yOffset); 0274 return QPoint(xSnap, ySnap); 0275 } 0276 0277 int PageLayoutEditor::scale(int n) const 0278 { 0279 return int(double(n) * m_zoomFactor); 0280 } 0281 0282 int PageLayoutEditor::unscale(int n) const 0283 { 0284 return int(double(n) / m_zoomFactor); 0285 } 0286 0287 QPoint PageLayoutEditor::scale(const QPoint &p) const 0288 { 0289 return QPoint(scale(p.x()), scale(p.y())); 0290 } 0291 0292 QPoint PageLayoutEditor::unscale(const QPoint &p) const 0293 { 0294 return QPoint(unscale(p.x()), unscale(p.y())); 0295 } 0296 0297 QRect PageLayoutEditor::scale(const QRect &r) const 0298 { 0299 return QRect(scale(r.topLeft()), scale(r.bottomRight())); 0300 } 0301 0302 QRect PageLayoutEditor::unscale(const QRect &r) const 0303 { 0304 return QRect(unscale(r.topLeft()), unscale(r.bottomRight())); 0305 } 0306 0307 #include "moc_PageLayoutEditor.cpp"