From c20ad212731526d46f872a8220c6a1f53696f7e1 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Sun, 10 Sep 2017 15:50:35 +0100 Subject: Treeview: Add support for rendering search filter matches as-you-type. --- desktop/treeview.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 230 insertions(+), 1 deletion(-) (limited to 'desktop/treeview.c') diff --git a/desktop/treeview.c b/desktop/treeview.c index 8b66730d5..85bc61d8e 100644 --- a/desktop/treeview.c +++ b/desktop/treeview.c @@ -2462,6 +2462,228 @@ static void treeview_redraw_tree( } +/** + * Draw a treeview normally, in tree mode. + * + * \param[in] tree The treeview we're rendering. + * \param[in] x X coordinate we're rendering the treeview at. + * \param[in] y Y coordinate we're rendering the treeview at. + * \param[in,out] render_y Current vertical position in tree, updated on exit. + * \param[in] r Clip rectangle. + * \param[in] data Redraw data for rendering contents. + * \param[in] ctx Current render context. + */ +static void treeview_redraw_search( + treeview *tree, + const int x, + const int y, + int *render_y_in_out, + struct rect *r, + struct content_redraw_data *data, + const struct redraw_context *ctx) +{ + struct treeview_node_style *style = &plot_style_odd; + enum treeview_resource_id res = TREE_RES_CONTENT; + int baseline = (tree_g.line_height * 3 + 2) / 4; + plot_font_style_t *infotext_style; + treeview_node *root = tree->root; + treeview_node *node = tree->root; + int render_y = *render_y_in_out; + plot_font_style_t *text_style; + plot_style_t *bg_style; + int sel_min, sel_max; + uint32_t count = 0; + struct rect rect; + int inset; + int x0; + + if (tree->drag.start.y > tree->drag.prev.y) { + sel_min = tree->drag.prev.y; + sel_max = tree->drag.start.y; + } else { + sel_min = tree->drag.start.y; + sel_max = tree->drag.prev.y; + } + + while (node != NULL) { + struct treeview_node_entry *entry; + struct bitmap *furniture; + bool invert_selection; + treeview_node *next; + int height; + int i; + + next = node->children; + + if (next != NULL) { + /* down to children */ + node = next; + } else { + /* No children. As long as we're not at the root, + * go to next sibling if present, or nearest ancestor + * with a next sibling. */ + + while (node != root && + node->next_sib == NULL) { + node = node->parent; + } + + if (node == root) + break; + + node = node->next_sib; + } + + assert(node != NULL); + assert(node != root); + assert(node->type == TREE_NODE_FOLDER || + node->type == TREE_NODE_ENTRY); + + if (node->type == TREE_NODE_FOLDER || + !(node->flags & TV_NFLAGS_MATCHED)) { + continue; + } + + count++; + inset = x + tree_g.window_padding; + height = tree_g.line_height; + + if ((render_y + height) < r->y0) { + /* This node's line is above clip region */ + render_y += height; + continue; + } + + style = (count & 0x1) ? &plot_style_odd : &plot_style_even; + if (tree->drag.type == TV_DRAG_SELECTION && + (render_y + height >= sel_min && + render_y < sel_max)) { + invert_selection = true; + } else { + invert_selection = false; + } + if ((node->flags & TV_NFLAGS_SELECTED && !invert_selection) || + (!(node->flags & TV_NFLAGS_SELECTED) && + invert_selection)) { + bg_style = &style->sbg; + text_style = &style->stext; + infotext_style = &style->sitext; + furniture = (node->flags & TV_NFLAGS_EXPANDED) ? + style->furn[TREE_FURN_CONTRACT].sel : + style->furn[TREE_FURN_EXPAND].sel; + } else { + bg_style = &style->bg; + text_style = &style->text; + infotext_style = &style->itext; + furniture = (node->flags & TV_NFLAGS_EXPANDED) ? + style->furn[TREE_FURN_CONTRACT].bmp : + style->furn[TREE_FURN_EXPAND].bmp; + } + + /* Render background */ + rect.x0 = r->x0; + rect.y0 = render_y; + rect.x1 = r->x1; + rect.y1 = render_y + height; + ctx->plot->rectangle(ctx, bg_style, &rect); + + /* Render toggle */ + ctx->plot->bitmap(ctx, + furniture, + inset, + render_y + tree_g.line_height / 4, + style->furn[TREE_FURN_EXPAND].size, + style->furn[TREE_FURN_EXPAND].size, + bg_style->fill_colour, + BITMAPF_NONE); + + /* Render icon */ + if (node->type == TREE_NODE_ENTRY) { + res = TREE_RES_CONTENT; + } else if (node->flags & TV_NFLAGS_SPECIAL) { + res = TREE_RES_FOLDER_SPECIAL; + } else { + res = TREE_RES_FOLDER; + } + + if (treeview_res[res].ready) { + /* Icon resource is available */ + data->x = inset + tree_g.step_width; + data->y = render_y + ((tree_g.line_height - + treeview_res[res].height + 1) / 2); + data->background_colour = bg_style->fill_colour; + + content_redraw(treeview_res[res].c, data, r, ctx); + } + + /* Render text */ + x0 = inset + tree_g.step_width + tree_g.icon_step; + ctx->plot->text(ctx, + text_style, + x0, render_y + baseline, + node->text.data, + node->text.len); + + /* Rendered the node */ + render_y += tree_g.line_height; + if (render_y > r->y1) { + /* Passed the bottom of what's in the clip region. + * Done. */ + break; + } + + + if (node->type != TREE_NODE_ENTRY || + !(node->flags & TV_NFLAGS_EXPANDED)) + /* Done everything for this node */ + continue; + + /* Render expanded entry fields */ + entry = (struct treeview_node_entry *)node; + for (i = 0; i < tree->n_fields - 1; i++) { + struct treeview_field *ef = &(tree->fields[i + 1]); + + if (ef->flags & TREE_FLAG_SHOW_NAME) { + int max_width = tree->field_width; + + ctx->plot->text(ctx, + infotext_style, + x0 + max_width - ef->value.width - tree_g.step_width, + render_y + baseline, + ef->value.data, + ef->value.len); + + ctx->plot->text(ctx, + infotext_style, + x0 + max_width, + render_y + baseline, + entry->fields[i].value.data, + entry->fields[i].value.len); + } else { + ctx->plot->text(ctx, + infotext_style, + x0, render_y + baseline, + entry->fields[i].value.data, + entry->fields[i].value.len); + } + + /* Rendered the expanded entry field */ + render_y += tree_g.line_height; + } + + /* Finished rendering expanded entry */ + + if (render_y > r->y1) { + /* Passed the bottom of what's in the clip region. + * Done. */ + break; + } + } + + *render_y_in_out = render_y; +} + + /* Exported interface, documented in treeview.h */ void treeview_redraw(treeview *tree, @@ -2533,7 +2755,14 @@ treeview_redraw(treeview *tree, render_y += tree_g.line_height; } - treeview_redraw_tree(tree, x, y, &render_y, &r, &data, &new_ctx); + /* Render the treeview data */ + if (tree->search.search == true) { + treeview_redraw_search(tree, x, y, + &render_y, &r, &data, &new_ctx); + } else { + treeview_redraw_tree(tree, x, y, + &render_y, &r, &data, &new_ctx); + } if (render_y < r.y1) { /* Fill the blank area at the bottom */ -- cgit v1.2.3