Example #1
0
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);
}
Example #2
0
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;
}