15 Commits

15 changed files with 425 additions and 53 deletions

3
.gitignore vendored
View File

@ -3,3 +3,6 @@
# Translation files # Translation files
*.qm *.qm
# Generic Build Dir
[Bb]uild/

148
CMakeLists.txt Normal file
View File

@ -0,0 +1,148 @@
project (pineapple-pictures)
cmake_minimum_required (VERSION 3.9.5)
include (GNUInstallDirs)
set (CMAKE_AUTOMOC ON)
set (CMAKE_AUTORCC ON)
set (QT_MINIMUM_VERSION "5.10")
find_package(Qt5 ${QT_MINIMUM_VERSION} CONFIG REQUIRED Widgets Svg LinguistTools)
set (PPIC_CPP_FILES
main.cpp
mainwindow.cpp
graphicsview.cpp
graphicsscene.cpp
bottombuttongroup.cpp
navigatorview.cpp
opacityhelper.cpp
toolbutton.cpp
)
set (PPIC_HEADER_FILES
mainwindow.h
graphicsview.h
graphicsscene.h
bottombuttongroup.h
navigatorview.h
opacityhelper.h
toolbutton.h
)
set (PPIC_QRC_FILES
resources.qrc
)
set (PPIC_RC_FILES
# yeah, it's empty.
)
set (EXE_NAME ppic)
# Translation
file (GLOB PPIC_TS_FILES languages/*.ts)
set (PPIC_CPP_FILES_FOR_I18N ${PPIC_CPP_FILES})
qt5_create_translation(PPIC_QM_FILES ${PPIC_CPP_FILES_FOR_I18N} ${PPIC_TS_FILES})
if (WIN32)
list(APPEND PPIC_RC_FILES pineapple-pictures.rc)
endif ()
add_executable (${EXE_NAME}
${PPIC_HEADER_FILES}
${PPIC_CPP_FILES}
${PPIC_QRC_FILES}
${PPIC_RC_FILES}
${PPIC_QM_FILES}
)
target_link_libraries (${EXE_NAME} Qt5::Widgets Qt5::Svg)
# Extra build settings
if (WIN32)
set_property (
TARGET ${EXE_NAME}
PROPERTY WIN32_EXECUTABLE true
)
endif ()
# Helper macros for install settings
macro (ppic_convert_to_relative_path _var)
# Make sure _var is a relative path
if (IS_ABSOLUTE "${${_var}}")
file (RELATIVE_PATH ${_var} "${CMAKE_INSTALL_PREFIX}" "${${_var}}")
endif ()
endmacro ()
# Install settings
if (WIN32)
# FIXME: try to avoid install to a "bin" subfolder under windows...
# when fixed, don't forget to update the CI config file...
set (BIN_INSTALL_DIR "") # seems useless, don't know why...
elseif (UNIX)
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX /usr)
endif ()
set (BIN_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}") # relative, usually "bin"
ppic_convert_to_relative_path(BIN_INSTALL_DIR)
set (LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}") # "lib" or "lib64"
ppic_convert_to_relative_path(LIB_INSTALL_DIR)
# install icon
install (
FILES icons/app-icon.svg
DESTINATION "${CMAKE_INSTALL_DATADIR}/icons/hicolor/48x48/apps"
RENAME pineapple-pictures.svg
)
# install shortcut
install (
FILES pineapple-pictures.desktop
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications"
)
endif()
set (INSTALL_TARGETS_DEFAULT_ARGS
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT Devel
)
install (
TARGETS ${EXE_NAME}
${INSTALL_TARGETS_DEFAULT_ARGS}
)
if (WIN32)
set (QM_FILE_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}/translations")
else ()
set (QM_FILE_INSTALL_DIR "${CMAKE_INSTALL_FULL_DATADIR}/pineapple-pictures/translations")
target_compile_definitions(${EXE_NAME}
PRIVATE QM_FILE_INSTALL_DIR=${QM_FILE_INSTALL_DIR}
)
endif ()
install (
FILES ${PPIC_QM_FILES}
DESTINATION ${QM_FILE_INSTALL_DIR}
)
# CPACK: General Settings
set (CPACK_GENERATOR "TBZ2")
set (CPACK_PACKAGE_NAME "PineapplePictures")
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Yet another image viewer")
set (CPACK_PACKAGE_VENDOR "Gary Wang")
set (CPACK_PACKAGE_CONTACT "https://github.com/BLumia/PineapplePictures/issues/")
if (WIN32)
# ...
elseif (APPLE)
# ...
elseif (UNIX)
set(CPACK_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
endif()
include(CPack)

View File

@ -1,5 +1,22 @@
Yet another image viewer. Yet another image viewer.
|CI|Build Status|
|---|---|
|Windows Build|[![Windows build status](https://ci.appveyor.com/api/projects/status/dbd8clww3cit6oa0/branch/master?svg=true)](https://ci.appveyor.com/project/BLumia/pineapplepictures/branch/master)|
![Pineapple Pictures - Main Window](https://repository-images.githubusercontent.com/211888654/21fb6300-269f-11ea-8e85-953e5d57da44)
## Get it!
- [GitHub Release Page](https://github.com/BLumia/PineapplePictures/releases)
- Archlinux AUR: [pineapple-pictures-git](https://aur.archlinux.org/packages/pineapple-pictures-git/)
## Help Translation!
[Translate this project on Transifex!](https://www.transifex.com/blumia/pineapple-pictures/)
Feel free to open up an issue to request an new language to translate.
## Uncleaned shits inside(TM): ## Uncleaned shits inside(TM):
- Mixed `CR LF` and `LF`. - Mixed `CR LF` and `LF`.

View File

@ -1,11 +1,8 @@
environment: environment:
matrix: matrix:
- build_name: mingw73_32_qt5_12_5 - build_name: mingw73_32_qt5_12_6
QTPATH: C:\Qt\5.12.5\mingw73_32 QTPATH: C:\Qt\5.12.6\mingw73_32
MINGW32: C:\Qt\Tools\mingw730_32 MINGW32: C:\Qt\Tools\mingw730_32
# - build_name: msvc2017_64
# QTPATH: C:\Qt\5.11.2\msvc2017_64
# MINGW32: C:\Qt\Tools\mingw530_32
install: install:
- cd %APPVEYOR_BUILD_FOLDER% - cd %APPVEYOR_BUILD_FOLDER%
@ -15,11 +12,13 @@ install:
build_script: build_script:
- mkdir build - mkdir build
- cd build - cd build
- qmake ..\PineapplePictures.pro - cmake -G "Unix Makefiles" -DCMAKE_MAKE_PROGRAM=mingw32-make -DCMAKE_INSTALL_PREFIX='%cd%' ..\
- mingw32-make - mingw32-make
- cd release - mingw32-make install
- del /a /f /q "*.o" "*.cpp" "*.h" # fixme: I don't know how to NOT make the binary installed to the ./bin/ folder...
- windeployqt --no-quick-import --no-translations --no-opengl-sw --no-angle --no-system-d3d-compiler --release .\PineapplePictures.exe - cd bin
- windeployqt --no-quick-import --no-translations --no-opengl-sw --no-angle --no-system-d3d-compiler --release .\ppic.exe
- tree
artifacts: artifacts:
- path: build\release - path: build\bin

View File

@ -8,6 +8,7 @@
#include <QGraphicsSvgItem> #include <QGraphicsSvgItem>
#include <QMovie> #include <QMovie>
#include <QLabel> #include <QLabel>
#include <QPainter>
GraphicsScene::GraphicsScene(QObject *parent) GraphicsScene::GraphicsScene(QObject *parent)
: QGraphicsScene(parent) : QGraphicsScene(parent)
@ -58,3 +59,24 @@ void GraphicsScene::showGif(const QString &filepath)
QPen(Qt::transparent)); QPen(Qt::transparent));
this->setSceneRect(m_theThing->boundingRect()); this->setSceneRect(m_theThing->boundingRect());
} }
bool GraphicsScene::trySetTransformationMode(Qt::TransformationMode mode)
{
QGraphicsPixmapItem * pixmapItem = qgraphicsitem_cast<QGraphicsPixmapItem *>(m_theThing);
if (pixmapItem) {
pixmapItem->setTransformationMode(mode);
return true;
}
return false;
}
QPixmap GraphicsScene::renderToPixmap()
{
QPixmap pixmap(sceneRect().toRect().size());
pixmap.fill(Qt::transparent);
QPainter p(&pixmap);
render(&p, sceneRect());
return pixmap;
}

View File

@ -15,6 +15,10 @@ public:
void showSvg(const QString &filepath); void showSvg(const QString &filepath);
void showGif(const QString &filepath); void showGif(const QString &filepath);
bool trySetTransformationMode(Qt::TransformationMode mode);
QPixmap renderToPixmap();
private: private:
QGraphicsItem * m_theThing; QGraphicsItem * m_theThing;
}; };

View File

@ -59,6 +59,13 @@ void GraphicsView::showImage(const QPixmap &pixmap)
checkAndDoFitInView(); checkAndDoFitInView();
} }
void GraphicsView::showImage(const QImage &image)
{
resetTransform();
scene()->showImage(QPixmap::fromImage(image));
checkAndDoFitInView();
}
void GraphicsView::showText(const QString &text) void GraphicsView::showText(const QString &text)
{ {
resetTransform(); resetTransform();
@ -110,6 +117,7 @@ void GraphicsView::zoomView(qreal scaleFactor)
{ {
m_enableFitInView = false; m_enableFitInView = false;
scale(scaleFactor, scaleFactor); scale(scaleFactor, scaleFactor);
applyTransformationModeByScaleFactor();
emit navigatorViewRequired(!isThingSmallerThanWindowWith(transform()), m_rotateAngle); emit navigatorViewRequired(!isThingSmallerThanWindowWith(transform()), m_rotateAngle);
} }
@ -129,6 +137,7 @@ void GraphicsView::rotateView(qreal rotateAngel)
void GraphicsView::fitInView(const QRectF &rect, Qt::AspectRatioMode aspectRadioMode) void GraphicsView::fitInView(const QRectF &rect, Qt::AspectRatioMode aspectRadioMode)
{ {
QGraphicsView::fitInView(rect, aspectRadioMode); QGraphicsView::fitInView(rect, aspectRadioMode);
applyTransformationModeByScaleFactor();
} }
void GraphicsView::checkAndDoFitInView() void GraphicsView::checkAndDoFitInView()
@ -206,9 +215,9 @@ void GraphicsView::dragEnterEvent(QDragEnterEvent *event)
} else { } else {
event->ignore(); event->ignore();
} }
qDebug() << event->mimeData() << "Drag Enter Event" // qDebug() << event->mimeData() << "Drag Enter Event"
<< event->mimeData()->hasUrls() << event->mimeData()->hasImage() // << event->mimeData()->hasUrls() << event->mimeData()->hasImage()
<< event->mimeData()->formats() << event->mimeData()->hasFormat("text/uri-list"); // << event->mimeData()->formats() << event->mimeData()->hasFormat("text/uri-list");
return QGraphicsView::dragEnterEvent(event); return QGraphicsView::dragEnterEvent(event);
} }
@ -278,9 +287,9 @@ void GraphicsView::setCheckerboardEnabled(bool enabled)
if (m_checkerboardEnabled) { if (m_checkerboardEnabled) {
// Prepare background check-board pattern // Prepare background check-board pattern
QPixmap tilePixmap(0x20, 0x20); QPixmap tilePixmap(0x20, 0x20);
tilePixmap.fill(QColor(35, 35, 35, 110)); tilePixmap.fill(QColor(35, 35, 35, 170));
QPainter tilePainter(&tilePixmap); QPainter tilePainter(&tilePixmap);
QColor color(40, 40, 40, 110); QColor color(45, 45, 45, 170);
tilePainter.fillRect(0, 0, 0x10, 0x10, color); tilePainter.fillRect(0, 0, 0x10, 0x10, color);
tilePainter.fillRect(0x10, 0x10, 0x10, 0x10, color); tilePainter.fillRect(0x10, 0x10, 0x10, 0x10, color);
tilePainter.end(); tilePainter.end();
@ -291,6 +300,15 @@ void GraphicsView::setCheckerboardEnabled(bool enabled)
} }
} }
void GraphicsView::applyTransformationModeByScaleFactor()
{
if (this->scaleFactor() < 1) {
scene()->trySetTransformationMode(Qt::SmoothTransformation);
} else {
scene()->trySetTransformationMode(Qt::FastTransformation);
}
}
void GraphicsView::resetWithScaleAndRotate(qreal scaleFactor, qreal rotateAngle) void GraphicsView::resetWithScaleAndRotate(qreal scaleFactor, qreal rotateAngle)
{ {
QGraphicsView::resetTransform(); QGraphicsView::resetTransform();

View File

@ -14,6 +14,7 @@ public:
void showFileFromUrl(const QUrl &url, bool requestGallery = false); void showFileFromUrl(const QUrl &url, bool requestGallery = false);
void showImage(const QPixmap &pixmap); void showImage(const QPixmap &pixmap);
void showImage(const QImage &image);
void showText(const QString &text); void showText(const QString &text);
void showSvg(const QString &filepath); void showSvg(const QString &filepath);
void showGif(const QString &filepath); void showGif(const QString &filepath);
@ -53,6 +54,7 @@ private:
bool isThingSmallerThanWindowWith(const QTransform &transform) const; bool isThingSmallerThanWindowWith(const QTransform &transform) const;
bool shouldIgnoreMousePressMoveEvent(const QMouseEvent *event) const; bool shouldIgnoreMousePressMoveEvent(const QMouseEvent *event) const;
void setCheckerboardEnabled(bool enabled); void setCheckerboardEnabled(bool enabled);
void applyTransformationModeByScaleFactor();
void resetWithScaleAndRotate(qreal scaleFactor, qreal rotateAngle); void resetWithScaleAndRotate(qreal scaleFactor, qreal rotateAngle);

View File

@ -4,7 +4,7 @@
<context> <context>
<name>GraphicsScene</name> <name>GraphicsScene</name>
<message> <message>
<location filename="../graphicsscene.cpp" line="15"/> <location filename="../graphicsscene.cpp" line="16"/>
<source>Drag image here</source> <source>Drag image here</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -12,22 +12,22 @@
<context> <context>
<name>GraphicsView</name> <name>GraphicsView</name>
<message> <message>
<location filename="../graphicsview.cpp" line="32"/> <location filename="../graphicsview.cpp" line="239"/>
<source>File url list is empty</source> <source>File url list is empty</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../graphicsview.cpp" line="46"/> <location filename="../graphicsview.cpp" line="44"/>
<source>File is not a valid image</source> <source>File is not a valid image</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../graphicsview.cpp" line="238"/> <location filename="../graphicsview.cpp" line="247"/>
<source>Image data is invalid</source> <source>Image data is invalid</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../graphicsview.cpp" line="245"/> <location filename="../graphicsview.cpp" line="254"/>
<source>Not supported mimedata: %1</source> <source>Not supported mimedata: %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -35,44 +35,74 @@
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>
<location filename="../mainwindow.cpp" line="229"/> <location filename="../mainwindow.cpp" line="143"/>
<location filename="../mainwindow.cpp" line="248"/> <source>File url list is empty</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="322"/>
<source>&amp;Copy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="343"/>
<source>Copy P&amp;ixmap</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="348"/>
<source>Copy &amp;File Path</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="358"/>
<source>&amp;Paste Image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="363"/>
<source>&amp;Paste Image File</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="368"/>
<location filename="../mainwindow.cpp" line="387"/>
<source>Stay on top</source> <source>Stay on top</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="235"/> <location filename="../mainwindow.cpp" line="374"/>
<location filename="../mainwindow.cpp" line="249"/> <location filename="../mainwindow.cpp" line="388"/>
<source>Protected mode</source> <source>Protected mode</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="241"/> <location filename="../mainwindow.cpp" line="380"/>
<source>Help</source> <source>Help</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="244"/> <location filename="../mainwindow.cpp" line="383"/>
<source>Launch application with image file path as argument to load the file.</source> <source>Launch application with image file path as argument to load the file.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="245"/> <location filename="../mainwindow.cpp" line="384"/>
<source>Drag and drop image file onto the window is also supported.</source> <source>Drag and drop image file onto the window is also supported.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="247"/> <location filename="../mainwindow.cpp" line="386"/>
<source>Context menu option explanation:</source> <source>Context menu option explanation:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="248"/> <location filename="../mainwindow.cpp" line="387"/>
<source>Make window stay on top of all other windows.</source> <source>Make window stay on top of all other windows.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="249"/> <location filename="../mainwindow.cpp" line="388"/>
<source>Avoid close window accidentally. (eg. by double clicking the window)</source> <source>Avoid close window accidentally. (eg. by double clicking the window)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -80,7 +110,7 @@
<context> <context>
<name>main</name> <name>main</name>
<message> <message>
<location filename="../main.cpp" line="18"/> <location filename="../main.cpp" line="24"/>
<source>File list.</source> <source>File list.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>

View File

@ -4,7 +4,7 @@
<context> <context>
<name>GraphicsScene</name> <name>GraphicsScene</name>
<message> <message>
<location filename="../graphicsscene.cpp" line="15"/> <location filename="../graphicsscene.cpp" line="16"/>
<source>Drag image here</source> <source>Drag image here</source>
<translation></translation> <translation></translation>
</message> </message>
@ -12,22 +12,22 @@
<context> <context>
<name>GraphicsView</name> <name>GraphicsView</name>
<message> <message>
<location filename="../graphicsview.cpp" line="32"/> <location filename="../graphicsview.cpp" line="239"/>
<source>File url list is empty</source> <source>File url list is empty</source>
<translation> URL </translation> <translation> URL </translation>
</message> </message>
<message> <message>
<location filename="../graphicsview.cpp" line="46"/> <location filename="../graphicsview.cpp" line="44"/>
<source>File is not a valid image</source> <source>File is not a valid image</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../graphicsview.cpp" line="238"/> <location filename="../graphicsview.cpp" line="247"/>
<source>Image data is invalid</source> <source>Image data is invalid</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../graphicsview.cpp" line="245"/> <location filename="../graphicsview.cpp" line="254"/>
<source>Not supported mimedata: %1</source> <source>Not supported mimedata: %1</source>
<translation> MimeData %1</translation> <translation> MimeData %1</translation>
</message> </message>
@ -35,44 +35,78 @@
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>
<location filename="../mainwindow.cpp" line="229"/> <location filename="../mainwindow.cpp" line="143"/>
<location filename="../mainwindow.cpp" line="248"/> <source>File url list is empty</source>
<translation> URL </translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="322"/>
<source>&amp;Copy</source>
<translation>(&amp;C)</translation>
</message>
<message>
<source>Copy &amp;Pixmap</source>
<translation type="vanished">(&amp;P)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="343"/>
<source>Copy P&amp;ixmap</source>
<translation>(&amp;I)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="348"/>
<source>Copy &amp;File Path</source>
<translation>(&amp;F)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="358"/>
<source>&amp;Paste Image</source>
<translation>(&amp;P)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="363"/>
<source>&amp;Paste Image File</source>
<translation>(&amp;P)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="368"/>
<location filename="../mainwindow.cpp" line="387"/>
<source>Stay on top</source> <source>Stay on top</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="235"/> <location filename="../mainwindow.cpp" line="374"/>
<location filename="../mainwindow.cpp" line="249"/> <location filename="../mainwindow.cpp" line="388"/>
<source>Protected mode</source> <source>Protected mode</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="241"/> <location filename="../mainwindow.cpp" line="380"/>
<source>Help</source> <source>Help</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="244"/> <location filename="../mainwindow.cpp" line="383"/>
<source>Launch application with image file path as argument to load the file.</source> <source>Launch application with image file path as argument to load the file.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="245"/> <location filename="../mainwindow.cpp" line="384"/>
<source>Drag and drop image file onto the window is also supported.</source> <source>Drag and drop image file onto the window is also supported.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="247"/> <location filename="../mainwindow.cpp" line="386"/>
<source>Context menu option explanation:</source> <source>Context menu option explanation:</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="248"/> <location filename="../mainwindow.cpp" line="387"/>
<source>Make window stay on top of all other windows.</source> <source>Make window stay on top of all other windows.</source>
<translation>使</translation> <translation>使</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="249"/> <location filename="../mainwindow.cpp" line="388"/>
<source>Avoid close window accidentally. (eg. by double clicking the window)</source> <source>Avoid close window accidentally. (eg. by double clicking the window)</source>
<translation></translation> <translation></translation>
</message> </message>
@ -80,7 +114,7 @@
<context> <context>
<name>main</name> <name>main</name>
<message> <message>
<location filename="../main.cpp" line="18"/> <location filename="../main.cpp" line="24"/>
<source>File list.</source> <source>File list.</source>
<translation></translation> <translation></translation>
</message> </message>

View File

@ -1,16 +1,27 @@
#include "mainwindow.h" #include "mainwindow.h"
#include <QApplication> #include <QApplication>
#include <QCommandLineParser> #include <QCommandLineParser>
#include <QDir>
#include <QTranslator> #include <QTranslator>
#include <QUrl> #include <QUrl>
// QM_FILE_INSTALL_DIR should be defined from the CMakeLists file.
#ifndef QM_FILE_INSTALL_DIR
#define QM_FILE_INSTALL_DIR ":/i18n/"
#endif // QM_FILE_INSTALL_DIR
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QApplication a(argc, argv); QApplication a(argc, argv);
// since we did `CONFIG += lrelease embed_translations`...
QTranslator translator; QTranslator translator;
translator.load(QString("PineapplePictures_%1").arg(QLocale::system().name()), ":/i18n/"); QString qmDir;
#ifdef _WIN32
qmDir = QDir(QCoreApplication::applicationDirPath()).absoluteFilePath("translations");
#else
qmDir = QT_STRINGIFY(QM_FILE_INSTALL_DIR);
#endif
translator.load(QString("PineapplePictures_%1").arg(QLocale::system().name()), qmDir);
a.installTranslator(&translator); a.installTranslator(&translator);
// parse commandline arguments // parse commandline arguments

View File

@ -17,6 +17,8 @@
#include <QShortcut> #include <QShortcut>
#include <QDir> #include <QDir>
#include <QCollator> #include <QCollator>
#include <QClipboard>
#include <QMimeData>
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
@ -173,12 +175,22 @@ void MainWindow::adjustWindowSizeBySceneRect()
} }
} }
// can be empty if it is NOT from a local file.
QUrl MainWindow::currentImageFileUrl() const
{
if (m_currentFileIndex != -1) {
return m_files.value(m_currentFileIndex);
}
return QUrl();
}
void MainWindow::loadGalleryBySingleLocalFile(const QString &path) void MainWindow::loadGalleryBySingleLocalFile(const QString &path)
{ {
QFileInfo info(path); QFileInfo info(path);
QDir dir(info.path()); QDir dir(info.path());
QString currentFileName = info.fileName(); QString currentFileName = info.fileName();
QStringList entryList = dir.entryList({"*.jpg", "*.jpeg", "*.png", "*.gif", "*.svg"}, QStringList entryList = dir.entryList({"*.jpg", "*.jpeg", "*.png", "*.gif", "*.svg", "*.bmp"},
QDir::Files | QDir::NoSymLinks, QDir::NoSort); QDir::Files | QDir::NoSymLinks, QDir::NoSort);
QCollator collator; QCollator collator;
@ -197,7 +209,7 @@ void MainWindow::loadGalleryBySingleLocalFile(const QString &path)
} }
} }
qDebug() << m_files << m_currentFileIndex; // qDebug() << m_files << m_currentFileIndex;
} }
void MainWindow::galleryPrev() void MainWindow::galleryPrev()
@ -256,8 +268,8 @@ void MainWindow::mousePressEvent(QMouseEvent *event)
if (event->buttons() & Qt::LeftButton && !isMaximized()) { if (event->buttons() & Qt::LeftButton && !isMaximized()) {
m_clickedOnWindow = true; m_clickedOnWindow = true;
m_oldMousePos = event->pos(); m_oldMousePos = event->pos();
qDebug() << m_oldMousePos << m_graphicsView->transform().m11() // qDebug() << m_oldMousePos << m_graphicsView->transform().m11()
<< m_graphicsView->transform().m22() << m_graphicsView->matrix().m12(); // << m_graphicsView->transform().m22() << m_graphicsView->matrix().m12();
event->accept(); event->accept();
} }
@ -307,6 +319,52 @@ void MainWindow::resizeEvent(QResizeEvent *event)
void MainWindow::contextMenuEvent(QContextMenuEvent *event) void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{ {
QMenu * menu = new QMenu; QMenu * menu = new QMenu;
QMenu * copyMenu = new QMenu(tr("&Copy"));
QUrl currentFileUrl = currentImageFileUrl();
QImage clipboardImage;
QUrl clipboardFileUrl;
const QMimeData * clipboardData = QApplication::clipboard()->mimeData();
if (clipboardData->hasImage()) {
QVariant imageVariant(clipboardData->imageData());
if (imageVariant.isValid()) {
clipboardImage = qvariant_cast<QImage>(imageVariant);
}
} else if (clipboardData->hasText()) {
QString clipboardText(clipboardData->text());
if (clipboardText.startsWith("PICTURE:")) {
QString maybeFilename(clipboardText.mid(8));
if (QFile::exists(maybeFilename)) {
clipboardFileUrl = QUrl::fromLocalFile(maybeFilename);
}
}
}
QAction * copyPixmap = new QAction(tr("Copy P&ixmap"));
connect(copyPixmap, &QAction::triggered, this, [ = ](){
QClipboard *cb = QApplication::clipboard();
cb->setPixmap(m_graphicsView->scene()->renderToPixmap());
});
QAction * copyFilePath = new QAction(tr("Copy &File Path"));
connect(copyFilePath, &QAction::triggered, this, [ = ](){
QClipboard *cb = QApplication::clipboard();
cb->setText(currentFileUrl.toLocalFile());
});
copyMenu->addAction(copyPixmap);
if (currentFileUrl.isValid()) {
copyMenu->addAction(copyFilePath);
}
QAction * pasteImage = new QAction(tr("&Paste Image"));
connect(pasteImage, &QAction::triggered, this, [ = ](){
m_graphicsView->showImage(clipboardImage);
});
QAction * pasteImageFile = new QAction(tr("&Paste Image File"));
connect(pasteImageFile, &QAction::triggered, this, [ = ](){
m_graphicsView->showFileFromUrl(clipboardFileUrl, true);
});
QAction * stayOnTopMode = new QAction(tr("Stay on top")); QAction * stayOnTopMode = new QAction(tr("Stay on top"));
connect(stayOnTopMode, &QAction::triggered, this, [ = ](){ connect(stayOnTopMode, &QAction::triggered, this, [ = ](){
toggleStayOnTop(); toggleStayOnTop();
@ -331,6 +389,18 @@ void MainWindow::contextMenuEvent(QContextMenuEvent *event)
}; };
m_graphicsView->showText(sl.join('\n')); m_graphicsView->showText(sl.join('\n'));
}); });
if (copyMenu->actions().count() == 1) {
menu->addActions(copyMenu->actions());
} else {
menu->addMenu(copyMenu);
}
if (!clipboardImage.isNull()) {
menu->addAction(pasteImage);
} else if (clipboardFileUrl.isValid()) {
menu->addAction(pasteImageFile);
}
menu->addSeparator();
menu->addAction(stayOnTopMode); menu->addAction(stayOnTopMode);
menu->addAction(protectedMode); menu->addAction(protectedMode);
menu->addSeparator(); menu->addSeparator();

View File

@ -25,6 +25,7 @@ public:
void showUrls(const QList<QUrl> &urls); void showUrls(const QList<QUrl> &urls);
void adjustWindowSizeBySceneRect(); void adjustWindowSizeBySceneRect();
QUrl currentImageFileUrl() const;
void loadGalleryBySingleLocalFile(const QString &path); void loadGalleryBySingleLocalFile(const QString &path);
void galleryPrev(); void galleryPrev();

View File

@ -0,0 +1,12 @@
[Desktop Entry]
Categories=Graphics;
Comment=Pineapple Pictures Image Viewer.
Exec=ppic %F
GenericName=Pictures
Icon=pineapple-pictures
Keywords=Picture;Image;Viewer;Jpg;Jpeg;Png;
MimeType=image/bmp;image/bmp24;image/jpg;image/jpe;image/jpeg;image/jpeg24;image/jng;image/pcd;image/pcx;image/png;image/tif;image/tiff;image/tiff24;image/dds;image/gif;image/sgi;image/j2k;image/jp2;image/pct;image/wdp;image/arw;image/icb;image/dng;image/vda;image/vst;image/svg;image/ptif;image/mef;image/xbm;image/svg+xml;
Name=Pineapple Pictures
StartupNotify=false
Type=Application
Terminal=false

1
pineapple-pictures.rc Normal file
View File

@ -0,0 +1 @@
IDI_ICON1 ICON DISCARDABLE "icons/app-icon.ico"