Added windows build howto into README
[imgsort.git] / sortimg.cpp
1
2 #include <QApplication>
3 #include <QStatusBar>
4
5 #include <cmath> // pow()
6
7 #include "sortimg.h"
8
9
10 int main(int argc, char ** argv) {
11   Q_INIT_RESOURCE(sortimg);
12
13   QApplication app(argc, argv);
14   app.setApplicationName("SortImg");
15
16   SortImg mainwindow;
17   mainwindow.show();
18
19   return app.exec();
20 }
21
22 QString size2string(const QSize & s) {
23   if (s.isValid()) {
24     QString str;
25     return str.sprintf("%dx%d", s.width(), s.height());
26   }
27   else return "InvalidSize";
28 }
29
30 bool string2size(const QString & s, QSize * r) {
31   if (s == "InvalidSize") {
32     *r = QSize();
33     return true;
34   }
35   QStringList ss = s.split('x');
36   if (ss.size() != 2) return false;
37   r->setWidth(ss.at(0).toInt());
38   r->setHeight(ss.at(1).toInt());
39   return true;
40 }
41
42
43
44 SortImg::SortImg() : pixmapViewer(QPixmap(":/title.jpg")) {
45
46   setCentralWidget(&pixmapViewer);
47
48
49   statusBar()->addPermanentWidget(&statusbar, 1);
50
51   pixmapViewer.setMinimumSize(si_settings_initial_width, si_settings_initial_height);
52   pixmapViewer.setMaximumSize(si_settings_initial_width, si_settings_initial_height);
53
54   status("<b>SortImg</b> 1.0 &copy; Libcha 2015");
55 }
56
57 SortImg::~SortImg() {
58   //ib->exportToCfgFile();
59   delete ibuf;
60   delete fbank;
61   delete main_iterator;
62 }
63
64 void SortImg::keyPressEvent(QKeyEvent * event) {
65   QString tmp;
66
67   QMainWindow::keyPressEvent(event);
68
69   // switch 1, see below switch 2
70   switch (event->key()) {
71     case Qt::Key_Escape:
72     case Qt::Key_Q:
73       QApplication::quit();
74       break;
75     case Qt::Key_S:
76       if(event->modifiers() & Qt::ShiftModifier) {
77         if (!(tmp = viewDirectoryDialog()).isEmpty()) {
78           welcomeShown = false;
79           reInitialize(tmp);
80         }
81       }
82       break;
83     case Qt::Key_Shift:
84       return;
85     default:
86       break;
87   }
88
89   if (welcomeShown) {
90     //if (reInitialize(".")) {
91     welcomeShown = false;
92     reInitialize(".");
93     return;
94     //}
95   }
96
97   // switch 2, see switch 1 above
98   switch (event->key()) {
99     case Qt::Key_Right:
100       next();
101       break;
102     case Qt::Key_Left:
103       prev();
104       break;
105     case Qt::Key_R:
106       if (event->modifiers() & Qt::ShiftModifier) {
107             finalizeResize();
108       }
109       break;
110     case Qt::Key_A:
111       markResize(si_settings_size_A);
112       break;
113     case Qt::Key_B:
114       markResize(si_settings_size_B);
115       break;
116     case Qt::Key_C:
117       markResize(si_settings_size_C);
118       break;
119     case Qt::Key_D:
120       markResize(si_settings_size_D);
121       break;
122     case Qt::Key_E:
123       markResize(si_settings_size_E);
124       break;
125     case Qt::Key_F:
126       markResize(si_settings_size_F);
127       break;
128     case Qt::Key_X:
129       markCrop();
130       break;
131     case Qt::Key_O:
132       rotateLeft();
133       break;
134     case Qt::Key_P:
135       rotateRight();
136       break;
137     case Qt::Key_K: // debug
138       status(scr.toString());
139       break;
140     case Qt::Key_L: // debug
141       status(main_iterator->getSCR().toString());
142       break;
143     case Qt::Key_Delete:
144       markDelete();
145       break;
146     default:
147       break;
148   }
149 }
150
151 void SortImg::wheelEvent(QWheelEvent * event) {
152   QMainWindow::wheelEvent(event);
153   if (ibuf == NULL) return;
154
155   int x = event->x() - pixmapViewer.x();
156   int y = event->y() - pixmapViewer.y();
157
158   double mydelta = double(event->delta()) / si_settings_mousewheel_step_base;
159   double ratio = pow(si_settings_mousewheel_zoom_base, mydelta);
160   double ratio_pre = ratio;
161   //qDebug() << "Zooming to ratio " << ratio << " (mydelta " << mydelta << ")";
162
163   QString cn = **main_iterator;
164
165   for (int i = 1; i <= si_settings_preload_zooms; i++, ratio_pre *= ratio) {
166     ibuf->prepareRescale(cn, scr.rezoom(ratio_pre, x, y));
167   }
168   //qDebug() << "Pre-rezoom: " << scr.toString();
169   scr = scr.rezoom(ratio, x, y);
170   //qDebug() << "Post-rezoom: " << scr.toString();
171   QImage * rqi = ibuf->getRescaled(cn, scr);
172   pixmapViewer.changePixmap(QPixmap::fromImage(*rqi));
173 }
174
175
176 void SortImg::showEvent(QShowEvent * event) {
177   QMainWindow::showEvent(event);
178   // do nothing, we wait for enter after welcome screen :)
179   move(si_settings_initial_x, si_settings_initial_y);
180   qDebug() << "PW size: " << size2string(pixmapViewer.size());
181   qDebug() << "PW min: " << size2string(pixmapViewer.minimumSize());
182   qDebug() << "PW max: " << size2string(pixmapViewer.maximumSize());
183 }
184 void SortImg::resizeEvent(QResizeEvent* event) {
185   QMainWindow::resizeEvent(event);
186   if (ibuf != NULL) {
187     ibuf->default_scr = ScaleCropRule(pixmapViewer.size());
188   }
189 }
190
191 bool SortImg::reInitialize(const QString & path) {
192   if (ibuf != NULL) delete ibuf;
193   ibuf = new ImageBuffer();
194   ibuf->default_scr = ScaleCropRule(pixmapViewer.size());
195
196   if (fbank != NULL) delete fbank;
197   fbank = new FileBank(path);
198   if (main_iterator != NULL) delete main_iterator;
199   main_iterator = fbank->iterator();
200   if (main_iterator->isValid()/*ib->importDirectory(path)*/) {
201     ibuf->addRange(main_iterator->subiterator_post(si_settings_preload_images));
202     viewCurrent();
203   }
204   else {
205     QMessageBox::warning(this, "SortImg", QString("No JPG files found in path: ") + path);
206     delete ibuf; ibuf = NULL;
207     delete fbank; fbank = NULL;
208     delete main_iterator; main_iterator = NULL;
209   }
210   viewCurrent();
211   return (ibuf != NULL);
212 }
213
214 void SortImg::finalizeResize() {
215   if (fbank == NULL) return;
216
217   targetResize();
218   ibuf->waitForFileRescales();
219
220   fbank->finalizeTmpDir();
221 }
222
223 void SortImg::viewCurrent() {
224   if (ibuf == NULL || fbank == NULL || main_iterator == NULL) {
225     pixmapViewer.changePixmap(QPixmap(":/title.jpg"));
226     status("<b>SortImg</b> 1.0 &copy; Libcha 2015");
227     welcomeShown  = true;
228     return;
229   }
230
231   scr = ibuf->default_scr;
232
233   QString cn = **main_iterator;
234   QImage * currqi = ibuf->getRescaled(cn);
235   QString deletedMessage = fbank->isMarkedAsDeleted(cn) ? " DELETE!" : "";
236   if (currqi != NULL) {
237     pixmapViewer.changePixmap(QPixmap::fromImage(*currqi));
238     QString cnf = QFileInfo(cn).baseName();
239     status(QString("<b>") + cnf + "</b> (" + size2string(ibuf->getOriginalSize(cn)) + ") <b>"
240            + main_iterator->getSCR().toShortString() + deletedMessage + "</b> ["
241            + QString::number(main_iterator->item_index() + 1) + "/"
242            + QString::number(main_iterator->total_items()) + "]");
243   }
244 }
245
246 void SortImg::next() {
247   if (fbank == NULL || ibuf == NULL || main_iterator == NULL) return;
248
249   if (!main_iterator->hasNext()) return;
250
251   targetResize();
252
253   ibuf->removeImage(*main_iterator->prev_get(si_settings_preload_images));
254   main_iterator->next_go();
255   //ibuf->addRange(main_iterator->subiterator_post(si_settings_preload_images));
256   ibuf->addImage(*main_iterator->next_get(si_settings_preload_images));
257
258   viewCurrent();
259 }
260
261 void SortImg::prev() {
262   if (fbank == NULL || ibuf == NULL || main_iterator == NULL) return;
263
264   if (!main_iterator->hasPrev()) return;
265
266   targetResize();
267
268   ibuf->removeImage(*main_iterator->next_get(si_settings_preload_images));
269   main_iterator->prev_go();
270   //ibuf->addRange(main_iterator->subiterator_post(si_settings_preload_images));
271   ibuf->addImage(*main_iterator->prev_get(si_settings_preload_images));
272
273   viewCurrent();
274 }
275
276 void SortImg::markResize(int res) {
277   //targetSize = res;
278
279   ScaleCropRule old_scr = main_iterator->getSCR();
280
281   if (old_scr.isJustResize()) {
282     main_iterator->setSCR(ScaleCropRule(QSize(res, res)));
283   }
284   else {
285     main_iterator->setSCR(old_scr.retarget(ScaleCropRule(QSize(res, res))));
286   }
287
288   status(QString("<b>Resize to: %1 !</b>").arg(res));
289 }
290
291 void SortImg::markCrop() {
292   if (main_iterator == NULL || ibuf == NULL) return;
293
294   ScaleCropRule old_scr = main_iterator->getSCR();
295   if (old_scr.crop_w == 0) {
296     old_scr = ScaleCropRule(ibuf->getOriginalSize(**main_iterator));
297   }
298
299   if (old_scr.isJustResize()) {
300     ScaleCropRule new_scr = scr.retarget(old_scr);
301     main_iterator->setSCR(new_scr);
302     status(QString("<b>Crop: ") + new_scr.toString() + "</b>");
303   }
304   else {
305     main_iterator->setSCR(ScaleCropRule(old_scr.cropRect().size()));
306     status("<b>DO NOT CROP</b>");
307   }
308 }
309
310 void SortImg::rotateLeft() {
311   if (main_iterator == NULL || ibuf == NULL) return;
312
313   ScaleCropRule miscr = main_iterator->getSCR();
314   miscr.rotate_left();
315   main_iterator->setSCR(miscr);
316
317   QString cn = **main_iterator;
318   scr.rotate_left();
319   //qDebug() << "Post-rezoom: " << scr.toString();
320   QImage * rqi = ibuf->getRescaled(cn, scr);
321   pixmapViewer.changePixmap(QPixmap::fromImage(*rqi));
322 }
323
324 void SortImg::rotateRight() {
325   if (main_iterator == NULL || ibuf == NULL) return;
326
327   ScaleCropRule miscr = main_iterator->getSCR();
328   miscr.rotate_right();
329   main_iterator->setSCR(miscr);
330
331   QString cn = **main_iterator;
332   scr.rotate_right();
333   //qDebug() << "Post-rezoom: " << scr.toString();
334   QImage * rqi = ibuf->getRescaled(cn, scr);
335   pixmapViewer.changePixmap(QPixmap::fromImage(*rqi));
336 }
337
338 void SortImg::markDelete() {
339   if (fbank == NULL || ibuf == NULL || main_iterator == NULL) return;
340
341   QString cn = **main_iterator;
342   if (fbank->isMarkedAsDeleted(cn)) {
343     fbank->unmarkDeleted(cn);
344     status("<b>Do NOT delete!</b>");
345   }
346   else {
347     fbank->markAsDeleted(cn);
348     status("<b>DELETE !!</b>");
349   }
350 }
351
352 void SortImg::targetResize() {
353   if (fbank == NULL || ibuf == NULL || main_iterator == NULL) return;
354   const ScaleCropRule & targetSCR = main_iterator->getSCR();
355   if (targetSCR.crop_w > 0) {
356     QString cn = **main_iterator;
357     //ScaleCropRule sc(targetSize, targetSize, 0, 0, targetSize, targetSize);
358     ibuf->rescaleToFile(cn, targetSCR, fbank->getTmpNameFor(cn));
359
360     targetSize = 0;
361   }
362 }
363
364 //void SortImg::msgbox(const QString & msg) {
365 //  QMessageBox msgBox;
366 //  msgBox.setText(msg);
367 //  msgBox.setWindowTitle("SortImg");
368 //  msgBox.exec();
369 // STUB
370
371 QString SortImg::viewDirectoryDialog() {
372   QFileDialog *fd = new QFileDialog;
373   QTreeView *tree = fd->findChild <QTreeView*>();
374   tree->setRootIsDecorated(true);
375   tree->setItemsExpandable(true);
376   fd->setFileMode(QFileDialog::Directory);
377   //fd->setOption(QFileDialog::ShowDirsOnly);
378   fd->setViewMode(QFileDialog::Detail);
379   int result = fd->exec();
380   if (result) {
381     return fd->selectedFiles()[0];
382   }
383   else {
384     return QString();
385   }
386 }