Krolyxon
Commit 6ffc64a

Branches

Refs →

nsxivcommands.c

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