Krolyxon
Commit 6d5a040

Branches

Refs →

nsxivcommands.c

481 lines · 8.9 KB · C

1/* Copyright 2011-2020 Bert Muennich
2 * Copyright 2021-2022 nsxiv contributors
3 *
4 * This file is a part of nsxiv.
5 *
6 * nsxiv is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License,
9 * or (at your option) any later version.
10 *
11 * nsxiv is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with nsxiv. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "nsxiv.h"
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <unistd.h>
26#include <sys/wait.h>
27
28#include "commands.h"
29
30extern img_t img;
31extern tns_t tns;
32extern win_t win;
33
34bool cg_quit(arg_t status)
35{
36 unsigned int i;
37
38 if (options->to_stdout && markcnt > 0) {
39 for (i = 0; i < filecnt; i++) {
40 if (files[i].flags & FF_MARK)
41 printf("%s%c", files[i].name, options->using_null ? '\0' : '\n');
42 }
43 }
44 exit(status);
45 return None; /* silence tcc warning */
46}
47
48bool cg_switch_mode(arg_t _)
49{
50 if (mode == MODE_IMAGE) {
51 if (tns.thumbs == NULL)
52 tns_init(&tns, files, &filecnt, &fileidx, &win);
53 img_close(&img, false);
54 reset_timeout(reset_cursor);
55 if (img.ss.on) {
56 img.ss.on = false;
57 reset_timeout(slideshow);
58 }
59 tns.dirty = true;
60 mode = MODE_THUMB;
61 } else {
62 load_image(fileidx);
63 mode = MODE_IMAGE;
64 }
65 close_info();
66 open_info();
67 title_dirty = true;
68 return true;
69}
70
71bool cg_toggle_fullscreen(arg_t _)
72{
73 win_toggle_fullscreen(&win);
74 /* redraw after next ConfigureNotify event */
75 set_timeout(redraw, TO_REDRAW_RESIZE, false);
76 if (mode == MODE_IMAGE)
77 img.checkpan = img.dirty = true;
78 else
79 tns.dirty = true;
80 return false;
81}
82
83bool cg_toggle_bar(arg_t _)
84{
85 win_toggle_bar(&win);
86 if (mode == MODE_IMAGE) {
87 if (win.bar.h > 0)
88 open_info();
89 else
90 close_info();
91 img.checkpan = img.dirty = true;
92 } else {
93 tns.dirty = true;
94 }
95 return true;
96}
97
98bool cg_prefix_external(arg_t _)
99{
100 handle_key_handler(true);
101 return false;
102}
103
104bool cg_reload_image(arg_t _)
105{
106 if (mode == MODE_IMAGE) {
107 load_image(fileidx);
108 } else {
109 win_set_cursor(&win, CURSOR_WATCH);
110 if (!tns_load(&tns, fileidx, true, false)) {
111 remove_file(fileidx, false);
112 tns.dirty = true;
113 }
114 }
115 return true;
116}
117
118bool cg_remove_image(arg_t _)
119{
120 remove_file(fileidx, true);
121 if (mode == MODE_IMAGE)
122 load_image(fileidx);
123 else
124 tns.dirty = true;
125 return true;
126}
127
128bool cg_first(arg_t _)
129{
130 if (mode == MODE_IMAGE && fileidx != 0) {
131 load_image(0);
132 return true;
133 } else if (mode == MODE_THUMB && fileidx != 0) {
134 fileidx = 0;
135 tns.dirty = true;
136 return true;
137 } else {
138 return false;
139 }
140}
141
142bool cg_n_or_last(arg_t _)
143{
144 int n = prefix != 0 && prefix - 1 < filecnt ? prefix - 1 : filecnt - 1;
145
146 if (mode == MODE_IMAGE && fileidx != n) {
147 load_image(n);
148 return true;
149 } else if (mode == MODE_THUMB && fileidx != n) {
150 fileidx = n;
151 tns.dirty = true;
152 return true;
153 } else {
154 return false;
155 }
156}
157
158bool cg_scroll_screen(arg_t dir)
159{
160 if (mode == MODE_IMAGE)
161 return img_pan(&img, dir, -1);
162 else
163 return tns_scroll(&tns, dir, true);
164}
165
166bool cg_zoom(arg_t d)
167{
168 if (mode == MODE_THUMB)
169 return tns_zoom(&tns, d);
170 else
171 return img_zoom(&img, d);
172}
173
174bool cg_toggle_image_mark(arg_t _)
175{
176 return mark_image(fileidx, !(files[fileidx].flags & FF_MARK));
177}
178
179bool cg_reverse_marks(arg_t _)
180{
181 int i;
182
183 for (i = 0; i < filecnt; i++) {
184 files[i].flags ^= FF_MARK;
185 markcnt += files[i].flags & FF_MARK ? 1 : -1;
186 }
187 if (mode == MODE_THUMB)
188 tns.dirty = true;
189 return true;
190}
191
192bool cg_mark_range(arg_t _)
193{
194 int d = markidx < fileidx ? 1 : -1, end, i;
195 bool dirty = false, on = !!(files[markidx].flags & FF_MARK);
196
197 for (i = markidx + d, end = fileidx + d; i != end; i += d)
198 dirty |= mark_image(i, on);
199 return dirty;
200}
201
202bool cg_unmark_all(arg_t _)
203{
204 int i;
205
206 for (i = 0; i < filecnt; i++)
207 files[i].flags &= ~FF_MARK;
208 markcnt = 0;
209 if (mode == MODE_THUMB)
210 tns.dirty = true;
211 return true;
212}
213
214bool cg_navigate_marked(arg_t n)
215{
216 int d, i;
217 int new = fileidx;
218
219 if (prefix > 0)
220 n *= prefix;
221 d = n > 0 ? 1 : -1;
222 for (i = fileidx + d; n != 0 && i >= 0 && i < filecnt; i += d) {
223 if (files[i].flags & FF_MARK) {
224 n -= d;
225 new = i;
226 }
227 }
228 if (new != fileidx) {
229 if (mode == MODE_IMAGE) {
230 load_image(new);
231 } else {
232 fileidx = new;
233 tns.dirty = true;
234 }
235 return true;
236 } else {
237 return false;
238 }
239}
240
241bool cg_change_gamma(arg_t d)
242{
243 if (img_change_gamma(&img, d * (prefix > 0 ? prefix : 1))) {
244 if (mode == MODE_THUMB)
245 tns.dirty = true;
246 return true;
247 } else {
248 return false;
249 }
250}
251
252bool ci_navigate(arg_t n)
253{
254 if (prefix > 0)
255 n *= prefix;
256 n += fileidx;
257 n = MAX(0, MIN(n, filecnt - 1));
258
259 if (n != fileidx) {
260 load_image(n);
261 return true;
262 } else {
263 return false;
264 }
265}
266
267bool ci_cursor_navigate(arg_t _)
268{
269 return ci_navigate(nav_button() - 1);
270}
271
272bool ci_alternate(arg_t _)
273{
274 load_image(alternate);
275 return true;
276}
277
278bool ci_navigate_frame(arg_t d)
279{
280 if (prefix > 0)
281 d *= prefix;
282 return !img.multi.animate && img_frame_navigate(&img, d);
283}
284
285bool ci_toggle_animation(arg_t _)
286{
287 bool dirty = false;
288
289 if (img.multi.cnt > 0) {
290 img.multi.animate = !img.multi.animate;
291 if (img.multi.animate) {
292 dirty = img_frame_animate(&img);
293 set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
294 } else {
295 reset_timeout(animate);
296 }
297 }
298 return dirty;
299}
300
301bool ci_scroll(arg_t dir)
302{
303 return img_pan(&img, dir, prefix);
304}
305
306bool ci_scroll_to_center(arg_t _)
307{
308 return img_pan_center(&img);
309}
310
311bool ci_scroll_to_edge(arg_t dir)
312{
313 return img_pan_edge(&img, dir);
314}
315
316bool ci_drag(arg_t drag_mode)
317{
318 int x, y, ox, oy;
319 float px, py;
320 XEvent e;
321
322 if ((int)(img.w * img.zoom) <= win.w && (int)(img.h * img.zoom) <= win.h)
323 return false;
324
325 win_set_cursor(&win, drag_mode == DRAG_ABSOLUTE ? CURSOR_DRAG_ABSOLUTE : CURSOR_DRAG_RELATIVE);
326 win_cursor_pos(&win, &x, &y);
327 ox = x;
328 oy = y;
329
330 while (true) {
331 if (drag_mode == DRAG_ABSOLUTE) {
332 px = MIN(MAX(0.0, x - win.w*0.1), win.w*0.8) / (win.w*0.8)
333 * (win.w - img.w * img.zoom);
334 py = MIN(MAX(0.0, y - win.h*0.1), win.h*0.8) / (win.h*0.8)
335 * (win.h - img.h * img.zoom);
336 } else {
337 px = img.x + x - ox;
338 py = img.y + y - oy;
339 }
340
341 if (img_pos(&img, px, py)) {
342 img_render(&img);
343 win_draw(&win);
344 }
345 XMaskEvent(win.env.dpy,
346 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
347 if (e.type == ButtonPress || e.type == ButtonRelease)
348 break;
349 while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e));
350 ox = x;
351 oy = y;
352 x = e.xmotion.x;
353 y = e.xmotion.y;
354 }
355 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
356 reset_cursor();
357
358 return true;
359}
360
361bool ci_set_zoom(arg_t zl)
362{
363 return img_zoom_to(&img, (prefix ? prefix : zl) / 100.0);
364}
365
366bool ci_fit_to_win(arg_t sm)
367{
368 return img_fit_win(&img, sm);
369}
370
371bool ci_rotate(arg_t degree)
372{
373 img_rotate(&img, degree);
374 return true;
375}
376
377bool ci_flip(arg_t dir)
378{
379 img_flip(&img, dir);
380 return true;
381}
382
383bool ci_toggle_antialias(arg_t _)
384{
385 img_toggle_antialias(&img);
386 return true;
387}
388
389bool ci_toggle_alpha(arg_t _)
390{
391 img.alpha = !img.alpha;
392 img.dirty = true;
393 return true;
394}
395
396bool ci_slideshow(arg_t _)
397{
398 if (prefix > 0) {
399 img.ss.on = true;
400 img.ss.delay = prefix * 10;
401 set_timeout(slideshow, img.ss.delay * 100, true);
402 } else if (img.ss.on) {
403 img.ss.on = false;
404 reset_timeout(slideshow);
405 } else {
406 img.ss.on = true;
407 }
408 return true;
409}
410
411bool ct_move_sel(arg_t dir)
412{
413 bool dirty = tns_move_selection(&tns, dir, prefix);
414 if (dirty) {
415 close_info();
416 open_info();
417 }
418 return dirty;
419}
420
421bool ct_reload_all(arg_t _)
422{
423 tns_free(&tns);
424 tns_init(&tns, files, &filecnt, &fileidx, &win);
425 tns.dirty = true;
426 return true;
427}
428
429bool ct_scroll(arg_t dir)
430{
431 return tns_scroll(&tns, dir, false);
432}
433
434bool ct_drag_mark_image(arg_t _)
435{
436 int sel;
437
438 if ((sel = tns_translate(&tns, xbutton_ev->x, xbutton_ev->y)) >= 0) {
439 XEvent e;
440 bool on = !(files[sel].flags & FF_MARK);
441
442 while (true) {
443 if (sel >= 0 && mark_image(sel, on))
444 redraw();
445 XMaskEvent(win.env.dpy,
446 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
447 if (e.type == ButtonPress || e.type == ButtonRelease)
448 break;
449 while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e));
450 sel = tns_translate(&tns, e.xbutton.x, e.xbutton.y);
451 }
452 }
453
454 return false;
455}
456
457bool ct_select(arg_t _)
458{
459 int sel;
460 bool dirty = false;
461 static Time firstclick;
462
463 if ((sel = tns_translate(&tns, xbutton_ev->x, xbutton_ev->y)) >= 0) {
464 if (sel != fileidx) {
465 tns_highlight(&tns, fileidx, false);
466 tns_highlight(&tns, sel, true);
467 fileidx = sel;
468 firstclick = xbutton_ev->time;
469 dirty = true;
470 } else if (xbutton_ev->time - firstclick <= TO_DOUBLE_CLICK) {
471 mode = MODE_IMAGE;
472 set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
473 load_image(fileidx);
474 dirty = true;
475 } else {
476 firstclick = xbutton_ev->time;
477 }
478 }
479
480 return dirty;
481}