8 Commits

Author SHA1 Message Date
1cbc1a3b72 feat: add option to provide a titlebar (default on) 2026-06-29 19:20:42 +08:00
8f0d4da7ad chore: update release info to 1.4.1 2026-04-05 17:09:13 +08:00
9c8ffb6c1b chore(CI): bump Qt and action version 2026-04-04 16:52:18 +08:00
4c5c5e6fc6 fix(CI): zlib dll renamed 2026-03-27 17:55:23 +08:00
b8cb10bb33 fix(CI): fixed kf6 version for appveyor build 2026-03-27 15:52:00 +08:00
6e2f40633e fix: correct version in CMakeLists, update CI for zlib 2026-03-27 15:06:11 +08:00
Hosted Weblate
a0ba7c1d17 i18n: Translations update from Hosted Weblate
Co-authored-by: Heimen Stoffels <vistausss@fastmail.com>
Translate-URL: https://hosted.weblate.org/projects/pineapple-pictures/application/nl/
Translation: pineapple-pictures/Application
2026-03-27 15:02:18 +08:00
Hosted Weblate
b6d759d7c6 i18n: Translations update from Hosted Weblate
Co-authored-by: Loc Huynh <huynhloc.contact@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pineapple-pictures/application/vi/
Translation: pineapple-pictures/Application
2026-03-11 20:32:50 +08:00
20 changed files with 401 additions and 56 deletions

View File

@@ -14,7 +14,7 @@ jobs:
run: |
apt update
apt install -y git ca-certificates curl file
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Get build dept.
run: |
apt install -y cmake qt6-base-dev qt6-svg-dev qt6-tools-dev libexiv2-dev
@@ -29,7 +29,7 @@ jobs:
run: |
cd build
apt install -y ./*.deb
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v6
with:
name: deepin-25-deb-package
path: build/*.deb

View File

@@ -8,11 +8,11 @@ jobs:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install Qt
uses: jurplel/install-qt-action@v4
with:
version: '6.10.2'
version: '6.10.3'
modules: 'qtimageformats'
cache: true
- name: Install Conan and Dependencies
@@ -33,7 +33,7 @@ jobs:
run: |
macdeployqt ./ppic.app -dmg
ls
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v6
with:
name: "macos-bundle"
path: "*.dmg"

View File

@@ -6,7 +6,7 @@ jobs:
ubuntu-24-04-build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Get build dept.
run: |
sudo apt update
@@ -22,7 +22,7 @@ jobs:
run: |
cd build
sudo apt install ./*.deb
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v6
with:
name: ubuntu-24.04-deb-package
path: build/*.deb

View File

@@ -8,7 +8,7 @@ jobs:
strategy:
matrix:
include:
- qt_ver: '6.10.2'
- qt_ver: '6.10.3'
vs: '2022'
aqt_arch: 'win64_msvc2022_64'
msvc_arch: 'x64'
@@ -16,7 +16,7 @@ jobs:
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install Qt
uses: jurplel/install-qt-action@v4
with:
@@ -35,7 +35,7 @@ jobs:
nmake
nmake clean
windeployqt --verbose=2 --no-quick-import --no-translations --no-opengl-sw --no-system-d3d-compiler --no-system-dxc-compiler --skip-plugin-types tls,networkinformation release\ppic.exe
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v6
with:
name: "windows-msvc${{ matrix.vs }}-qt${{ matrix.qt_ver }}-qmake-package"
path: release/*
@@ -45,7 +45,7 @@ jobs:
strategy:
matrix:
include:
- qt_ver: '6.10.2'
- qt_ver: '6.10.3'
vs: '2022'
aqt_arch: 'win64_msvc2022_64'
msvc_arch: 'x64'
@@ -53,7 +53,7 @@ jobs:
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install Qt
uses: jurplel/install-qt-action@v4
with:
@@ -79,9 +79,9 @@ jobs:
ren .\exiv2-0.28.7-2022msvc-AMD64 dependencies_bin
echo ::endgroup::
echo ::group::===== zlib =====
curl -fsSL -o zlib_src.zip https://zlib.net/zlib131.zip
curl -fsSL -o zlib_src.zip https://zlib.net/zlib132.zip
7z x zlib_src.zip -y -o"dependencies_src"
ren .\dependencies_src\zlib-1.3.1 zlib || goto :error
ren .\dependencies_src\zlib-1.3.2 zlib || goto :error
cmake ./dependencies_src/zlib -Bbuild_dependencies/zlib -DCMAKE_INSTALL_PREFIX="dependencies_bin" || goto :error
cmake --build build_dependencies/zlib --config Release --target=install || goto :error
echo ::endgroup::
@@ -135,7 +135,7 @@ jobs:
if ErrorLevel 8 (exit /B 1)
copy LICENSE build\bin
exit /B 0
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v6
with:
name: "windows-msvc${{ matrix.vs }}-qt${{ matrix.qt_ver }}-cmake-package"
path: build/bin/*

View File

@@ -4,7 +4,7 @@
cmake_minimum_required(VERSION 3.16)
project(pineapple-pictures VERSION 1.3.0) # don't forget to update NEWS file and AppStream metadata.
project(pineapple-pictures VERSION 1.4.1) # don't forget to update NEWS file and AppStream metadata.
include(GNUInstallDirs)
include(FeatureSummary)
@@ -44,6 +44,7 @@ set (PPIC_CPP_FILES
app/graphicsview.cpp
app/graphicsscene.cpp
app/bottombuttongroup.cpp
app/titlebar.cpp
app/navigatorview.cpp
app/opacityhelper.cpp
app/toolbutton.cpp
@@ -65,6 +66,7 @@ set (PPIC_HEADER_FILES
app/graphicsview.h
app/graphicsscene.h
app/bottombuttongroup.h
app/titlebar.h
app/navigatorview.h
app/opacityhelper.h
app/toolbutton.h

11
NEWS
View File

@@ -1,3 +1,14 @@
Version 1.4.1
~~~~~~~~~~~~~
Released: 2026-04-05
Miscellaneous:
* Update translations
* Update Qt version to 6.10.3 for Windows and macOS pre-built binaries
Contributors:
Heimen Stoffels (vistaus), Loc Huynh (hthienloc)
Version 1.4.0
~~~~~~~~~~~~~
Released: 2026-02-11

View File

@@ -7,6 +7,7 @@
#include "settings.h"
#include "toolbutton.h"
#include "bottombuttongroup.h"
#include "titlebar.h"
#include "graphicsview.h"
#include "navigatorview.h"
#include "graphicsscene.h"
@@ -101,20 +102,20 @@ MainWindow::MainWindow(QWidget *parent)
connect(m_graphicsView, &GraphicsView::viewportRectChanged,
m_gv, &NavigatorView::updateMainViewportRegion);
m_closeButton = new ToolButton(true, m_graphicsView);
m_closeButton->setIconSize(QSize(32, 32));
m_closeButton->setFixedSize(QSize(50, 50));
m_closeButton->setIconResourcePath(":/icons/window-close.svg");
m_titleBar = new TitleBar(this);
m_titleBar->setCloseButtonOnly(!Settings::instance()->showTitleBar());
connect(m_closeButton, &QAbstractButton::clicked,
connect(m_titleBar, &TitleBar::closeRequested,
this, &MainWindow::closeWindow);
connect(m_titleBar, &TitleBar::maximizeToggleRequested,
this, &MainWindow::toggleMaximize);
m_prevButton = new ToolButton(false, m_graphicsView);
m_prevButton = new ToolButton(m_graphicsView);
m_prevButton->setIconSize(QSize(75, 75));
m_prevButton->setIconResourcePath(":/icons/go-previous.svg");
m_prevButton->setVisible(false);
m_prevButton->setOpacity(0, false);
m_nextButton = new ToolButton(false, m_graphicsView);
m_nextButton = new ToolButton(m_graphicsView);
m_nextButton->setIconSize(QSize(75, 75));
m_nextButton->setIconResourcePath(":/icons/go-next.svg");
m_nextButton->setVisible(false);
@@ -138,7 +139,7 @@ MainWindow::MainWindow(QWidget *parent)
m_bottomButtonGroup->setOpacity(0, false);
m_gv->setOpacity(0, false);
m_closeButton->setOpacity(0, false);
m_titleBar->setOpacity(0, false);
connect(m_pm, &PlaylistManager::totalCountChanged, this, &MainWindow::updateGalleryButtonsVisibility);
@@ -161,7 +162,7 @@ MainWindow::MainWindow(QWidget *parent)
});
// allow some mouse events can go through these widgets for resizing window.
installResizeCapture(m_closeButton);
installResizeCapture(m_titleBar);
installResizeCapture(m_graphicsView);
installResizeCapture(m_graphicsView->viewport());
installResizeCapture(m_gv);
@@ -323,7 +324,7 @@ void MainWindow::enterEvent(QEnterEvent *event)
m_bottomButtonGroup->setOpacity(1);
m_gv->setOpacity(1);
m_closeButton->setOpacity(1);
m_titleBar->setOpacity(1);
m_prevButton->setOpacity(1);
m_nextButton->setOpacity(1);
@@ -335,7 +336,7 @@ void MainWindow::leaveEvent(QEvent *event)
m_bottomButtonGroup->setOpacity(0);
m_gv->setOpacity(0);
m_closeButton->setOpacity(0);
m_titleBar->setOpacity(0);
m_prevButton->setOpacity(0);
m_nextButton->setOpacity(0);
@@ -612,7 +613,12 @@ void MainWindow::closeWindow()
void MainWindow::updateWidgetsPosition()
{
m_closeButton->move(width() - m_closeButton->width(), 0);
if (m_titleBar->closeButtonOnly()) {
const int bw = m_titleBar->closeButtonWidth();
m_titleBar->setGeometry(width() - bw, 0, bw, m_titleBar->height());
} else {
m_titleBar->setGeometry(0, 0, width(), m_titleBar->height());
}
m_prevButton->move(25, (height() - m_prevButton->sizeHint().height()) / 2);
m_nextButton->move(width() - m_nextButton->sizeHint().width() - 25,
(height() - m_prevButton->sizeHint().height()) / 2);
@@ -624,7 +630,7 @@ void MainWindow::updateWidgetsPosition()
void MainWindow::toggleProtectedMode()
{
m_protectedMode = !m_protectedMode;
m_closeButton->setVisible(!m_protectedMode);
m_titleBar->setCloseButtonVisible(!m_protectedMode);
updateGalleryButtonsVisibility();
}

View File

@@ -20,6 +20,7 @@ QT_END_NAMESPACE
class ActionManager;
class PlaylistManager;
class ToolButton;
class TitleBar;
class GraphicsView;
class NavigatorView;
class BottomButtonGroup;
@@ -123,9 +124,9 @@ private:
QPropertyAnimation *m_floatUpAnimation;
QParallelAnimationGroup *m_exitAnimationGroup;
QFileSystemWatcher *m_fileSystemWatcher;
ToolButton *m_closeButton;
ToolButton *m_prevButton;
ToolButton *m_nextButton;
TitleBar *m_titleBar;
GraphicsView *m_graphicsView;
NavigatorView *m_gv;
BottomButtonGroup *m_bottomButtonGroup;

View File

@@ -55,6 +55,11 @@ bool Settings::useBuiltInCloseAnimation() const
return m_qsettings->value("use_built_in_close_animation", true).toBool();
}
bool Settings::showTitleBar() const
{
return m_qsettings->value("show_title_bar", true).toBool();
}
bool Settings::useLightCheckerboard() const
{
return m_qsettings->value("use_light_checkerboard", false).toBool();
@@ -123,6 +128,12 @@ void Settings::setUseBuiltInCloseAnimation(bool on)
m_qsettings->sync();
}
void Settings::setShowTitleBar(bool on)
{
m_qsettings->setValue("show_title_bar", on);
m_qsettings->sync();
}
void Settings::setUseLightCheckerboard(bool light)
{
m_qsettings->setValue("use_light_checkerboard", light);

View File

@@ -36,6 +36,7 @@ public:
bool stayOnTop() const;
bool useBuiltInCloseAnimation() const;
bool showTitleBar() const;
bool useLightCheckerboard() const;
bool loopGallery() const;
bool autoLongImageMode() const;
@@ -47,6 +48,7 @@ public:
void setStayOnTop(bool on);
void setUseBuiltInCloseAnimation(bool on);
void setShowTitleBar(bool on);
void setUseLightCheckerboard(bool light);
void setLoopGallery(bool on);
void setAutoLongImageMode(bool on);

View File

@@ -21,6 +21,7 @@ SettingsDialog::SettingsDialog(QWidget *parent)
: QDialog(parent)
, m_stayOnTop(new QCheckBox)
, m_useBuiltInCloseAnimation(new QCheckBox)
, m_showTitleBar(new QCheckBox)
, m_useLightCheckerboard(new QCheckBox)
, m_loopGallery(new QCheckBox)
, m_autoLongImageMode(new QCheckBox)
@@ -123,6 +124,7 @@ SettingsDialog::SettingsDialog(QWidget *parent)
settingsForm->addRow(tr("Stay on top when start-up"), m_stayOnTop);
settingsForm->addRow(tr("Use built-in close window animation"), m_useBuiltInCloseAnimation);
settingsForm->addRow(tr("Show title bar"), m_showTitleBar);
settingsForm->addRow(tr("Use light-color checkerboard"), m_useLightCheckerboard);
settingsForm->addRow(tr("Loop the loaded gallery"), m_loopGallery);
settingsForm->addRow(tr("Auto long image mode"), m_autoLongImageMode);
@@ -134,6 +136,7 @@ SettingsDialog::SettingsDialog(QWidget *parent)
m_stayOnTop->setChecked(Settings::instance()->stayOnTop());
m_useBuiltInCloseAnimation->setChecked(Settings::instance()->useBuiltInCloseAnimation());
m_showTitleBar->setChecked(Settings::instance()->showTitleBar());
m_useLightCheckerboard->setChecked(Settings::instance()->useLightCheckerboard());
m_loopGallery->setChecked(Settings::instance()->loopGallery());
m_autoLongImageMode->setChecked(Settings::instance()->autoLongImageMode());
@@ -172,6 +175,10 @@ SettingsDialog::SettingsDialog(QWidget *parent)
Settings::instance()->setUseBuiltInCloseAnimation(state == Qt::Checked);
});
connect(m_showTitleBar, &QCHECKBOX_CHECKSTATECHANGED, this, [ = ](QT_CHECKSTATE state){
Settings::instance()->setShowTitleBar(state == Qt::Checked);
});
connect(m_useLightCheckerboard, &QCHECKBOX_CHECKSTATECHANGED, this, [ = ](QT_CHECKSTATE state){
Settings::instance()->setUseLightCheckerboard(state == Qt::Checked);
});

View File

@@ -24,6 +24,7 @@ public slots:
private:
QCheckBox * m_stayOnTop = nullptr;
QCheckBox * m_useBuiltInCloseAnimation = nullptr;
QCheckBox * m_showTitleBar = nullptr;
QCheckBox * m_useLightCheckerboard = nullptr;
QCheckBox * m_loopGallery = nullptr;
QCheckBox * m_autoLongImageMode = nullptr;

218
app/titlebar.cpp Normal file
View File

@@ -0,0 +1,218 @@
// SPDX-FileCopyrightText: 2025 Gary Wang <git@blumia.net>
//
// SPDX-License-Identifier: MIT
#include "titlebar.h"
#include "opacityhelper.h"
#include <QPainter>
#include <QStyle>
#include <QMouseEvent>
#include <QEvent>
#include <QEnterEvent>
#include <QWindow>
#include <QCursor>
TitleBar::TitleBar(QWidget *parent)
: QWidget(parent)
, m_opacityHelper(new OpacityHelper(this))
, m_closeIcon(QStringLiteral(":/icons/window-close.svg"))
{
setFixedHeight(32);
setMouseTracking(true);
setAttribute(Qt::WA_Hover, true);
if (QWidget *win = window())
win->installEventFilter(this);
}
void TitleBar::setOpacity(qreal opacity, bool animated)
{
m_opacityHelper->setOpacity(opacity, animated);
}
void TitleBar::setCloseButtonVisible(bool visible)
{
if (m_closeButtonVisible == visible)
return;
m_closeButtonVisible = visible;
if (!visible) {
m_closeHovered = false;
m_closePressed = false;
}
update();
}
void TitleBar::setCloseButtonOnly(bool only)
{
if (m_closeButtonOnly == only)
return;
m_closeButtonOnly = only;
update();
}
QRect TitleBar::closeButtonRect() const
{
const int btnWidth = closeButtonWidth();
return QRect(width() - btnWidth, 0, btnWidth, height());
}
void TitleBar::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter painter(this);
// Subtle translucent backdrop so the title bar region is distinguishable
// (similar to the bottom button group). Skipped in close-button-only mode.
if (!m_closeButtonOnly) {
painter.fillRect(rect(), QColor(0, 0, 0, 120));
}
const QRect closeRect = closeButtonRect();
// Title text (leave room for the close button).
QRect labelRect = rect().adjusted(8, 0, 0, 0);
if (m_closeButtonVisible)
labelRect.setRight(closeRect.left() - 2);
const QString title = window() ? window()->windowTitle() : QString();
if (!m_closeButtonOnly && !title.isEmpty()) {
const QString elided = painter.fontMetrics().elidedText(title, Qt::ElideRight, labelRect.width());
const int flags = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine;
painter.setPen(Qt::black);
painter.drawText(labelRect.adjusted(1, 1, 1, 1), flags, elided);
painter.setPen(Qt::white);
painter.drawText(labelRect, flags, elided);
}
if (m_closeButtonVisible) {
if (m_closeHovered) {
painter.fillRect(closeRect,
m_closePressed ? QColor(0xC5, 0x0F, 0x1F)
: QColor(0xE8, 0x11, 0x23));
}
const int sz = height() / 3 * 2;
const QRect iconRect = QStyle::alignedRect(layoutDirection(), Qt::AlignCenter,
QSize(sz, sz), closeRect);
m_closeIcon.paint(&painter, iconRect);
}
}
void TitleBar::mousePressEvent(QMouseEvent *event)
{
if (event->button() != Qt::LeftButton) {
QWidget::mousePressEvent(event);
return;
}
if (m_closeButtonVisible && closeButtonRect().contains(event->pos())) {
m_closePressed = true;
m_dragPending = false;
update();
event->accept();
return;
}
m_dragPending = true;
m_moveStartPos = event->pos();
event->accept();
}
void TitleBar::mouseMoveEvent(QMouseEvent *event)
{
if (m_closeButtonVisible) {
const bool hovered = closeButtonRect().contains(event->pos());
if (hovered != m_closeHovered) {
m_closeHovered = hovered;
update();
}
}
if (event->buttons() & Qt::LeftButton && m_dragPending
&& !window()->isMaximized() && !window()->isFullScreen()) {
if (QWindow *wh = window()->windowHandle()) {
if (!wh->startSystemMove())
window()->move(event->globalPosition().toPoint() - m_moveStartPos);
}
event->accept();
}
QWidget::mouseMoveEvent(event);
}
void TitleBar::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
const bool wasClosePressed = m_closePressed;
m_closePressed = false;
m_dragPending = false;
update();
if (wasClosePressed && m_closeButtonVisible
&& closeButtonRect().contains(event->pos())) {
emit closeRequested();
event->accept();
return;
}
}
QWidget::mouseReleaseEvent(event);
}
void TitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton
&& !(m_closeButtonVisible && closeButtonRect().contains(event->pos()))) {
emit maximizeToggleRequested();
event->accept();
return;
}
QWidget::mouseDoubleClickEvent(event);
}
void TitleBar::enterEvent(QEnterEvent *event)
{
Q_UNUSED(event);
if (m_closeButtonVisible) {
const bool hovered = closeButtonRect().contains(mapFromGlobal(QCursor::pos()));
if (hovered != m_closeHovered) {
m_closeHovered = hovered;
update();
}
}
QWidget::enterEvent(event);
}
void TitleBar::leaveEvent(QEvent *event)
{
if (m_closeHovered) {
m_closeHovered = false;
update();
}
QWidget::leaveEvent(event);
}
bool TitleBar::eventFilter(QObject *watched, QEvent *event)
{
if (watched == window()) {
switch (event->type()) {
case QEvent::WindowTitleChange:
case QEvent::WindowStateChange:
case QEvent::ActivationChange:
update();
break;
default:
break;
}
}
return QWidget::eventFilter(watched, event);
}
QSize TitleBar::sizeHint() const
{
return QSize(0, 32);
}

60
app/titlebar.h Normal file
View File

@@ -0,0 +1,60 @@
// SPDX-FileCopyrightText: 2025 Gary Wang <git@blumia.net>
//
// SPDX-License-Identifier: MIT
#ifndef TITLEBAR_H
#define TITLEBAR_H
#include <QWidget>
#include <QIcon>
QT_BEGIN_NAMESPACE
class QPaintEvent;
class QMouseEvent;
class QEvent;
class QEnterEvent;
QT_END_NAMESPACE
class OpacityHelper;
class TitleBar : public QWidget
{
Q_OBJECT
public:
explicit TitleBar(QWidget *parent = nullptr);
void setOpacity(qreal opacity, bool animated = true);
void setCloseButtonVisible(bool visible);
bool closeButtonOnly() const { return m_closeButtonOnly; }
void setCloseButtonOnly(bool only);
int closeButtonWidth() const { return qMax(height(), 46); }
signals:
void closeRequested();
void maximizeToggleRequested();
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
void enterEvent(QEnterEvent *event) override;
void leaveEvent(QEvent *event) override;
bool eventFilter(QObject *watched, QEvent *event) override;
QSize sizeHint() const override;
private:
QRect closeButtonRect() const;
OpacityHelper *m_opacityHelper;
QIcon m_closeIcon;
bool m_closeButtonVisible = true;
bool m_closeButtonOnly = false;
bool m_closeHovered = false;
bool m_closePressed = false;
bool m_dragPending = false;
QPoint m_moveStartPos;
};
#endif // TITLEBAR_H

View File

@@ -11,7 +11,7 @@
#include <QGraphicsOpacityEffect>
#include <QPropertyAnimation>
ToolButton::ToolButton(bool hoverColor, QWidget *parent)
ToolButton::ToolButton(QWidget *parent)
: QPushButton(parent)
, m_opacityHelper(new OpacityHelper(this))
{
@@ -19,11 +19,6 @@ ToolButton::ToolButton(bool hoverColor, QWidget *parent)
QString qss = "QPushButton {"
"background: transparent;"
"}";
if (hoverColor) {
qss += "QPushButton:hover {"
"background: red;"
"}";
}
setStyleSheet(qss);
}

View File

@@ -12,7 +12,7 @@ class ToolButton : public QPushButton
{
Q_OBJECT
public:
ToolButton(bool hoverColor = false, QWidget * parent = nullptr);
ToolButton(QWidget * parent = nullptr);
void setIconResourcePath(const QString &iconp);
public slots:

View File

@@ -240,27 +240,27 @@
<location filename="../mainwindow.cpp" line="734"/>
<location filename="../mainwindow.cpp" line="764"/>
<source>Save As</source>
<translation type="unfinished"></translation>
<translation>Opslaan als</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="710"/>
<source>No image is currently open.</source>
<translation type="unfinished"></translation>
<translation>Er is geen afbeelding geopend.</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="722"/>
<source>%1 Image (*.%2)</source>
<translation type="unfinished"></translation>
<translation>%1-afbeelding (*.%2)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="728"/>
<source>No supported image formats are available.</source>
<translation type="unfinished"></translation>
<translation>Er zijn geen ondersteunde formaten beschikbaar.</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="765"/>
<source>Failed to save image: %1</source>
<translation type="unfinished"></translation>
<translation>De afbeelding kan niet worden opgeslagen: %1</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="854"/>
@@ -324,7 +324,7 @@
<message>
<location filename="../actionmanager.cpp" line="88"/>
<source>Save &amp;As...</source>
<translation type="unfinished"></translation>
<translation>Opslaan &amp;als</translation>
</message>
<message>
<location filename="../actionmanager.cpp" line="93"/>
@@ -359,7 +359,7 @@
<message>
<location filename="../actionmanager.cpp" line="107"/>
<source>Fit long image</source>
<translation type="unfinished"></translation>
<translation>Lange afbeelding inpassen</translation>
</message>
<message>
<location filename="../actionmanager.cpp" line="110"/>
@@ -891,7 +891,7 @@
<message>
<location filename="../settingsdialog.cpp" line="129"/>
<source>Limit SVG support to SVG Tiny 1.2</source>
<translation type="unfinished"></translation>
<translation>Svg-ondersteuning beperken tot SVG Tiny 1.2</translation>
</message>
<message>
<location filename="../settingsdialog.cpp" line="130"/>

View File

@@ -225,27 +225,27 @@ Loc Huynh &lt;https://github.com/hthienloc&gt;</translation>
<location filename="../mainwindow.cpp" line="734"/>
<location filename="../mainwindow.cpp" line="764"/>
<source>Save As</source>
<translation type="unfinished"></translation>
<translation>Lưu dưới dạng</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="710"/>
<source>No image is currently open.</source>
<translation type="unfinished"></translation>
<translation>Hiện tại không hình nh nào đưc mở.</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="722"/>
<source>%1 Image (*.%2)</source>
<translation type="unfinished"></translation>
<translation>Hình nh %1 (*.%2)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="728"/>
<source>No supported image formats are available.</source>
<translation type="unfinished"></translation>
<translation>Không đnh dạng hình nh đưc hỗ trợ.</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="765"/>
<source>Failed to save image: %1</source>
<translation type="unfinished"></translation>
<translation>Không lưu đưc hình nh: %1</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="854"/>
@@ -309,7 +309,7 @@ Loc Huynh &lt;https://github.com/hthienloc&gt;</translation>
<message>
<location filename="../actionmanager.cpp" line="88"/>
<source>Save &amp;As...</source>
<translation type="unfinished"></translation>
<translation>Lưu &amp;dưới dạng...</translation>
</message>
<message>
<location filename="../actionmanager.cpp" line="93"/>

View File

@@ -11,7 +11,7 @@ environment:
- job_name: mingw_64_qt6_8
QTDIR: C:\Qt\6.8\mingw_64
MINGW64: C:\Qt\mingw_64\Tools\mingw1310_64
KF_BRANCH: master
KF_BRANCH: v6.24.0
EXIV2_VERSION: "0.28.7"
EXIV2_CMAKE_OPTIONS: "-DEXIV2_ENABLE_BROTLI=OFF -DEXIV2_ENABLE_INIH=OFF -DEXIV2_BUILD_EXIV2_COMMAND=OFF"
PPIC_CMAKE_OPTIONS: "-DPREFER_QT_5=OFF"
@@ -39,9 +39,9 @@ build_script:
- cd %APPVEYOR_BUILD_FOLDER%
# download and install zlib for KArchive
- cd %LIBZ%
- curl -fsSL -o zlib131.zip https://zlib.net/zlib131.zip
- 7z x zlib131.zip -y
- cd zlib-1.3.1
- curl -fsSL -o zlib132.zip https://zlib.net/zlib132.zip
- 7z x zlib132.zip -y
- cd zlib-1.3.2
- mkdir build
- cd build
- cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%CMAKE_INSTALL_PREFIX%
@@ -134,7 +134,7 @@ build_script:
- copy %CMAKE_INSTALL_PREFIX%\bin\libexpat-1.dll
- copy %CMAKE_INSTALL_PREFIX%\bin\libexiv2.dll
- copy %CMAKE_INSTALL_PREFIX%\bin\libavif.dll
- copy %CMAKE_INSTALL_PREFIX%\bin\libzlib.dll
- copy %CMAKE_INSTALL_PREFIX%\bin\libz.dll
- copy %CMAKE_INSTALL_PREFIX%\bin\libKF?Archive.dll
- windeployqt %WINDEPLOYQT_ARGS% .\ppic.exe
# copy 3rdparty licenses for the libs we vendored for windows...

View File

@@ -4,18 +4,26 @@
<name>Pineapple Pictures</name>
<name xml:lang="es">Pineapple Pictures</name>
<name xml:lang="ja">Pineapple Pictures</name>
<name xml:lang="ko">Pineapple Pictures</name>
<name xml:lang="nl">Pineapple Afbeeldingen</name>
<name xml:lang="ru">Pineapple Pictures</name>
<name xml:lang="sl">Pineapple Slike</name>
<name xml:lang="ta">அன்னாசி படங்கள்</name>
<name xml:lang="tr">Pineapple Resimler</name>
<name xml:lang="uk">Pineapple Pictures</name>
<name xml:lang="vi">Pineapple Pictures</name>
<name xml:lang="zh-CN">菠萝看图</name>
<summary>Image Viewer</summary>
<summary xml:lang="es">Visor de imágenes</summary>
<summary xml:lang="ja">画像ビューアー</summary>
<summary xml:lang="ko">이미지 뷰어</summary>
<summary xml:lang="nl">Afbeeldingsweergave</summary>
<summary xml:lang="ru">Просмотр изображений</summary>
<summary xml:lang="sl">Pregledovalnik slik</summary>
<summary xml:lang="ta">பட பார்வையாளர்</summary>
<summary xml:lang="tr">Resim Görüntüleyici</summary>
<summary xml:lang="uk">Переглядач зображень</summary>
<summary xml:lang="vi">Trình xem ảnh</summary>
<summary xml:lang="zh-CN">图像查看器</summary>
<metadata_license>CC0-1.0</metadata_license>
<project_license>MIT</project_license>
@@ -23,10 +31,13 @@
<p>Pineapple Pictures is a lightweight and easy-to-use image viewer that comes with a handy navigation thumbnail when zoom-in, and doesn't contain any image management support.</p>
<p xml:lang="es">Pineapple Pictures es un visor de imágenes ligero y fácil de usar que viene con una práctica miniatura de navegación al hacer zoom, y no contiene ningún soporte de gestión de imágenes.</p>
<p xml:lang="ja">Pineapple Picturesは、ズームイン時に便利なナビゲーションサムネイルを備えた軽量で使いやすい画像ビューアです。画像管理のサポートは含まれていません。</p>
<p xml:lang="ko">Pineapple Pictures는 가볍고 사용하기 쉬운 이미지 뷰어로, 확대 시 편리한 내비게이션 썸네일과 함께 제공되며 이미지 관리 지원이 포함되어 있지 않습니다.</p>
<p xml:lang="nl">Pineapple Afbeeldingen is een licht en eenvoudig te gebruiken afbeeldingsweergaveprogramma met miniatuurnavigatie na inzoomen. Het programma heeft echter geen fotobeheermogelijkheid.</p>
<p xml:lang="ru">Pineapple Pictures - это легкий и простой в использовании просмотрщик изображений, оснащенный удобной навигацией по миниатюрам при увеличении масштаба и не содержащий никакой поддержки управления изображениями.</p>
<p xml:lang="sl">Pineapple Pictures je lahek in enostaven pregledovalnik slik, ki ima pri povečavi priročno sličico za navigacijo in ne vsebuje nobene podpore za upravljanje slik.</p>
<p xml:lang="ta">அன்னாசி படங்கள் ஒரு இலகுரக மற்றும் பயன்படுத்த எளிதான பட பார்வையாளராகும், இது பெரிதாக்கும்போது ஒரு எளிமையான வழிசெலுத்தல் சிறுபடத்துடன் வருகிறது, மேலும் எந்த பட மேலாண்மை ஆதரவையும் கொண்டிருக்கவில்லை.</p>
<p xml:lang="uk">Pineapple Pictures це легкий і простий у використанні переглядач зображень, який постачається зі зручною навігаційною мініатюрою при збільшенні масштабу і не містить жодної підтримки керування зображеннями.</p>
<p xml:lang="vi">Pineapple Pictures là trình xem hình ảnh nhẹ và dễ sử dụng, đi kèm với hình thu nhỏ điều hướng tiện dụng khi phóng to và không chứa bất kỳ hỗ trợ quản lý hình ảnh nào.</p>
<p xml:lang="zh-CN">菠萝看图是一个轻量级易用的图像查看器,在图片放大时提供了方便的鸟瞰导航功能,且不包含任何图片管理功能。</p>
</description>
<developer id="net.blumia">
@@ -50,10 +61,13 @@
<caption>Main window when an image file is loaded</caption>
<caption xml:lang="es">Ventana principal cuando se carga un archivo de imagen</caption>
<caption xml:lang="ja">画像ファイル読み込み時のメインウィンドウ</caption>
<caption xml:lang="ko">이미지 파일이 로드될 때 기본 창</caption>
<caption xml:lang="nl">Hoofdvenster na het laden van een afbeelding</caption>
<caption xml:lang="ru">Основное окно после загрузки файла изображения</caption>
<caption xml:lang="sl">Glavno okno ob nalaganju slikovne datoteke</caption>
<caption xml:lang="ta">ஒரு படக் கோப்பு ஏற்றப்படும் போது முதன்மையான சாளரம்</caption>
<caption xml:lang="uk">Головне вікно після завантаження файлу зображення</caption>
<caption xml:lang="vi">Cửa sổ chính khi tải tệp hình ảnh</caption>
<caption xml:lang="zh-CN">加载图片后的主窗口</caption>
<image type="source" width="1503" height="640">https://pineapple-pictures.sourceforge.io/ppic-gui-static.png</image>
</screenshot>
@@ -61,10 +75,13 @@
<caption>Zooming in a raster image</caption>
<caption xml:lang="es">Ampliar una imagen rasterizada</caption>
<caption xml:lang="ja">ラスター画像の拡大</caption>
<caption xml:lang="ko">래스터 이미지 확대하기</caption>
<caption xml:lang="nl">Inzoomen op een roosterafbeelding</caption>
<caption xml:lang="ru">Масштабирование растрового изображения</caption>
<caption xml:lang="sl">Povečevanje rastrske slike</caption>
<caption xml:lang="ta">ராச்டர் படத்தில் பெரிதாக்குதல்</caption>
<caption xml:lang="uk">Масштабування растрового зображення</caption>
<caption xml:lang="vi">Phóng to hình ảnh raster</caption>
<caption xml:lang="zh-CN">放大浏览位图</caption>
<image type="source" width="771" height="553">https://pineapple-pictures.sourceforge.io/ppic-zoom-raster.png</image>
</screenshot>
@@ -72,15 +89,29 @@
<caption>Zooming in a vector image</caption>
<caption xml:lang="es">Ampliar una imagen vectorial</caption>
<caption xml:lang="ja">ベクター画像の拡大</caption>
<caption xml:lang="ko">벡터 이미지 확대하기</caption>
<caption xml:lang="nl">Inzoomen op een vectorafbeelding</caption>
<caption xml:lang="ru">Масштабирование векторного изображения</caption>
<caption xml:lang="sl">Povečevanje vektorske slike</caption>
<caption xml:lang="ta">ஒரு திசையன் படத்தில் பெரிதாக்குதல்</caption>
<caption xml:lang="uk">Масштабування векторного зображення</caption>
<caption xml:lang="vi">Phóng to hình ảnh vector</caption>
<caption xml:lang="zh-CN">放大浏览矢量图</caption>
<image type="source" width="771" height="553">https://pineapple-pictures.sourceforge.io/ppic-zoom-svg.png</image>
</screenshot>
</screenshots>
<releases>
<release type="stable" version="1.4.1" date="2026-04-05T00:00:00Z">
<description>
<p>This release includes the following changes:</p>
<ul>
<li>Update translations</li>
<li>Update Qt version to 6.10.3 for Windows and macOS pre-built binaries</li>
</ul>
<p>With contributions from:</p>
<p>Heimen Stoffels (vistaus), Loc Huynh (hthienloc)</p>
</description>
</release>
<release type="stable" version="1.4.0" date="2026-02-11T00:00:00Z">
<description>
<p>This release adds the following features:</p>