Krolyxon
Commit 364c3d6

Branches

Refs →

nsxivcommands.c

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