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.
This commit is contained in:
Miguel de Icaza 1998-11-03 01:32:38 +00:00
parent 9989eb0202
commit 2f091b9509
2 changed files with 154 additions and 50 deletions

View File

@ -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

View File

@ -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 */