Adding upstream version 0.5.0.
This commit is contained in:
parent
de1fa415b2
commit
d53be78755
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
build
|
||||
*.kdev4
|
||||
src/translations/lximage-qt
|
169
CHANGELOG
Normal file
169
CHANGELOG
Normal file
@ -0,0 +1,169 @@
|
||||
|
||||
lximage-qt-0.5.0 / 2016-09-24
|
||||
=============================
|
||||
|
||||
* Bump version to 0.5.0 (#67)
|
||||
* Remove Core and Qt from Categories in desktop file (#64)
|
||||
* Extend README.md
|
||||
* Fix broken compatibility introduced by libfm-qt API changes. This closes lxde/lximage-qt#63.
|
||||
* Add Catalan translations
|
||||
* Quieten compiler warning
|
||||
* Code cleanup
|
||||
* Use LXQtCompilerSettings cmake module
|
||||
* Treat SVG files separately as SVG images
|
||||
* build: Update translations based on *.ui
|
||||
* Fix typo in Portuguese translation for desktop file
|
||||
* Fix typo in German translation for desktop file (#55)
|
||||
* build: Use external translations (#54)
|
||||
* ts-files removal (#53)
|
||||
* Hide cursor smartly in fullscreen mode
|
||||
* build: Use liblxqt's TranslateDesktop module
|
||||
* Adds support for GIF animation.
|
||||
* Implement an EOG-like behavior on starting By clicking on an image for the first time, the user wants to see it clearly with lximage-qt. So, the following behavior is implemented here:
|
||||
* Add --version command line option
|
||||
* Fix missing Russian translation in desktop file
|
||||
* Fix memory leak if taking screenshot with cursor
|
||||
* Polish translation updated
|
||||
* Another update
|
||||
* Improved Russian translation - thanks to uazure
|
||||
* Fix typo
|
||||
* Add Russian translation
|
||||
* Italian translation update
|
||||
* CMake: Adapt to libfm-qt Targets
|
||||
* Turn on C++11 support. This closes bug lxde/lximage-qt #36.
|
||||
* Exec should have an argument
|
||||
* all GPL files are (or any later)
|
||||
* Add release script
|
||||
* Update translations
|
||||
* Set the color table properly for scaled images
|
||||
* Add Greek (el) translation Remove needless country variant from language code
|
||||
* Corrected language code (de_DE -> de) of german translation, marked translations as done.
|
||||
* replace tabs with spaces
|
||||
* remove trailing spaces
|
||||
* replace glib with Qt for command-line parsing
|
||||
* Don't save file in private mode
|
||||
* Prevents the slideshow timeout to be set to 0 in the UI
|
||||
* Correctly include CMake modules in intree/superbuild mode
|
||||
* Remove lximage-qt from the Utilities category
|
||||
* Update README
|
||||
* Update .gitignore
|
||||
* Hungarian translations added
|
||||
* save and restore window size and maximized state
|
||||
|
||||
0.4.0 / 2015-02-18
|
||||
==================
|
||||
|
||||
* Release v0.4.0
|
||||
* src/CMakeLists.txt: do not completely overwrite CMAKE_CXX_FLAGS
|
||||
* Create lximage-qt_it.desktop
|
||||
* Create lximage-qt_it.ts
|
||||
* CMakeLists cleanups
|
||||
* Portuguese update
|
||||
* Added german translation, re-generated all other .ts files.
|
||||
* Added keyboard shortcut to print.
|
||||
* Adds .desktop translation support
|
||||
* Portuguese language update
|
||||
* Remove debian directory (Close #9)
|
||||
* Fix typo Zoomo -> Zoom
|
||||
* Use proper naming conventions for translations
|
||||
* Clean up CMakeLists, dropping support for Qt 5
|
||||
|
||||
0.3.0 / 2014-10-15
|
||||
==================
|
||||
|
||||
* Release v0.3.0
|
||||
* Rename preferencedialog.ui to preferencesdialog.ui
|
||||
* Ignore build dir.
|
||||
* debian: enable qt5 by default
|
||||
* Fix lxde/lxde-qt #269 - Screenshots are not saved aedequately unless file extension is chosen manually.
|
||||
* Support Qt5 and libfm-qt5.
|
||||
* Make sure all enums are handled in switch
|
||||
|
||||
0.2.0 / 2014-05-09
|
||||
==================
|
||||
|
||||
* Release 0.2.0
|
||||
* Update desktop files
|
||||
* Update README/COPYING/AUTHORS
|
||||
* Add some missing link_directories()
|
||||
* Commit from LXDE Pootle server by user yinghua_wang.: 70 of 70 strings translated (0 fuzzy).
|
||||
* Add CPack rules for creating tarball
|
||||
* Avoid creating a scaled image cache if current scale factor is 1.0 (original size).
|
||||
* Rewrite the scaled image caching code in LxImage::ImageView to improve its readability and correctness.
|
||||
* Add LxImage::Job class as a base class for multi-threading jobs.
|
||||
* Avoid copying subimages to speed up scaling images.
|
||||
* Limit the size of pixmap cache.
|
||||
* Limit the size of pixmap cache.
|
||||
* Create a cache for the high-quality scaled image of the currently viewport and use it to override the default paintEvent() of QGraphicsView as needed. This improves the image quality a lot when we scale down large photos.
|
||||
* Cancel autoZoomFit when calling zoomOriginal(), zoomIn(), and zoomOut().
|
||||
* Add copy and paste buttons to the toolbar.
|
||||
* Automatically zoom to fit current window size by default.
|
||||
* Make the preferences dialog non-modal and apply the settings to all existing windows.
|
||||
* Add "Delete file" and "File properties" actions to the file menu.
|
||||
* Add a very basic thumbnails pane based on Fm::FolderView of libfm-qt.
|
||||
* Implement the preferences dialog. * Enable keyboard shortcuts in fullscreen mode.
|
||||
* Implement very basic slide show functionality.
|
||||
* Jump to the previous or the next image by using mouse wheel.
|
||||
* Avoid scaling up an image while zoomFit() if it's smaller than the current view.
|
||||
* Support grabbing mouse cursor when taking a screenshot.
|
||||
* Add very basic printing support.
|
||||
* Commit from LXDE Pootle server by user adrianoh2.: 70 of 70 strings translated (0 fuzzy).
|
||||
* Commit from LXDE Pootle server by user Fitoschido.: 70 of 70 strings translated (0 fuzzy).
|
||||
* Commit from LXDE Pootle server by user hirkmt.: 70 of 70 strings translated (0 fuzzy).
|
||||
* Remove xsettings support and add an option in the preference dialog to set a fallback icon theme instead.
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* Improve cmake integration for translations. The *.ts files are only updated when UPDATE_TRANSLATIONS cmake option is turned on.
|
||||
* Commit from LXDE Pootle server by user zvacet.: 65 of 70 strings translated (0 fuzzy).
|
||||
* Commit from LXDE Pootle server by user zvacet.: 50 of 70 strings translated (0 fuzzy).
|
||||
* Commit from LXDE Pootle server by user wwycheuk.: 65 of 70 strings translated (0 fuzzy).
|
||||
* Commit from LXDE Pootle server by user mbouzada.: 70 of 70 strings translated (0 fuzzy).
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* Commit from LXDE Pootle server by user Fitoschido.: 68 of 70 strings translated (0 fuzzy).
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* Corrected caml cased string toolBar.
|
||||
* Commit from LXDE Pootle server by user smarquespt.: 70 of 70 strings translated (0 fuzzy).
|
||||
* Commit from LXDE Pootle server by user brother.: 24 of 24 strings translated (0 fuzzy).
|
||||
* Correct misspelled 'Zoom'.
|
||||
* Commit from LXDE Pootle server by user andika.: 70 of 70 strings translated (0 fuzzy).
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* Commit from LXDE Pootle server by user strebski.: 70 of 70 strings translated (0 fuzzy).
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* Commit from LXDE Pootle server by user LStranger.: 70 of 70 strings translated (0 fuzzy).
|
||||
* Commit from LXDE Pootle server by user brother.: 70 of 70 strings translated (0 fuzzy).
|
||||
* Commit from LXDE Pootle server by user LStranger.: 2 of 70 strings translated (0 fuzzy).
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* New files added from LXDE Pootle server based on templates
|
||||
* Add zh_TW translation and a template ts file.
|
||||
* Add a desktop entry file for the built-in screenshot tool.
|
||||
* Add --screenshot command line argument to launch the built-in screenshot utility.
|
||||
* Improve the screenshot tool. Implement pasting from clipboard.
|
||||
* Add ability to taking screenshots to lximage-qt.
|
||||
* debian : Add missing libx11 build-depend
|
||||
* Add missing files.
|
||||
* Add Xdg::DesktopSettings for detecting desktop-specific settings. Get icon theme name via XSettings or config files when available.
|
||||
* Supporting saving files. (needs some more polishing, though).
|
||||
* Add a basic debian directory to enable daily builds.
|
||||
* Add a context menu.
|
||||
* Use libexif to read EXIF orientation tags then apply them to images loaded.
|
||||
* Refactor - move image loading code to LxImage::LoadImageJob class.
|
||||
* Remove unused data member.
|
||||
* Add a preferences dialog (not working yet). Little adjustment for menu positions and add placeholders for features not implemented.
|
||||
* Fix filename encoding handling so non-English filenames can be passed correctly from command line arguments.
|
||||
* Canonicalize filenames passed through command line arguments. Add an icon borrowed from GPicView. Rearrange menus and implement "fullscreen" and "copy to clipboard".
|
||||
* Implement basic single instance support and command line argument parsing.
|
||||
* Properly cancel pending tasks and make going back/forward more smooth. Enhance window title display.
|
||||
* Little fix to avoid loading a cancelled image.
|
||||
* Supports rotation of images.
|
||||
* Use the latest libfm-qt APIs to filter out non-image files. Implement jumping to first and last file in the folder.
|
||||
* Fix incorrect reference couting of GCancellable objects to avoid crashes. Add some shortcut keys to improve usability.
|
||||
* Use glib/gio GInputStream + GIOSchedulerJob to load the images with multi-threading. Refactor, simplify class methods of LxImage::MainWindow.
|
||||
* Use libfm to load folders containing the specified image. Add dependency on libexif for future implementation of EXIF related stuff. Add LxImage::Applcation class to handle application initiation.
|
||||
* Initial import into git
|
@ -5,7 +5,7 @@ project(lximage-qt)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(MAJOR_VERSION 0)
|
||||
set(MINOR_VERSION 4)
|
||||
set(MINOR_VERSION 5)
|
||||
set(PATCH_VERSION 0)
|
||||
set(LXIMAGE_VERSION ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION})
|
||||
|
||||
@ -13,35 +13,18 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
# C++ 11 support
|
||||
if (CMAKE_VERSION VERSION_LESS "3.1")
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
if(COMPILER_SUPPORTS_CXX11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
else()
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
|
||||
# -std=c++0x is deprecated but some tools e.g. qmake or older gcc are still using it
|
||||
if(COMPILER_SUPPORTS_CXX0X)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
else()
|
||||
message(FATAL_ERROR "Compiler ${CMAKE_CXX_COMPILER} does not support c++11/c++0x")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
endif()
|
||||
|
||||
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
find_package(Qt5DBus REQUIRED)
|
||||
find_package(Qt5PrintSupport REQUIRED QUIET)
|
||||
find_package(Qt5X11Extras REQUIRED QUIET)
|
||||
find_package(Qt5LinguistTools REQUIRED QUIET)
|
||||
find_package(Qt5Svg REQUIRED QUIET)
|
||||
find_package(fm-qt REQUIRED QUIET)
|
||||
find_package(lxqt REQUIRED) #just a build dependency for .desktop files translation
|
||||
message(STATUS "Building with Qt ${Qt5Core_VERSION_STRING}")
|
||||
|
||||
include(LXQtCompilerSettings NO_POLICY_SCOPE)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
# FIXME: we'll need this to provide detail info for photos in the future
|
||||
|
26
README.md
26
README.md
@ -1,3 +1,25 @@
|
||||
# lximage-qt
|
||||
# LXImage-Qt
|
||||
|
||||
The Qt port of LXImage, a simple and fast image viewer.
|
||||
## Overview
|
||||
|
||||
LXImage-Qt is the Qt port of LXImage, a simple and fast image viewer.
|
||||
|
||||
In addition it features a tool to take screenshots.
|
||||
|
||||
It is maintained by the LXQt project but can be used independently from this desktop environment.
|
||||
|
||||
## Installation
|
||||
|
||||
### Compiling source code
|
||||
|
||||
Runtime dependencies are qtx11extras and [libfm-qt](https://github.com/lxde/libfm-qt) (LXImage-Qt used to depend on [PCManFM-Qt](https://github.com/lxde/pcmanfm-qt) but the relevant code belongs to what was outsourced in libfm-qt).
|
||||
Additional build dependencies are CMake and optionally Git to pull latest VCS checkouts. The localization files were outsourced to repository [lxqt-l10n](https://github.com/lxde/lxqt-l10n) so the corresponding dependencies are needed, too. Please refer to this repository's `README.md` for further information.
|
||||
|
||||
Code configuration is handled by CMake. CMake variable `CMAKE_INSTALL_PREFIX` has to be set to `/usr` on most operating systems.
|
||||
|
||||
To build run `make`, to install `make install` which accepts variable `DESTDIR` as usual.
|
||||
|
||||
### Binary packages
|
||||
|
||||
Official binary packages are available in Arch Linux, Debian (as of Debian stretch), Fedora and openSUSE (Leap 42.1 and Tumbleweed).
|
||||
Just use the distributions' package manager to search for string 'lximage'.
|
||||
|
@ -7,5 +7,5 @@ Icon=lximage-qt
|
||||
Exec=lximage-qt %F
|
||||
StartupNotify=true
|
||||
Terminal=false
|
||||
Categories=Graphics;Core;Qt;Viewer;RasterGraphics;2DGraphics;Photography;
|
||||
Categories=Graphics;Viewer;RasterGraphics;2DGraphics;Photography;
|
||||
MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/png;image/tiff;image/x-bmp;image/x-pcx;image/x-tga;image/x-portable-pixmap;image/x-portable-bitmap;image/x-targa;image/x-portable-greymap;application/pcx;image/svg+xml;image/svg-xml;
|
||||
|
@ -1,6 +1,3 @@
|
||||
# set visibility to hidden to hide symbols, unlesss they're exporeted manually in the code
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
|
||||
|
||||
include_directories(
|
||||
${X11_INCLUDE_DIR}
|
||||
${XFIXES_INCLUDE_DIRS}
|
||||
@ -81,7 +78,7 @@ add_definitions(
|
||||
-DLXIMAGE_VERSION="${LXIMAGE_VERSION}"
|
||||
)
|
||||
|
||||
set(QT_LIBRARIES Qt5::Widgets Qt5::Core Qt5::DBus Qt5::PrintSupport Qt5::X11Extras)
|
||||
set(QT_LIBRARIES Qt5::Widgets Qt5::Core Qt5::DBus Qt5::PrintSupport Qt5::X11Extras Qt5::Svg)
|
||||
|
||||
target_link_libraries(lximage-qt
|
||||
fm-qt
|
||||
|
@ -35,8 +35,8 @@ static const char* ifaceName = "org.lxde.LxImage.Application";
|
||||
|
||||
Application::Application(int& argc, char** argv):
|
||||
QApplication(argc, argv),
|
||||
windowCount_(0),
|
||||
libFm() {
|
||||
libFm(),
|
||||
windowCount_(0) {
|
||||
setApplicationVersion(LXIMAGE_VERSION);
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ bool Application::init(int argc, char** argv) {
|
||||
new ApplicationAdaptor(this);
|
||||
dbus.registerObject("/Application", this);
|
||||
|
||||
connect(this, SIGNAL(aboutToQuit()), SLOT(onAboutToQuit()));
|
||||
connect(this, &Application::aboutToQuit, this, &Application::onAboutToQuit);
|
||||
|
||||
if(settings_.useFallbackIconTheme())
|
||||
QIcon::setThemeName(settings_.fallbackIconTheme());
|
||||
@ -179,6 +179,5 @@ void Application::editPreferences() {
|
||||
}
|
||||
|
||||
void Application::onAboutToQuit() {
|
||||
qDebug("aboutToQuit");
|
||||
settings_.save();
|
||||
}
|
||||
|
@ -41,11 +41,9 @@ public:
|
||||
|
||||
void addWindow() { // call this when you create a new toplevel window
|
||||
++windowCount_;
|
||||
qDebug("add window");
|
||||
}
|
||||
|
||||
void removeWindow() { // call this when you destroy a toplevel window
|
||||
qDebug("remove window");
|
||||
--windowCount_;
|
||||
if(0 == windowCount_)
|
||||
quit();
|
||||
|
@ -24,21 +24,25 @@
|
||||
#include <QPainter>
|
||||
#include <QTimer>
|
||||
#include <QPolygon>
|
||||
#include <QDebug>
|
||||
#include <QStyle>
|
||||
#include <QLabel>
|
||||
#include <QGraphicsProxyWidget>
|
||||
#include <QGraphicsSvgItem>
|
||||
|
||||
#define CURSOR_HIDE_DELY 3000
|
||||
|
||||
namespace LxImage {
|
||||
|
||||
ImageView::ImageView(QWidget* parent):
|
||||
QGraphicsView(parent),
|
||||
imageItem_(new QGraphicsRectItem()),
|
||||
scene_(new QGraphicsScene(this)),
|
||||
gifMovie_(NULL),
|
||||
imageItem_(new QGraphicsRectItem()),
|
||||
gifMovie_(nullptr),
|
||||
cacheTimer_(nullptr),
|
||||
cursorTimer_(nullptr),
|
||||
scaleFactor_(1.0),
|
||||
autoZoomFit_(false),
|
||||
cacheTimer_(NULL),
|
||||
scaleFactor_(1.0) {
|
||||
isSVG(false) {
|
||||
|
||||
setViewportMargins(0, 0, 0, 0);
|
||||
setContentsMargins(0, 0, 0, 0);
|
||||
@ -58,6 +62,10 @@ ImageView::~ImageView() {
|
||||
cacheTimer_->stop();
|
||||
delete cacheTimer_;
|
||||
}
|
||||
if(cursorTimer_) {
|
||||
cursorTimer_->stop();
|
||||
delete cursorTimer_;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -88,6 +96,34 @@ void ImageView::mouseDoubleClickEvent(QMouseEvent* event) {
|
||||
QAbstractScrollArea::mouseDoubleClickEvent(event);
|
||||
}
|
||||
|
||||
void ImageView::mousePressEvent(QMouseEvent * event) {
|
||||
QGraphicsView::mousePressEvent(event);
|
||||
if(cursorTimer_) cursorTimer_->stop();
|
||||
}
|
||||
|
||||
void ImageView::mouseReleaseEvent(QMouseEvent* event) {
|
||||
QGraphicsView::mouseReleaseEvent(event);
|
||||
if(cursorTimer_) cursorTimer_->start(CURSOR_HIDE_DELY);
|
||||
}
|
||||
|
||||
void ImageView::mouseMoveEvent(QMouseEvent* event) {
|
||||
QGraphicsView::mouseMoveEvent(event);
|
||||
if(cursorTimer_ && (viewport()->cursor().shape() == Qt::BlankCursor
|
||||
|| viewport()->cursor().shape() == Qt::OpenHandCursor)) {
|
||||
cursorTimer_->start(CURSOR_HIDE_DELY); // restart timer
|
||||
viewport()->setCursor(Qt::OpenHandCursor);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageView::focusInEvent(QFocusEvent* event) {
|
||||
QGraphicsView::focusInEvent(event);
|
||||
if(cursorTimer_ && (viewport()->cursor().shape() == Qt::BlankCursor
|
||||
|| viewport()->cursor().shape() == Qt::OpenHandCursor)) {
|
||||
cursorTimer_->start(CURSOR_HIDE_DELY); // restart timer
|
||||
viewport()->setCursor(Qt::OpenHandCursor);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageView::resizeEvent(QResizeEvent* event) {
|
||||
QGraphicsView::resizeEvent(event);
|
||||
if(autoZoomFit_)
|
||||
@ -136,10 +172,13 @@ void ImageView::zoomOriginal() {
|
||||
}
|
||||
|
||||
void ImageView::setImage(QImage image, bool show) {
|
||||
if(gifMovie_ && show) { // a gif animation was shown
|
||||
if(show && (gifMovie_ || isSVG)) { // a gif animation or SVG file was shown before
|
||||
scene_->clear();
|
||||
delete gifMovie_;
|
||||
gifMovie_ = NULL;
|
||||
isSVG = false;
|
||||
if(gifMovie_) { // should be deleted explicitly
|
||||
delete gifMovie_;
|
||||
gifMovie_ = nullptr;
|
||||
}
|
||||
// recreate the rect item
|
||||
imageItem_ = new QGraphicsRectItem();
|
||||
imageItem_->hide();
|
||||
@ -168,21 +207,24 @@ void ImageView::setImage(QImage image, bool show) {
|
||||
}
|
||||
|
||||
void ImageView::setGifAnimation(QString fileName) {
|
||||
QImage image(fileName);
|
||||
if(image.isNull()) {
|
||||
image_ = QImage();
|
||||
imageItem_->hide();
|
||||
imageItem_->setBrush(QBrush());
|
||||
/* the built-in gif reader gives the first frame, which won't
|
||||
be shown but is used for tracking position and dimensions */
|
||||
image_ = QImage(fileName);
|
||||
if(image_.isNull()) {
|
||||
if(imageItem_) {
|
||||
imageItem_->hide();
|
||||
imageItem_->setBrush(QBrush());
|
||||
}
|
||||
scene_->setSceneRect(0, 0, 0, 0);
|
||||
}
|
||||
else {
|
||||
scene_->clear();
|
||||
imageItem_ = NULL; // it's deleted by clear();
|
||||
imageItem_ = nullptr; // it's deleted by clear();
|
||||
if(gifMovie_) {
|
||||
delete gifMovie_;
|
||||
gifMovie_ = NULL;
|
||||
gifMovie_ = nullptr;
|
||||
}
|
||||
QPixmap pix(image.size());
|
||||
QPixmap pix(image_.size());
|
||||
pix.fill(Qt::transparent);
|
||||
QGraphicsItem *gifItem = new QGraphicsPixmapItem(pix);
|
||||
QLabel *gifLabel = new QLabel();
|
||||
@ -192,9 +234,6 @@ void ImageView::setGifAnimation(QString fileName) {
|
||||
gifLabel->setMovie(gifMovie_);
|
||||
gifWidget->setWidget(gifLabel);
|
||||
gifMovie_->start();
|
||||
/* the first frame won't be shown but will be
|
||||
used for tracking position and dimensions */
|
||||
image_ = gifMovie_->currentImage();
|
||||
scene_->addItem(gifItem);
|
||||
scene_->setSceneRect(gifItem->boundingRect());
|
||||
}
|
||||
@ -204,6 +243,29 @@ void ImageView::setGifAnimation(QString fileName) {
|
||||
queueGenerateCache(); // deletes the cache timer in this case
|
||||
}
|
||||
|
||||
void ImageView::setSVG(QString fileName) {
|
||||
image_ = QImage(fileName); // for tracking position and dimensions
|
||||
if(image_.isNull()) {
|
||||
if(imageItem_) {
|
||||
imageItem_->hide();
|
||||
imageItem_->setBrush(QBrush());
|
||||
}
|
||||
scene_->setSceneRect(0, 0, 0, 0);
|
||||
}
|
||||
else {
|
||||
scene_->clear();
|
||||
imageItem_ = nullptr;
|
||||
isSVG = true;
|
||||
QGraphicsSvgItem *svgItem = new QGraphicsSvgItem(fileName);
|
||||
scene_->addItem(svgItem);
|
||||
scene_->setSceneRect(svgItem->boundingRect());
|
||||
}
|
||||
|
||||
if(autoZoomFit_)
|
||||
zoomFit();
|
||||
queueGenerateCache(); // deletes the cache timer in this case
|
||||
}
|
||||
|
||||
void ImageView::setScaleFactor(double factor) {
|
||||
if(factor != scaleFactor_) {
|
||||
scaleFactor_ = factor;
|
||||
@ -215,7 +277,7 @@ void ImageView::setScaleFactor(double factor) {
|
||||
|
||||
void ImageView::paintEvent(QPaintEvent* event) {
|
||||
// if the image is scaled and we have a high quality cached image
|
||||
if(scaleFactor_ != 1.0 && !cachedPixmap_.isNull()) {
|
||||
if(imageItem_ && scaleFactor_ != 1.0 && !cachedPixmap_.isNull()) {
|
||||
// rectangle of the whole image in viewport coordinate
|
||||
QRect viewportImageRect = sceneToViewport(imageItem_->rect());
|
||||
// the visible part of the image.
|
||||
@ -244,20 +306,20 @@ void ImageView::queueGenerateCache() {
|
||||
cachedPixmap_ = QPixmap();
|
||||
|
||||
// we don't need to cache the scaled image if its the same as the original image (scale:1.0)
|
||||
// no cache for gif animations either
|
||||
if(scaleFactor_ == 1.0 || gifMovie_) {
|
||||
// no cache for gif animations or SVG images either
|
||||
if(scaleFactor_ == 1.0 || gifMovie_ || isSVG) {
|
||||
if(cacheTimer_) {
|
||||
cacheTimer_->stop();
|
||||
delete cacheTimer_;
|
||||
cacheTimer_ = NULL;
|
||||
cacheTimer_ = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!cacheTimer_ && !gifMovie_) {
|
||||
if(!cacheTimer_) {
|
||||
cacheTimer_ = new QTimer();
|
||||
cacheTimer_->setSingleShot(true);
|
||||
connect(cacheTimer_, SIGNAL(timeout()), SLOT(generateCache()));
|
||||
connect(cacheTimer_, &QTimer::timeout, this, &ImageView::generateCache);
|
||||
}
|
||||
if(cacheTimer_)
|
||||
cacheTimer_->start(200); // restart the timer
|
||||
@ -267,7 +329,9 @@ void ImageView::queueGenerateCache() {
|
||||
void ImageView::generateCache() {
|
||||
// disable the one-shot timer
|
||||
cacheTimer_->deleteLater();
|
||||
cacheTimer_ = NULL;
|
||||
cacheTimer_ = nullptr;
|
||||
|
||||
if(!imageItem_ || image_.isNull()) return;
|
||||
|
||||
// generate a cache for "the visible part" of the scaled image
|
||||
// rectangle of the whole image in viewport coordinate
|
||||
@ -295,12 +359,6 @@ void ImageView::generateCache() {
|
||||
// convert the cached scaled image to pixmap
|
||||
cachedPixmap_ = QPixmap::fromImage(scaled);
|
||||
viewport()->update();
|
||||
/*
|
||||
qDebug() << "viewportImageRect" << viewportImageRect
|
||||
<< "cachedRect_" << cachedRect_
|
||||
<< "cachedSceneRect_" << cachedSceneRect_
|
||||
<< "subRect" << subRect;
|
||||
*/
|
||||
}
|
||||
|
||||
// convert viewport coordinate to the original image (not scaled).
|
||||
@ -317,5 +375,26 @@ QRect ImageView::sceneToViewport(const QRectF& rect) {
|
||||
return QRect(topLeft, bottomRight);
|
||||
}
|
||||
|
||||
void ImageView::blankCursor() {
|
||||
viewport()->setCursor(Qt::BlankCursor);
|
||||
}
|
||||
|
||||
void ImageView::hideCursor(bool enable) {
|
||||
if(enable) {
|
||||
if(cursorTimer_) delete cursorTimer_;
|
||||
cursorTimer_ = new QTimer(this);
|
||||
cursorTimer_->setSingleShot(true);
|
||||
connect(cursorTimer_, &QTimer::timeout, this, &ImageView::blankCursor);
|
||||
if(viewport()->cursor().shape() == Qt::OpenHandCursor)
|
||||
cursorTimer_->start(CURSOR_HIDE_DELY);
|
||||
}
|
||||
else if (cursorTimer_) {
|
||||
cursorTimer_->stop();
|
||||
delete cursorTimer_;
|
||||
cursorTimer_ = nullptr;
|
||||
if(viewport()->cursor().shape() == Qt::BlankCursor)
|
||||
viewport()->setCursor(Qt::OpenHandCursor);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace LxImage
|
||||
|
@ -42,6 +42,7 @@ public:
|
||||
|
||||
void setImage(QImage image, bool show = true);
|
||||
void setGifAnimation(QString fileName);
|
||||
void setSVG(QString fileName);
|
||||
|
||||
QImage image() {
|
||||
return image_;
|
||||
@ -67,9 +68,16 @@ public:
|
||||
autoZoomFit_ = value;
|
||||
}
|
||||
|
||||
// if set to true, hides the cursor after 3s of inactivity
|
||||
void hideCursor(bool enable);
|
||||
|
||||
protected:
|
||||
virtual void wheelEvent(QWheelEvent* event);
|
||||
virtual void mouseDoubleClickEvent(QMouseEvent* event);
|
||||
virtual void mousePressEvent(QMouseEvent* event);
|
||||
virtual void mouseReleaseEvent(QMouseEvent* event);
|
||||
virtual void mouseMoveEvent(QMouseEvent* event);
|
||||
virtual void focusInEvent(QFocusEvent* event);
|
||||
virtual void resizeEvent(QResizeEvent* event);
|
||||
virtual void paintEvent(QPaintEvent* event);
|
||||
|
||||
@ -80,6 +88,7 @@ private:
|
||||
|
||||
private Q_SLOTS:
|
||||
void generateCache();
|
||||
void blankCursor();
|
||||
|
||||
private:
|
||||
QGraphicsScene* scene_; // the topmost container of all graphic items
|
||||
@ -90,8 +99,10 @@ private:
|
||||
QRect cachedRect_; // rectangle containing the cached region (in viewport coordinate)
|
||||
QRect cachedSceneRect_; // rectangle containing the cached region (in scene/original image coordinate)
|
||||
QTimer* cacheTimer_;
|
||||
QTimer *cursorTimer_; // for hiding cursor in fullscreen mode
|
||||
double scaleFactor_;
|
||||
bool autoZoomFit_;
|
||||
bool isSVG; // is the image an SVG file?
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ Job::~Job() {
|
||||
|
||||
// This is called from the worker thread, not main thread
|
||||
gboolean Job::_jobThread(GIOSchedulerJob* job, GCancellable* cancellable, Job* pThis) {
|
||||
bool ret = pThis->run();
|
||||
pThis->run();
|
||||
// do final step in the main thread
|
||||
if(!g_cancellable_is_cancelled(pThis->cancellable_))
|
||||
g_io_scheduler_job_send_to_mainloop(job, GSourceFunc(_finish), pThis, NULL);
|
||||
|
@ -29,8 +29,8 @@ using namespace LxImage;
|
||||
|
||||
LoadImageJob::LoadImageJob(MainWindow* window, FmPath* filePath):
|
||||
Job(),
|
||||
path_(fm_path_ref(filePath)),
|
||||
mainWindow_(window) {
|
||||
mainWindow_(window),
|
||||
path_(fm_path_ref(filePath)) {
|
||||
}
|
||||
|
||||
LoadImageJob::~LoadImageJob() {
|
||||
@ -71,7 +71,7 @@ bool LoadImageJob::run() {
|
||||
// use libexif to extract additional info embedded in jpeg files
|
||||
ExifLoader *exif_loader = exif_loader_new();
|
||||
// write image data to exif loader
|
||||
int ret = exif_loader_write(exif_loader, (unsigned char*)imageBuffer.data().constData(), (unsigned int)imageBuffer.size());
|
||||
exif_loader_write(exif_loader, (unsigned char*)imageBuffer.data().constData(), (unsigned int)imageBuffer.size());
|
||||
ExifData *exif_data = exif_loader_get_data(exif_loader);
|
||||
exif_loader_unref(exif_loader);
|
||||
if(exif_data) {
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include <QPainter>
|
||||
#include <QPrintDialog>
|
||||
#include <QPrinter>
|
||||
#include <QDebug>
|
||||
#include <QWheelEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QTimer>
|
||||
@ -36,6 +35,7 @@
|
||||
#include <QDockWidget>
|
||||
#include <QScrollBar>
|
||||
#include <QDesktopWidget>
|
||||
#include <QGraphicsSvgItem>
|
||||
#include "application.h"
|
||||
#include <libfm-qt/path.h>
|
||||
#include <libfm-qt/folderview.h>
|
||||
@ -46,21 +46,21 @@ using namespace LxImage;
|
||||
|
||||
MainWindow::MainWindow():
|
||||
QMainWindow(),
|
||||
currentFile_(NULL),
|
||||
slideShowTimer_(NULL),
|
||||
// currentFileInfo_(NULL),
|
||||
loadJob_(NULL),
|
||||
saveJob_(NULL),
|
||||
folder_(NULL),
|
||||
folderPath_(NULL),
|
||||
contextMenu_(new QMenu(this)),
|
||||
slideShowTimer_(nullptr),
|
||||
image_(),
|
||||
currentFile_(nullptr),
|
||||
// currentFileInfo_(nullptr),
|
||||
imageModified_(false),
|
||||
folder_(nullptr),
|
||||
folderPath_(nullptr),
|
||||
folderModel_(new Fm::FolderModel()),
|
||||
proxyModel_(new Fm::ProxyFolderModel()),
|
||||
modelFilter_(new ModelFilter()),
|
||||
imageModified_(false),
|
||||
contextMenu_(new QMenu(this)),
|
||||
thumbnailsDock_(NULL),
|
||||
thumbnailsView_(NULL),
|
||||
image_() {
|
||||
thumbnailsDock_(nullptr),
|
||||
thumbnailsView_(nullptr),
|
||||
loadJob_(nullptr),
|
||||
saveJob_(nullptr) {
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose); // FIXME: check if current image is saved before close
|
||||
|
||||
@ -70,8 +70,8 @@ MainWindow::MainWindow():
|
||||
Settings& settings = app->settings();
|
||||
|
||||
ui.setupUi(this);
|
||||
connect(ui.actionScreenshot, SIGNAL(triggered(bool)), app, SLOT(screenshot()));
|
||||
connect(ui.actionPreferences, SIGNAL(triggered(bool)), app ,SLOT(editPreferences()));
|
||||
connect(ui.actionScreenshot, &QAction::triggered, app, &Application::screenshot);
|
||||
connect(ui.actionPreferences, &QAction::triggered, app , &Application::editPreferences);
|
||||
|
||||
proxyModel_->addFilter(modelFilter_);
|
||||
proxyModel_->sort(Fm::FolderModel::ColumnFileName, Qt::AscendingOrder);
|
||||
@ -79,7 +79,7 @@ MainWindow::MainWindow():
|
||||
|
||||
// build context menu
|
||||
ui.view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(ui.view, SIGNAL(customContextMenuRequested(QPoint)), SLOT(onContextMenu(QPoint)));
|
||||
connect(ui.view, &QWidget::customContextMenuRequested, this, &MainWindow::onContextMenu);
|
||||
|
||||
// install an event filter on the image view
|
||||
ui.view->installEventFilter(this);
|
||||
@ -107,11 +107,11 @@ MainWindow::MainWindow():
|
||||
|
||||
// create shortcuts
|
||||
QShortcut* shortcut = new QShortcut(Qt::Key_Left, this);
|
||||
connect(shortcut, SIGNAL(activated()), SLOT(on_actionPrevious_triggered()));
|
||||
connect(shortcut, &QShortcut::activated, this, &MainWindow::on_actionPrevious_triggered);
|
||||
shortcut = new QShortcut(Qt::Key_Right, this);
|
||||
connect(shortcut, SIGNAL(activated()), SLOT(on_actionNext_triggered()));
|
||||
connect(shortcut, &QShortcut::activated, this, &MainWindow::on_actionNext_triggered);
|
||||
shortcut = new QShortcut(Qt::Key_Escape, this);
|
||||
connect(shortcut, SIGNAL(activated()), SLOT(onExitFullscreen()));
|
||||
connect(shortcut, &QShortcut::activated, this, &MainWindow::onExitFullscreen);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
@ -174,7 +174,6 @@ void MainWindow::on_actionZoomOut_triggered() {
|
||||
}
|
||||
|
||||
void MainWindow::onFolderLoaded(FmFolder* folder) {
|
||||
qDebug("Finish loading: %d files", proxyModel_->rowCount());
|
||||
// if currently we're showing a file, get its index in the folder now
|
||||
// since the folder is fully loaded.
|
||||
if(currentFile_ && !currentIndex_.isValid()) {
|
||||
@ -207,14 +206,14 @@ void MainWindow::pasteImage(QImage newImage) {
|
||||
// cancel loading of current image
|
||||
if(loadJob_) {
|
||||
loadJob_->cancel(); // the job object will be freed automatically later
|
||||
loadJob_ = NULL;
|
||||
loadJob_ = nullptr;
|
||||
}
|
||||
setModified(true);
|
||||
|
||||
currentIndex_ = QModelIndex(); // invaludate current index since we don't have a folder model now
|
||||
if(currentFile_)
|
||||
fm_path_unref(currentFile_);
|
||||
currentFile_ = NULL;
|
||||
currentFile_ = nullptr;
|
||||
|
||||
image_ = newImage;
|
||||
ui.view->setImage(image_);
|
||||
@ -302,7 +301,13 @@ void MainWindow::on_actionSave_triggered() {
|
||||
void MainWindow::on_actionSaveAs_triggered() {
|
||||
if(saveJob_) // if we're currently saving another file
|
||||
return;
|
||||
QString fileName = saveFileName(currentFile_ ? Fm::Path(currentFile_).displayName() : QString());
|
||||
QString baseName;
|
||||
if(currentFile_) {
|
||||
char* dispName = fm_path_display_name(currentFile_, false);
|
||||
baseName = QString::fromUtf8(dispName);
|
||||
g_free(dispName);
|
||||
}
|
||||
QString fileName = saveFileName(baseName);
|
||||
if(!fileName.isEmpty()) {
|
||||
FmPath* path = fm_path_new_for_str(qPrintable(fileName));
|
||||
// save the image file asynchronously
|
||||
@ -354,7 +359,6 @@ void MainWindow::on_actionNext_triggered() {
|
||||
FmFileInfo* info = proxyModel_->fileInfoFromIndex(index);
|
||||
if(info) {
|
||||
FmPath* path = fm_file_info_get_path(info);
|
||||
qDebug("try load: %s", fm_path_get_basename(path));
|
||||
loadImage(path, index);
|
||||
}
|
||||
}
|
||||
@ -365,7 +369,6 @@ void MainWindow::on_actionPrevious_triggered() {
|
||||
return;
|
||||
if(currentIndex_.isValid()) {
|
||||
QModelIndex index;
|
||||
qDebug("current row: %d", currentIndex_.row());
|
||||
if(currentIndex_.row() > 0)
|
||||
index = proxyModel_->index(currentIndex_.row() - 1, 0);
|
||||
else
|
||||
@ -373,7 +376,6 @@ void MainWindow::on_actionPrevious_triggered() {
|
||||
FmFileInfo* info = proxyModel_->fileInfoFromIndex(index);
|
||||
if(info) {
|
||||
FmPath* path = fm_file_info_get_path(info);
|
||||
qDebug("try load: %s", fm_path_get_basename(path));
|
||||
loadImage(path, index);
|
||||
}
|
||||
}
|
||||
@ -385,7 +387,6 @@ void MainWindow::on_actionFirst_triggered() {
|
||||
FmFileInfo* info = proxyModel_->fileInfoFromIndex(index);
|
||||
if(info) {
|
||||
FmPath* path = fm_file_info_get_path(info);
|
||||
qDebug("try load: %s", fm_path_get_basename(path));
|
||||
loadImage(path, index);
|
||||
}
|
||||
}
|
||||
@ -396,8 +397,7 @@ void MainWindow::on_actionLast_triggered() {
|
||||
if(index.isValid()) {
|
||||
FmFileInfo* info = proxyModel_->fileInfoFromIndex(index);
|
||||
if(info) {
|
||||
FmPath* path = fm_file_info_get_path(info);
|
||||
qDebug("try load: %s", fm_path_get_basename(path));
|
||||
FmPath* path = fm_file_info_get_path(info);;
|
||||
loadImage(path, index);
|
||||
}
|
||||
}
|
||||
@ -423,7 +423,7 @@ void MainWindow::loadFolder(FmPath* newFolderPath) {
|
||||
|
||||
// the image is loaded (the method is only called if the loading is not cancelled)
|
||||
void MainWindow::onImageLoaded(LoadImageJob* job) {
|
||||
loadJob_ = NULL; // the job object will be freed later automatically
|
||||
loadJob_ = nullptr; // the job object will be freed later automatically
|
||||
|
||||
image_ = job->image();
|
||||
ui.view->setAutoZoomFit(true);
|
||||
@ -448,12 +448,11 @@ void MainWindow::onImageSaved(SaveImageJob* job) {
|
||||
if(!job->error()) {
|
||||
setModified(false);
|
||||
}
|
||||
saveJob_ = NULL;
|
||||
saveJob_ = nullptr;
|
||||
}
|
||||
|
||||
// filter events of other objects, mainly the image view.
|
||||
bool MainWindow::eventFilter(QObject* watched, QEvent* event) {
|
||||
// qDebug() << event;
|
||||
if(watched == ui.view) { // we got an event for the image view
|
||||
switch(event->type()) {
|
||||
case QEvent::Wheel: { // mouse wheel event
|
||||
@ -585,7 +584,7 @@ void MainWindow::loadImage(FmPath* filePath, QModelIndex index) {
|
||||
// cancel loading of current image
|
||||
if(loadJob_) {
|
||||
loadJob_->cancel(); // the job object will be freed automatically later
|
||||
loadJob_ = NULL;
|
||||
loadJob_ = nullptr;
|
||||
}
|
||||
if(imageModified_) {
|
||||
// TODO: ask the user to save the modified image?
|
||||
@ -601,21 +600,27 @@ void MainWindow::loadImage(FmPath* filePath, QModelIndex index) {
|
||||
image_ = QImage();
|
||||
|
||||
const char* basename = fm_path_get_basename(currentFile_);
|
||||
char* mimeType = g_content_type_guess(basename, NULL, 0, NULL);
|
||||
if(mimeType && strcmp(mimeType, "image/gif") == 0) {
|
||||
g_free(mimeType);
|
||||
char *file_Name = fm_path_to_str(currentFile_);
|
||||
QString fileName(file_Name);
|
||||
g_free(file_Name);
|
||||
char* mime_type = g_content_type_guess(basename, NULL, 0, NULL);
|
||||
QString mimeType;
|
||||
if (mime_type) {
|
||||
mimeType = QString(mime_type);
|
||||
g_free(mime_type);
|
||||
}
|
||||
if(mimeType == "image/gif"
|
||||
|| mimeType == "image/svg+xml" || mimeType == "image/svg+xml-compressed") {
|
||||
char *file_name = fm_path_to_str(currentFile_);
|
||||
QString fileName(file_name);
|
||||
g_free(file_name);
|
||||
ui.view->setAutoZoomFit(true); // like in onImageLoaded()
|
||||
ui.view->setGifAnimation(fileName);
|
||||
if(mimeType == "image/gif")
|
||||
ui.view->setGifAnimation(fileName);
|
||||
else
|
||||
ui.view->setSVG(fileName);
|
||||
image_ = ui.view->image();
|
||||
updateUI();
|
||||
show();
|
||||
}
|
||||
else {
|
||||
if(mimeType)
|
||||
g_free(mimeType);
|
||||
// start a new gio job to load the specified image
|
||||
loadJob_ = new LoadImageJob(this, filePath);
|
||||
loadJob_->start();
|
||||
@ -633,55 +638,55 @@ void MainWindow::saveImage(FmPath* filePath) {
|
||||
// FIXME: add a cancel button to the UI? update status bar?
|
||||
}
|
||||
|
||||
QGraphicsItem* MainWindow::getGifItem() {
|
||||
if(!ui.view->items().isEmpty()) {
|
||||
QGraphicsItem *gifItem = ui.view->items().at(0);
|
||||
if(gifItem->isWidget()) // we have gif animation
|
||||
return gifItem;
|
||||
}
|
||||
return NULL;
|
||||
QGraphicsItem* MainWindow::getGraphicsItem() {
|
||||
if(!ui.view->items().isEmpty())
|
||||
return ui.view->items().at(0);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::on_actionRotateClockwise_triggered() {
|
||||
QGraphicsItem *gifItem = getGifItem();
|
||||
QGraphicsItem *graphItem = getGraphicsItem();
|
||||
if(!image_.isNull()) {
|
||||
QTransform transform;
|
||||
transform.rotate(90.0);
|
||||
image_ = image_.transformed(transform, Qt::SmoothTransformation);
|
||||
/* when this is a gif animation, we need to rotate the first frame
|
||||
/* when this is GIF or SVG, we need to rotate its corresponding QImage
|
||||
without showing it to have the right measure for auto-zooming */
|
||||
ui.view->setImage(image_, gifItem ? false : true);
|
||||
ui.view->setImage(image_, graphItem->isWidget() // we have gif animation
|
||||
|| static_cast<QGraphicsSvgItem*>(graphItem) // an SVG image
|
||||
? false : true);
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
if(gifItem) {
|
||||
if(graphItem) {
|
||||
QTransform transform;
|
||||
transform.translate(gifItem->sceneBoundingRect().height(), 0);
|
||||
transform.translate(graphItem->sceneBoundingRect().height(), 0);
|
||||
transform.rotate(90);
|
||||
// we need to apply transformations in the reverse order
|
||||
QTransform prevTrans = gifItem->transform();
|
||||
gifItem->setTransform(transform, false);
|
||||
gifItem->setTransform(prevTrans, true);
|
||||
QTransform prevTrans = graphItem->transform();
|
||||
graphItem->setTransform(transform, false);
|
||||
graphItem->setTransform(prevTrans, true);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionRotateCounterclockwise_triggered() {
|
||||
QGraphicsItem *gifItem = getGifItem();
|
||||
QGraphicsItem *graphItem = getGraphicsItem();
|
||||
if(!image_.isNull()) {
|
||||
QTransform transform;
|
||||
transform.rotate(-90.0);
|
||||
image_ = image_.transformed(transform, Qt::SmoothTransformation);
|
||||
ui.view->setImage(image_, gifItem ? false : true);
|
||||
ui.view->setImage(image_, graphItem->isWidget() || static_cast<QGraphicsSvgItem*>(graphItem)
|
||||
? false : true);
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
if(gifItem) {
|
||||
if(graphItem) {
|
||||
QTransform transform;
|
||||
transform.translate(0, gifItem->sceneBoundingRect().width());
|
||||
transform.translate(0, graphItem->sceneBoundingRect().width());
|
||||
transform.rotate(-90);
|
||||
QTransform prevTrans = gifItem->transform();
|
||||
gifItem->setTransform(transform, false);
|
||||
gifItem->setTransform(prevTrans, true);
|
||||
QTransform prevTrans = graphItem->transform();
|
||||
graphItem->setTransform(transform, false);
|
||||
graphItem->setTransform(prevTrans, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -708,37 +713,37 @@ void MainWindow::on_actionPaste_triggered() {
|
||||
}
|
||||
|
||||
void MainWindow::on_actionFlipVertical_triggered() {
|
||||
if(QGraphicsItem *gifItem = getGifItem()) {
|
||||
bool hasQGraphicsItem(false);
|
||||
if(QGraphicsItem *graphItem = getGraphicsItem()) {
|
||||
hasQGraphicsItem = true;
|
||||
QTransform transform;
|
||||
transform.scale(1, -1);
|
||||
transform.translate(0, -gifItem->sceneBoundingRect().height());
|
||||
QTransform prevTrans = gifItem->transform();
|
||||
gifItem->setTransform(transform, false);
|
||||
gifItem->setTransform(prevTrans, true);
|
||||
setModified(true);
|
||||
/* we don't need to flip the first frame because its position
|
||||
and dimensions are the same as before while it isn't shown */
|
||||
transform.translate(0, -graphItem->sceneBoundingRect().height());
|
||||
QTransform prevTrans = graphItem->transform();
|
||||
graphItem->setTransform(transform, false);
|
||||
graphItem->setTransform(prevTrans, true);
|
||||
}
|
||||
else if(!image_.isNull()) {
|
||||
if(!image_.isNull()) {
|
||||
image_ = image_.mirrored(false, true);
|
||||
ui.view->setImage(image_);
|
||||
ui.view->setImage(image_, !hasQGraphicsItem);
|
||||
setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionFlipHorizontal_triggered() {
|
||||
if(QGraphicsItem *gifItem = getGifItem()) {
|
||||
bool hasQGraphicsItem(false);
|
||||
if(QGraphicsItem *graphItem = getGraphicsItem()) {
|
||||
hasQGraphicsItem = true;
|
||||
QTransform transform;
|
||||
transform.scale(-1, 1);
|
||||
transform.translate(-gifItem->sceneBoundingRect().width(), 0);
|
||||
QTransform prevTrans = gifItem->transform();
|
||||
gifItem->setTransform(transform, false);
|
||||
gifItem->setTransform(prevTrans, true);
|
||||
setModified(true);
|
||||
transform.translate(-graphItem->sceneBoundingRect().width(), 0);
|
||||
QTransform prevTrans = graphItem->transform();
|
||||
graphItem->setTransform(transform, false);
|
||||
graphItem->setTransform(prevTrans, true);
|
||||
}
|
||||
else if(!image_.isNull()) {
|
||||
image_ = image_.mirrored(true, false);
|
||||
ui.view->setImage(image_);
|
||||
if(!image_.isNull()) {
|
||||
image_ = image_.mirrored(true, true);
|
||||
ui.view->setImage(image_, !hasQGraphicsItem);
|
||||
setModified(true);
|
||||
}
|
||||
}
|
||||
@ -767,11 +772,9 @@ void MainWindow::on_actionPrint_triggered() {
|
||||
QRect pageRect = printer.pageRect();
|
||||
int cols = (image_.width() / pageRect.width()) + (image_.width() % pageRect.width() ? 1 : 0);
|
||||
int rows = (image_.height() / pageRect.height()) + (image_.height() % pageRect.height() ? 1 : 0);
|
||||
// qDebug() << "page:" << printer.pageRect() << "image:" << image_.size() << "cols, rows:" << cols << rows;
|
||||
for(int row = 0; row < rows; ++row) {
|
||||
for(int col = 0; col < cols; ++col) {
|
||||
QRect srcRect(pageRect.width() * col, pageRect.height() * row, pageRect.width(), pageRect.height());
|
||||
// qDebug() << "row:" << row << "col:" << col << "src:" << srcRect << "page:" << printer.pageRect();
|
||||
painter.drawImage(QPoint(0, 0), image_, srcRect);
|
||||
if(col + 1 == cols && row + 1 == rows) // this is the last page
|
||||
break;
|
||||
@ -795,7 +798,7 @@ void MainWindow::on_actionSlideShow_triggered(bool checked) {
|
||||
if(!slideShowTimer_) {
|
||||
slideShowTimer_ = new QTimer();
|
||||
// switch to the next image when timeout
|
||||
connect(slideShowTimer_, SIGNAL(timeout()), SLOT(on_actionNext_triggered()));
|
||||
connect(slideShowTimer_, &QTimer::timeout, this, &MainWindow::on_actionNext_triggered);
|
||||
}
|
||||
Application* app = static_cast<Application*>(qApp);
|
||||
slideShowTimer_->start(app->settings().slideShowInterval() * 1000);
|
||||
@ -805,7 +808,7 @@ void MainWindow::on_actionSlideShow_triggered(bool checked) {
|
||||
else {
|
||||
if(slideShowTimer_) {
|
||||
delete slideShowTimer_;
|
||||
slideShowTimer_ = NULL;
|
||||
slideShowTimer_ = nullptr;
|
||||
ui.actionSlideShow->setIcon(QIcon::fromTheme("media-playback-start"));
|
||||
}
|
||||
}
|
||||
@ -838,15 +841,16 @@ void MainWindow::setShowThumbnails(bool show) {
|
||||
QCoreApplication::processEvents();
|
||||
listView->scrollTo(currentIndex_, QAbstractItemView::PositionAtCenter);
|
||||
}
|
||||
connect(thumbnailsView_->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(onThumbnailSelChanged(QItemSelection,QItemSelection)));
|
||||
connect(thumbnailsView_->selectionModel(), &QItemSelectionModel::selectionChanged,
|
||||
this, &MainWindow::onThumbnailSelChanged);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(thumbnailsDock_) {
|
||||
delete thumbnailsView_;
|
||||
thumbnailsView_ = NULL;
|
||||
thumbnailsView_ = nullptr;
|
||||
delete thumbnailsDock_;
|
||||
thumbnailsDock_ = NULL;
|
||||
thumbnailsDock_ = nullptr;
|
||||
}
|
||||
proxyModel_->setShowThumbnails(false);
|
||||
}
|
||||
@ -876,6 +880,7 @@ void MainWindow::changeEvent(QEvent* event) {
|
||||
addAction(action);
|
||||
}
|
||||
addActions(ui.menubar->actions());
|
||||
ui.view->hideCursor(true);
|
||||
}
|
||||
else { // restore to normal window mode
|
||||
ui.view->setFrameStyle(QFrame::StyledPanel|QFrame::Sunken);
|
||||
@ -890,6 +895,7 @@ void MainWindow::changeEvent(QEvent* event) {
|
||||
ui.statusBar->show();
|
||||
if(thumbnailsDock_)
|
||||
thumbnailsDock_->show();
|
||||
ui.view->hideCursor(false);
|
||||
}
|
||||
}
|
||||
QWidget::changeEvent(event);
|
||||
|
@ -126,7 +126,7 @@ private:
|
||||
void updateUI();
|
||||
void setModified(bool modified);
|
||||
QModelIndex indexFromPath(FmPath* filePath);
|
||||
QGraphicsItem* getGifItem();
|
||||
QGraphicsItem* getGraphicsItem();
|
||||
|
||||
// GObject related signal handers and callbacks
|
||||
static void _onFolderLoaded(FmFolder* folder, MainWindow* _this) {
|
||||
|
@ -221,7 +221,7 @@
|
||||
<string>Zoom &In</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl++</string>
|
||||
<string>Ctrl+=</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionZoomOut">
|
||||
@ -288,6 +288,9 @@
|
||||
<property name="text">
|
||||
<string>Original Size</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+0</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionZoomFit">
|
||||
<property name="icon">
|
||||
|
@ -96,8 +96,6 @@ static void findIconThemesInDir(QHash<QString, QString>& iconThemes, QString dir
|
||||
}
|
||||
|
||||
void PreferencesDialog::initIconThemes(Settings& settings) {
|
||||
Application* app = static_cast<Application*>(qApp);
|
||||
|
||||
// check if auto-detection is done (for example, from xsettings)
|
||||
if(settings.useFallbackIconTheme()) { // auto-detection failed
|
||||
// load xdg icon themes and select the current one
|
||||
|
@ -28,8 +28,8 @@ using namespace LxImage;
|
||||
|
||||
SaveImageJob::SaveImageJob(MainWindow* window, FmPath* filePath):
|
||||
Job(),
|
||||
path_(fm_path_ref(filePath)),
|
||||
mainWindow_(window),
|
||||
path_(fm_path_ref(filePath)),
|
||||
image_(window->image()) {
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <QPainter>
|
||||
#include "application.h"
|
||||
#include <QDesktopWidget>
|
||||
#include <QScreen>
|
||||
|
||||
#include <QX11Info>
|
||||
#include <X11/Xlib.h>
|
||||
@ -83,7 +84,7 @@ QRect ScreenshotDialog::windowFrame(WId wid) {
|
||||
int x, y;
|
||||
// translate to root coordinate
|
||||
XTranslateCoordinates(QX11Info::display(), wid, wa.root, 0, 0, &x, &y, &child);
|
||||
qDebug("%d, %d, %d, %d", x, y, wa.width, wa.height);
|
||||
//qDebug("%d, %d, %d, %d", x, y, wa.width, wa.height);
|
||||
result.setRect(x, y, wa.width, wa.height);
|
||||
|
||||
// get the frame widths added by the window manager
|
||||
@ -140,38 +141,42 @@ void ScreenshotDialog::doScreenshot() {
|
||||
}
|
||||
}
|
||||
|
||||
QPixmap pixmap;
|
||||
pixmap = QPixmap::grabWindow(wid, x, y, width, height);
|
||||
QImage image = pixmap.toImage();
|
||||
QImage image;
|
||||
QScreen *screen = QGuiApplication::primaryScreen();
|
||||
if(screen) {
|
||||
QPixmap pixmap = screen->grabWindow(wid, x, y, width, height);
|
||||
image = pixmap.toImage();
|
||||
|
||||
if(hasXfixes_ && ui.includeCursor->isChecked()) {
|
||||
// capture the cursor if needed
|
||||
XFixesCursorImage* cursor = XFixesGetCursorImage(QX11Info::display());
|
||||
if(cursor) {
|
||||
if(cursor->pixels) { // pixles should be an ARGB array
|
||||
QImage cursorImage;
|
||||
if(sizeof(long) == 4) {
|
||||
// FIXME: will we encounter byte-order problems here?
|
||||
cursorImage = QImage((uchar*)cursor->pixels, cursor->width, cursor->height, QImage::Format_ARGB32);
|
||||
if(hasXfixes_ && ui.includeCursor->isChecked()) {
|
||||
// capture the cursor if needed
|
||||
XFixesCursorImage* cursor = XFixesGetCursorImage(QX11Info::display());
|
||||
if(cursor) {
|
||||
if(cursor->pixels) { // pixles should be an ARGB array
|
||||
QImage cursorImage;
|
||||
if(sizeof(long) == 4) {
|
||||
// FIXME: will we encounter byte-order problems here?
|
||||
cursorImage = QImage((uchar*)cursor->pixels, cursor->width, cursor->height, QImage::Format_ARGB32);
|
||||
}
|
||||
else { // XFixes returns long integers which is not 32 bit on 64 bit systems.
|
||||
long len = cursor->width * cursor->height;
|
||||
quint32* buf = new quint32[len];
|
||||
for(long i = 0; i < len; ++i)
|
||||
buf[i] = (quint32)cursor->pixels[i];
|
||||
cursorImage = QImage((uchar*)buf, cursor->width, cursor->height, QImage::Format_ARGB32, [](void* b) { delete[] (quint32*)b; }, buf);
|
||||
}
|
||||
// paint the cursor on the current image
|
||||
QPainter painter(&image);
|
||||
painter.drawImage(cursor->x - cursor->xhot, cursor->y - cursor->yhot, cursorImage);
|
||||
}
|
||||
else { // XFixes returns long integers which is not 32 bit on 64 bit systems.
|
||||
long len = cursor->width * cursor->height;
|
||||
quint32* buf = new quint32[len];
|
||||
for(long i = 0; i < len; ++i)
|
||||
buf[i] = (quint32)cursor->pixels[i];
|
||||
cursorImage = QImage((uchar*)buf, cursor->width, cursor->height, QImage::Format_ARGB32, [](void* b) { delete[] (quint32*)b; }, buf);
|
||||
}
|
||||
// paint the cursor on the current image
|
||||
QPainter painter(&image);
|
||||
painter.drawImage(cursor->x - cursor->xhot, cursor->y - cursor->yhot, cursorImage);
|
||||
XFree(cursor);
|
||||
}
|
||||
XFree(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
Application* app = static_cast<Application*>(qApp);
|
||||
MainWindow* window = app->createWindow();
|
||||
window->pasteImage(image);
|
||||
if(!image.isNull())
|
||||
window->pasteImage(image);
|
||||
window->show();
|
||||
|
||||
deleteLater(); // destroy ourself
|
||||
|
@ -27,11 +27,11 @@ using namespace LxImage;
|
||||
Settings::Settings():
|
||||
useFallbackIconTheme_(QIcon::themeName().isEmpty() || QIcon::themeName() == "hicolor"),
|
||||
bgColor_(255, 255, 255),
|
||||
fullScreenBgColor_(0, 0, 0),
|
||||
showThumbnails_(false),
|
||||
showSidePane_(false),
|
||||
fullScreenBgColor_(0, 0, 0),
|
||||
fallbackIconTheme_("oxygen"),
|
||||
slideShowInterval_(5),
|
||||
fallbackIconTheme_("oxygen"),
|
||||
fixedWindowWidth_(640),
|
||||
fixedWindowHeight_(480),
|
||||
lastWindowWidth_(640),
|
||||
@ -49,7 +49,7 @@ bool Settings::load() {
|
||||
fullScreenBgColor_ = settings.value("fullScreenBgColor", fullScreenBgColor_).value<QColor>();
|
||||
// showThumbnails_;
|
||||
// showSidePane_;
|
||||
int slideShowInterval_ = settings.value("slideShowInterval", slideShowInterval_).toInt();
|
||||
slideShowInterval_ = settings.value("slideShowInterval", slideShowInterval_).toInt();
|
||||
|
||||
settings.beginGroup("Window");
|
||||
fixedWindowWidth_ = settings.value("FixedWidth", 640).toInt();
|
||||
|
4
src/translations/lximage-qt-screenshot_ca.desktop
Normal file
4
src/translations/lximage-qt-screenshot_ca.desktop
Normal file
@ -0,0 +1,4 @@
|
||||
#Translations
|
||||
Name[ca]=Captura de pantalla
|
||||
GenericName[ca]=Captura de pantalla
|
||||
Comment[ca]=Preneu una captura de pantalla
|
4
src/translations/lximage-qt_ca.desktop
Normal file
4
src/translations/lximage-qt_ca.desktop
Normal file
@ -0,0 +1,4 @@
|
||||
#Translations
|
||||
Name[ca]=LXImage
|
||||
GenericName[ca]=Visualitzador d'imatges
|
||||
Comment[ca]=El visualitzador d'imatges de LXQt
|
Loading…
x
Reference in New Issue
Block a user