clistglib

Swap two items in GList (GLib)


I am having a difficulty figuring out how to swap two items in a GList. I need to swap two items in the list so that their order change when rendering. How can I do that?

How can I do that to move up and move down items in this list ?

For example I want to make a function to move up or down items in GtkTreeView. I try this for moving up:

    typedef struct Settings settings;
    struct Settings
    {
        GList *l;
    };

    typedef struct Preset preset;
    struct Preset
    {
        char* title;
        float freq;
    };

    settings sts;

    void move_up_button(GtkWidget *widget, gpointer(data))
    {
        preset *ps;
        int *row, pos;
        .....................................

        row = gtk_tree_path_get_indices(path);

        ps = g_list_nth_data(sts.l, *row);
        g_assert(ps);

        pos = g_list_index(sts.l, (gpointer)ps);
        pos--;

        sts.l = g_list_remove(sts.l, (gpointer)ps);
        sts.l = g_list_insert(sts.l, (gpointer)ps, pos);

        .......................................
    }

How to simplify this without using the GList remove and insert functions?

Thanks


Solution

  • I assume you're talking about consecutive elements in the list.

    In that case, let A and B represent the two elements (in that order) you wish to swap. Then you need to make sure that

    Try this:

    GList *element_a, *element_b;
    
    ...
    
    /* Swap elements A and B */
    element_a->prev->next = element_b;
    element_b->prev = element_a->prev;
    
    element_a->next = element_b->next;
    element_b->next->prev = element_a;
    
    element_b->next = element_a;
    element_a->prev = element_b;
    

    Edit: Given the code you've added to your question try this instead, which manipulates the list elements' pointers instead of using g_list_remove and g_list_insert:

    GList *button_element, *preceding_element;
    
    ....
    
    row = gtk_tree_path_get_indices(path);
    
    button_element = g_list_nth(sts.l, *row);
    g_assert(button_element->data);
    
    /* Swap the button with its preceding element, if there is one */
    preceding_element = button_element->prev;
    if(preceding_element) {
      if(preceding_element->prev) {
        preceding_element->prev->next = button_element;
        button_element->prev = preceding_element->prev;
      }
      else {
        /* The preceding element is the head of the list, which we must update */
        sts.l = button_element;
        button_element->prev = NULL;
      }
    
      preceding_element->next = button_element->next;
      if(button_element->next) {
        button_element->next->prev = preceding_element;
      }
    
      button_element->next = preceding_element;
      preceding_element->prev = button_element;
    }