Skip to content

Commit

Permalink
Add basic support for drag and drop of lists
Browse files Browse the repository at this point in the history
Added a generic gui component for lists, so that we can use it for
layer, cameras and materials.  For the moment this supposes that the
list items are all based on the same structure that starts with a ref
counting and two pointers to next and prev items.

I think I should create some kind of base struct for all the lists to
avoid this though.

Since I make all the list behave the same, I changed the order of the
layers.  Hopefully this is acceptable.
  • Loading branch information
guillaumechereau committed Oct 21, 2024
1 parent 07a796a commit a7f498f
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 56 deletions.
57 changes: 57 additions & 0 deletions src/gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2050,3 +2050,60 @@ float gui_get_item_height(void)
ImGuiStyle& style = ImGui::GetStyle();
return style.FramePadding.y * 2 + ImGui::GetFontSize();
}

typedef struct list_item list_item_t;
struct list_item {
int ret;
list_item_t *next, *prev;
};

static void list_move_item(list_item_t **list, list_item_t *item, int d)
{
// XXX: ugly code.
list_item_t *other = NULL;
assert(d == -1 || d == +1);
if (d == -1) {
other = item->next;
SWAP(other, item);
} else if (item != *list) {
other = item->prev;
}
if (!other || !item) return;
DL_DELETE(*list, item);
DL_PREPEND_ELEM(*list, other, item);
}

void gui_list(const gui_list_t *list)
{
list_item_t **items = (list_item_t**)list->items;
list_item_t *item;
bool is_current;
int i;
int move_dir = 0;
int count;
list_item_t *move_item = NULL;

DL_COUNT(*items, item, count);

gui_group_begin(NULL);
i = 0;
DL_FOREACH(*items, item) {
is_current = *list->current == item;
if (list->render((void*)item, i, is_current)) {
*list->current = item;
if (is_current && list->can_be_null) {
*list->current = NULL;
}
}
if (!move_dir && ImGui::IsItemActive() && !ImGui::IsItemHovered()) {
move_dir = ImGui::GetMouseDragDelta(0).y < 0.f ? +1 : -1;
move_item = item;
}
i++;
}
gui_group_end();

if (move_item) {
list_move_item(items, move_item, move_dir);
}
}
14 changes: 14 additions & 0 deletions src/gui.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,20 @@ bool gui_context_menu_begin(const char *label);
void gui_context_menu_end(void);
void gui_context_menu_button(const char *label, int icon);


/*
* Experimental support for list, with drag and drap support.
*/

typedef struct {
void **items;
void **current;
bool (*render)(void *item, int idx, bool current);
bool can_be_null;
} gui_list_t;

void gui_list(const gui_list_t *list);

/*
* to avoid, for manual layout.
*/
Expand Down
24 changes: 12 additions & 12 deletions src/gui/cameras_panel.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,24 @@

#include "goxel.h"

static bool render_camera_item(void *item, int idx, bool is_current)
{
camera_t *cam = item;
return gui_layer_item(idx, 0, NULL, NULL, &is_current, cam->name,
sizeof(cam->name));
}

void gui_cameras_panel(void)
{
camera_t *cam;
int i = 0;
bool current;
float rot[3][3], e1[3], e2[3], eul[3], pitch, yaw, v;
char buf[256];

gui_group_begin(NULL);
DL_FOREACH(goxel.image->cameras, cam) {
current = goxel.image->active_camera == cam;
if (gui_layer_item(i, 0, NULL, NULL, &current,
cam->name, sizeof(cam->name))) {
goxel.image->active_camera = cam;
}
i++;
}
gui_group_end();
gui_list(&(gui_list_t) {
.items = (void**)&goxel.image->cameras,
.current = (void**)&goxel.image->active_camera,
.render = render_camera_item,
});

gui_row_begin(0);
gui_action_button(ACTION_img_new_camera, NULL, 0);
Expand Down
54 changes: 29 additions & 25 deletions src/gui/layers_panel.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,39 +82,43 @@ static void layers_context_menu(void)
}
}

static bool render_layer_item(void *item, int idx, bool current)
{
layer_t *layer = item;
int icons_count, icons[8];
bool visible;

visible = layer->visible;
icons_count = 0;
if (layer->base_id) icons[icons_count++] = ICON_LINK;
if (layer->shape) icons[icons_count++] = ICON_SHAPE;
if (layer->mode == MODE_SUB) icons[icons_count++] = ICON_SUBTRACT;
if (layer->mode == MODE_INTERSECT)
icons[icons_count++] = ICON_INTERSECT;
gui_layer_item(idx, icons_count, icons, &visible, &current,
layer->name, sizeof(layer->name));
if (visible != layer->visible) {
layer->visible = visible;
if (gui_is_key_down(KEY_LEFT_SHIFT))
toggle_layer_only_visible(layer);
}
return current;
}

void gui_layers_panel(void)
{
layer_t *layer;
material_t *material;
int i = 0, bbox[2][3];
int icons_count, icons[8];
bool current, visible, bounded;
bool current, bounded;
char buf[256];
const int MODES[] = {MODE_OVER, MODE_SUB, MODE_INTERSECT, MODE_PAINT};

gui_group_begin(NULL);
DL_FOREACH_REVERSE(goxel.image->layers, layer) {
current = goxel.image->active_layer == layer;
visible = layer->visible;
icons_count = 0;
if (layer->base_id) icons[icons_count++] = ICON_LINK;
if (layer->shape) icons[icons_count++] = ICON_SHAPE;
if (layer->mode == MODE_SUB) icons[icons_count++] = ICON_SUBTRACT;
if (layer->mode == MODE_INTERSECT)
icons[icons_count++] = ICON_INTERSECT;
gui_layer_item(i, icons_count, icons, &visible, &current,
layer->name, sizeof(layer->name));
if (current && goxel.image->active_layer != layer) {
goxel.image->active_layer = layer;
}
if (visible != layer->visible) {
layer->visible = visible;
if (gui_is_key_down(KEY_LEFT_SHIFT))
toggle_layer_only_visible(layer);
}
i++;
}
gui_group_end();
gui_list(&(gui_list_t) {
.items = (void**)&goxel.image->layers,
.current = (void**)&goxel.image->active_layer,
.render = render_layer_item,
});

gui_row_begin(0);
gui_action_button(ACTION_img_new_layer, NULL, 0);
Expand Down
29 changes: 13 additions & 16 deletions src/gui/material_panel.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,24 @@

#include "goxel.h"

static bool render_material_item(void *item, int idx, bool is_current)
{
material_t *mat = item;
return gui_layer_item(idx, 0, NULL, NULL, &is_current, mat->name,
sizeof(mat->name));
}

void gui_material_panel(void)
{
material_t *mat = NULL;
int i = 0;
bool is_current;
float base_color_e, emission_e, emission;

gui_group_begin(NULL);
DL_FOREACH(goxel.image->materials, mat) {
is_current = goxel.image->active_material == mat;
if (gui_layer_item(i, 0, NULL, NULL, &is_current, mat->name,
sizeof(mat->name))) {
if (is_current) {
goxel.image->active_material = mat;
} else {
goxel.image->active_material = NULL;
}
}
i++;
}
gui_group_end();
gui_list(&(gui_list_t) {
.items = (void**)&goxel.image->materials,
.current = (void**)&goxel.image->active_material,
.render = render_material_item,
.can_be_null = true,
});

gui_row_begin(0);
gui_action_button(ACTION_img_new_material, NULL, 0);
Expand Down
4 changes: 2 additions & 2 deletions src/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -818,12 +818,12 @@ ACTION_REGISTER(ACTION_img_del_layer,

static void a_image_move_layer_up(void)
{
image_move_layer(goxel.image, goxel.image->active_layer, -1);
image_move_layer(goxel.image, goxel.image->active_layer, +1);
}

static void a_image_move_layer_down(void)
{
image_move_layer(goxel.image, goxel.image->active_layer, +1);
image_move_layer(goxel.image, goxel.image->active_layer, -1);
}


Expand Down
2 changes: 1 addition & 1 deletion src/material.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@
typedef struct material material_t;
struct material {
int ref;
material_t *next, *prev; // List of materials in an image.
char name[128]; // 127 chars max.
float metallic;
float roughness;
float base_color[4]; // Linear color.
float emission[3];
material_t *next, *prev; // List of materials in an image.
};

#define MATERIAL_DEFAULT (material_t){ \
Expand Down

0 comments on commit a7f498f

Please sign in to comment.