/* * scribiu -- read notebooks and voice memos from Livescribe pens * Copyright (C) 2015 Javier S. Pedro * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "notebookview.h" #define VIEW_MARGIN 2 #define PAGE_SEPARATION 100 NotebookView::NotebookView(QWidget *parent) : QGraphicsView(parent), _nb(new AfdNotebook(this)), _replay(new PaperReplay(this)), _zoom(100), _curPage(0) { setScene(new QGraphicsScene(this)); setTransformationAnchor(AnchorUnderMouse); setDragMode(ScrollHandDrag); setRenderHints(QPainter::Antialiasing); } void NotebookView::setNotebook(const QString &path) { removePages(); _nbPath = path; if (!path.isEmpty()) { if (createPages()) { emit pageNumbersChanged(); if (!_pages.isEmpty()) { _curPage = _pages.begin().key(); centerOn(_pages[_curPage]); emit curPageChanged(); } } else { qWarning() << "Could not open notebook:" << _nbPath; } } } QString NotebookView::notebook() const { return _nbPath; } void NotebookView::setPaperReplay(const QString &path) { _replayPath = path; // TODO reload; for now, please set this before the notebook } QString NotebookView::paperReplay() const { return _replayPath; } QList NotebookView::pageNumbers() const { return _pages.keys(); } int NotebookView::curPage() const { return _curPage; } void NotebookView::setCurPage(int page) { if (page != _curPage) { _curPage = page; if (_zoom > 100) { setZoom(100); } if (_pages.contains(_curPage)) { centerOn(_pages[_curPage]); } emit curPageChanged(); } } int NotebookView::zoom() const { return _zoom; } void NotebookView::setZoom(int zoom) { if (zoom != _zoom) { _zoom = zoom; calculateScale(); } } QSize NotebookView::getCurPageSize() const { return _nb->getPageSize(_curPage); } QRect NotebookView::getCurPageTrim() const { return _nb->getPageTrim(_curPage); } QImage NotebookView::exportPage(int pageNum) const { const QRect pageTrim = getCurPageTrim(); QImage image(pageTrim.width() / 4, pageTrim.height() / 4, QImage::Format_RGB32); QPainter painter(&image); painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); renderPage(&painter, pageNum, QRectF(), pageTrim); return image; } void NotebookView::renderPage(QPainter *painter, int pageNum, const QRectF &target, const QRectF &source) const { QGraphicsScene scene; PageItem *item = new PageItem(_nb, 0, pageNum); scene.addItem(item); scene.render(painter, target, source, Qt::KeepAspectRatio); } void NotebookView::requestPaperReplay(const QString &file, qint64 time) { emit paperReplayRequested(file, time); } void NotebookView::clear() { removePages(); emit pageNumbersChanged(); } void NotebookView::prevPage() { QMap::iterator it = _pages.lowerBound(_curPage); if (it != _pages.end() && it != _pages.begin()) { --it; setCurPage(it.key()); } } void NotebookView::nextPage() { QMap::iterator it = _pages.upperBound(_curPage); if (it != _pages.end()) { setCurPage(it.key()); } } void NotebookView::resizeEvent(QResizeEvent *event) { QGraphicsView::resizeEvent(event); calculateScale(); } void NotebookView::scrollContentsBy(int dx, int dy) { QGraphicsView::scrollContentsBy(dx, dy); QGraphicsItem *item = itemAt(size().width() / 2, size().height() / 2); while (item && item->type() != PageItem::Type) { item = item->parentItem(); } if (item && item->type() == PageItem::Type) { PageItem * page = static_cast(item); int centerPage = page->pageNum(); if (centerPage != _curPage) { _curPage = centerPage; emit curPageChanged(); } } } void NotebookView::removePages() { _pages.clear(); scene()->clear(); scene()->setSceneRect(QRectF()); _nb->close(); _replay->close(); _maxPageSize.setWidth(0); _maxPageSize.setHeight(0); if (_zoom > 100) { _zoom = 100; emit zoomChanged(_zoom); } resetTransform(); } bool NotebookView::createPages() { if (!_nb->open(_nbPath)) return false; QStringList pens = _nb->penSerials(); if (pens.isEmpty()) return false; // Failure to open paperreplay data is not fatal bool haveReplay = _replay->open(_replayPath, _nb->guid()); QList pagesWithStrokes = _nb->pagesWithStrokes(pens.first()); Q_ASSERT(_pages.isEmpty()); _maxPageSize.setWidth(0); _maxPageSize.setHeight(0); foreach (int pageNum, pagesWithStrokes) { PageItem *page = new PageItem(_nb, haveReplay ? _replay : 0, pageNum); QRectF box = page->boundingRect(); if (box.width() > _maxPageSize.width()) { _maxPageSize.setWidth(box.width()); } if (box.height() > _maxPageSize.height()) { _maxPageSize.setHeight(box.height()); } _pages.insert(pageNum, page); } calculateScale(); qreal curY = 0; foreach (PageItem *page, _pages) { QRectF box = page->boundingRect(); page->setPos((_maxPageSize.width() - box.width()) / 2.0, curY); curY += box.height(); curY += PAGE_SEPARATION; scene()->addItem(page); } scene()->setSceneRect(0, 0, _maxPageSize.width(), curY); return true; } void NotebookView::calculateScale() { if (_pages.isEmpty() || _maxPageSize.isEmpty()) return; const int margin = VIEW_MARGIN; QRectF viewRect = viewport()->rect().adjusted(margin, margin, -margin, margin); qreal baseScale = qMin(viewRect.width() / _maxPageSize.width(), viewRect.height() / _maxPageSize.height()); resetTransform(); scale(baseScale, baseScale); if (_zoom < 100) { qreal s = 0.25 + ((_zoom / 100.0) * 0.75); scale(s, s); } else if (_zoom > 100) { qreal s = 1.0 + (_zoom - 100) * 0.015; scale(s, s); } }