commit ab4ae60ad89cba4cca0d2f9b802628358fefaf0a
parent b89bcf2956326f4ff6f11e2f105f8301b8adc3ba
Author: lumidify <nobody@lumidify.org>
Date:   Tue, 21 Sep 2021 14:47:41 +0200
Don't allow coordinates below 0; allow rectangle to be kept when going backwards
Diffstat:
6 files changed, 42 insertions(+), 18 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
@@ -2,6 +2,7 @@
 * Rewrite using Xlib and Imlib2
 * Add command-line options and man pages
 * Add automatic resizing of image when resizing window
+* Allow the rectangle to be kept when going backwards (Shift + Return)
 * Add croptool_crop
 
 1.0 -> 1.1
diff --git a/LICENSE b/LICENSE
@@ -1,6 +1,6 @@
 Copyright (c) 2021 lumidify <nobody@lumidify.org>
 
-Permission to use, copy, modify, and distribute this software for any
+Permission to use, copy, modify, and/or distribute this software for any
 purpose with or without fee is hereby granted, provided that the above
 copyright notice and this permission notice appear in all copies.
 
diff --git a/TODO b/TODO
@@ -1,3 +1,5 @@
 * Proper path handling (allow paths including "'", etc.)
 * Draw pixmap on exposure events instead of doing the
   expensive image resizing each time
+* Maybe add zooming support
+* Maybe optionally show rectangle coordinates on screen
diff --git a/croptool.1 b/croptool.1
@@ -1,4 +1,4 @@
-.Dd April 1, 2021
+.Dd September 21, 2021
 .Dt CROPTOOL 1
 .Os
 .Sh NAME
@@ -94,6 +94,9 @@ that is printed for the cropping command.
 In other words, when switching to an image that is a different size and
 thus scaled differently, the displayed rectangle will stay the same even
 though the pixels covered in the original image are different.
+.It SHIFT + RETURN
+Go to the last image, copying the current cropping rectangle.
+The same caveat as above applies.
 .It TAB
 Switch the color of the cropping rectangle between the primary and secondary colors.
 .It DELETE
diff --git a/croptool.c b/croptool.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2021 lumidify <nobody@lumidify.org>
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
@@ -144,8 +144,8 @@ static int collide_line(int x, int y, int x0, int y0, int x1, int y1);
 static int collide_rect(int x, int y, struct Rect rect);
 static void switch_color(void);
 static void clear_selection(void);
-static void last_picture(void);
 static void next_picture(int copy_box);
+static void last_picture(int copy_box);
 static void change_picture(Imlib_Image new_image, int new_selection, int copy_box);
 static void get_scaled_size(int orig_w, int orig_h, int *scaled_w, int *scaled_h);
 static void set_selection(
@@ -860,9 +860,19 @@ static void
 drag_motion(XEvent event) {
 	if (state.cur_selection < 0 || !state.selections[state.cur_selection].valid)
 		return;
-	struct Rect *rect = &state.selections[state.cur_selection].rect;
-	state.cursor_x = event.xbutton.x;
-	state.cursor_y = event.xbutton.y;
+	struct Selection *sel = &state.selections[state.cur_selection];
+	struct Rect *rect = &sel->rect;
+
+	/* don't allow coordinates to go below 0 */
+	if (event.xbutton.x >= 0)
+		state.cursor_x = event.xbutton.x;
+	else
+		state.cursor_x = 0;
+	if (event.xbutton.y >= 0)
+		state.cursor_y = event.xbutton.y;
+	else
+		state.cursor_y = 0;
+
 	int x0 = rect->x0, x1 = rect->x1;
 	int y0 = rect->y0, y1 = rect->y1;
 	sort_coordinates(&x0, &y0, &x1, &y1);
@@ -872,10 +882,13 @@ drag_motion(XEvent event) {
 	if (state.moving) {
 		int x_delta = state.cursor_x - state.move_handle.x;
 		int y_delta = state.cursor_y - state.move_handle.y;
-		rect->x0 += x_delta;
-		rect->y0 += y_delta;
-		rect->x1 += x_delta;
-		rect->y1 += y_delta;
+		/* don't allow coordinates to go below 0 */
+		int x_realdelta = x0 + x_delta >= 0 ? x_delta : -x0;
+		int y_realdelta = y0 + y_delta >= 0 ? y_delta : -y0;
+		rect->x0 += x_realdelta;
+		rect->x1 += x_realdelta;
+		rect->y0 += y_realdelta;
+		rect->y1 += y_realdelta;
 		state.move_handle.x = state.cursor_x;
 		state.move_handle.y = state.cursor_y;
 	} else if (state.resizing) {
@@ -1011,6 +1024,7 @@ next_picture(int copy_box) {
 			state.filenames[tmp_cur_selection] = NULL;
 		}
 	}
+	/* immediately exit program if no loadable image is found on startup */
 	if (state.cur_selection < 0 && !tmp_image) {
 		fprintf(stderr, "No loadable images found.\n");
 		cleanup();
@@ -1022,9 +1036,10 @@ next_picture(int copy_box) {
 	change_picture(tmp_image, tmp_cur_selection, copy_box);
 }
 
-/* show the previous image in the argument list - unloadable files are skipped */
+/* show the previous image in the argument list - unloadable files are skipped
+ * copy_box determines whether the current selection is copied */
 static void
-last_picture(void) {
+last_picture(int copy_box) {
 	if (state.cur_selection <= 0)
 		return;
 	Imlib_Image tmp_image = NULL;
@@ -1047,7 +1062,7 @@ last_picture(void) {
 	if (!tmp_image)
 		return;
 
-	change_picture(tmp_image, tmp_cur_selection, 0);
+	change_picture(tmp_image, tmp_cur_selection, copy_box);
 }
 
 static void
@@ -1075,13 +1090,16 @@ key_press(XEvent event) {
 	XLookupString(&event.xkey, buf, sizeof(buf), &sym, NULL);
 	switch (sym) {
 	case XK_Left:
-		last_picture();
+		last_picture(0);
 		break;
 	case XK_Right:
 		next_picture(0);
 		break;
 	case XK_Return:
-		next_picture(1);
+		if (event.xkey.state & ShiftMask)
+			last_picture(1);
+		else
+			next_picture(1);
 		break;
 	case XK_Delete:
 		clear_selection();
@@ -1092,7 +1110,7 @@ key_press(XEvent event) {
 	case XK_space:
 		XGetWindowAttributes(state.dpy, state.win, &attrs);
 		resize_window(attrs.width, attrs.height);
-		/* queue update separately to it also redraws when
+		/* queue update separately so it also redraws when
 		   size didn't change */
 		queue_update(0, 0, state.window_w, state.window_h);
 		break;
diff --git a/croptool_crop.c b/croptool_crop.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2021 lumidify <nobody@lumidify.org>
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *