This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch master
in repository evisum.

View the commit online.

commit 675a993c6c4e9aed9d4469eebeb2c4d91ee840de
Author: Alastair Poole <[email protected]>
AuthorDate: Mon Mar 30 05:18:03 2026 +0100

    codex: holy shit
---
 src/bin/evisum_config.c             |  39 +++++
 src/bin/evisum_config.h             |   1 +
 src/bin/ui/evisum_ui.c              |  29 ++++
 src/bin/ui/evisum_ui.h              |   1 +
 src/bin/ui/evisum_ui_process_list.c |  17 +-
 src/bin/ui/evisum_ui_process_view.c |   4 +-
 src/bin/ui/evisum_ui_widget_exel.c  | 305 ++++++++++++++++++++++++++++++++++--
 src/bin/ui/evisum_ui_widget_exel.h  |  16 +-
 8 files changed, 393 insertions(+), 19 deletions(-)

diff --git a/src/bin/evisum_config.c b/src/bin/evisum_config.c
index df5c7ce..3285def 100644
--- a/src/bin/evisum_config.c
+++ b/src/bin/evisum_config.c
@@ -106,6 +106,44 @@ config_init(void) {
                                   proc.field_widths[PROC_FIELD_WIDTH_DISK_READ], EET_T_INT);
     EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_widths.disk_write",
                                   proc.field_widths[PROC_FIELD_WIDTH_DISK_WRITE], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.cmd",
+                                  proc.field_order[PROC_FIELD_CMD], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.uid",
+                                  proc.field_order[PROC_FIELD_UID], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.pid",
+                                  proc.field_order[PROC_FIELD_PID], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.threads",
+                                  proc.field_order[PROC_FIELD_THREADS], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.cpu",
+                                  proc.field_order[PROC_FIELD_CPU], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.pri",
+                                  proc.field_order[PROC_FIELD_PRI], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.nice",
+                                  proc.field_order[PROC_FIELD_NICE], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.files",
+                                  proc.field_order[PROC_FIELD_FILES], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.size",
+                                  proc.field_order[PROC_FIELD_SIZE], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.virt",
+                                  proc.field_order[PROC_FIELD_VIRT], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.disk_write",
+                                  proc.field_order[PROC_FIELD_DISK_WRITE], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.disk_read",
+                                  proc.field_order[PROC_FIELD_DISK_READ], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.net_in",
+                                  proc.field_order[PROC_FIELD_NET_IN], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.net_out",
+                                  proc.field_order[PROC_FIELD_NET_OUT], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.rss",
+                                  proc.field_order[PROC_FIELD_RSS], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.shared",
+                                  proc.field_order[PROC_FIELD_SHARED], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.state",
+                                  proc.field_order[PROC_FIELD_STATE], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.time",
+                                  proc.field_order[PROC_FIELD_TIME], EET_T_INT);
+    EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.field_order.cpu_usage",
+                                  proc.field_order[PROC_FIELD_CPU_USAGE], EET_T_INT);
     EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.show_statusbar", proc.show_statusbar,
                                   EET_T_UCHAR);
     EET_DATA_DESCRIPTOR_ADD_BASIC(_evisum_conf_descriptor, Evisum_Config, "proc.transparent", proc.transparent,
@@ -192,6 +230,7 @@ _config_init() {
                        | (1u << PROC_FIELD_VIRT)
                        | (1u << PROC_FIELD_CPU_USAGE);
     cfg->proc.alpha = 100;
+    for (int i = PROC_FIELD_CMD; i < PROC_FIELD_MAX; i++) cfg->proc.field_order[i] = i;
 
     cfg->cpu.visual = eina_stringshare_add("default");
 
diff --git a/src/bin/evisum_config.h b/src/bin/evisum_config.h
index 0bcfc3b..8f4ef47 100644
--- a/src/bin/evisum_config.h
+++ b/src/bin/evisum_config.h
@@ -24,6 +24,7 @@ typedef struct _Evisum_Config {
         unsigned char poll_delay;
         unsigned int fields;
         int field_widths[EVISUM_PROC_FIELD_WIDTHS_MAX];
+        int field_order[EVISUM_PROC_FIELD_WIDTHS_MAX];
 
         Eina_Bool show_statusbar;
         Eina_Bool transparent;
diff --git a/src/bin/ui/evisum_ui.c b/src/bin/ui/evisum_ui.c
index 2ff53ed..4c4b7ab 100644
--- a/src/bin/ui/evisum_ui.c
+++ b/src/bin/ui/evisum_ui.c
@@ -20,6 +20,31 @@ int EVISUM_EVENT_CONFIG_CHANGED;
 
 static Evas_Object *_slider_alpha = NULL;
 
+static void
+_proc_field_order_sanitize(int *order) {
+    unsigned char seen[EVISUM_PROC_FIELD_WIDTHS_MAX] = { 0 };
+    int out[EVISUM_PROC_FIELD_WIDTHS_MAX] = { 0 };
+    int pos = PROC_FIELD_CMD;
+
+    if (!order) return;
+
+    for (int i = PROC_FIELD_CMD; i < PROC_FIELD_MAX; i++) {
+        int id = order[i];
+        if ((id >= PROC_FIELD_CMD) && (id < PROC_FIELD_MAX) && !seen[id]) {
+            out[pos++] = id;
+            seen[id] = 1;
+        }
+    }
+
+    for (int id = PROC_FIELD_CMD; id < PROC_FIELD_MAX; id++) {
+        if (seen[id]) continue;
+        out[pos++] = id;
+        seen[id] = 1;
+    }
+
+    for (int i = PROC_FIELD_CMD; i < PROC_FIELD_MAX; i++) order[i] = out[i];
+}
+
 void
 evisum_ui_config_save(Evisum_Ui *ui) {
     Eina_Bool notify = 0;
@@ -54,6 +79,7 @@ evisum_ui_config_save(Evisum_Ui *ui) {
         config()->proc.fields = ui->proc.fields;
         for (int i = 0; i < EVISUM_PROC_FIELD_WIDTHS_MAX; i++)
             config()->proc.field_widths[i] = ui->proc.field_widths[i];
+        for (int i = 0; i < EVISUM_PROC_FIELD_WIDTHS_MAX; i++) config()->proc.field_order[i] = ui->proc.field_order[i];
         proc_info_kthreads_show_set(ui->proc.show_kthreads);
     }
 
@@ -130,6 +156,9 @@ evisum_ui_config_load(Evisum_Ui *ui) {
     ui->proc.transparent = config()->proc.transparent;
     ui->proc.alpha = config()->proc.alpha;
     for (int i = 0; i < EVISUM_PROC_FIELD_WIDTHS_MAX; i++) ui->proc.field_widths[i] = config()->proc.field_widths[i];
+    for (int i = 0; i < EVISUM_PROC_FIELD_WIDTHS_MAX; i++) ui->proc.field_order[i] = config()->proc.field_order[i];
+    _proc_field_order_sanitize(ui->proc.field_order);
+    for (int i = 0; i < EVISUM_PROC_FIELD_WIDTHS_MAX; i++) config()->proc.field_order[i] = ui->proc.field_order[i];
 
     ui->proc.width = config()->proc.width;
     ui->proc.height = config()->proc.height;
diff --git a/src/bin/ui/evisum_ui.h b/src/bin/ui/evisum_ui.h
index 6da24d4..b357fc7 100644
--- a/src/bin/ui/evisum_ui.h
+++ b/src/bin/ui/evisum_ui.h
@@ -43,6 +43,7 @@ typedef struct _Evisum_Ui {
         int sort_type;
         unsigned int fields;
         int field_widths[EVISUM_PROC_FIELD_WIDTHS_MAX];
+        int field_order[EVISUM_PROC_FIELD_WIDTHS_MAX];
         Eina_Bool sort_reverse;
         Eina_Bool show_self;
         Eina_Bool show_kthreads;
diff --git a/src/bin/ui/evisum_ui_process_list.c b/src/bin/ui/evisum_ui_process_list.c
index d7b98d7..c4d7eda 100644
--- a/src/bin/ui/evisum_ui_process_list.c
+++ b/src/bin/ui/evisum_ui_process_list.c
@@ -87,6 +87,7 @@ typedef struct {
 static void _evisum_ui_process_list_content_reset(Evisum_Ui_Process_List_View *view);
 static void _evisum_ui_process_list_content_update_all(Evisum_Ui_Process_List_View *view);
 static void _evisum_ui_process_list_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info EINA_UNUSED);
+static void _evisum_ui_process_list_fields_reordered_cb(void *data);
 static Evas_Object *_evisum_ui_process_list_sort_button_add(Evas_Object *parent, Evisum_Ui_Process_List_View *view,
                                                             Proc_Sort type, double weight_x);
 
@@ -239,6 +240,7 @@ _evisum_ui_process_list_fields_mouse_up_cb(void *data EINA_UNUSED, Evas *e EINA_
     ev = event_info;
     view = data;
 
+    if (evisum_ui_widget_exel_field_reorder_mouse_up(view->widget_exel, ev)) return;
     evisum_ui_widget_exel_fields_menu_show(view->widget_exel, obj, ev);
 }
 
@@ -281,19 +283,31 @@ _evisum_ui_process_list_fields_resize_done_cb(void *data) {
     evisum_ui_config_save(view->ui);
 }
 
+static void
+_evisum_ui_process_list_fields_reordered_cb(void *data) {
+    Evisum_Ui_Process_List_View *view = data;
+    if (!view) return;
+
+    _evisum_ui_process_list_content_reset(view);
+    evisum_ui_config_save(view->ui);
+}
+
 static void
 _evisum_ui_process_list_fields_init(Evisum_Ui_Process_List_View *view) {
     view->widget_exel = evisum_ui_widget_exel_create(view->win);
     if (!view->widget_exel) return;
 
     evisum_ui_widget_exel_field_bounds_set(view->widget_exel, PROC_FIELD_CMD, PROC_FIELD_MAX);
+    evisum_ui_widget_exel_field_order_bind(view->widget_exel, view->ui->proc.field_order);
+    evisum_ui_widget_exel_field_reorder_enabled_set(view->widget_exel, EINA_TRUE);
     evisum_ui_widget_exel_resize_hit_width_set(view->widget_exel, PROC_COL_RESIZE_HIT_WIDTH);
     evisum_ui_widget_exel_state_bind(view->widget_exel, &view->ui->proc.fields, view->ui->proc.field_widths);
     evisum_ui_widget_exel_callbacks_set(view->widget_exel, _evisum_ui_process_list_fields_reference_mask_get_cb,
                                         _evisum_ui_process_list_fields_changed_cb,
                                         _evisum_ui_process_list_fields_applied_cb,
                                         _evisum_ui_process_list_fields_resize_live_cb,
-                                        _evisum_ui_process_list_fields_resize_done_cb, view);
+                                        _evisum_ui_process_list_fields_resize_done_cb,
+                                        _evisum_ui_process_list_fields_reordered_cb, view);
 
     for (int i = PROC_FIELD_CMD; i < PROC_FIELD_MAX; i++) {
         Proc_Sort type;
@@ -883,6 +897,7 @@ _evisum_ui_process_list_field_header_mouse_up_cb(void *data, Evas *e EINA_UNUSED
     (void) e;
     (void) obj;
     if (!view || !ev) return;
+    if (evisum_ui_widget_exel_field_reorder_mouse_up(view->widget_exel, ev)) return;
     evisum_ui_widget_exel_field_resize_mouse_up(view->widget_exel, ev);
 }
 
diff --git a/src/bin/ui/evisum_ui_process_view.c b/src/bin/ui/evisum_ui_process_view.c
index 773dfb3..d78dc28 100644
--- a/src/bin/ui/evisum_ui_process_view.c
+++ b/src/bin/ui/evisum_ui_process_view.c
@@ -1670,7 +1670,7 @@ evisum_ui_process_view_win_add(Evisum_Ui *ui, int pid, Evisum_Proc_Action action
     evisum_ui_widget_exel_field_bounds_set(view->threads.widget_exel, 0, 5);
     evisum_ui_widget_exel_resize_hit_width_set(view->threads.widget_exel, 0);
     evisum_ui_widget_exel_state_bind(view->threads.widget_exel, &view->threads.fields_mask, view->threads.field_widths);
-    evisum_ui_widget_exel_callbacks_set(view->threads.widget_exel, NULL, NULL, NULL, NULL, NULL, view);
+    evisum_ui_widget_exel_callbacks_set(view->threads.widget_exel, NULL, NULL, NULL, NULL, NULL, NULL, view);
 
     view->children.widget_exel = evisum_ui_widget_exel_create(view->win);
     if (!view->children.widget_exel) {
@@ -1685,7 +1685,7 @@ evisum_ui_process_view_win_add(Evisum_Ui *ui, int pid, Evisum_Proc_Action action
     evisum_ui_widget_exel_resize_hit_width_set(view->children.widget_exel, 0);
     evisum_ui_widget_exel_state_bind(view->children.widget_exel, &view->children.fields_mask,
                                      view->children.field_widths);
-    evisum_ui_widget_exel_callbacks_set(view->children.widget_exel, NULL, NULL, NULL, NULL, NULL, view);
+    evisum_ui_widget_exel_callbacks_set(view->children.widget_exel, NULL, NULL, NULL, NULL, NULL, NULL, view);
 
     tabs = _evisum_ui_process_view_tabs_add(win, view);
 
diff --git a/src/bin/ui/evisum_ui_widget_exel.c b/src/bin/ui/evisum_ui_widget_exel.c
index 2dae011..c283ebd 100644
--- a/src/bin/ui/evisum_ui_widget_exel.c
+++ b/src/bin/ui/evisum_ui_widget_exel.c
@@ -2,6 +2,7 @@
 #include "evisum_ui_util.h"
 
 #include <limits.h>
+#include <stdlib.h>
 #include <string.h>
 
 #define EVISUM_UI_WIDGET_EXEL_FIELDS_MAX 64
@@ -9,6 +10,7 @@
 #define EVISUM_UI_WIDGET_EXEL_DEFAULT_FIELD_MAX   32
 #define EVISUM_UI_WIDGET_EXEL_DEFAULT_HIT_WIDTH   8
 #define EVISUM_UI_WIDGET_EXEL_DEFAULT_CACHE_SIZE  30
+#define EVISUM_UI_WIDGET_EXEL_DRAG_THRESHOLD      6
 
 typedef struct {
     int id;
@@ -30,11 +32,13 @@ typedef struct {
     int resize_hit_width;
     unsigned int *fields_mask;
     int *field_widths;
+    int *field_order;
     Evisum_Ui_Widget_Exel_Reference_Mask_Get_Cb reference_mask_get_cb;
     Evisum_Ui_Widget_Exel_Fields_Changed_Cb fields_changed_cb;
     Evisum_Ui_Widget_Exel_Fields_Applied_Cb fields_applied_cb;
     Evisum_Ui_Widget_Exel_Resize_Live_Cb resize_live_cb;
     Evisum_Ui_Widget_Exel_Resize_Done_Cb resize_done_cb;
+    Evisum_Ui_Widget_Exel_Fields_Reordered_Cb fields_reordered_cb;
     void *data;
 } Evisum_Ui_Widget_Exel_Params;
 
@@ -42,6 +46,7 @@ struct _Evisum_Ui_Widget_Exel {
     Evisum_Ui_Widget_Exel_Params p;
     unsigned int fields_mask_state;
     int field_widths_state[EVISUM_UI_WIDGET_EXEL_FIELDS_MAX];
+    int field_order_state[EVISUM_UI_WIDGET_EXEL_FIELDS_MAX];
     Exel_Field fields[EVISUM_UI_WIDGET_EXEL_FIELDS_MAX];
     Evisum_Ui_Cache *cache;
     Evas_Object *root;
@@ -58,6 +63,15 @@ struct _Evisum_Ui_Widget_Exel {
     Evas_Coord resize_start_x;
     Evas_Coord resize_start_w;
     int resize_dir;
+    int drag_field;
+    Evas_Coord drag_start_x;
+    Evas_Coord drag_start_y;
+    Evas_Coord drag_offset_x;
+    Evas_Coord drag_offset_y;
+    Evas_Object *drag_proxy;
+    Eina_Bool reorder_enabled;
+    Eina_Bool dragging;
+    Eina_Bool drag_pending;
 
     Eina_Bool resizing;
     Eina_Bool ignore_sort_click;
@@ -76,6 +90,67 @@ _evisum_ui_widget_exel_field_get(const Evisum_Ui_Widget_Exel *wx, int id) {
     return (Exel_Field *) &wx->fields[id];
 }
 
+static void
+_evisum_ui_widget_exel_field_order_sanitize(Evisum_Ui_Widget_Exel *wx) {
+    unsigned char seen[EVISUM_UI_WIDGET_EXEL_FIELDS_MAX] = { 0 };
+    int out[EVISUM_UI_WIDGET_EXEL_FIELDS_MAX] = { 0 };
+    int pos;
+
+    if (!wx || !wx->p.field_order) return;
+
+    pos = wx->p.field_first;
+    for (int i = wx->p.field_first; i < wx->p.field_max; i++) {
+        int id = wx->p.field_order[i];
+        if (id < wx->p.field_first || id >= wx->p.field_max) continue;
+        if (seen[id]) continue;
+        out[pos++] = id;
+        seen[id] = 1;
+    }
+
+    for (int id = wx->p.field_first; id < wx->p.field_max; id++) {
+        if (seen[id]) continue;
+        out[pos++] = id;
+    }
+
+    for (int i = wx->p.field_first; i < wx->p.field_max; i++) wx->p.field_order[i] = out[i];
+}
+
+static int
+_evisum_ui_widget_exel_field_order_pos_get(const Evisum_Ui_Widget_Exel *wx, int id) {
+    if (!wx || !wx->p.field_order) return -1;
+    for (int i = wx->p.field_first; i < wx->p.field_max; i++) {
+        if (wx->p.field_order[i] == id) return i;
+    }
+    return -1;
+}
+
+static Eina_Bool
+_evisum_ui_widget_exel_field_order_move_to_pos(Evisum_Ui_Widget_Exel *wx, int id, int to_pos) {
+    int from_pos;
+    int value;
+    int reorder_min_pos;
+
+    if (!wx || !wx->p.field_order) return EINA_FALSE;
+    if (id < wx->p.field_first || id >= wx->p.field_max) return EINA_FALSE;
+    reorder_min_pos = wx->p.field_first + 1;
+    if (reorder_min_pos >= wx->p.field_max) reorder_min_pos = wx->p.field_first;
+    if (to_pos < reorder_min_pos) to_pos = reorder_min_pos;
+    if (to_pos >= wx->p.field_max) to_pos = wx->p.field_max - 1;
+
+    from_pos = _evisum_ui_widget_exel_field_order_pos_get(wx, id);
+    if (from_pos < 0 || from_pos == to_pos) return EINA_FALSE;
+
+    value = wx->p.field_order[from_pos];
+    if (from_pos < to_pos) {
+        for (int i = from_pos; i < to_pos; i++) wx->p.field_order[i] = wx->p.field_order[i + 1];
+    } else {
+        for (int i = from_pos; i > to_pos; i--) wx->p.field_order[i] = wx->p.field_order[i - 1];
+    }
+    wx->p.field_order[to_pos] = value;
+
+    return EINA_TRUE;
+}
+
 static Eina_Bool
 _evisum_ui_widget_exel_field_id_valid(const Evisum_Ui_Widget_Exel *wx, int id) {
     if (!wx) return EINA_FALSE;
@@ -85,10 +160,16 @@ _evisum_ui_widget_exel_field_id_valid(const Evisum_Ui_Widget_Exel *wx, int id) {
 
 static int
 _evisum_ui_widget_exel_field_prev_visible_get(const Evisum_Ui_Widget_Exel *wx, int id) {
-    int i;
+    int pos;
 
-    for (i = id - 1; i >= wx->p.field_first; i--) {
-        if (evisum_ui_widget_exel_field_enabled_get(wx, i)) return i;
+    if (!wx || !wx->p.field_order) return 0;
+
+    pos = _evisum_ui_widget_exel_field_order_pos_get(wx, id);
+    if (pos < 0) return 0;
+
+    for (int i = pos - 1; i >= wx->p.field_first; i--) {
+        int prev_id = wx->p.field_order[i];
+        if (evisum_ui_widget_exel_field_enabled_get(wx, prev_id)) return prev_id;
     }
 
     return 0;
@@ -113,6 +194,7 @@ _evisum_ui_widget_exel_fields_sync(Evisum_Ui_Widget_Exel *wx) {
     int i;
 
     if (!wx || !wx->p.fields_mask) return;
+    _evisum_ui_widget_exel_field_order_sanitize(wx);
 
     for (i = wx->p.field_first; i < wx->p.field_max; i++) {
         Exel_Field *f = _evisum_ui_widget_exel_field_get(wx, i);
@@ -263,7 +345,8 @@ _evisum_ui_widget_exel_fields_menu_create(Evisum_Ui_Widget_Exel *wx) {
     evas_object_show(hbx);
 
     for (i = wx->p.field_first + 1; i < wx->p.field_max; i++) {
-        Exel_Field *f = _evisum_ui_widget_exel_field_get(wx, i);
+        int id = wx->p.field_order ? wx->p.field_order[i] : i;
+        Exel_Field *f = _evisum_ui_widget_exel_field_get(wx, id);
         if (!f || !f->btn || !f->desc) continue;
 
         ck = elm_check_add(wx->p.parent);
@@ -290,6 +373,119 @@ _evisum_ui_widget_exel_fields_menu_create(Evisum_Ui_Widget_Exel *wx) {
     return o;
 }
 
+static int
+_evisum_ui_widget_exel_drop_pos_get(const Evisum_Ui_Widget_Exel *wx, Evas_Coord x) {
+    int reorder_min_pos;
+    int last_visible;
+
+    if (!wx || !wx->p.field_order) return -1;
+    reorder_min_pos = wx->p.field_first + 1;
+    if (reorder_min_pos >= wx->p.field_max) reorder_min_pos = wx->p.field_first;
+    last_visible = reorder_min_pos;
+
+    for (int i = reorder_min_pos; i < wx->p.field_max; i++) {
+        int id = wx->p.field_order[i];
+        Exel_Field *f = _evisum_ui_widget_exel_field_get(wx, id);
+        Evas_Coord ox = 0, ow = 0;
+
+        if (!f || !f->btn) continue;
+        if (!f->enabled) continue;
+        if (id == wx->drag_field) continue;
+
+        evas_object_geometry_get(f->btn, &ox, NULL, &ow, NULL);
+        if (x < (ox + (ow / 2))) return i;
+        last_visible = i;
+    }
+
+    return last_visible + 1;
+}
+
+static Eina_Bool
+_evisum_ui_widget_exel_reorder_commit(Evisum_Ui_Widget_Exel *wx, Evas_Coord x) {
+    int drop_pos;
+    int from_pos;
+    int to_pos;
+    Eina_Bool changed;
+
+    if (!wx || !wx->p.field_order || !wx->dragging) return EINA_FALSE;
+
+    drop_pos = _evisum_ui_widget_exel_drop_pos_get(wx, x);
+    if (drop_pos < wx->p.field_first) return EINA_FALSE;
+
+    from_pos = _evisum_ui_widget_exel_field_order_pos_get(wx, wx->drag_field);
+    if (from_pos < 0) return EINA_FALSE;
+
+    if (drop_pos > from_pos) to_pos = drop_pos - 1;
+    else to_pos = drop_pos;
+
+    changed = _evisum_ui_widget_exel_field_order_move_to_pos(wx, wx->drag_field, to_pos);
+    if (!changed) return EINA_FALSE;
+
+    wx->ignore_sort_click = 1;
+    if (wx->header_tb) {
+        elm_table_clear(wx->header_tb, EINA_FALSE);
+        evisum_ui_widget_exel_fields_pack_visible(wx, wx->header_tb, 0);
+    }
+
+    if (wx->p.fields_reordered_cb) wx->p.fields_reordered_cb(wx->p.data);
+
+    return EINA_TRUE;
+}
+
+static void
+_evisum_ui_widget_exel_drag_proxy_del(Evisum_Ui_Widget_Exel *wx) {
+    if (!wx) return;
+    if (!wx->drag_proxy) return;
+    evas_object_del(wx->drag_proxy);
+    wx->drag_proxy = NULL;
+}
+
+static void
+_evisum_ui_widget_exel_drag_proxy_move(Evisum_Ui_Widget_Exel *wx, Evas_Coord x, Evas_Coord y) {
+    if (!wx || !wx->drag_proxy) return;
+    evas_object_move(wx->drag_proxy, x - wx->drag_offset_x, y - wx->drag_offset_y);
+}
+
+static void
+_evisum_ui_widget_exel_drag_proxy_create(Evisum_Ui_Widget_Exel *wx) {
+    Exel_Field *f;
+    Evas_Object *src;
+    Evas_Object *proxy;
+    Evas_Coord ox = 0, oy = 0, ow = 0, oh = 0;
+    const char *text;
+    Eina_Bool reverse;
+
+    if (!wx) return;
+    if (wx->drag_proxy) return;
+    if (!wx->dragging) return;
+
+    f = _evisum_ui_widget_exel_field_get(wx, wx->drag_field);
+    if (!f || !f->btn) return;
+    src = ""
+
+    evas_object_geometry_get(src, &ox, &oy, &ow, &oh);
+    text = elm_object_text_get(src);
+    reverse = (Eina_Bool) (intptr_t) evas_object_data_get(src, "sort_reverse");
+
+    proxy = evisum_ui_widget_exel_sort_header_button_add(wx->p.win, text ? text : "", reverse, 0.0, FILL, NULL, NULL);
+    if (!proxy) return;
+
+    evas_object_size_hint_min_set(proxy, ow, oh);
+    evas_object_size_hint_max_set(proxy, ow, oh);
+    evas_object_resize(proxy, ow, oh);
+    evas_object_move(proxy, ox, oy);
+    evas_object_layer_set(proxy, EVAS_LAYER_MAX);
+    evas_object_show(proxy);
+    wx->drag_proxy = proxy;
+
+    wx->drag_offset_x = wx->drag_start_x - ox;
+    wx->drag_offset_y = wx->drag_start_y - oy;
+    if (wx->drag_offset_x < 0) wx->drag_offset_x = ow / 2;
+    if (wx->drag_offset_x > ow) wx->drag_offset_x = ow / 2;
+    if (wx->drag_offset_y < 0) wx->drag_offset_y = oh / 2;
+    if (wx->drag_offset_y > oh) wx->drag_offset_y = oh / 2;
+}
+
 static void
 _evisum_ui_widget_exel_field_header_mouse_down_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) {
     Evisum_Ui_Widget_Exel *wx = data;
@@ -303,14 +499,18 @@ _evisum_ui_widget_exel_field_header_mouse_down_cb(void *data, Evas *e EINA_UNUSE
     evas_object_geometry_get(obj, &x, NULL, &w, NULL);
     field = (int) (intptr_t) evas_object_data_get(obj, "field_id");
     if (field < wx->p.field_first || field >= wx->p.field_max) return;
+    if (field == wx->p.field_first) return;
 
     if (ev->canvas.x >= (x + w - ELM_SCALE_SIZE(wx->p.resize_hit_width))) {
+        _evisum_ui_widget_exel_drag_proxy_del(wx);
         wx->resizing = 1;
         wx->resize_btn = obj;
         wx->resize_field = field;
         wx->resize_start_x = ev->canvas.x;
         wx->resize_start_w = w;
         wx->resize_dir = 1;
+        wx->drag_pending = 0;
+        wx->dragging = 0;
         return;
     }
 
@@ -327,7 +527,19 @@ _evisum_ui_widget_exel_field_header_mouse_down_cb(void *data, Evas *e EINA_UNUSE
         wx->resize_field = prev;
         wx->resize_start_x = ev->canvas.x;
         wx->resize_dir = 1;
+        wx->drag_pending = 0;
+        wx->dragging = 0;
+        return;
     }
+
+    if (!wx->reorder_enabled) return;
+
+    _evisum_ui_widget_exel_drag_proxy_del(wx);
+    wx->drag_field = field;
+    wx->drag_start_x = ev->canvas.x;
+    wx->drag_start_y = ev->canvas.y;
+    wx->drag_pending = 1;
+    wx->dragging = 0;
 }
 
 static void
@@ -337,6 +549,7 @@ _evisum_ui_widget_exel_field_header_mouse_up_cb(void *data, Evas *e EINA_UNUSED,
 
     if (!wx || !ev) return;
 
+    if (evisum_ui_widget_exel_field_reorder_mouse_up(wx, ev)) return;
     evisum_ui_widget_exel_field_resize_mouse_up(wx, ev);
     evisum_ui_widget_exel_fields_menu_show(wx, obj, ev);
 }
@@ -369,10 +582,12 @@ evisum_ui_widget_exel_create(Evas_Object *parent) {
     wx->fields_mask_state = UINT_MAX;
     for (i = p.field_first; i < p.field_max; i++) {
         wx->field_widths_state[i] = 0;
+        wx->field_order_state[i] = i;
     }
 
     p.fields_mask = &wx->fields_mask_state;
     p.field_widths = wx->field_widths_state;
+    p.field_order = wx->field_order_state;
     p.data = ""
     wx->p = p;
     wx->owns_state = EINA_TRUE;
@@ -493,9 +708,30 @@ evisum_ui_widget_exel_field_bounds_set(Evisum_Ui_Widget_Exel *wx, int field_firs
 
     wx->p.field_first = field_first;
     wx->p.field_max = field_max;
+    for (int i = wx->p.field_first; i < wx->p.field_max; i++) {
+        if (!wx->p.field_order) wx->field_order_state[i] = i;
+        else if ((wx->p.field_order[i] < wx->p.field_first) || (wx->p.field_order[i] >= wx->p.field_max))
+            wx->p.field_order[i] = i;
+    }
+    _evisum_ui_widget_exel_field_order_sanitize(wx);
     _evisum_ui_widget_exel_fields_sync(wx);
 }
 
+void
+evisum_ui_widget_exel_field_order_bind(Evisum_Ui_Widget_Exel *wx, int *field_order) {
+    if (!wx) return;
+
+    if (field_order) wx->p.field_order = field_order;
+    else wx->p.field_order = wx->field_order_state;
+    _evisum_ui_widget_exel_field_order_sanitize(wx);
+}
+
+void
+evisum_ui_widget_exel_field_reorder_enabled_set(Evisum_Ui_Widget_Exel *wx, Eina_Bool enabled) {
+    if (!wx) return;
+    wx->reorder_enabled = enabled;
+}
+
 void
 evisum_ui_widget_exel_resize_hit_width_set(Evisum_Ui_Widget_Exel *wx, int hit_width) {
     if (!wx) return;
@@ -509,13 +745,15 @@ evisum_ui_widget_exel_callbacks_set(Evisum_Ui_Widget_Exel *wx,
                                     Evisum_Ui_Widget_Exel_Fields_Changed_Cb fields_changed_cb,
                                     Evisum_Ui_Widget_Exel_Fields_Applied_Cb fields_applied_cb,
                                     Evisum_Ui_Widget_Exel_Resize_Live_Cb resize_live_cb,
-                                    Evisum_Ui_Widget_Exel_Resize_Done_Cb resize_done_cb, void *data) {
+                                    Evisum_Ui_Widget_Exel_Resize_Done_Cb resize_done_cb,
+                                    Evisum_Ui_Widget_Exel_Fields_Reordered_Cb fields_reordered_cb, void *data) {
     if (!wx) return;
     wx->p.reference_mask_get_cb = reference_mask_get_cb;
     wx->p.fields_changed_cb = fields_changed_cb;
     wx->p.fields_applied_cb = fields_applied_cb;
     wx->p.resize_live_cb = resize_live_cb;
     wx->p.resize_done_cb = resize_done_cb;
+    wx->p.fields_reordered_cb = fields_reordered_cb;
     wx->p.data = ""
 }
 
@@ -531,6 +769,7 @@ evisum_ui_widget_exel_free(Evisum_Ui_Widget_Exel *wx) {
     }
     evisum_ui_widget_exel_fields_menu_dismiss(wx);
     evisum_ui_widget_exel_deferred_call_cancel(wx);
+    _evisum_ui_widget_exel_drag_proxy_del(wx);
     if (wx->cache) evisum_ui_item_cache_free(wx->cache);
     if (wx->root) evas_object_del(wx->root);
     wx->header_tb = NULL;
@@ -580,12 +819,11 @@ evisum_ui_widget_exel_field_enabled_get(const Evisum_Ui_Widget_Exel *wx, int id)
 
 static int
 _evisum_ui_widget_exel_last_visible_field_get(const Evisum_Ui_Widget_Exel *wx) {
-    int i;
-
     if (!wx) return 0;
 
-    for (i = wx->p.field_max - 1; i >= wx->p.field_first; i--) {
-        if (evisum_ui_widget_exel_field_enabled_get(wx, i)) return i;
+    for (int i = wx->p.field_max - 1; i >= wx->p.field_first; i--) {
+        int id = wx->p.field_order ? wx->p.field_order[i] : i;
+        if (evisum_ui_widget_exel_field_enabled_get(wx, id)) return id;
     }
 
     return wx->p.field_first;
@@ -599,14 +837,15 @@ evisum_ui_widget_exel_field_is_last_visible(const Evisum_Ui_Widget_Exel *wx, int
 
 int
 evisum_ui_widget_exel_fields_pack_visible(Evisum_Ui_Widget_Exel *wx, Evas_Object *tb, int col_start) {
-    int i, col = col_start;
+    int col = col_start;
 
     if (!wx || !tb) return col_start;
 
     _evisum_ui_widget_exel_fields_sync(wx);
 
-    for (i = wx->p.field_first; i < wx->p.field_max; i++) {
-        Exel_Field *f = _evisum_ui_widget_exel_field_get(wx, i);
+    for (int i = wx->p.field_first; i < wx->p.field_max; i++) {
+        int id = wx->p.field_order ? wx->p.field_order[i] : i;
+        Exel_Field *f = _evisum_ui_widget_exel_field_get(wx, id);
         if (!f || !f->btn) continue;
 
         if (!f->enabled) {
@@ -747,6 +986,23 @@ _evisum_ui_widget_exel_win_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_O
                                          void *event_info) {
     Evisum_Ui_Widget_Exel *wx = data;
     Evas_Event_Mouse_Move *ev = event_info;
+
+    if (!wx || !ev) return;
+
+    if (wx->drag_pending) {
+        Evas_Coord dx = ev->cur.canvas.x - wx->drag_start_x;
+        Evas_Coord dy = ev->cur.canvas.y - wx->drag_start_y;
+        if ((abs(dx) >= ELM_SCALE_SIZE(EVISUM_UI_WIDGET_EXEL_DRAG_THRESHOLD))
+            || (abs(dy) >= ELM_SCALE_SIZE(EVISUM_UI_WIDGET_EXEL_DRAG_THRESHOLD))) {
+            wx->drag_pending = 0;
+            wx->dragging = 1;
+            wx->ignore_sort_click = 1;
+            _evisum_ui_widget_exel_drag_proxy_create(wx);
+        }
+    }
+    if (wx->dragging && !wx->drag_proxy) _evisum_ui_widget_exel_drag_proxy_create(wx);
+    if (wx->dragging) _evisum_ui_widget_exel_drag_proxy_move(wx, ev->cur.canvas.x, ev->cur.canvas.y);
+
     _evisum_ui_widget_exel_field_resize_mouse_move(wx, ev);
 }
 
@@ -775,6 +1031,24 @@ evisum_ui_widget_exel_field_resize_mouse_up(Evisum_Ui_Widget_Exel *wx, Evas_Even
     if (wx->p.resize_done_cb) wx->p.resize_done_cb(wx->p.data);
 }
 
+Eina_Bool
+evisum_ui_widget_exel_field_reorder_mouse_up(Evisum_Ui_Widget_Exel *wx, Evas_Event_Mouse_Up *ev) {
+    Eina_Bool handled = EINA_FALSE;
+
+    if (!wx || !ev) return EINA_FALSE;
+    if (ev->button != 1) return EINA_FALSE;
+
+    if (wx->dragging) handled = _evisum_ui_widget_exel_reorder_commit(wx, ev->canvas.x);
+    else if (wx->drag_pending) handled = EINA_FALSE;
+
+    _evisum_ui_widget_exel_drag_proxy_del(wx);
+    wx->drag_pending = 0;
+    wx->dragging = 0;
+    wx->drag_field = 0;
+
+    return handled;
+}
+
 Eina_Bool
 evisum_ui_widget_exel_sort_ignore_consume(Evisum_Ui_Widget_Exel *wx) {
     if (!wx) return 0;
@@ -1166,6 +1440,7 @@ evisum_ui_widget_exel_sort_header_button_state_set(Evas_Object *btn, Eina_Bool r
     else elm_icon_standard_set(ic, "go-up");
 
     elm_object_part_content_set(btn, "icon", ic);
+    evas_object_data_set(btn, "sort_reverse", (void *) (intptr_t) reverse);
     evas_object_show(ic);
 }
 
@@ -1222,14 +1497,14 @@ _evisum_ui_widget_exel_item_create_from_fields(Evas_Object *parent) {
     Evisum_Ui_Widget_Exel *wx = evas_object_data_get(parent, "widget_exel");
     Evisum_Ui_Widget_Exel_Item_Cell_Def defs[EVISUM_UI_WIDGET_EXEL_FIELDS_MAX];
     unsigned int n = 0;
-    int i;
 
     if (!wx) return NULL;
 
     _evisum_ui_widget_exel_fields_sync(wx);
 
-    for (i = wx->p.field_first; i < wx->p.field_max; i++) {
-        Exel_Field *f = _evisum_ui_widget_exel_field_get(wx, i);
+    for (int i = wx->p.field_first; i < wx->p.field_max; i++) {
+        int id = wx->p.field_order ? wx->p.field_order[i] : i;
+        Exel_Field *f = _evisum_ui_widget_exel_field_get(wx, id);
         if (!f || !f->row_def_set || !f->enabled) continue;
         defs[n++] = f->row_def;
     }
diff --git a/src/bin/ui/evisum_ui_widget_exel.h b/src/bin/ui/evisum_ui_widget_exel.h
index fe73d82..7aaa0d1 100644
--- a/src/bin/ui/evisum_ui_widget_exel.h
+++ b/src/bin/ui/evisum_ui_widget_exel.h
@@ -40,6 +40,7 @@ typedef void (*Evisum_Ui_Widget_Exel_Fields_Changed_Cb)(void *data, Eina_Bool ch
 typedef void (*Evisum_Ui_Widget_Exel_Fields_Applied_Cb)(void *data, Eina_Bool changed);
 typedef void (*Evisum_Ui_Widget_Exel_Resize_Live_Cb)(void *data);
 typedef void (*Evisum_Ui_Widget_Exel_Resize_Done_Cb)(void *data);
+typedef void (*Evisum_Ui_Widget_Exel_Fields_Reordered_Cb)(void *data);
 
 typedef struct {
     int id;
@@ -94,6 +95,14 @@ void evisum_ui_widget_exel_state_bind(Evisum_Ui_Widget_Exel *wx, unsigned int *f
  * Must be called before registering fields when using non-default ranges. */
 void evisum_ui_widget_exel_field_bounds_set(Evisum_Ui_Widget_Exel *wx, int field_first, int field_max);
 
+/* Bind an external ordered list of field ids keyed by display position.
+ * Pass NULL to keep/create widget-owned order state. */
+void evisum_ui_widget_exel_field_order_bind(Evisum_Ui_Widget_Exel *wx, int *field_order);
+
+/* Enable/disable drag-reordering of field headers.
+ * Reordering is opt-in so existing views keep current interaction behavior. */
+void evisum_ui_widget_exel_field_reorder_enabled_set(Evisum_Ui_Widget_Exel *wx, Eina_Bool enabled);
+
 /* Set header-resize hit width in pixels for edge drag detection.
  * Keep zero to disable resize hit-testing. */
 void evisum_ui_widget_exel_resize_hit_width_set(Evisum_Ui_Widget_Exel *wx, int hit_width);
@@ -104,7 +113,8 @@ void evisum_ui_widget_exel_callbacks_set(Evisum_Ui_Widget_Exel *wx,
                                          Evisum_Ui_Widget_Exel_Fields_Changed_Cb fields_changed_cb,
                                          Evisum_Ui_Widget_Exel_Fields_Applied_Cb fields_applied_cb,
                                          Evisum_Ui_Widget_Exel_Resize_Live_Cb resize_live_cb,
-                                         Evisum_Ui_Widget_Exel_Resize_Done_Cb resize_done_cb, void *data);
+                                         Evisum_Ui_Widget_Exel_Resize_Done_Cb resize_done_cb,
+                                         Evisum_Ui_Widget_Exel_Fields_Reordered_Cb fields_reordered_cb, void *data);
 
 /* Release the exel widget controller and any menu state it owns.
  * Call this during view teardown to avoid leaked UI objects and stale pointers. */
@@ -160,6 +170,10 @@ void evisum_ui_widget_exel_field_resize_attach(Evisum_Ui_Widget_Exel *wx, Evas_O
  * This commits final width state and triggers configured resize-done callbacks. */
 void evisum_ui_widget_exel_field_resize_mouse_up(Evisum_Ui_Widget_Exel *wx, Evas_Event_Mouse_Up *ev);
 
+/* Process mouse-up for drag-reordering and commit any field order changes.
+ * Returns true when a reorder interaction was handled. */
+Eina_Bool evisum_ui_widget_exel_field_reorder_mouse_up(Evisum_Ui_Widget_Exel *wx, Evas_Event_Mouse_Up *ev);
+
 /* Consume and clear the internal "ignore next sort click" flag set after resizing.
  * Use this at sort-click entry points to prevent accidental sort toggles on drag release. */
 Eina_Bool evisum_ui_widget_exel_sort_ignore_consume(Evisum_Ui_Widget_Exel *wx);

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to