diff --git a/Viewer/InfoBox.cpp b/Viewer/InfoBox.cpp index bc1f80db..5f0a5335 100644 --- a/Viewer/InfoBox.cpp +++ b/Viewer/InfoBox.cpp @@ -1,358 +1,360 @@ /* Copyright (C) 2003-2019 The KPhotoAlbum Development Team 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 2 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "InfoBox.h" // Qt includes #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include #include #include #include #ifdef HAVE_KGEOMAP #include #endif #include "VisibleOptionsMenu.h" using namespace Settings; Viewer::InfoBox::InfoBox(Viewer::ViewerWidget *viewer) : QTextBrowser(viewer) , m_viewer(viewer) , m_hoveringOverLink(false) , m_infoBoxResizer(this) , m_menu(nullptr) #ifdef HAVE_KGEOMAP , m_map(nullptr) #endif { setFrameStyle(Box | Plain); setLineWidth(1); setMidLineWidth(0); setAutoFillBackground(false); QPalette p = palette(); // we want a transparent background, not the default widget grey p.setColor(QPalette::Base, QColor(0, 0, 0, 170)); // r, g, b, A // adapt other colors as necessary p.setColor(QPalette::Text, Qt::white); p.setColor(QPalette::Link, p.color(QPalette::Link).lighter()); setPalette(p); m_jumpToContext = new QToolButton(this); m_jumpToContext->setIcon(QIcon::fromTheme(QString::fromUtf8("kphotoalbum"))); m_jumpToContext->setFixedSize(16, 16); connect(m_jumpToContext, &QToolButton::clicked, this, &InfoBox::jumpToContext); - connect(this, SIGNAL(highlighted(QString)), SLOT(linkHovered(QString))); + // overloaded signal requires explicit cast: + void (InfoBox::*highlighted)(const QString &) = &InfoBox::highlighted; + connect(this, highlighted, this, &InfoBox::linkHovered); #ifdef HAVE_KGEOMAP m_showOnMap = new QToolButton(this); m_showOnMap->setIcon(QIcon::fromTheme(QString::fromUtf8("atmosphere"))); m_showOnMap->setFixedSize(16, 16); m_showOnMap->setCursor(Qt::ArrowCursor); m_showOnMap->setToolTip(i18n("Show the geographic position of this image on a map")); connect(m_showOnMap, &QToolButton::clicked, this, &InfoBox::launchMapView); m_showOnMap->hide(); connect(m_viewer, &ViewerWidget::soughtTo, this, &InfoBox::updateMapForCurrentImage); #endif KRatingWidget *rating = new KRatingWidget; // Unfortunately, the KRatingWidget now thinks that it has some absurdly big // dimensions. This call will persuade it to stay reasonably small. rating->adjustSize(); for (int i = 0; i <= 10; ++i) { rating->setRating(i); // QWidget::grab() does not create an alpha channel // Therefore, we need to create a mask using heuristics (yes, this is slow, but we only do it once) QPixmap pixmap = rating->grab(); pixmap.setMask(pixmap.createHeuristicMask()); m_ratingPixmap.append(pixmap); } delete rating; } QVariant Viewer::InfoBox::loadResource(int type, const QUrl &name) { if (name.scheme() == QString::fromUtf8("kratingwidget")) { int rating = name.port(); Q_ASSERT(0 <= rating && rating <= 10); return m_ratingPixmap[rating]; } return QTextBrowser::loadResource(type, name); } void Viewer::InfoBox::setSource(const QUrl &source) { int index = source.path().toInt(); QPair p = m_linkMap[index]; QString category = p.first; QString value = p.second; Browser::BrowserWidget::instance()->load(category, value); showBrowser(); } void Viewer::InfoBox::setInfo(const QString &text, const QMap> &linkMap) { m_linkMap = linkMap; setText(text); hackLinkColorForQt52(); #ifdef HAVE_KGEOMAP if (m_viewer->currentInfo()->coordinates().hasCoordinates()) { m_showOnMap->show(); } else { m_showOnMap->hide(); } #endif setSize(); } void Viewer::InfoBox::setSize() { const int maxWidth = Settings::SettingsData::instance()->infoBoxWidth(); const int maxHeight = Settings::SettingsData::instance()->infoBoxHeight(); document()->setPageSize(QSize(maxWidth, maxHeight)); bool showVerticalBar = document()->size().height() > maxHeight; setVerticalScrollBarPolicy(showVerticalBar ? Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); const int realWidth = static_cast(document()->idealWidth()) + (showVerticalBar ? verticalScrollBar()->width() + frameWidth() : 0) + m_jumpToContext->width() + 10; resize(realWidth, qMin((int)document()->size().height(), maxHeight)); } void Viewer::InfoBox::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { possiblyStartResize(event->pos()); } QTextBrowser::mousePressEvent(event); } void Viewer::InfoBox::mouseReleaseEvent(QMouseEvent *event) { if (m_infoBoxResizer.isActive()) { Settings::SettingsData::instance()->setInfoBoxWidth(width()); Settings::SettingsData::instance()->setInfoBoxHeight(height()); } m_infoBoxResizer.deactivate(); QTextBrowser::mouseReleaseEvent(event); } void Viewer::InfoBox::mouseMoveEvent(QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) { if (m_infoBoxResizer.isActive()) { m_infoBoxResizer.setPos(event->pos()); } else { m_viewer->infoBoxMove(); } // Do not tell QTextBrowser about the mouse movement, as this will just start a selection. } else { updateCursor(event->pos()); QTextBrowser::mouseMoveEvent(event); } } void Viewer::InfoBox::linkHovered(const QString &linkName) { if (linkName.isEmpty()) { emit noTagHovered(); } else { emit tagHovered(m_linkMap[linkName.toInt()]); } m_hoveringOverLink = !linkName.isNull(); } void Viewer::InfoBox::jumpToContext() { Browser::BrowserWidget::instance()->addImageView(m_viewer->currentInfo()->fileName()); showBrowser(); } void Viewer::InfoBox::showBrowser() { QDesktopWidget *desktop = qApp->desktop(); if (desktop->screenNumber(Browser::BrowserWidget::instance()) == desktop->screenNumber(m_viewer)) { if (m_viewer->showingFullScreen()) { m_viewer->setShowFullScreen(false); } MainWindow::Window::theMainWindow()->raise(); } } /** * Update the cursor based on the cursors position in the info box */ void Viewer::InfoBox::updateCursor(const QPoint &pos) { const int border = 25; bool left = (pos.x() < border); bool right = pos.x() > width() - border; bool top = pos.y() < border; bool bottom = pos.y() > height() - border; Settings::Position windowPos = Settings::SettingsData::instance()->infoBoxPosition(); Qt::CursorShape shape = Qt::SizeAllCursor; if (m_hoveringOverLink) { shape = Qt::PointingHandCursor; } else if (atBlackoutPos(left, right, top, bottom, windowPos)) { shape = Qt::SizeAllCursor; } else if ((left && top) || (right && bottom)) { shape = Qt::SizeFDiagCursor; } else if ((left && bottom) || (right && top)) { shape = Qt::SizeBDiagCursor; } else if (top || bottom) { shape = Qt::SizeVerCursor; } else if (left || right) { shape = Qt::SizeHorCursor; } setCursor(shape); viewport()->setCursor(shape); } /** * Return true if we are at an edge of the image info box that is towards the edge of the viewer. * We can forexample not make the box taller at the bottom if the box is sitting at the bottom of the viewer. */ bool Viewer::InfoBox::atBlackoutPos(bool left, bool right, bool top, bool bottom, Settings::Position pos) const { return (left && (pos == Left || pos == TopLeft || pos == BottomLeft)) || (right && (pos == Right || pos == TopRight || pos == BottomRight)) || (top && (pos == Top || pos == TopLeft || pos == TopRight)) || (bottom && (pos == Bottom || pos == BottomLeft || pos == BottomRight)); } void Viewer::InfoBox::possiblyStartResize(const QPoint &pos) { const int border = 25; bool left = (pos.x() < border); bool right = pos.x() > width() - border; bool top = pos.y() < border; bool bottom = pos.y() > height() - border; if (left || right || top || bottom) { m_infoBoxResizer.setup(left, right, top, bottom); } } void Viewer::InfoBox::resizeEvent(QResizeEvent *) { QPoint pos = viewport()->rect().adjusted(0, 2, -m_jumpToContext->width() - 2, 0).topRight(); m_jumpToContext->move(pos); #ifdef HAVE_KGEOMAP pos.setY(pos.y() + 20); m_showOnMap->move(pos); #endif } /** * @brief override the color of links because the one in the palette isn't used. * As can be seen in the referenced links, QTextBrowser uses the global palette for setting the link color. * Until it uses the widget palette, we have to do this workaround. * @see https://bugreports.qt.io/browse/QTBUG-28998 * @see https://codereview.qt-project.org/c/qt/qtbase/+/68874/2/src/gui/text/qtexthtmlparser.cpp */ void Viewer::InfoBox::hackLinkColorForQt52() { QTextCursor cursor(document()); QBrush linkColor = palette().link(); Q_FOREVER { QTextCharFormat f = cursor.charFormat(); if (f.isAnchor()) { f.setForeground(linkColor); QTextCursor c2 = cursor; c2.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); c2.setCharFormat(f); } if (cursor.atEnd()) { break; } cursor.movePosition(QTextCursor::NextCharacter); } } void Viewer::InfoBox::contextMenuEvent(QContextMenuEvent *event) { if (!m_menu) { m_menu = new VisibleOptionsMenu(m_viewer, new KActionCollection((QObject *)nullptr)); connect(m_menu, &VisibleOptionsMenu::visibleOptionsChanged, m_viewer, &ViewerWidget::updateInfoBox); } m_menu->exec(event->globalPos()); } #ifdef HAVE_KGEOMAP void Viewer::InfoBox::launchMapView() { if (!m_map) { m_map = new Map::MapView(m_viewer, Map::MapView::MapViewWindow); } m_map->addImage(m_viewer->currentInfo()); m_map->setShowThumbnails(false); m_map->zoomToMarkers(); m_map->show(); m_map->raise(); } void Viewer::InfoBox::updateMapForCurrentImage(DB::FileName) { if (!m_map) { return; } if (m_viewer->currentInfo()->coordinates().hasCoordinates()) { m_map->displayStatus(Map::MapView::MapStatus::ImageHasCoordinates); m_map->clear(); m_map->addImage(m_viewer->currentInfo()); m_map->setCenter(m_viewer->currentInfo()); } else { m_map->displayStatus(Map::MapView::MapStatus::ImageHasNoCoordinates); } } #endif // vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/Viewer/TaggedArea.cpp b/Viewer/TaggedArea.cpp index 0cbe250a..5be818a0 100644 --- a/Viewer/TaggedArea.cpp +++ b/Viewer/TaggedArea.cpp @@ -1,82 +1,95 @@ /* Copyright (C) 2014-2019 The KPhotoAlbum Development Team 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 2 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "TaggedArea.h" #include +#include +#include Viewer::TaggedArea::TaggedArea(QWidget *parent) : QFrame(parent) { setFrameShape(QFrame::Box); setStyleSheet(QString::fromLatin1( "Viewer--TaggedArea { border: none; background-color: none; }" - "Viewer--TaggedArea:hover, Viewer--TaggedArea[selected=\"true\"]{ border: 1px solid rgb(0,255,0,99); background-color: rgb(255,255,255,30); }" + "Viewer--TaggedArea:hover, Viewer--TaggedArea[selected=\"true\"] {" + " border: 1px solid rgb(0,255,0,99); background-color: rgb(255,255,255,30);" + " }" "Viewer--TaggedArea[highlighted=\"true\"]{ border: 1px solid rgb(255,128,0,99); background-color: rgb(255,255,255,30); }")); } Viewer::TaggedArea::~TaggedArea() { } void Viewer::TaggedArea::setTagInfo(QString category, QString localizedCategory, QString tag) { setToolTip(tag + QString::fromLatin1(" (") + localizedCategory + QString::fromLatin1(")")); m_tagInfo = QPair(category, tag); } void Viewer::TaggedArea::setActualGeometry(QRect geometry) { m_actualGeometry = geometry; } QRect Viewer::TaggedArea::actualGeometry() const { return m_actualGeometry; } void Viewer::TaggedArea::setSelected(bool selected) { m_selected = selected; + repolish(); } bool Viewer::TaggedArea::selected() const { return m_selected; } void Viewer::TaggedArea::deselect() { setSelected(false); } void Viewer::TaggedArea::checkIsSelected(QPair tagData) { - m_selected = (tagData == m_tagInfo); + setSelected(tagData == m_tagInfo); +} + +void Viewer::TaggedArea::repolish() +{ + style()->unpolish(this); + style()->polish(this); + update(); } bool Viewer::TaggedArea::highlighted() const { return m_highlighted; } void Viewer::TaggedArea::setHighlighted(bool highlighted) { m_highlighted = highlighted; + repolish(); } // vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/Viewer/TaggedArea.h b/Viewer/TaggedArea.h index d514de1a..dae13396 100644 --- a/Viewer/TaggedArea.h +++ b/Viewer/TaggedArea.h @@ -1,77 +1,84 @@ /* Copyright (C) 2014-2019 The KPhotoAlbum Development Team 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 2 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef TAGGEDAREA_H #define TAGGEDAREA_H #include namespace Viewer { class TaggedArea : public QFrame { Q_OBJECT Q_PROPERTY(bool selected MEMBER m_selected READ selected WRITE setSelected RESET deselect) Q_PROPERTY(bool highlighted MEMBER m_highlighted READ highlighted WRITE setHighlighted) public: explicit TaggedArea(QWidget *parent = 0); ~TaggedArea() override; void setTagInfo(QString category, QString localizedCategory, QString tag); void setActualGeometry(QRect geometry); QRect actualGeometry() const; /** * @brief When selected, the TaggedArea is shown (just like when hovering with the mouse). * This is used to make the area visible when the corresponding tag in the ViewerWidget is hovered. * @return \c true, if the area is visible. */ bool selected() const; void setSelected(bool selected); void deselect(); /** * @brief highlighted * @return \c true, when the area should be visibly highlighted, \c false otherwise. */ bool highlighted() const; /** * @brief setHighlighted sets the highlighted property of the area. * An area with the highlighted tag set to \c true will be visibly highlighted. * @param highlighted */ void setHighlighted(bool highlighted); public slots: /** * @brief checkIsSelected set the \c selected property if tagData matches the tag. * @param tagData */ void checkIsSelected(QPair tagData); +protected: + /** + * @brief repolish tells the widget to reevaluate its style. + * This required when the style is dynamically changed because a property changed. + */ + void repolish(); + private: QPair m_tagInfo; QRect m_actualGeometry; - bool m_selected; - bool m_highlighted; + bool m_selected = false; + bool m_highlighted = false; }; } #endif // TAGGEDAREA_H // vi:expandtab:tabstop=4 shiftwidth=4: