static void node_editor_demo(struct zr_context *ctx, struct node_editor *nodedit) { int n = 0; struct zr_rect total_space; const struct zr_input *in = &ctx->input; struct zr_command_buffer *canvas; struct node *updated = 0; struct zr_panel layout; if (zr_begin(ctx, &layout, "Node Editor", zr_rect(50, 50, 650, 650), ZR_WINDOW_BORDER|ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_CLOSABLE|ZR_WINDOW_MOVABLE)) { /* allocate complete window space */ canvas = zr_window_get_canvas(ctx); total_space = zr_window_get_content_region(ctx); zr_layout_space_begin(ctx, ZR_STATIC, total_space.h, (zr_size)nodedit->node_count); { struct zr_panel node, menu; struct node *it = nodedit->begin; struct zr_rect size = zr_layout_space_bounds(ctx); if (nodedit->show_grid) { /* display grid */ float x, y; const float grid_size = 32.0f; const struct zr_color grid_color = zr_rgb(50, 50, 50); for (x = (float)fmod(size.x - nodedit->scrolling.x, grid_size); x < size.w; x += grid_size) zr_draw_line(canvas, x+size.x, size.y, x+size.x, size.y+size.h, grid_color); for (y = (float)fmod(size.y - nodedit->scrolling.y, grid_size); y < size.h; y += grid_size) zr_draw_line(canvas, size.x, y+size.y, size.x+size.w, y+size.y, grid_color); } /* execute each node as a moveable group */ while (it) { /* calculate scrolled node window position and size */ zr_layout_space_push(ctx, zr_rect(it->bounds.x - nodedit->scrolling.x, it->bounds.y - nodedit->scrolling.y, it->bounds.w, it->bounds.h)); /* execute node window */ if (zr_group_begin(ctx, &node, it->name, ZR_WINDOW_MOVABLE|ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER|ZR_WINDOW_TITLE)) { /* always have last selected node on top */ if (zr_input_mouse_clicked(in, ZR_BUTTON_LEFT, node.bounds) && (!(it->prev && zr_input_mouse_clicked(in, ZR_BUTTON_LEFT, zr_layout_space_rect_to_screen(ctx, node.bounds)))) && nodedit->end != it) { updated = it; } /* ================= NODE CONTENT =====================*/ zr_layout_row_dynamic(ctx, 25, 1); zr_button_color(ctx, it->color, ZR_BUTTON_DEFAULT); it->color.r = (zr_byte)zr_propertyi(ctx, "#R:", 0, it->color.r, 255, 1,1); it->color.g = (zr_byte)zr_propertyi(ctx, "#G:", 0, it->color.g, 255, 1,1); it->color.b = (zr_byte)zr_propertyi(ctx, "#B:", 0, it->color.b, 255, 1,1); it->color.a = (zr_byte)zr_propertyi(ctx, "#A:", 0, it->color.a, 255, 1,1); /* ====================================================*/ zr_group_end(ctx); } { /* node connector and linking */ float space; struct zr_rect bounds; bounds = zr_layout_space_rect_to_local(ctx, node.bounds); bounds.x += nodedit->scrolling.x; bounds.y += nodedit->scrolling.y; it->bounds = bounds; /* output connector */ space = node.bounds.h / ((it->output_count) + 1); for (n = 0; n < it->output_count; ++n) { struct zr_rect circle; circle.x = node.bounds.x + node.bounds.w-4; circle.y = node.bounds.y + space * (n+1); circle.w = 8; circle.h = 8; zr_draw_circle(canvas, circle, zr_rgb(100, 100, 100)); /* start linking process */ if (zr_input_has_mouse_click_down_in_rect(in, ZR_BUTTON_LEFT, circle, zr_true)) { nodedit->linking.active = zr_true; nodedit->linking.node = it; nodedit->linking.input_id = it->ID; nodedit->linking.input_slot = n; } /* draw curve from linked node slot to mouse position */ if (nodedit->linking.active && nodedit->linking.node == it && nodedit->linking.input_slot == n) { struct zr_vec2 l0 = zr_vec2(circle.x + 3, circle.y + 3); struct zr_vec2 l1 = in->mouse.pos; zr_draw_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y, l1.x - 50.0f, l1.y, l1.x, l1.y, zr_rgb(100, 100, 100)); } } /* input connector */ space = node.bounds.h / ((it->input_count) + 1); for (n = 0; n < it->input_count; ++n) { struct zr_rect circle; circle.x = node.bounds.x-4; circle.y = node.bounds.y + space * (n+1); circle.w = 8; circle.h = 8; zr_draw_circle(canvas, circle, zr_rgb(100, 100, 100)); if (zr_input_is_mouse_released(in, ZR_BUTTON_LEFT) && zr_input_is_mouse_hovering_rect(in, circle) && nodedit->linking.active && nodedit->linking.node != it) { nodedit->linking.active = zr_false; node_editor_link(nodedit, nodedit->linking.input_id, nodedit->linking.input_slot, it->ID, n); } } } it = it->next; } /* reset linking connection */ if (nodedit->linking.active && zr_input_is_mouse_released(in, ZR_BUTTON_LEFT)) { nodedit->linking.active = zr_false; nodedit->linking.node = NULL; fprintf(stdout, "linking failed\n"); } /* draw each link */ for (n = 0; n < nodedit->link_count; ++n) { struct node_link *link = &nodedit->links[n]; struct node *ni = node_editor_find(nodedit, link->input_id); struct node *no = node_editor_find(nodedit, link->output_id); float spacei = node.bounds.h / ((ni->output_count) + 1); float spaceo = node.bounds.h / ((no->input_count) + 1); struct zr_vec2 l0 = zr_layout_space_to_screen(ctx, zr_vec2(ni->bounds.x + ni->bounds.w, 3+ni->bounds.y + spacei * (link->input_slot+1))); struct zr_vec2 l1 = zr_layout_space_to_screen(ctx, zr_vec2(no->bounds.x, 3 + no->bounds.y + spaceo * (link->output_slot+1))); l0.x -= nodedit->scrolling.x; l0.y -= nodedit->scrolling.y; l1.x -= nodedit->scrolling.x; l1.y -= nodedit->scrolling.y; zr_draw_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y, l1.x - 50.0f, l1.y, l1.x, l1.y, zr_rgb(100, 100, 100)); } if (updated) { /* reshuffle nodes to have last recently selected node on top */ node_editor_pop(nodedit, updated); node_editor_push(nodedit, updated); } /* node selection */ if (zr_input_mouse_clicked(in, ZR_BUTTON_LEFT, zr_layout_space_bounds(ctx))) { it = nodedit->begin; nodedit->selected = NULL; nodedit->bounds = zr_rect(in->mouse.pos.x, in->mouse.pos.y, 100, 200); while (it) { struct zr_rect b = zr_layout_space_rect_to_screen(ctx, it->bounds); b.x -= nodedit->scrolling.x; b.y -= nodedit->scrolling.y; if (zr_input_is_mouse_hovering_rect(in, b)) nodedit->selected = it; it = it->next; } } /* contextual menu */ if (zr_contextual_begin(ctx, &menu, 0, zr_vec2(100, 220), zr_window_get_bounds(ctx))) { const char *grid_option[] = {"Show Grid", "Hide Grid"}; zr_layout_row_dynamic(ctx, 25, 1); if (zr_contextual_item(ctx, "New", ZR_TEXT_CENTERED)) node_editor_add(nodedit, "New", zr_rect(400, 260, 180, 220), zr_rgb(255, 255, 255), 1, 2); if (zr_contextual_item(ctx, grid_option[nodedit->show_grid],ZR_TEXT_CENTERED)) nodedit->show_grid = !nodedit->show_grid; zr_contextual_end(ctx); } } zr_layout_space_end(ctx); /* window content scrolling */ if (zr_input_is_mouse_hovering_rect(in, zr_window_get_bounds(ctx)) && zr_input_is_mouse_down(in, ZR_BUTTON_MIDDLE)) { nodedit->scrolling.x += in->mouse.delta.x; nodedit->scrolling.y += in->mouse.delta.y; } } zr_end(ctx); }
static int file_browser_run(struct file_browser *browser, int width, int height) { struct zr_context context; struct media *media = &browser->media; struct icons *icons = &media->icons; struct zr_rect total_space; browser->window.bounds.w = width; browser->window.bounds.h = height; zr_begin(&context, &browser->window, NULL); { struct zr_context sub; float row_layout[3]; /* output path directory selector in the menubar */ zr_menubar_begin(&context); { char *d = browser->directory; char *begin = d + 1; zr_layout_row_dynamic(&context, 25, 6); zr_style_push_property(&browser->config, ZR_PROPERTY_ITEM_SPACING, zr_vec2(0, 4)); while (*d++) { if (*d == '/') { *d = '\0'; if (zr_button_text(&context, begin, ZR_BUTTON_DEFAULT)) { *d++ = '/'; *d = '\0'; file_browser_reload_directory_content(browser, browser->directory); break; } *d = '/'; begin = d + 1; } } zr_style_pop_property(&browser->config); } zr_menubar_end(&context); /* window layout */ total_space = zr_space(&context); row_layout[0] = (total_space.w - 8) * browser->ratio_sel; row_layout[1] = 8; row_layout[2] = (total_space.w - 8) * browser->ratio_dir; zr_layout_row(&context, ZR_STATIC, total_space.h, 3, row_layout); zr_style_push_property(&browser->config, ZR_PROPERTY_ITEM_SPACING, zr_vec2(0, 4)); /* output special important directory list in own window */ zr_group_begin(&context, &sub, NULL, ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER, browser->sel); { struct zr_image home = icons->home.img; struct zr_image desktop = icons->desktop.img; struct zr_image computer = icons->computer.img; zr_layout_row_dynamic(&sub, 40, 1); zr_style_push_property(&browser->config, ZR_PROPERTY_ITEM_SPACING, zr_vec2(0, 0)); if (zr_button_text_image(&sub, home, "home", ZR_TEXT_CENTERED, ZR_BUTTON_DEFAULT)) file_browser_reload_directory_content(browser, browser->home); if (zr_button_text_image(&sub,desktop,"desktop",ZR_TEXT_CENTERED, ZR_BUTTON_DEFAULT)) file_browser_reload_directory_content(browser, browser->desktop); if (zr_button_text_image(&sub,computer,"computer",ZR_TEXT_CENTERED,ZR_BUTTON_DEFAULT)) file_browser_reload_directory_content(browser, "/"); zr_style_pop_property(&browser->config); } zr_group_end(&context, &sub, &browser->sel); { /* scaler */ struct zr_rect bounds; struct zr_input *in = &browser->input; zr_layout_peek(&bounds, &context); zr_spacing(&context, 1); if ((zr_input_is_mouse_hovering_rect(in, bounds) || zr_input_is_mouse_prev_hovering_rect(in, bounds)) && zr_input_is_mouse_down(in, ZR_BUTTON_LEFT)) { float sel = row_layout[0] + in->mouse.delta.x; float dir = row_layout[2] - in->mouse.delta.x; browser->ratio_sel = sel / (total_space.w - 8); browser->ratio_dir = dir / (total_space.w - 8); } } /* output directory content window */ zr_group_begin(&context, &sub, NULL, ZR_WINDOW_BORDER, browser->dir); { int index = -1; size_t i = 0, j = 0, k = 0; size_t rows = 0, cols = 0; size_t count = browser->dir_count + browser->file_count; cols = 4; rows = count / cols; for (i = 0; i <= rows; i += 1) { { /* draw one row of icons */ size_t n = j + cols; zr_layout_row_dynamic(&sub, 135, cols); zr_style_push_color(&browser->config, ZR_COLOR_BUTTON, zr_rgb(45, 45, 45)); zr_style_push_color(&browser->config, ZR_COLOR_BORDER, zr_rgb(45, 45, 45)); for (; j < count && j < n; ++j) { if (j < browser->dir_count) { /* draw and execute directory buttons */ if (zr_button_image(&sub,icons->directory.img,ZR_BUTTON_DEFAULT)) index = (int)j; } else { /* draw and execute files buttons */ struct icon *icon; size_t fileIndex = ((size_t)j - browser->dir_count); icon = media_icon_for_file(media,browser->files[fileIndex]); if (zr_button_image(&sub, icon->img, ZR_BUTTON_DEFAULT)) { strncpy(browser->file, browser->directory, MAX_PATH_LEN); n = strlen(browser->file); strncpy(browser->file + n, browser->files[fileIndex], MAX_PATH_LEN - n); return 0; } } } zr_style_pop_color(&browser->config); zr_style_pop_color(&browser->config); } { /* draw one row of labels */ size_t n = k + cols; zr_layout_row_dynamic(&sub, 20, cols); for (; k < count && k < n; k++) { if (k < browser->dir_count) { zr_label(&sub, browser->directories[k], ZR_TEXT_CENTERED); } else { size_t t = k-browser->dir_count; zr_label(&sub,browser->files[t],ZR_TEXT_CENTERED); } } } } if (index != -1) { size_t n = strlen(browser->directory); strncpy(browser->directory + n, browser->directories[index], MAX_PATH_LEN - n); n = strlen(browser->directory); if (n < MAX_PATH_LEN - 1) { browser->directory[n] = '/'; browser->directory[n+1] = '\0'; } file_browser_reload_directory_content(browser, browser->directory); } } zr_group_end(&context, &sub, &browser->dir); zr_style_pop_property(&browser->config); } zr_end(&context, &browser->window); return 1; }