1430 lines
46 KiB
C++
1430 lines
46 KiB
C++
#include "Dialog/mainwindow.h"
|
|
#include "Dialog/aboutsoftwaredialog.h"
|
|
#include "Dialog/createreversedialog.h"
|
|
#include "Dialog/exportdialog.h"
|
|
#include "Dialog/newdialog.h"
|
|
#include "Dialog/reduceframedialog.h"
|
|
#include "Dialog/scalegifdialog.h"
|
|
#include "Dialog/sponsordialog.h"
|
|
#include "UndoCommand/cropimagecommand.h"
|
|
#include "UndoCommand/delayframecommand.h"
|
|
#include "UndoCommand/delframedircommand.h"
|
|
#include "UndoCommand/flipframecommand.h"
|
|
#include "UndoCommand/insertframecommand.h"
|
|
#include "UndoCommand/moveframecommand.h"
|
|
#include "UndoCommand/reduceframecommand.h"
|
|
#include "UndoCommand/removeframecommand.h"
|
|
#include "UndoCommand/replaceframecommand.h"
|
|
#include "UndoCommand/reverseframecommand.h"
|
|
#include "UndoCommand/rotateframecommand.h"
|
|
#include "UndoCommand/scaleframecommand.h"
|
|
#include <DInputDialog>
|
|
#include <DMenu>
|
|
#include <DMessageManager>
|
|
#include <DTitlebar>
|
|
#include <DToolBar>
|
|
#include <DToolButton>
|
|
#include <QApplication>
|
|
#include <QClipboard>
|
|
#include <QCloseEvent>
|
|
#include <QDesktopServices>
|
|
#include <QDragEnterEvent>
|
|
#include <QDropEvent>
|
|
#include <QFileDialog>
|
|
#include <QListWidgetItem>
|
|
#include <QMessageBox>
|
|
#include <QMimeData>
|
|
#include <QProcess>
|
|
#include <QRubberBand>
|
|
#include <QSettings>
|
|
#include <QShortcut>
|
|
#include <QVBoxLayout>
|
|
#include <QWidget>
|
|
#include <QtConcurrent>
|
|
|
|
#define ICONRES(name) QIcon(":/images/" name ".png")
|
|
|
|
#define CheckEnabled \
|
|
if (curfilename.isEmpty()) \
|
|
return;
|
|
|
|
MainWindow::MainWindow(DMainWindow *parent) : DMainWindow(parent) {
|
|
setMinimumSize(800, 600);
|
|
setWindowTitle(tr("WingGifEditor"));
|
|
setWindowIcon(ICONRES("icon"));
|
|
setAcceptDrops(true);
|
|
auto w = new QWidget(this);
|
|
setCentralWidget(w);
|
|
auto vlayout = new QVBoxLayout(w);
|
|
editor = new GifEditor(QPixmap(":/images/icon.png"), w);
|
|
editor->setInteractive(true);
|
|
editor->setAcceptDrops(true);
|
|
vlayout->addWidget(editor);
|
|
|
|
imglist = new QListWidget(w);
|
|
imglist->setFlow(QListWidget::TopToBottom);
|
|
imglist->setViewMode(QListWidget::IconMode);
|
|
imglist->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn);
|
|
imglist->setSelectionMode(
|
|
QAbstractItemView::SelectionMode::ExtendedSelection);
|
|
imglist->setIconSize(QSize(100, 100));
|
|
imglist->setFixedHeight(140);
|
|
imglist->setLayoutDirection(Qt::LayoutDirection::LeftToRight);
|
|
imglist->setResizeMode(QListView::Adjust);
|
|
imglist->setDragDropMode(QListWidget::DragDropMode::NoDragDrop);
|
|
imglist->setDefaultDropAction(Qt::DropAction::TargetMoveAction);
|
|
vlayout->addWidget(imglist);
|
|
|
|
connect(imglist, &QListWidget::itemSelectionChanged, this, [=] {
|
|
editor->setBackgroudPix(gif.frameimg(imglist->currentRow()));
|
|
this->showGifMessage();
|
|
});
|
|
|
|
auto title = titlebar();
|
|
title->setIcon(ICONRES("icon"));
|
|
title->setTitle(tr("WingGifEditor"));
|
|
|
|
auto menu = new DMenu(this);
|
|
QAction *a;
|
|
|
|
auto keyselrev =
|
|
QKeySequence(Qt::KeyboardModifier::ControlModifier | Qt::Key_I);
|
|
auto keygoto =
|
|
QKeySequence(Qt::KeyboardModifier::ControlModifier | Qt::Key_G);
|
|
auto keybeginframe = QKeySequence(Qt::Key_Home);
|
|
auto keylastframe = QKeySequence(Qt::Key_Left);
|
|
auto keynextframe = QKeySequence(Qt::Key_Right);
|
|
auto keyendframe = QKeySequence(Qt::Key_End);
|
|
auto keyplay = QKeySequence(Qt::Key_F5);
|
|
auto keypause = QKeySequence(Qt::Key_F10);
|
|
auto keyreduceframe =
|
|
QKeySequence(Qt::KeyboardModifier::ControlModifier | Qt::Key_D);
|
|
auto keyrmleft =
|
|
QKeySequence(Qt::KeyboardModifier::ControlModifier | Qt::Key_J);
|
|
auto keyrmright =
|
|
QKeySequence(Qt::KeyboardModifier::ControlModifier | Qt::Key_K);
|
|
auto keyrev = QKeySequence(Qt::KeyboardModifier::ControlModifier |
|
|
Qt::KeyboardModifier::ShiftModifier | Qt::Key_I);
|
|
auto keymvl =
|
|
QKeySequence(Qt::KeyboardModifier::ControlModifier | Qt::Key_BracketLeft);
|
|
auto keymvr = QKeySequence(Qt::KeyboardModifier::ControlModifier |
|
|
Qt::Key_BracketRight);
|
|
auto keysetdelay =
|
|
QKeySequence(Qt::KeyboardModifier::ControlModifier | Qt::Key_T);
|
|
auto keyscaledelay =
|
|
QKeySequence(Qt::KeyboardModifier::ControlModifier |
|
|
Qt::KeyboardModifier::ShiftModifier | Qt::Key_T);
|
|
auto keyscalepic =
|
|
QKeySequence(Qt::KeyboardModifier::ShiftModifier | Qt::Key_T);
|
|
auto keycutpic =
|
|
QKeySequence(Qt::KeyboardModifier::ControlModifier |
|
|
Qt::KeyboardModifier::ShiftModifier | Qt::Key_X);
|
|
|
|
#define AddMenuIconAction(Icon, Title, Slot, Owner) \
|
|
a = new QAction(Owner); \
|
|
a->setText(Title); \
|
|
a->setIcon(ICONRES(Icon)); \
|
|
connect(a, &QAction::triggered, this, &Slot); \
|
|
Owner->addAction(a);
|
|
|
|
#define AddMenuAction(Title, Slot, Owner) \
|
|
a = new QAction(Owner); \
|
|
a->setText(Title); \
|
|
connect(a, &QAction::triggered, this, &Slot); \
|
|
Owner->addAction(a);
|
|
|
|
#define AddMenuShortcutAction(Icon, Title, Slot, Owner, ShortCut) \
|
|
AddMenuIconAction(Icon, Title, Slot, Owner); \
|
|
a->setShortcut(ShortCut); \
|
|
a->setShortcutVisibleInContextMenu(true);
|
|
|
|
#define AddToolSubMenuShortcutAction(Icon, Title, Slot, ShortCut) \
|
|
AddMenuShortcutAction(Icon, Title, Slot, tm, ShortCut)
|
|
|
|
#define AddMenuDB() \
|
|
a->setDisabled(true); \
|
|
dismenu.append(a)
|
|
|
|
auto tm = new QMenu(this);
|
|
tm->setIcon(ICONRES("file"));
|
|
tm->setTitle(tr("File"));
|
|
|
|
auto m = new QMenu(this);
|
|
m->setIcon(ICONRES("new"));
|
|
m->setTitle(tr("New"));
|
|
AddMenuIconAction("pics", tr("NewFromPics"), MainWindow::on_new_frompics, m);
|
|
AddMenuIconAction("gifs", tr("NewFromGifs"), MainWindow::on_new_fromgifs, m);
|
|
tm->addMenu(m);
|
|
|
|
AddMenuShortcutAction("open", tr("Open"), MainWindow::on_open, tm,
|
|
QKeySequence::Open);
|
|
AddMenuShortcutAction("save", tr("Save"), MainWindow::on_save, tm,
|
|
QKeySequence::Save);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("saveas", tr("SaveAs"), MainWindow::on_saveas, tm,
|
|
QKeySequence::SaveAs);
|
|
AddMenuDB();
|
|
AddMenuIconAction("export", tr("Export"), MainWindow::on_export, tm);
|
|
tm->addSeparator();
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("close", tr("Close"), MainWindow::on_close, tm,
|
|
QKeySequence::Close);
|
|
|
|
menu->addMenu(tm);
|
|
|
|
tm = new QMenu(this);
|
|
tm->setTitle(tr("Edit"));
|
|
tm->setIcon(ICONRES("edit"));
|
|
AddMenuShortcutAction("undo", tr("Undo"), MainWindow::on_undo, tm,
|
|
QKeySequence::Undo);
|
|
a->setDisabled(true);
|
|
undomenu = a;
|
|
AddMenuShortcutAction("redo", tr("Redo"), MainWindow::on_redo, tm,
|
|
QKeySequence::Redo);
|
|
a->setDisabled(true);
|
|
redomenu = a;
|
|
tm->addSeparator();
|
|
AddMenuShortcutAction("cut", tr("Cut"), MainWindow::on_cut, tm,
|
|
QKeySequence::Cut);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("copy", tr("Copy"), MainWindow::on_copy, tm,
|
|
QKeySequence::Copy);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("paste", tr("Paste"), MainWindow::on_paste, tm,
|
|
QKeySequence::Paste);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("del", tr("Delete"), MainWindow::on_del, tm,
|
|
QKeySequence::Delete);
|
|
AddMenuDB();
|
|
tm->addSeparator();
|
|
AddMenuShortcutAction("selall", tr("SelectAll"), MainWindow::on_selall, tm,
|
|
QKeySequence::SelectAll);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("desel", tr("Deselect"), MainWindow::on_desel, tm,
|
|
QKeySequence::Deselect);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("selrev", tr("ReverseSelection"),
|
|
MainWindow::on_selreverse, tm, keyselrev);
|
|
AddMenuDB();
|
|
tm->addSeparator();
|
|
AddMenuShortcutAction("jmp", tr("Goto"), MainWindow::on_goto, tm, keygoto);
|
|
AddMenuDB();
|
|
menu->addMenu(tm);
|
|
|
|
tm = new QMenu(this);
|
|
tm->setIcon(ICONRES("play"));
|
|
tm->setTitle(tr("Play"));
|
|
AddMenuShortcutAction("first", tr("FirstFrame"), MainWindow::on_beginframe,
|
|
tm, keybeginframe);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("back", tr("LastFrame"), MainWindow::on_last, tm,
|
|
keylastframe);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("gifplay", tr("Play"), MainWindow::on_play, tm,
|
|
keyplay);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("pause", tr("Stop"), MainWindow::on_stop, tm, keypause);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("foreword", tr("NextFrame"), MainWindow::on_next, tm,
|
|
keynextframe);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("last", tr("EndFrame"), MainWindow::on_endframe, tm,
|
|
keylastframe);
|
|
AddMenuDB();
|
|
title->setMenu(menu);
|
|
|
|
tm = new QMenu(this);
|
|
tm->setIcon(ICONRES("pic"));
|
|
tm->setTitle(tr("Picture"));
|
|
AddMenuShortcutAction("rmframe", tr("ReduceFrame"),
|
|
MainWindow::on_decreaseframe, tm, keyreduceframe);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("rml", tr("DeleteBefore"), MainWindow::on_delbefore, tm,
|
|
keyrmleft);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("rmr", tr("DeleteAfter"), MainWindow::on_delafter, tm,
|
|
keyrmright);
|
|
AddMenuDB();
|
|
tm->addSeparator();
|
|
AddMenuShortcutAction("mvf", tr("MoveLeft"), MainWindow::on_moveleft, tm,
|
|
keymvl);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("mvb", tr("MoveRight"), MainWindow::on_moveright, tm,
|
|
keymvr);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("reverse", tr("Reverse"), MainWindow::on_reverse, tm,
|
|
keyrev);
|
|
AddMenuDB();
|
|
tm->addSeparator();
|
|
AddMenuShortcutAction("setdelay", tr("SetDelay"), MainWindow::on_setdelay, tm,
|
|
keysetdelay);
|
|
AddMenuDB();
|
|
AddMenuIconAction("pics", tr("InsertPics"), MainWindow::on_insertpic, tm);
|
|
AddMenuDB();
|
|
AddMenuIconAction("gifs", tr("MergeGIfs"), MainWindow::on_merge, tm);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("scale", tr("ScaleGif"), MainWindow::on_scalepic, tm,
|
|
keyscalepic);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("cutpic", tr("CutGif"), MainWindow::on_cutpic, tm,
|
|
keycutpic);
|
|
AddMenuDB();
|
|
tm->addSeparator();
|
|
AddMenuIconAction("fliph", tr("FilpH"), MainWindow::on_fliph, tm);
|
|
AddMenuDB();
|
|
AddMenuIconAction("flipv", tr("FlipV"), MainWindow::on_flipv, tm);
|
|
AddMenuDB();
|
|
AddMenuIconAction("rotatel", tr("RotateLeft"), MainWindow::on_clockwise, tm);
|
|
AddMenuDB();
|
|
AddMenuIconAction("rotater", tr("RotateR"), MainWindow::on_anticlockwise, tm);
|
|
AddMenuDB();
|
|
menu->addMenu(tm);
|
|
|
|
tm = new DMenu(this);
|
|
tm->setTitle(tr("Effect"));
|
|
tm->setIcon(ICONRES("effect"));
|
|
AddMenuIconAction("blank", tr("ExportBlank"), MainWindow::on_exportapply, tm);
|
|
AddMenuDB();
|
|
AddMenuIconAction("model", tr("ApplyModel"), MainWindow::on_applypic, tm);
|
|
AddMenuDB();
|
|
tm->addSeparator();
|
|
AddMenuIconAction("reverseplus", tr("CreateReverse"),
|
|
MainWindow::on_createreverse, tm);
|
|
AddMenuDB();
|
|
AddMenuShortcutAction("scaledelay", tr("ScaleDelay"),
|
|
MainWindow::on_scaledelay, tm, keyscaledelay);
|
|
AddMenuDB();
|
|
AddMenuIconAction("onion", tr("OnionMask"), MainWindow::on_onion, tm);
|
|
AddMenuDB();
|
|
menu->addMenu(tm);
|
|
|
|
tm = new DMenu(this);
|
|
tm->setTitle(tr("Author"));
|
|
tm->setIcon(ICONRES("author"));
|
|
AddMenuIconAction("setting", tr("Setting"), MainWindow::on_setting, tm);
|
|
AddMenuIconAction("fullscreen", tr("FullScreen"), MainWindow::on_fullscreen,
|
|
tm);
|
|
tm->addSeparator();
|
|
AddMenuIconAction("soft", tr("About"), MainWindow::on_about, tm);
|
|
AddMenuIconAction("sponsor", tr("Sponsor"), MainWindow::on_sponsor, tm);
|
|
AddMenuIconAction("wiki", tr("Wiki"), MainWindow::on_wiki, tm);
|
|
a = new QAction(ICONRES("qt"), tr("AboutQT"), tm);
|
|
connect(a, &QAction::triggered, this, [=] { QMessageBox::aboutQt(this); });
|
|
tm->addAction(a);
|
|
menu->addMenu(tm);
|
|
|
|
auto toolbar = new DToolBar(this);
|
|
toolbar->toggleViewAction()->setVisible(false);
|
|
|
|
#define AddToolBarAction(Icon, Owner, Slot, ToolTip) \
|
|
a = new QAction(Owner); \
|
|
a->setIcon(ICONRES(Icon)); \
|
|
connect(a, &QAction::triggered, this, &Slot); \
|
|
a->setToolTip(ToolTip); \
|
|
Owner->addAction(a);
|
|
|
|
#define AddToolBarTool(Icon, Slot, ToolTip) \
|
|
AddToolBarAction(Icon, toolbar, Slot, ToolTip)
|
|
|
|
DToolButton *tbtn;
|
|
DMenu *tmenu;
|
|
|
|
#define AddToolBtnBegin(DIcon) \
|
|
tbtn = new DToolButton(this); \
|
|
tbtn->setIcon(ICONRES(DIcon)); \
|
|
tmenu = new DMenu(this);
|
|
|
|
#define AddToolBtnBtn(Icon, Title, Slot) \
|
|
a = new QAction(ICONRES(Icon), Title, this); \
|
|
connect(a, &QAction::triggered, this, &Slot); \
|
|
tmenu->addAction(a);
|
|
|
|
#define AddToolBtnEnd() \
|
|
tbtn->setMenu(tmenu); \
|
|
tbtn->setPopupMode(DToolButton::ToolButtonPopupMode::InstantPopup); \
|
|
toolbar->addWidget(tbtn);
|
|
|
|
AddToolBtnBegin("new") {
|
|
AddToolBtnBtn("pics", tr("NewFromPics"), MainWindow::on_new_frompics);
|
|
AddToolBtnBtn("gifs", tr("NewFromGifs"), MainWindow::on_new_fromgifs);
|
|
}
|
|
AddToolBtnEnd();
|
|
|
|
#define AddToolDB() \
|
|
a->setEnabled(false); \
|
|
distool.append(a);
|
|
|
|
AddToolBarTool("open", MainWindow::on_open, tr("Open"));
|
|
AddToolBarTool("save", MainWindow::on_save, tr("Save"));
|
|
AddToolDB();
|
|
AddToolBarTool("saveas", MainWindow::on_saveas, tr("SaveAs"));
|
|
AddToolDB();
|
|
AddToolBarTool("export", MainWindow::on_export, tr("Export"));
|
|
AddToolDB();
|
|
toolbar->addSeparator();
|
|
AddToolBarTool("undo", MainWindow::on_undo, tr("Undo"));
|
|
a->setEnabled(false);
|
|
undotool = a;
|
|
AddToolBarTool("redo", MainWindow::on_redo, tr("Redo"));
|
|
a->setEnabled(false);
|
|
redotool = a;
|
|
AddToolBarTool("cut", MainWindow::on_cut, tr("Cut"));
|
|
AddToolDB();
|
|
AddToolBarTool("copy", MainWindow::on_copy, tr("Copy"));
|
|
AddToolDB();
|
|
AddToolBarTool("paste", MainWindow::on_paste, tr("Paste"));
|
|
AddToolDB();
|
|
AddToolBarTool("del", MainWindow::on_del, tr("Delete"));
|
|
AddToolDB();
|
|
AddToolBarTool("selall", MainWindow::on_selall, tr("SelectAll"));
|
|
AddToolDB();
|
|
AddToolBarTool("desel", MainWindow::on_desel, tr("Deselect"));
|
|
AddToolDB();
|
|
AddToolBarTool("selrev", MainWindow::on_selreverse, tr("ReverseSelection"));
|
|
AddToolDB();
|
|
AddToolBarTool("jmp", MainWindow::on_goto, tr("Goto"));
|
|
AddToolDB();
|
|
toolbar->addSeparator();
|
|
AddToolBarTool("setting", MainWindow::on_setting, tr("Setting"));
|
|
AddToolBarTool("soft", MainWindow::on_about, tr("About"));
|
|
AddToolBarTool("sponsor", MainWindow::on_sponsor, tr("Sponsor"));
|
|
AddToolBarTool("wiki", MainWindow::on_wiki, tr("Wiki"));
|
|
toolbar->setObjectName("main");
|
|
addToolBar(toolbar);
|
|
|
|
addToolBarBreak();
|
|
toolbar = new DToolBar(this);
|
|
toolbar->toggleViewAction()->setVisible(false);
|
|
AddToolBarTool("rmframe", MainWindow::on_decreaseframe, tr("ReduceFrame"));
|
|
AddToolDB();
|
|
AddToolBarTool("rml", MainWindow::on_delbefore, tr("DeleteBefore"));
|
|
AddToolDB();
|
|
AddToolBarTool("rmr", MainWindow::on_delafter, tr("DeleteAfter"));
|
|
AddToolDB();
|
|
AddToolBarTool("mvf", MainWindow::on_moveleft, tr("MoveLeft"));
|
|
AddToolDB();
|
|
AddToolBarTool("mvb", MainWindow::on_moveright, tr("MoveRight"));
|
|
AddToolDB();
|
|
AddToolBarTool("reverse", MainWindow::on_reverse, tr("Reverse"));
|
|
AddToolDB();
|
|
toolbar->addSeparator();
|
|
AddToolBarTool("setdelay", MainWindow::on_setdelay, tr("SetDelay"));
|
|
AddToolDB();
|
|
AddToolBarTool("pics", MainWindow::on_insertpic, tr("InsertPics"));
|
|
AddToolDB();
|
|
AddToolBarTool("gifs", MainWindow::on_merge, tr("MergeGIfs"));
|
|
AddToolDB();
|
|
AddToolBarTool("scale", MainWindow::on_scalepic, tr("ScaleGif"));
|
|
AddToolDB();
|
|
AddToolBarTool("cutpic", MainWindow::on_cutpic, tr("CutGif"));
|
|
AddToolDB();
|
|
toolbar->addSeparator();
|
|
AddToolBarTool("fliph", MainWindow::on_fliph, tr("FilpH"));
|
|
AddToolDB();
|
|
AddToolBarTool("flipv", MainWindow::on_flipv, tr("FlipV"));
|
|
AddToolDB();
|
|
AddToolBarTool("rotatel", MainWindow::on_clockwise, tr("RotateLeft"));
|
|
AddToolDB();
|
|
AddToolBarTool("rotater", MainWindow::on_anticlockwise, tr("RotateR"));
|
|
AddToolDB();
|
|
toolbar->setObjectName("pic");
|
|
addToolBar(toolbar);
|
|
|
|
toolbar = new DToolBar(this);
|
|
toolbar->toggleViewAction()->setVisible(false);
|
|
AddToolBarTool("first", MainWindow::on_beginframe, tr("FirstFrame"));
|
|
AddToolDB();
|
|
AddToolBarTool("back", MainWindow::on_last, tr("LastFrame"));
|
|
AddToolDB();
|
|
AddToolBarTool("gifplay", MainWindow::on_play, tr("Play"));
|
|
AddToolDB();
|
|
AddToolBarTool("pause", MainWindow::on_stop, tr("Stop"));
|
|
AddToolDB();
|
|
AddToolBarTool("foreword", MainWindow::on_next, tr("NextFrame"));
|
|
AddToolDB();
|
|
AddToolBarTool("last", MainWindow::on_endframe, tr("EndFrame"));
|
|
AddToolDB();
|
|
toolbar->setObjectName("play");
|
|
addToolBar(toolbar);
|
|
|
|
toolbar = new DToolBar(this);
|
|
toolbar->toggleViewAction()->setVisible(false);
|
|
AddToolBarTool("blank", MainWindow::on_exportapply, tr("ExportBlank"));
|
|
AddToolDB();
|
|
AddToolBarTool("model", MainWindow::on_applypic, tr("ApplyModel"));
|
|
AddToolDB();
|
|
AddToolBarTool("reverseplus", MainWindow::on_createreverse,
|
|
tr("CreateReverse"));
|
|
AddToolDB();
|
|
AddToolBarTool("scaledelay", MainWindow::on_scaledelay, tr("ScaleDelay"));
|
|
AddToolDB();
|
|
toolbar->setObjectName("effect");
|
|
addToolBar(toolbar);
|
|
|
|
status = new DStatusBar(this);
|
|
DLabel *l;
|
|
|
|
#define AddNamedStatusLabel(Var, Content) \
|
|
Var = new DLabel(this); \
|
|
Var->setText(Content); \
|
|
status->addPermanentWidget(Var);
|
|
|
|
#define AddStatusLabel(Content) AddNamedStatusLabel(l, Content)
|
|
#define LoadPixMap(Var, Icon) Var.load(":/images/" Icon ".png");
|
|
|
|
#define AddStausILable(PixMap, Icon, Label, OPixMap, OIcon, GPixMap, GIcon) \
|
|
LoadPixMap(PixMap, Icon); \
|
|
LoadPixMap(OPixMap, OIcon); \
|
|
LoadPixMap(GPixMap, GIcon) Label = new DLabel(this); \
|
|
Label->setPixmap(GPixMap); \
|
|
Label->setScaledContents(true); \
|
|
Label->setFixedSize(20, 20); \
|
|
Label->setAlignment(Qt::AlignCenter); \
|
|
status->addPermanentWidget(Label); \
|
|
AddStatusLabel(QString(' '));
|
|
|
|
#define AddFunctionIconButton(Var, Icon) \
|
|
Var = new DIconButton(this); \
|
|
Var->setIcon(ICONRES(Icon)); \
|
|
Var->setIconSize(QSize(20, 20)); \
|
|
status->addPermanentWidget(Var);
|
|
|
|
AddStausILable(infoSaved, "saved", iSaved, infoUnsaved, "unsaved", infoSaveg,
|
|
"saveg");
|
|
iSaved->setToolTip(tr("InfoSave"));
|
|
AddStausILable(infoWriteable, "writable", iReadWrite, infoReadonly,
|
|
"readonly", inforwg, "rwg");
|
|
iReadWrite->setToolTip(tr("InfoReadWrite"));
|
|
AddFunctionIconButton(iSetfitInView, "fitinview");
|
|
iSetfitInView->setToolTip(tr("FitInView"));
|
|
iSetfitInView->setEnabled(false);
|
|
AddStatusLabel(QString(5, ' '));
|
|
connect(iSetfitInView, &DIconButton::clicked, this,
|
|
[=] { editor->fitPicEditor(); });
|
|
setStatusBar(status);
|
|
|
|
auto pgif = &gif;
|
|
connect(pgif, &GifDecoder::frameRemoved, this, [=](int index) {
|
|
auto item = imglist->item(index);
|
|
imglist->removeItemWidget(item);
|
|
delete item;
|
|
this->showGifMessage();
|
|
});
|
|
connect(pgif, &GifDecoder::frameMoved, this, [=](int from, int to) {
|
|
auto max = qMax(from, to);
|
|
auto min = qMin(from, to);
|
|
for (auto i = min; i <= max; i++) {
|
|
auto p = imglist->item(i);
|
|
p->setIcon(gif.thumbnail(i));
|
|
p->setText(QString("%1 %2 ms").arg(i).arg(gif.frameDelay(i)));
|
|
}
|
|
});
|
|
connect(pgif, &GifDecoder::frameRefreshAll, this,
|
|
&MainWindow::refreshImglist);
|
|
connect(pgif, &GifDecoder::frameDelaySet, this, [=](int index, int delay) {
|
|
imglist->item(index)->setText(QString("%1 %2 ms").arg(index).arg(delay));
|
|
});
|
|
connect(pgif, &GifDecoder::frameRefreshImg, this, [=](int index) {
|
|
imglist->item(index)->setIcon(gif.thumbnail(index));
|
|
imglist->itemSelectionChanged();
|
|
});
|
|
connect(pgif, &GifDecoder::frameRefreshImgCurrent, this,
|
|
[=] { imglist->itemSelectionChanged(); });
|
|
connect(pgif, &GifDecoder::frameRefreshLabel, this,
|
|
&MainWindow::refreshListLabel);
|
|
connect(pgif, &GifDecoder::frameMerge, this, [=](int start, int count) {
|
|
auto end = start + count - 1;
|
|
for (int i = end; i >= start; i--) {
|
|
auto p = new QListWidgetItem(
|
|
gif.thumbnail(i),
|
|
QString("%1 %2 ms").arg(i).arg(gif.frameDelay(i)));
|
|
p->setSizeHint(QSize(120, 120));
|
|
imglist->insertItem(start, p);
|
|
}
|
|
this->showGifMessage();
|
|
});
|
|
connect(pgif, &GifDecoder::frameInsert, this, [=](int index) {
|
|
auto p = new QListWidgetItem(
|
|
gif.thumbnail(index),
|
|
QString("%1 %2 ms").arg(index).arg(gif.frameDelay(index)));
|
|
p->setSizeHint(QSize(120, 120));
|
|
imglist->insertItem(index, p);
|
|
this->showGifMessage();
|
|
});
|
|
connect(pgif, &GifDecoder::frameImageChanged, this, [=] {
|
|
auto len = imglist->count();
|
|
for (auto i = 0; i < len; i++) {
|
|
imglist->item(i)->setIcon(gif.thumbnail(i));
|
|
}
|
|
editor->setBackgroudPix(gif.frameimg(imglist->currentRow()));
|
|
});
|
|
|
|
player = new PlayGifManager(this);
|
|
connect(player, &PlayGifManager::tick, this,
|
|
[=](int index) { imglist->setCurrentRow(index); });
|
|
|
|
connect(&undo, &QUndoStack::canUndoChanged, this, [=](bool b) {
|
|
CheckEnabled;
|
|
undomenu->setEnabled(b);
|
|
undotool->setEnabled(b);
|
|
});
|
|
|
|
connect(&undo, &QUndoStack::canRedoChanged, this, [=](bool b) {
|
|
CheckEnabled;
|
|
redomenu->setEnabled(b);
|
|
redotool->setEnabled(b);
|
|
});
|
|
connect(&undo, &QUndoStack::cleanChanged, this, [=](bool clean) {
|
|
CheckEnabled;
|
|
this->setSaved(clean && curfilename != ":");
|
|
});
|
|
|
|
cuttingdlg = new CropGifDialog(this);
|
|
connect(cuttingdlg, &CropGifDialog::selRectChanged, editor,
|
|
&GifEditor::setSelRect);
|
|
connect(cuttingdlg, &CropGifDialog::crop, this,
|
|
[=](int x, int y, int w, int h) {
|
|
CheckEnabled;
|
|
editor->endCrop();
|
|
this->setEditMode(true);
|
|
if (x < 0 || y < 0 || w < 0 || h < 0)
|
|
return;
|
|
undo.push(new CropImageCommand(&gif, x, y, w, h));
|
|
editor->fitPicEditor();
|
|
});
|
|
connect(cuttingdlg, &CropGifDialog::pressCancel, this, [=] {
|
|
CheckEnabled;
|
|
editor->endCrop();
|
|
this->setEditMode(true);
|
|
});
|
|
connect(editor, &GifEditor::selRectChanged, cuttingdlg,
|
|
&CropGifDialog::setSelRect);
|
|
|
|
#define ConnectShortCut(ShortCut, Slot) \
|
|
s = new QShortcut(ShortCut, this); \
|
|
connect(s, &QShortcut::activated, this, &Slot);
|
|
|
|
QShortcut *s;
|
|
|
|
ConnectShortCut(QKeySequence::Open, MainWindow::on_open);
|
|
ConnectShortCut(QKeySequence::Save, MainWindow::on_save);
|
|
ConnectShortCut(QKeySequence::SaveAs, MainWindow::on_saveas);
|
|
ConnectShortCut(QKeySequence::Close, MainWindow::on_close);
|
|
ConnectShortCut(QKeySequence::Undo, MainWindow::on_undo);
|
|
ConnectShortCut(QKeySequence::Redo, MainWindow::on_redo);
|
|
ConnectShortCut(QKeySequence::Cut, MainWindow::on_cut);
|
|
ConnectShortCut(QKeySequence::Copy, MainWindow::on_copy);
|
|
ConnectShortCut(QKeySequence::Paste, MainWindow::on_paste);
|
|
ConnectShortCut(QKeySequence::Delete, MainWindow::on_del);
|
|
ConnectShortCut(QKeySequence::SelectAll, MainWindow::on_selall);
|
|
ConnectShortCut(QKeySequence::Deselect, MainWindow::on_desel);
|
|
ConnectShortCut(keyselrev, MainWindow::on_selreverse);
|
|
ConnectShortCut(keygoto, MainWindow::on_goto);
|
|
ConnectShortCut(keybeginframe, MainWindow::on_beginframe);
|
|
ConnectShortCut(keylastframe, MainWindow::on_last);
|
|
ConnectShortCut(keyplay, MainWindow::on_play);
|
|
ConnectShortCut(keypause, MainWindow::on_stop);
|
|
ConnectShortCut(keynextframe, MainWindow::on_next);
|
|
ConnectShortCut(keylastframe, MainWindow::on_endframe);
|
|
ConnectShortCut(keyreduceframe, MainWindow::on_decreaseframe);
|
|
ConnectShortCut(keyrmleft, MainWindow::on_delbefore);
|
|
ConnectShortCut(keyrmright, MainWindow::on_delafter);
|
|
ConnectShortCut(keymvl, MainWindow::on_moveleft);
|
|
ConnectShortCut(keymvr, MainWindow::on_moveright);
|
|
ConnectShortCut(keyrev, MainWindow::on_reverse);
|
|
ConnectShortCut(keysetdelay, MainWindow::on_setdelay);
|
|
ConnectShortCut(keyscalepic, MainWindow::on_scalepic);
|
|
ConnectShortCut(keycutpic, MainWindow::on_cutpic);
|
|
ConnectShortCut(keyscaledelay, MainWindow::on_scaledelay);
|
|
|
|
m_settings = Settings::instance();
|
|
m_settings->loadWindowStatus(this);
|
|
lastusedpath = m_settings->loadFileDialogCurrent();
|
|
m_settingd.state = WinState(m_settings->windowState());
|
|
switch (m_settingd.state) {
|
|
case Normal:
|
|
break;
|
|
case Maximum:
|
|
showMaximized();
|
|
break;
|
|
case Minimum:
|
|
showMinimized();
|
|
break;
|
|
}
|
|
m_settingd.cmdline = m_settings->reprocessingCmdline();
|
|
m_settingd.terminal = m_settings->terminal();
|
|
}
|
|
|
|
void MainWindow::openGif(QString filename) {
|
|
WaitingDialog d;
|
|
d.start(tr("OpenGif"));
|
|
if (!gif.load(filename)) {
|
|
setEditMode(false);
|
|
DMessageManager::instance()->sendMessage(this, ICONRES("icon"),
|
|
"OpenError");
|
|
QMessageBox::critical(this, tr("OpenError"),
|
|
QString(GifErrorString(gif.getLastError())));
|
|
return;
|
|
}
|
|
curfilename = filename;
|
|
imglist->setCurrentRow(0);
|
|
editor->fitPicEditor();
|
|
setEditMode(true);
|
|
setSaved(true);
|
|
setWritable(QFileInfo(filename).permission(QFile::WriteUser));
|
|
showGifMessage();
|
|
d.close();
|
|
}
|
|
|
|
bool MainWindow::checkIsGif(QString filename) {
|
|
QFile f(filename);
|
|
if (f.open(QFile::ReadOnly)) {
|
|
char *bu = new char[GIF_STAMP_LEN];
|
|
f.read(bu, GIF_STAMP_LEN);
|
|
return !memcmp(GIF_STAMP, bu, GIF_STAMP_LEN) ||
|
|
!memcmp(GIF87_STAMP, bu, GIF_STAMP_LEN) ||
|
|
!memcmp(GIF89_STAMP, bu, GIF_STAMP_LEN);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void MainWindow::refreshImglist() {
|
|
auto pos = imglist->currentRow();
|
|
imglist->clear();
|
|
auto len = gif.frameCount();
|
|
for (int i = 0; i < len; i++) {
|
|
auto p = new QListWidgetItem(
|
|
gif.thumbnail(i), QString("%1 %2 ms").arg(i).arg(gif.frameDelay(i)),
|
|
imglist);
|
|
p->setSizeHint(QSize(120, 120));
|
|
}
|
|
imglist->setCurrentRow(pos);
|
|
this->showGifMessage();
|
|
}
|
|
|
|
void MainWindow::refreshListLabel(int start) {
|
|
auto len = gif.frameCount();
|
|
for (int i = start; i < len; i++) {
|
|
imglist->item(i)->setText(
|
|
QString("%1 %2 ms").arg(i).arg(gif.frameDelay(i)));
|
|
}
|
|
}
|
|
|
|
void MainWindow::setEditMode(bool b) {
|
|
for (auto item : distool)
|
|
item->setEnabled(b);
|
|
for (auto item : dismenu)
|
|
item->setEnabled(item);
|
|
iSetfitInView->setEnabled(b);
|
|
}
|
|
|
|
bool MainWindow::ensureSafeClose() {
|
|
if (!undo.isClean()) {
|
|
if (QMessageBox::question(
|
|
this, tr("ConfirmClose"),
|
|
tr("ConfirmSave") + "\n" +
|
|
(curfilename == ":" ? tr("Untitle") : curfilename)) ==
|
|
QMessageBox::No)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void MainWindow::setSaved(bool b) {
|
|
iSaved->setPixmap(b ? infoSaved : infoUnsaved);
|
|
}
|
|
|
|
void MainWindow::setWritable(bool b) {
|
|
iReadWrite->setPixmap(b ? infoWriteable : infoReadonly);
|
|
}
|
|
|
|
void MainWindow::showGifMessage(QString message) {
|
|
status->showMessage(QString(5, ' ') + message +
|
|
QString(tr("%1 frame | %2 total")
|
|
.arg(imglist->currentRow())
|
|
.arg(gif.frameCount())));
|
|
}
|
|
|
|
bool MainWindow::saveGif(QString filename) {
|
|
GifEncoder gifsaver;
|
|
auto size = gif.size();
|
|
if (gifsaver.open(filename, size.width(), size.height())) {
|
|
QApplication::processEvents();
|
|
auto &frames = gif.frames();
|
|
for (auto &frame : frames) {
|
|
gifsaver.push(frame.image, frame.delayTime / 10);
|
|
QApplication::processEvents();
|
|
}
|
|
gifsaver.close();
|
|
undo.setClean();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void MainWindow::on_new_frompics() {
|
|
player->stop();
|
|
if (ensureSafeClose()) {
|
|
NewDialog d(NewType::FromPics, this);
|
|
if (d.exec()) {
|
|
WaitingDialog dw;
|
|
dw.start(tr("NewFromPicsGif"));
|
|
gif.loadfromImages(d.getResult());
|
|
curfilename = ":"; //表示新建
|
|
setSaved(false);
|
|
setWritable(true);
|
|
setEditMode(true);
|
|
imglist->setCurrentRow(0);
|
|
showGifMessage();
|
|
dw.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_new_fromgifs() {
|
|
player->stop();
|
|
if (ensureSafeClose()) {
|
|
NewDialog d(NewType::FromGifs, this);
|
|
if (d.exec()) {
|
|
WaitingDialog dw;
|
|
dw.start(tr("NewFromGifsGif"));
|
|
gif.loadfromGifs(d.getResult());
|
|
curfilename = ":"; //表示新建
|
|
setSaved(false);
|
|
setWritable(true);
|
|
setEditMode(true);
|
|
imglist->setCurrentRow(0);
|
|
showGifMessage();
|
|
dw.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_open() {
|
|
player->stop();
|
|
if (ensureSafeClose()) {
|
|
auto filename = QFileDialog::getOpenFileName(this, tr("ChooseFile"),
|
|
lastusedpath, "gif (*.gif)");
|
|
if (filename.isEmpty())
|
|
return;
|
|
|
|
lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
|
|
gif.close();
|
|
undo.clear();
|
|
|
|
if (checkIsGif(filename)) {
|
|
openGif(filename);
|
|
} else {
|
|
DMessageManager::instance()->sendMessage(this, ICONRES("open"),
|
|
tr("InvalidGif"));
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_del() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
QVector<int> indices;
|
|
for (auto item : imglist->selectionModel()->selectedIndexes()) {
|
|
indices.append(item.row());
|
|
}
|
|
undo.push(new RemoveFrameCommand(&gif, imglist, indices));
|
|
}
|
|
|
|
void MainWindow::on_selall() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
imglist->selectAll();
|
|
}
|
|
|
|
void MainWindow::on_selreverse() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto len = imglist->count();
|
|
for (auto i = 0; i < len; i++) {
|
|
auto item = imglist->item(i);
|
|
item->setSelected(!item->isSelected());
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_desel() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto cur = imglist->currentRow();
|
|
imglist->setCurrentRow(cur);
|
|
}
|
|
|
|
void MainWindow::on_goto() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
bool ok;
|
|
auto index =
|
|
DInputDialog::getInt(this, tr("Goto"), tr("PleaseInputIndex"),
|
|
imglist->currentRow(), 0, imglist->count(), 1, &ok);
|
|
if (ok) {
|
|
imglist->setCurrentRow(index);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_beginframe() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
imglist->setCurrentRow(0);
|
|
}
|
|
|
|
void MainWindow::on_last() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto pos = imglist->currentRow();
|
|
if (pos > 0) {
|
|
imglist->setCurrentRow(pos - 1);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_play() {
|
|
CheckEnabled;
|
|
QList<int> ints;
|
|
auto len = gif.frameCount();
|
|
for (auto i = 0; i < len; i++) {
|
|
ints.append(gif.frameDelay(i));
|
|
}
|
|
player->setTickIntervals(ints);
|
|
player->play(imglist->currentRow());
|
|
}
|
|
|
|
void MainWindow::on_stop() {
|
|
CheckEnabled;
|
|
player->stop();
|
|
}
|
|
|
|
void MainWindow::on_next() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto pos = imglist->currentRow();
|
|
auto max = imglist->count();
|
|
if (pos < max - 1) {
|
|
imglist->setCurrentRow(pos + 1);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_endframe() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
imglist->setCurrentRow(imglist->count() - 1);
|
|
}
|
|
|
|
void MainWindow::on_decreaseframe() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
ReduceFrameDialog d(imglist->count(), this);
|
|
if (d.exec()) {
|
|
auto res = d.getResult();
|
|
auto from = res.start;
|
|
auto step = res.stepcount;
|
|
auto to = res.end;
|
|
QVector<int> delindices, modinter;
|
|
auto ii = from + 1;
|
|
auto q = step + 1;
|
|
for (auto i = ii; i <= to; i++) {
|
|
if (i == ii + step) {
|
|
ii += q;
|
|
delindices.append(i);
|
|
} else {
|
|
modinter.append(gif.frameDelay(i) * (q + 1) / q);
|
|
}
|
|
}
|
|
|
|
undo.push(new ReduceFrameCommand(&gif, delindices, modinter));
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_delbefore() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto pos = imglist->currentRow();
|
|
undo.push(new DelFrameDirCommand(&gif, pos, DelDirection::Before, imglist));
|
|
}
|
|
|
|
void MainWindow::on_delafter() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto pos = imglist->currentRow();
|
|
undo.push(new DelFrameDirCommand(&gif, pos, DelDirection::After, imglist));
|
|
}
|
|
|
|
void MainWindow::on_saveas() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto filename = QFileDialog::getSaveFileName(this, tr("ChooseSaveFile"),
|
|
lastusedpath, "gif (*.gif)");
|
|
if (filename.isEmpty())
|
|
return;
|
|
lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
|
|
|
|
WaitingDialog d;
|
|
d.start(tr("SaveAsGif"));
|
|
if (saveGif(filename)) {
|
|
d.setMessage(tr("Reprocessing"));
|
|
if (reprocessImage(filename))
|
|
DMessageManager::instance()->sendMessage(this, ICONRES("saveas"),
|
|
tr("SaveAsSuccess"));
|
|
curfilename = filename;
|
|
} else {
|
|
DMessageManager::instance()->sendMessage(this, ICONRES("saveas"),
|
|
"SaveAsFail");
|
|
}
|
|
d.stop();
|
|
}
|
|
|
|
void MainWindow::on_export() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
ExportDialog d;
|
|
if (d.exec()) {
|
|
auto res = d.getResult();
|
|
QString ext;
|
|
switch (res.type) {
|
|
case ExportImageType::PNG: {
|
|
ext = "png";
|
|
break;
|
|
}
|
|
case ExportImageType::JPG: {
|
|
ext = "jpg";
|
|
break;
|
|
}
|
|
case ExportImageType::TIFF: {
|
|
ext = "tiff";
|
|
break;
|
|
}
|
|
case ExportImageType::WEBP: {
|
|
ext = "webp";
|
|
break;
|
|
}
|
|
}
|
|
|
|
WaitingDialog d;
|
|
d.start(tr("ExportFrames"));
|
|
if (gif.exportImages(res.path, ext)) {
|
|
DMessageManager::instance()->sendMessage(this, ICONRES("saveas"),
|
|
tr("ExportSuccess"));
|
|
} else {
|
|
DMessageManager::instance()->sendMessage(this, ICONRES("saveas"),
|
|
tr("ExportFail"));
|
|
}
|
|
d.stop();
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_close() {
|
|
player->stop();
|
|
if (ensureSafeClose()) {
|
|
gif.close();
|
|
editor->setBackgroudPix(QPixmap(":/images/icon.png"));
|
|
editor->fitPicEditor();
|
|
editor->scale(0.5, 0.5);
|
|
iSaved->setPixmap(infoSaveg);
|
|
iReadWrite->setPixmap(inforwg);
|
|
status->showMessage("");
|
|
curfilename.clear();
|
|
undo.clear();
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_setting() {
|
|
SettingDialog dialog(m_settingd, this);
|
|
if (dialog.exec()) {
|
|
m_settingd = dialog.getResult();
|
|
m_settings->setWindowState(m_settingd.state);
|
|
m_settings->setTerminal(m_settingd.terminal);
|
|
m_settings->setReprocessingCmdline(m_settingd.cmdline);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_undo() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
undo.undo();
|
|
}
|
|
|
|
void MainWindow::on_redo() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
undo.redo();
|
|
}
|
|
|
|
void MainWindow::on_copy() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto sels = imglist->selectionModel()->selectedRows();
|
|
QList<QGifFrameInfoData> sel;
|
|
auto frames = gif.frames();
|
|
for (auto &i : sels) {
|
|
sel.append(frames[i.row()]);
|
|
}
|
|
ClipBoardHelper::setImageFrames(sel);
|
|
}
|
|
|
|
void MainWindow::on_cut() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto sels = imglist->selectionModel()->selectedRows();
|
|
QList<QGifFrameInfoData> sel;
|
|
QVector<int> indices;
|
|
auto frames = gif.frames();
|
|
for (auto &i : sels) {
|
|
indices.append(i.row());
|
|
sel.append(frames[i.row()]);
|
|
}
|
|
ClipBoardHelper::setImageFrames(sel);
|
|
undo.push(new RemoveFrameCommand(&gif, imglist, indices));
|
|
}
|
|
|
|
void MainWindow::on_paste() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto pos = imglist->currentRow() + 1;
|
|
QList<QGifFrameInfoData> imgs;
|
|
ClipBoardHelper::getImageFrames(imgs);
|
|
if (imgs.count()) {
|
|
undo.push(new InsertFrameCommand(&gif, imglist, pos, imgs));
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_save() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
if (curfilename == ":") {
|
|
on_saveas();
|
|
return;
|
|
}
|
|
|
|
WaitingDialog d;
|
|
d.start(tr("SaveGif"));
|
|
if (saveGif(curfilename)) {
|
|
d.setMessage(tr("Reprocessing"));
|
|
undo.setClean();
|
|
if (reprocessImage(curfilename))
|
|
DMessageManager::instance()->sendMessage(this, ICONRES("save"),
|
|
tr("SaveSuccess"));
|
|
} else {
|
|
DMessageManager::instance()->sendMessage(this, ICONRES("save"), "SaveFail");
|
|
}
|
|
d.stop();
|
|
}
|
|
|
|
void MainWindow::on_reverse() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
undo.push(new ReverseFrameCommand(&gif));
|
|
refreshImglist();
|
|
}
|
|
|
|
void MainWindow::on_moveleft() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto pos = imglist->currentRow();
|
|
undo.push(new MoveFrameCommand(&gif, imglist, MoveFrameDirection::Left, pos));
|
|
}
|
|
|
|
void MainWindow::on_moveright() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto pos = imglist->currentRow();
|
|
undo.push(
|
|
new MoveFrameCommand(&gif, imglist, MoveFrameDirection::Right, pos));
|
|
}
|
|
|
|
void MainWindow::on_createreverse() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
CreateReverseDialog d(imglist->count(), this);
|
|
if (d.exec()) {
|
|
auto res = d.getResult();
|
|
auto frames = gif.frames();
|
|
auto bu = frames.mid(res.start, res.end - res.start + 1);
|
|
std::reverse(bu.begin(), bu.end());
|
|
undo.push(new InsertFrameCommand(&gif, imglist, res.end, bu));
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_setdelay() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto mod = QGuiApplication::keyboardModifiers();
|
|
auto indices = imglist->selectionModel()->selectedRows();
|
|
bool ok;
|
|
auto time = DInputDialog::getInt(this, tr("DelayTime"), tr("Inputms"), 40, 1,
|
|
INT_MAX, 1, &ok);
|
|
if (ok) {
|
|
QVector<int> is;
|
|
if (mod != Qt::KeyboardModifier::ControlModifier) {
|
|
for (auto i : indices) {
|
|
is.append(i.row());
|
|
}
|
|
}
|
|
undo.push(new DelayFrameCommand(&gif, is, time));
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_scaledelay() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto mod = QGuiApplication::keyboardModifiers();
|
|
bool ok;
|
|
auto scale = DInputDialog::getInt(this, tr("ScaleDelayTime"),
|
|
tr("InputPercent"), 100, 1, 100, 1, &ok);
|
|
QVector<int> is;
|
|
if (ok) {
|
|
if (mod != Qt::KeyboardModifier::ControlModifier) {
|
|
auto indices = imglist->selectionModel()->selectedRows();
|
|
|
|
for (auto i : indices) {
|
|
is.append(i.row());
|
|
}
|
|
}
|
|
undo.push(new DelayScaleCommand(&gif, is, scale));
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_insertpic() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto filenames = QFileDialog::getOpenFileNames(
|
|
this, tr("ChooseFile"), lastusedpath, tr("Images (*.jpg *.tiff *.png)"));
|
|
|
|
if (filenames.isEmpty())
|
|
return;
|
|
lastusedpath = QFileInfo(filenames.first()).absoluteDir().absolutePath();
|
|
auto pos = imglist->currentRow() + 1;
|
|
GifDecoder buffer;
|
|
buffer.loadfromImages(filenames, gif.size());
|
|
if (buffer.frameCount())
|
|
undo.push(new InsertFrameCommand(&gif, imglist, pos, buffer.frames()));
|
|
buffer.close();
|
|
}
|
|
|
|
void MainWindow::on_merge() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto filenames = QFileDialog::getOpenFileNames(this, tr("ChooseFile"),
|
|
lastusedpath, "gif (*.gif)");
|
|
|
|
if (filenames.isEmpty())
|
|
return;
|
|
lastusedpath = QFileInfo(filenames.first()).absoluteDir().absolutePath();
|
|
auto pos = imglist->currentRow() + 1;
|
|
GifDecoder buffer;
|
|
buffer.loadfromGifs(filenames, gif.size());
|
|
if (buffer.frameCount())
|
|
undo.push(new InsertFrameCommand(&gif, imglist, pos, buffer.frames()));
|
|
buffer.close();
|
|
}
|
|
|
|
void MainWindow::on_scalepic() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
ScaleGIFDialog d(gif.size(), this);
|
|
if (d.exec()) {
|
|
auto res = d.getResult();
|
|
undo.push(new ScaleFrameCommand(&gif, res.width, res.height));
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_cutpic() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
setEditMode(false);
|
|
QRectF rect;
|
|
editor->initCrop(rect);
|
|
cuttingdlg->setMaxSize(rect.size().toSize());
|
|
cuttingdlg->setSelRect(rect);
|
|
cuttingdlg->show();
|
|
}
|
|
|
|
void MainWindow::on_fliph() {
|
|
player->stop();
|
|
player->stop();
|
|
CheckEnabled;
|
|
undo.push(new FlipFrameCommand(&gif, FlipDirection::Horizontal));
|
|
}
|
|
|
|
void MainWindow::on_flipv() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
undo.push(new FlipFrameCommand(&gif, FlipDirection::Vertical));
|
|
}
|
|
|
|
void MainWindow::on_clockwise() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
undo.push(new RotateFrameCommand(&gif, editor, true));
|
|
}
|
|
|
|
void MainWindow::on_anticlockwise() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
undo.push(new RotateFrameCommand(&gif, editor, false));
|
|
}
|
|
|
|
void MainWindow::on_exportapply() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
auto filename = QFileDialog::getSaveFileName(this, tr("ChooseSaveFile"),
|
|
lastusedpath, "png (*.png)");
|
|
if (filename.isEmpty())
|
|
return;
|
|
lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
|
|
QImage img(gif.size(), QImage::Format_RGBA8888);
|
|
img.fill(Qt::transparent);
|
|
img.save(filename);
|
|
DMessageManager::instance()->sendMessage(this, ICONRES("blank"),
|
|
tr("ExportSuccess"));
|
|
}
|
|
|
|
void MainWindow::on_applypic() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
|
|
if (QGuiApplication::keyboardModifiers() ==
|
|
Qt::KeyboardModifier::ControlModifier) {
|
|
|
|
auto filename = QFileDialog::getOpenFileName(this, tr("ChooseFile"),
|
|
lastusedpath, "png (*.png)");
|
|
if (filename.isEmpty())
|
|
return;
|
|
|
|
lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
|
|
|
|
QVector<QImage> imgs;
|
|
QVector<int> empty;
|
|
QImage img;
|
|
if (img.load(filename)) {
|
|
if (img.size() == gif.size()) {
|
|
auto frames = gif.frames();
|
|
for (auto &f : frames) {
|
|
QImage bimg = f.image.copy();
|
|
QPainter painter(&bimg);
|
|
painter.drawImage(QPoint(), img, img.rect());
|
|
imgs.append(bimg);
|
|
}
|
|
undo.push(new ReplaceFrameCommand(&gif, empty, imgs));
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
auto indices = imglist->selectionModel()->selectedRows();
|
|
if (!indices.count()) {
|
|
DMessageManager::instance()->sendMessage(this, ICONRES("model"),
|
|
tr("NoSelection"));
|
|
return;
|
|
}
|
|
|
|
auto filename = QFileDialog::getOpenFileName(this, tr("ChooseFile"),
|
|
lastusedpath, "png (*.png)");
|
|
if (filename.isEmpty())
|
|
return;
|
|
|
|
lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
|
|
|
|
QVector<int> rows;
|
|
QVector<QImage> imgs;
|
|
|
|
QImage img;
|
|
if (img.load(filename)) {
|
|
if (img.size() == gif.size()) {
|
|
auto frames = gif.frames();
|
|
for (auto i : indices) {
|
|
rows.append(i.row());
|
|
QImage bimg = frames[i.row()].image.copy();
|
|
QPainter painter(&bimg);
|
|
painter.drawImage(QPoint(), img, img.rect());
|
|
imgs.append(bimg);
|
|
}
|
|
undo.push(new ReplaceFrameCommand(&gif, rows, imgs));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
DMessageManager::instance()->sendMessage(this, ICONRES("model"),
|
|
tr("InvalidModel"));
|
|
}
|
|
|
|
void MainWindow::on_onion() {
|
|
player->stop();
|
|
CheckEnabled;
|
|
if (QGuiApplication::keyboardModifiers() ==
|
|
Qt::KeyboardModifier::ControlModifier) {
|
|
gif.setOnionIndex(-1);
|
|
} else {
|
|
bool ok;
|
|
auto index = DInputDialog::getInt(
|
|
this, tr("OnionMask"), tr("PleaseInputIndex"),
|
|
imglist->currentRow() + 1, -1, imglist->count(), 1, &ok);
|
|
if (ok) {
|
|
gif.setOnionIndex(index);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_fullscreen() { showFullScreen(); }
|
|
|
|
void MainWindow::on_about() {
|
|
AboutSoftwareDialog d;
|
|
d.exec();
|
|
}
|
|
|
|
void MainWindow::on_sponsor() {
|
|
SponsorDialog d;
|
|
d.exec();
|
|
}
|
|
|
|
void MainWindow::on_wiki() {
|
|
QDesktopServices::openUrl(QUrl("https://code.gitlink.org.cn/wingsummer/"
|
|
"WingGifEditor/wiki/%E4%BB%8B%E7%BB%8D"));
|
|
}
|
|
|
|
bool MainWindow::reprocessImage(QString filename) {
|
|
if (m_settingd.cmdline.length()) {
|
|
QFileInfo info(m_settingd.terminal);
|
|
if (info.exists() && info.isExecutable()) {
|
|
if (QProcess::execute(m_settingd.terminal,
|
|
{"-c", m_settingd.cmdline.arg(filename)}) < 0) {
|
|
QMessageBox::critical(this, tr("Error"), tr("ImagingError"));
|
|
return false;
|
|
}
|
|
} else {
|
|
DMessageManager::instance()->sendMessage(this, ICONRES("icon"),
|
|
tr("InvaildTerminal"));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void MainWindow::closeEvent(QCloseEvent *event) {
|
|
player->stop();
|
|
if (ensureSafeClose()) {
|
|
m_settings->saveWindowStatus(this);
|
|
gif.close();
|
|
event->accept();
|
|
} else
|
|
event->ignore();
|
|
}
|
|
|
|
void MainWindow::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); }
|
|
|
|
void MainWindow::dragEnterEvent(QDragEnterEvent *event) {
|
|
if (event->mimeData()->hasUrls())
|
|
event->acceptProposedAction();
|
|
else
|
|
event->ignore();
|
|
}
|
|
|
|
void MainWindow::dropEvent(QDropEvent *event) {
|
|
const QMimeData *mimeData = event->mimeData();
|
|
if (mimeData->hasUrls()) {
|
|
auto filename = mimeData->urls().first().toLocalFile();
|
|
openGif(filename);
|
|
}
|
|
}
|