From 5aab042fae43cb8cffe3c69c982f664643869031 Mon Sep 17 00:00:00 2001 From: Christopher James Lahey Date: Mon, 26 Mar 2001 20:42:15 +0000 Subject: Added util/e-bit-array.lo. 2001-03-26 Christopher James Lahey * gal/Makefile.am (libgal_la_LIBADD): Added util/e-bit-array.lo. * gal/util/Makefile.am: Added e-bit-array.c and e-bit-array.h. * gal/util/e-bit-array.c, gal/util/e-bit-array.h: New class containing the implementation of the bit array used in e-selection-model-array. * gal/widgets/e-selection-model-array.c, e-selection-model-array.h: Refactored the bit array implementation into a separate class. * gal/widgets/e-selection-model-simple.c: Changed how it clears the bit array of the ESelectionModelArray parent class. * gal/widgets/e-selection-model.h: Added code to make the declaration of EForeachFunc only get included once. svn path=/trunk/; revision=8955 --- e-util/e-bit-array.c | 386 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 386 insertions(+) create mode 100644 e-util/e-bit-array.c (limited to 'e-util/e-bit-array.c') diff --git a/e-util/e-bit-array.c b/e-util/e-bit-array.c new file mode 100644 index 0000000000..ba65c53120 --- /dev/null +++ b/e-util/e-bit-array.c @@ -0,0 +1,386 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-selection-model-array.c: a Selection Model + * + * Author: + * Christopher James Lahey + * + * (C) 2000, 2001 Ximian, Inc. + */ +#include +#include +#include "e-bit-array.h" +#include "gal/util/e-util.h" + +#define EBA_CLASS(e) ((EBitArrayClass *)((GtkObject *)e)->klass) + +#define PARENT_TYPE (gtk_object_get_type ()) + +#define ONES ((guint32) 0xffffffff) + +#define BOX(n) ((n) / 32) +#define OFFSET(n) (31 - ((n) % 32)) +#define BITMASK(n) ((guint32)(((guint32) 0x1) << OFFSET((n)))) +#define BITMASK_LEFT(n) ((((n) % 32) == 0) ? 0 : (ONES << (32 - ((n) % 32)))) +#define BITMASK_RIGHT(n) ((guint32)(((guint32) ONES) >> ((n) % 32))) + +static GtkObjectClass *parent_class; + +static void +e_bit_array_insert_real(EBitArray *eba, int row) +{ + int box; + int i; + if(eba->bit_count >= 0) { + /* Add another word if needed. */ + if ((eba->bit_count & 0x1f) == 0) { + eba->data = g_renew(gint, eba->data, (eba->bit_count >> 5) + 1); + eba->data[eba->bit_count >> 5] = 0; + } + + /* The box is the word that our row is in. */ + box = BOX(row); + /* Shift all words to the right of our box right one bit. */ + for (i = eba->bit_count >> 5; i > box; i--) { + eba->data[i] = (eba->data[i] >> 1) | (eba->data[i - 1] << 31); + } + + /* Shift right half of box one bit to the right. */ + eba->data[box] = (eba->data[box] & BITMASK_LEFT(row)) | ((eba->data[box] & BITMASK_RIGHT(row)) >> 1); + eba->bit_count ++; + } +} + +static void +e_bit_array_delete_real(EBitArray *eba, int row, gboolean move_selection_mode) +{ + int box; + int i; + int last; + int selected = FALSE; + if(eba->bit_count >= 0) { + guint32 bitmask; + box = row >> 5; + last = eba->bit_count >> 5; + + /* Build bitmasks for the left and right half of the box */ + bitmask = BITMASK_RIGHT(row) >> 1; + if (move_selection_mode) + selected = e_bit_array_value_at(eba, row); + /* Shift right half of box one bit to the left. */ + eba->data[box] = (eba->data[box] & BITMASK_LEFT(row))| ((eba->data[box] & bitmask) << 1); + + /* Shift all words to the right of our box left one bit. */ + if (box < last) { + eba->data[box] &= eba->data[box + 1] >> 31; + + for (i = box + 1; i < last; i++) { + eba->data[i] = (eba->data[i] << 1) | (eba->data[i + 1] >> 31); + } + /* this over-runs our memory! */ + /*eba->data[i] = eba->data[i] << 1; */ + } + eba->bit_count --; + /* Remove the last word if not needed. */ + if ((eba->bit_count & 0x1f) == 0) { + eba->data = g_renew(gint, eba->data, eba->bit_count >> 5); + } + if (move_selection_mode && selected) { + e_bit_array_select_single_row (eba, row > 0 ? row - 1 : 0); + } + } +} + +/* FIXME : Improve efficiency here. */ +void +e_bit_array_delete(EBitArray *eba, int row, int count) +{ + int i; + for (i = 0; i < count; i++) + e_bit_array_delete_real(eba, row, FALSE); +} + +/* FIXME : Improve efficiency here. */ +void +e_bit_array_delete_single_mode(EBitArray *eba, int row, int count) +{ + int i; + for (i = 0; i < count; i++) + e_bit_array_delete_real(eba, row, TRUE); +} + +/* FIXME : Improve efficiency here. */ +void +e_bit_array_insert(EBitArray *eba, int row, int count) +{ + int i; + for (i = 0; i < count; i++) + e_bit_array_insert_real(eba, row); +} + +/* FIXME: Implement this more efficiently. */ +void +e_bit_array_move_row(EBitArray *eba, int old_row, int new_row) +{ + e_bit_array_delete_real(eba, old_row, FALSE); + e_bit_array_insert_real(eba, new_row); +} + +static void +eba_destroy (GtkObject *object) +{ + EBitArray *eba; + + eba = E_BIT_ARRAY (object); + + g_free(eba->data); +} + +/** + * e_selection_model_is_row_selected + * @selection: #EBitArray to check + * @n: The row to check + * + * This routine calculates whether the given row is selected. + * + * Returns: %TRUE if the given row is selected + */ +gboolean +e_bit_array_value_at (EBitArray *eba, + gint n) +{ + if (eba->bit_count < n || eba->bit_count == 0) + return 0; + else + return (eba->data[BOX(n)] >> OFFSET(n)) & 0x1; +} + +/** + * e_selection_model_foreach + * @selection: #EBitArray to traverse + * @callback: The callback function to call back. + * @closure: The closure + * + * This routine calls the given callback function once for each + * selected row, passing closure as the closure. + */ +void +e_bit_array_foreach (EBitArray *eba, + EForeachFunc callback, + gpointer closure) +{ + int i; + int last = (eba->bit_count + 31) / 32; + for (i = 0; i < last; i++) { + if (eba->data[i]) { + int j; + guint32 value = eba->data[i]; + for (j = 0; j < 32; j++) { + if (value & 0x80000000) { + callback(i * 32 + j, closure); + } + value <<= 1; + } + } + } +} + +/** + * e_selection_model_clear + * @selection: #EBitArray to clear + * + * This routine clears the selection to no rows selected. + */ +void +e_bit_array_clear(EBitArray *eba) +{ + g_free(eba->data); + eba->data = NULL; + eba->bit_count = 0; +} + +#define PART(x,n) (((x) & (0x01010101 << n)) >> n) +#define SECTION(x, n) (((x) >> (n * 8)) & 0xff) + +/** + * e_selection_model_selected_count + * @selection: #EBitArray to count + * + * This routine calculates the number of rows selected. + * + * Returns: The number of rows selected in the given model. + */ +gint +e_bit_array_selected_count (EBitArray *eba) +{ + gint count; + int i; + int last; + + if (!eba->data) + return 0; + + count = 0; + + last = BOX(eba->bit_count - 1); + + for (i = 0; i <= last; i++) { + int j; + guint32 thiscount = 0; + for (j = 0; j < 8; j++) + thiscount += PART(eba->data[i], j); + for (j = 0; j < 4; j++) + count += SECTION(thiscount, j); + } + + return count; +} + +/** + * e_selection_model_select_all + * @selection: #EBitArray to select all + * + * This routine selects all the rows in the given + * #EBitArray. + */ +void +e_bit_array_select_all (EBitArray *eba) +{ + int i; + + if (!eba->data) + eba->data = g_new0 (gint, (eba->bit_count + 31) / 32); + + for (i = 0; i < (eba->bit_count + 31) / 32; i ++) { + eba->data[i] = ONES; + } + + /* need to zero out the bits corresponding to the rows not + selected in the last full 32 bit mask */ + if (eba->bit_count % 32) { + int unselected_mask = 0; + int num_unselected_in_last_byte = 32 - eba->bit_count % 32; + + for (i = 0; i < num_unselected_in_last_byte; i ++) + unselected_mask |= 1 << i; + + eba->data[(eba->bit_count + 31) / 32 - 1] &= ~unselected_mask; + } +} + +/** + * e_selection_model_invert_selection + * @selection: #EBitArray to invert + * + * This routine inverts all the rows in the given + * #EBitArray. + */ +void +e_bit_array_invert_selection (EBitArray *eba) +{ + int i; + + if (!eba->data) + eba->data = g_new0 (gint, (eba->bit_count + 31) / 32); + + for (i = 0; i < (eba->bit_count + 31) / 32; i ++) { + eba->data[i] = ~eba->data[i]; + } +} + +int +e_bit_array_bit_count (EBitArray *eba) +{ + return eba->bit_count; +} + +#define OPERATE(object, i,mask,grow) ((grow) ? (((object)->data[(i)]) |= ((guint32) ~(mask))) : (((object)->data[(i)]) &= (mask))) + +void +e_bit_array_change_one_row(EBitArray *eba, int row, gboolean grow) +{ + int i; + i = BOX(row); + + OPERATE(eba, i, ~BITMASK(row), grow); +} + +void +e_bit_array_change_range(EBitArray *eba, int start, int end, gboolean grow) +{ + int i, last; + if (start != end) { + i = BOX(start); + last = BOX(end); + + if (i == last) { + OPERATE(eba, i, BITMASK_LEFT(start) | BITMASK_RIGHT(end), grow); + } else { + OPERATE(eba, i, BITMASK_LEFT(start), grow); + if (grow) + for (i ++; i < last; i++) + eba->data[i] = ONES; + else + for (i ++; i < last; i++) + eba->data[i] = 0; + OPERATE(eba, i, BITMASK_RIGHT(end), grow); + } + } +} + +void +e_bit_array_select_single_row (EBitArray *eba, int row) +{ + int i; + for (i = 0; i < ((eba->bit_count + 31) / 32); i++) { + if (!((i == BOX(row) && eba->data[i] == BITMASK(row)) || + (i != BOX(row) && eba->data[i] == 0))) { + g_free(eba->data); + eba->data = g_new0(gint, (eba->bit_count + 31) / 32); + eba->data[BOX(row)] = BITMASK(row); + + break; + } + } +} + +void +e_bit_array_toggle_single_row (EBitArray *eba, int row) +{ + if (eba->data[BOX(row)] & BITMASK(row)) + eba->data[BOX(row)] &= ~BITMASK(row); + else + eba->data[BOX(row)] |= BITMASK(row); +} + + +static void +e_bit_array_init (EBitArray *eba) +{ + eba->data = NULL; + eba->bit_count = 0; +} + +static void +e_bit_array_class_init (EBitArrayClass *klass) +{ + GtkObjectClass *object_class; + + parent_class = gtk_type_class (PARENT_TYPE); + + object_class = GTK_OBJECT_CLASS(klass); + + object_class->destroy = eba_destroy; +} + +E_MAKE_TYPE(e_bit_array, "EBitArray", EBitArray, + e_bit_array_class_init, e_bit_array_init, PARENT_TYPE); + +EBitArray * +e_bit_array_new (int count) +{ + EBitArray *eba = gtk_type_new (e_bit_array_get_type ()); + eba->bit_count = count; + eba->data = g_new0(gint, (eba->bit_count + 31) / 32); + return eba; +} -- cgit v1.2.3