URI: 
       tDon't allow coordinates below 0; allow rectangle to be kept when going backwards - croptool - Image cropping tool
  HTML git clone git://lumidify.org/croptool.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/git/croptool.git (encrypted, but very slow)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit ab4ae60ad89cba4cca0d2f9b802628358fefaf0a
   DIR parent b89bcf2956326f4ff6f11e2f105f8301b8adc3ba
  HTML 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:
         M CHANGELOG                           |       1 +
         M LICENSE                             |       2 +-
         M TODO                                |       2 ++
         M croptool.1                          |       5 ++++-
         M croptool.c                          |      48 +++++++++++++++++++++----------
         M croptool_crop.c                     |       2 +-
       
       6 files changed, 42 insertions(+), 18 deletions(-)
       ---
   DIR diff --git a/CHANGELOG b/CHANGELOG
       t@@ -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
   DIR diff --git a/LICENSE b/LICENSE
       t@@ -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.
        
   DIR diff --git a/TODO b/TODO
       t@@ -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
   DIR diff --git a/croptool.1 b/croptool.1
       t@@ -1,4 +1,4 @@
       -.Dd April 1, 2021
       +.Dd September 21, 2021
        .Dt CROPTOOL 1
        .Os
        .Sh NAME
       t@@ -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
   DIR diff --git a/croptool.c b/croptool.c
       t@@ -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.
         *
       t@@ -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(
       t@@ -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);
       t@@ -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) {
       t@@ -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();
       t@@ -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;
       t@@ -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
       t@@ -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();
       t@@ -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;
   DIR diff --git a/croptool_crop.c b/croptool_crop.c
       t@@ -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.
         *