From 2f091b950923416e541de4a39edf3eac6a5e1517 Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Tue, 3 Nov 1998 01:32:38 +0000 Subject: [PATCH] 1998-11-02 Federico Mena Quintero * gdesktop.c: Now desktop icons are stored in the layout_slots array. We need to know which icons are in which slots. (unselect_all): Use the layout_slots array. (desktop_icon_info_place): Append the icon to the list in the proper slot. (desktop_icon_info_new): Initialize the position and slot fields in the desktop icon info structure. (desktop_icon_info_free): Remove the icon from its slot. (desktop_destroy): Destroy the layout slots and the icons properly. (remove_from_slot): New convenience function to remove an icon from the slot it is in. (get_icon_snap_pos): Do a bit nicer snapping by really using the closest slot. Added a last_selected_icon variable to keep track of the icon that was last selected, for shift+click selections. (select_icon): Finish selection semantics and clean up. Now it is nice and simple and complete. (select_range): New function that handles range selections. --- gnome/ChangeLog | 22 ++++++ gnome/gdesktop.c | 182 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 154 insertions(+), 50 deletions(-) diff --git a/gnome/ChangeLog b/gnome/ChangeLog index 3b1851d0d..7614612ed 100644 --- a/gnome/ChangeLog +++ b/gnome/ChangeLog @@ -1,3 +1,25 @@ +1998-11-02 Federico Mena Quintero + + * gdesktop.c: Now desktop icons are stored in the layout_slots + array. We need to know which icons are in which slots. + (unselect_all): Use the layout_slots array. + (desktop_icon_info_place): Append the icon to the list in the + proper slot. + (desktop_icon_info_new): Initialize the position and slot fields + in the desktop icon info structure. + (desktop_icon_info_free): Remove the icon from its slot. + (desktop_destroy): Destroy the layout slots and the icons + properly. + (remove_from_slot): New convenience function to remove an icon + from the slot it is in. + (get_icon_snap_pos): Do a bit nicer snapping by really using the + closest slot. + Added a last_selected_icon variable to keep track of the icon that + was last selected, for shift+click selections. + (select_icon): Finish selection semantics and clean up. Now it is + nice and simple and complete. + (select_range): New function that handles range selections. + 1998-11-01 Federico Mena Quintero * gdesktop-icon.h (DesktopIcon): Added a child item for stippling diff --git a/gnome/gdesktop.c b/gnome/gdesktop.c index b04226998..3c7ad62d5 100644 --- a/gnome/gdesktop.c +++ b/gnome/gdesktop.c @@ -33,11 +33,17 @@ enum icon_type { struct desktop_icon_info { GtkWidget *dicon; /* The desktop icon widget */ int x, y; /* Position in the desktop */ + int slot; /* Index of the slot the icon is in, or -1 for none */ char *filename; /* The file this icon refers to (relative to the desktop_directory) */ enum icon_type type; /* Type of icon, used to determine menu and DnD behavior */ int selected : 1; /* Is the icon selected? */ }; +struct layout_slot { + int num_icons; /* Number of icons in this slot */ + GList *icons; /* The list of icons in this slot */ +}; + /* Configuration options for the desktop */ @@ -53,13 +59,13 @@ static char *desktop_directory; */ static int layout_cols; static int layout_rows; -static int *layout_slots; - -/* The list of desktop icons (desktop_icon_info structures) */ -static GList *desktop_icons; +static struct layout_slot *layout_slots; #define l_slots(x, y) (layout_slots[(x) * layout_rows + (y)]) +/* The last icon to be selected */ +static struct desktop_icon_info *last_selected_icon; + /* Looks for a free slot in the layout_slots array and returns the coordinates that coorespond to * it. "Free" means it either has zero icons in it, or it has the minimum number of icons of all @@ -72,12 +78,12 @@ get_icon_auto_pos (int *x, int *y) int u, v; int val; - min = l_slots (0, 0); + min = l_slots (0, 0).num_icons; min_x = min_y = 0; for (u = 0; u < layout_cols; u++) for (v = 0; v < layout_rows; v++) { - val = l_slots (u, v); + val = l_slots (u, v).num_icons; if (val == 0) { /* Optimization: if it is zero, return immediately */ @@ -109,16 +115,16 @@ get_icon_snap_pos (int *x, int *y) int val, dist; int dx, dy; - min = l_slots (0, 0); + min = l_slots (0, 0).num_icons; min_x = min_y = 0; min_dist = INT_MAX; - sx = DESKTOP_SNAP_X * (*x / DESKTOP_SNAP_X); - sy = DESKTOP_SNAP_Y * (*y / DESKTOP_SNAP_Y); + sx = DESKTOP_SNAP_X * ((*x + DESKTOP_SNAP_X / 2) / DESKTOP_SNAP_X); + sy = DESKTOP_SNAP_Y * ((*y + DESKTOP_SNAP_Y / 2) / DESKTOP_SNAP_Y); for (u = 0; u < layout_cols; u++) for (v = 0; v < layout_rows; v++) { - val = l_slots (u, v); + val = l_slots (u, v).num_icons; dx = sx - u; dy = sy - v; @@ -135,6 +141,20 @@ get_icon_snap_pos (int *x, int *y) *y = min_y * DESKTOP_SNAP_Y; } +/* Removes an icon from the slot it is in, if any */ +static void +remove_from_slot (struct desktop_icon_info *dii) +{ + if (dii->slot == -1) + return; + + g_assert (layout_slots[dii->slot].num_icons >= 1); + g_assert (layout_slots[dii->slot].icons != NULL); + + layout_slots[dii->slot].num_icons--; + layout_slots[dii->slot].icons = g_list_remove (layout_slots[dii->slot].icons, dii); +} + /* Places a desktop icon. If auto_pos is true, then the function will look for a place to position * the icon automatically, else it will use the specified coordinates, snapped to the grid if the * global desktop_snap_icons flag is set. @@ -151,9 +171,14 @@ desktop_icon_info_place (struct desktop_icon_info *dii, int auto_pos, int xpos, /* Increase the number of icons in the corresponding slot */ + remove_from_slot (dii); + u = xpos / DESKTOP_SNAP_X; v = ypos / DESKTOP_SNAP_Y; - l_slots (u, v)++; + + dii->slot = u * layout_rows + v; + layout_slots[dii->slot].num_icons++; + layout_slots[dii->slot].icons = g_list_append (layout_slots[dii->slot].icons, dii); /* Move the icon */ @@ -166,35 +191,89 @@ desktop_icon_info_place (struct desktop_icon_info *dii, int auto_pos, int xpos, static void unselect_all (void) { + int i; GList *l; struct desktop_icon_info *dii; - for (l = desktop_icons; l; l = l->next) { - dii = l->data; + for (i = 0; i < (layout_cols * layout_rows); i++) + for (l = layout_slots[i].icons; l; l = l->next) { + dii = l->data; - if (dii->selected) { - desktop_icon_select (dii->dicon, FALSE); - dii->selected = FALSE; + if (dii->selected) { + desktop_icon_select (DESKTOP_ICON (dii->dicon), FALSE); + dii->selected = FALSE; + } } +} + +/* Sets the selection state of a range to the specified value. The range starts at the + * last_selected_icon and ends at the specified icon. + */ +static void +select_range (struct desktop_icon_info *dii, int sel) +{ + int min, max; + int i; + GList *l; + struct desktop_icon_info *ldii, *min_dii, *max_dii; + + /* Find out the selection range */ + + if (!last_selected_icon) + last_selected_icon = dii; + + if (last_selected_icon->slot < dii->slot) { + min = last_selected_icon->slot; + max = dii->slot; + min_dii = last_selected_icon; + max_dii = dii; + } else { + min = dii->slot; + max = last_selected_icon->slot; + min_dii = dii; + max_dii = last_selected_icon; } + + /* Select! */ + + for (i = min; i <= max; i++) + for (l = layout_slots[i].icons; l; l = l->next) { + ldii = l->data; + + if (((i == min) && ((ldii->x < min_dii->x) || (ldii->y < min_dii->y))) + || ((i == max) && ((ldii->x > max_dii->x) || (ldii->y > max_dii->y)))) + continue; + + desktop_icon_select (DESKTOP_ICON (dii->dicon), sel); + dii->selected = sel; + } } /* Handles icon selection and unselection due to button presses */ static void select_icon (struct desktop_icon_info *dii, GdkEventButton *event) { - if (!(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK))) { - /* Click on an unselected icon unselects everything and selects the icon */ + int range; + int additive; + + range = ((event->state & GDK_SHIFT_MASK) != 0); + additive = ((event->state & GDK_CONTROL_MASK) != 0); + + if (!additive) unselect_all (); - desktop_icon_select (dii->dicon, TRUE); - dii->selected = TRUE; - } else if (event->state & GDK_SHIFT_MASK) { - ; /* FIXME: handle range selection */ - } else if (event->state & GDK_CONTROL_MASK) { - /* Control-click on an icon toggles its selected state */ - desktop_icon_select (dii->dicon, !dii->selected); - dii->selected = !dii->selected; - } + + if (!range) { + if (additive) { + desktop_icon_select (DESKTOP_ICON (dii->dicon), !dii->selected); + dii->selected = !dii->selected; + } else if (!dii->selected) { + desktop_icon_select (DESKTOP_ICON (dii->dicon), TRUE); + dii->selected = TRUE; + } + + last_selected_icon = dii; + } else + select_range (dii, TRUE); } /* Handler for events on desktop icons. The on_text flag specifies whether the event ocurred on the @@ -283,6 +362,9 @@ desktop_icon_info_new (char *filename, int auto_pos, int xpos, int ypos) dii = g_new (struct desktop_icon_info, 1); dii->dicon = desktop_icon_new (icon_name, filename); + dii->x = 0; + dii->y = 0; + dii->slot = -1; dii->filename = g_strdup (filename); dii->type = S_ISDIR (s.st_mode) ? ICON_DIRECTORY : ICON_FILE; dii->selected = FALSE; @@ -305,8 +387,6 @@ desktop_icon_info_new (char *filename, int auto_pos, int xpos, int ypos) /* Place the icon and append it to the list */ desktop_icon_info_place (dii, auto_pos, xpos, ypos); - desktop_icons = g_list_append (desktop_icons, dii); - return dii; } @@ -316,16 +396,8 @@ desktop_icon_info_new (char *filename, int auto_pos, int xpos, int ypos) static void desktop_icon_info_free (struct desktop_icon_info *dii) { - int u, v; - gtk_widget_destroy (dii->dicon); - - /* Decrease the number of icons in the corresponding slot */ - - u = dii->x / DESKTOP_SNAP_X; - v = dii->y / DESKTOP_SNAP_Y; - l_slots (u, v)--; - g_assert (l_slots (u, v) >= 0); + remove_from_slot (dii); g_free (dii->filename); g_free (dii); @@ -337,7 +409,7 @@ create_layout_info (void) { layout_cols = (gdk_screen_width () + DESKTOP_SNAP_X - 1) / DESKTOP_SNAP_X; layout_rows = (gdk_screen_height () + DESKTOP_SNAP_Y - 1) / DESKTOP_SNAP_Y; - layout_slots = g_new0 (int, layout_cols * layout_rows); + layout_slots = g_new0 (struct layout_slot, layout_cols * layout_rows); } /* Check that the user's desktop directory exists, and if not, create it with a symlink to the @@ -380,7 +452,8 @@ load_initial_desktop_icons (void) DIR *dir; char *full_name; int have_pos, x, y; - GList *list; + int i; + GList *l; struct desktop_icon_info *dii; dir = mc_opendir (desktop_directory); @@ -409,10 +482,11 @@ load_initial_desktop_icons (void) /* Show all the icons */ - for (list = desktop_icons; list; list = list->next) { - dii = list->data; - gtk_widget_show (dii->dicon); - } + for (i = 0; i < (layout_cols * layout_rows); i++) + for (l = layout_slots[i].icons; l; l = l->next) { + dii = l->data; + gtk_widget_show (dii->dicon); + } } /** @@ -429,22 +503,30 @@ desktop_init (void) load_initial_desktop_icons (); } -/** desktop_destroy +/** + * desktop_destroy * * Shuts the desktop down by destroying the desktop icons. */ void desktop_destroy (void) { - GList *list; + int i; + GList *l; + struct desktop_icon_info *dii; /* Destroy the desktop icons */ - for (list = desktop_icons; list; list = list->next) - desktop_icon_info_free (list->data); + for (i = 0; i < (layout_cols * layout_rows); i++) { + l = layout_slots[i].icons; - g_list_free (desktop_icons); - desktop_icons = NULL; + while (l) { + dii = l->data; + l = l->next; + + desktop_icon_info_free (dii); + } + } /* Cleanup */