Browse Source

1998-11-02 Federico Mena Quintero <federico@nuclecu.unam.mx>

	* 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.
Miguel de Icaza 26 years ago
parent
commit
2f091b9509
2 changed files with 154 additions and 50 deletions
  1. 22 0
      gnome/ChangeLog
  2. 132 50
      gnome/gdesktop.c

+ 22 - 0
gnome/ChangeLog

@@ -1,3 +1,25 @@
+1998-11-02  Federico Mena Quintero  <federico@nuclecu.unam.mx>
+
+	* 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  <federico@nuclecu.unam.mx>
 
 	* gdesktop-icon.h (DesktopIcon): Added a child item for stippling

+ 132 - 50
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 */