Gitweb links:
...log
http://git.netsurf-browser.org/netsurf.git/shortlog/c20ad212731526d46f872a8220c6a1f53696f7e1
...commit
http://git.netsurf-browser.org/netsurf.git/commit/c20ad212731526d46f872a8220c6a1f53696f7e1
...tree
http://git.netsurf-browser.org/netsurf.git/tree/c20ad212731526d46f872a8220c6a1f53696f7e1
The branch, master has been updated
via c20ad212731526d46f872a8220c6a1f53696f7e1 (commit)
via c478f35c81478e48d3a86ac57e7bb7c34a3ce107 (commit)
via f41f7486bae2162ec6f33c1cf5de344e812fef1a (commit)
via d627b930f2d70da0c6a8bd7481050a288db628c9 (commit)
via 50688cde51ae5f78af59a43d56ad687f62e9bfe5 (commit)
via 37127c4a52b6d85faef379ad6c6e07f63b1ccf46 (commit)
via 43cdd742212ae0b47080717bfab028b1c78fbebc (commit)
via 3a02a4ea484685e5fce9c6c77f521670959d926b (commit)
via adbcb7f1b904c1a725fab4be7323a350f9ce02a8 (commit)
via f877069399608c8805d871b0ff08852186467490 (commit)
via 3d2adf4330851a147763c9d853f00fc914f1b8f9 (commit)
via 1420d01a2190ef7a4d6ded135c59b697e44194b4 (commit)
via 521651ea5194ec1aac65d95c8e0bd33000b6bad9 (commit)
from 8123e65351788fa633962c4f5e1bb41f1ef346e2 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=c20ad212731526d46f872a8220c6a1f53696f7e1
commit c20ad212731526d46f872a8220c6a1f53696f7e1
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Treeview: Add support for rendering search filter matches as-you-type.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 8b66730..85bc61d 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 */
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=c478f35c81478e48d3a86ac57e7bb7c34a3ce107
commit c478f35c81478e48d3a86ac57e7bb7c34a3ce107
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Treeview: Split tree-style treeview rendering out into helper.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 46772c2..8b66730 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -2243,38 +2243,40 @@ nserror treeview_expand(treeview *tree, bool
only_folders)
}
-/* Exported interface, documented in treeview.h */
-void
-treeview_redraw(treeview *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_tree(
+ treeview *tree,
const int x,
const int y,
- struct rect *clip,
+ int *render_y_in_out,
+ struct rect *r,
+ struct content_redraw_data *data,
const struct redraw_context *ctx)
{
- struct redraw_context new_ctx = *ctx;
- treeview_node *node, *root, *next;
- struct treeview_node_entry *entry;
struct treeview_node_style *style = &plot_style_odd;
- struct content_redraw_data data;
- struct rect r;
- struct rect rect;
- uint32_t count = 0;
- int render_y = y;
- int inset;
- int x0;
- int baseline = (tree_g.line_height * 3 + 2) / 4;
enum treeview_resource_id res = TREE_RES_CONTENT;
- plot_style_t *bg_style;
- plot_font_style_t *text_style;
+ int baseline = (tree_g.line_height * 3 + 2) / 4;
plot_font_style_t *infotext_style;
- struct bitmap *furniture;
- int height;
+ 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;
- bool invert_selection;
-
- assert(tree != NULL);
- assert(tree->root != NULL);
- assert(tree->root->flags & TV_NFLAGS_EXPANDED);
+ 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;
@@ -2284,64 +2286,14 @@ treeview_redraw(treeview *tree,
sel_max = tree->drag.prev.y;
}
- /* Start knockout rendering if it's available for this plotter */
- if (ctx->plot->option_knockout) {
- knockout_plot_start(ctx, &new_ctx);
- }
-
- /* Set up clip rectangle */
- r.x0 = clip->x0 + x;
- r.y0 = clip->y0 + y;
- r.x1 = clip->x1 + x;
- r.y1 = clip->y1 + y;
- new_ctx.plot->clip(&new_ctx, &r);
-
- /* Draw the tree */
- node = root = tree->root;
-
- /* Setup common content redraw data */
- data.width = tree_g.icon_size;
- data.height = tree_g.icon_size;
- data.scale = 1;
- data.repeat_x = false;
- data.repeat_y = false;
-
- if (tree->flags & TREEVIEW_SEARCHABLE) {
- if (render_y < r.y1) {
- enum treeview_resource_id icon = TREE_RES_SEARCH;
-
- /* Fill the blank area at the bottom */
- rect.x0 = r.x0;
- rect.y0 = render_y;
- rect.x1 = r.x1;
- rect.y1 = render_y + tree_g.line_height;
- new_ctx.plot->rectangle(&new_ctx, &plot_style_even.bg,
- &rect);
-
- if (treeview_res[icon].ready) {
- /* Icon resource is available */
- data.x = tree_g.window_padding;
- data.y = render_y + ((tree_g.line_height -
- treeview_res[icon].height + 1) /
- 2);
- data.background_colour = plot_style_even.bg.
- fill_colour;
-
- content_redraw(treeview_res[icon].c,
- &data, &r, &new_ctx);
- }
-
- textarea_redraw(tree->search.textarea,
- x + tree_g.window_padding +
- tree_g.icon_step, y,
- plot_style_even.bg.fill_colour, 1.0,
- &r, &new_ctx);
- }
- render_y += tree_g.line_height;
- }
-
while (node != NULL) {
+ struct treeview_node_entry *entry;
+ struct bitmap *furniture;
+ bool invert_selection;
+ treeview_node *next;
+ int height;
int i;
+
next = (node->flags & TV_NFLAGS_EXPANDED) ?
node->children : NULL;
@@ -2374,7 +2326,7 @@ treeview_redraw(treeview *tree,
height = (node->type == TREE_NODE_ENTRY) ? node->height :
tree_g.line_height;
- if ((render_y + height) < r.y0) {
+ if ((render_y + height) < r->y0) {
/* This node's line is above clip region */
render_y += height;
continue;
@@ -2407,21 +2359,21 @@ treeview_redraw(treeview *tree,
}
/* Render background */
- rect.x0 = r.x0;
+ rect.x0 = r->x0;
rect.y0 = render_y;
- rect.x1 = r.x1;
+ rect.x1 = r->x1;
rect.y1 = render_y + height;
- new_ctx.plot->rectangle(&new_ctx, bg_style, &rect);
+ ctx->plot->rectangle(ctx, bg_style, &rect);
/* Render toggle */
- new_ctx.plot->bitmap(&new_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);
+ 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) {
@@ -2434,26 +2386,25 @@ treeview_redraw(treeview *tree,
if (treeview_res[res].ready) {
/* Icon resource is available */
- data.x = inset + tree_g.step_width;
- data.y = render_y + ((tree_g.line_height -
+ 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;
+ data->background_colour = bg_style->fill_colour;
- content_redraw(treeview_res[res].c,
- &data, &r, &new_ctx);
+ content_redraw(treeview_res[res].c, data, r, ctx);
}
/* Render text */
x0 = inset + tree_g.step_width + tree_g.icon_step;
- new_ctx.plot->text(&new_ctx,
- text_style,
- x0, render_y + baseline,
- node->text.data,
- node->text.len);
+ 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) {
+ if (render_y > r->y1) {
/* Passed the bottom of what's in the clip region.
* Done. */
break;
@@ -2473,25 +2424,25 @@ treeview_redraw(treeview *tree,
if (ef->flags & TREE_FLAG_SHOW_NAME) {
int max_width = tree->field_width;
- new_ctx.plot->text(&new_ctx,
- infotext_style,
- x0 + max_width -
ef->value.width - tree_g.step_width,
- render_y + baseline,
- ef->value.data,
- ef->value.len);
-
- new_ctx.plot->text(&new_ctx,
- infotext_style,
- x0 + max_width,
- render_y + baseline,
- entry->fields[i].value.data,
- entry->fields[i].value.len);
+ 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 {
- new_ctx.plot->text(&new_ctx,
- infotext_style,
- x0, render_y + baseline,
- entry->fields[i].value.data,
- entry->fields[i].value.len);
+ 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 */
@@ -2500,13 +2451,90 @@ treeview_redraw(treeview *tree,
/* Finished rendering expanded entry */
- if (render_y > r.y1) {
+ 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,
+ const int x,
+ const int y,
+ struct rect *clip,
+ const struct redraw_context *ctx)
+{
+ struct redraw_context new_ctx = *ctx;
+ struct content_redraw_data data;
+ struct rect r;
+ struct rect rect;
+ int render_y = y;
+
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+ assert(tree->root->flags & TV_NFLAGS_EXPANDED);
+
+ /* Start knockout rendering if it's available for this plotter */
+ if (ctx->plot->option_knockout) {
+ knockout_plot_start(ctx, &new_ctx);
+ }
+
+ /* Set up clip rectangle */
+ r.x0 = clip->x0 + x;
+ r.y0 = clip->y0 + y;
+ r.x1 = clip->x1 + x;
+ r.y1 = clip->y1 + y;
+ new_ctx.plot->clip(&new_ctx, &r);
+
+ /* Setup common content redraw data */
+ data.width = tree_g.icon_size;
+ data.height = tree_g.icon_size;
+ data.scale = 1;
+ data.repeat_x = false;
+ data.repeat_y = false;
+
+ if (tree->flags & TREEVIEW_SEARCHABLE) {
+ if (render_y < r.y1) {
+ enum treeview_resource_id icon = TREE_RES_SEARCH;
+
+ /* Fill the blank area at the bottom */
+ rect.x0 = r.x0;
+ rect.y0 = render_y;
+ rect.x1 = r.x1;
+ rect.y1 = render_y + tree_g.line_height;
+ new_ctx.plot->rectangle(&new_ctx, &plot_style_even.bg,
+ &rect);
+
+ if (treeview_res[icon].ready) {
+ /* Icon resource is available */
+ data.x = tree_g.window_padding;
+ data.y = render_y + ((tree_g.line_height -
+ treeview_res[icon].height + 1) /
+ 2);
+ data.background_colour = plot_style_even.bg.
+ fill_colour;
+
+ content_redraw(treeview_res[icon].c,
+ &data, &r, &new_ctx);
+ }
+
+ textarea_redraw(tree->search.textarea,
+ x + tree_g.window_padding +
+ tree_g.icon_step, y,
+ plot_style_even.bg.fill_colour, 1.0,
+ &r, &new_ctx);
+ }
+ render_y += tree_g.line_height;
+ }
+
+ treeview_redraw_tree(tree, x, y, &render_y, &r, &data, &new_ctx);
+
if (render_y < r.y1) {
/* Fill the blank area at the bottom */
rect.x0 = r.x0;
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=f41f7486bae2162ec6f33c1cf5de344e812fef1a
commit f41f7486bae2162ec6f33c1cf5de344e812fef1a
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Treeview: Add node matching to search text modification callback.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 765d927..46772c2 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -22,10 +22,13 @@
* Treeview handling implementation.
*/
+#include <string.h>
+
#include "utils/utils.h"
#include "utils/log.h"
#include "utils/nsurl.h"
#include "utils/nsoption.h"
+#include "utils/config.h"
#include "netsurf/bitmap.h"
#include "netsurf/content.h"
#include "netsurf/plotters.h"
@@ -104,7 +107,8 @@ enum treeview_node_flags {
TV_NFLAGS_NONE = 0, /**< No node flags set */
TV_NFLAGS_EXPANDED = (1 << 0), /**< Whether node is expanded */
TV_NFLAGS_SELECTED = (1 << 1), /**< Whether node is selected */
- TV_NFLAGS_SPECIAL = (1 << 2) /**< Render as special node */
+ TV_NFLAGS_SPECIAL = (1 << 2), /**< Render as special node */
+ TV_NFLAGS_MATCHED = (1 << 3), /**< Whether node matches search */
};
@@ -211,8 +215,9 @@ struct treeview_edit {
* Treeview search box details
*/
struct treeview_search {
- struct textarea *textarea; /**< Search box. Never NULL. */
- bool active; /**< Whether the search box is active */
+ struct textarea *textarea; /**< Search box. */
+ bool active; /**< Whether the search box has focus. */
+ bool search; /**< Whether we have a search term. */
};
@@ -1566,6 +1571,117 @@ static struct textarea *treeview__create_textarea(
/**
+ * Data used when doing a treeview walk for search.
+ */
+struct treeview_search_walk_data {
+ treeview *tree; /**< The treeview to search. */
+ const char *text; /**< The string being searched for. */
+ const unsigned int len; /**< Length of string being searched for. */
+ int window_height; /**< Accumulate height for matching entries. */
+};
+
+
+/**
+ * Treewalk node callback for handling search.
+ *
+ * \param[in] n Current node.
+ * \param[in] ctx Treeview search context.
+ * \param[in,out] skip_children Flag to allow children to be skipped.
+ * \param[in,out] end Flag to allow iteration to be finished early.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror treeview__search_walk_cb(
+ treeview_node *n,
+ void *ctx,
+ bool *skip_children,
+ bool *end)
+{
+ struct treeview_search_walk_data *sw = ctx;
+
+ if (n->type != TREE_NODE_ENTRY) {
+ return NSERROR_OK;
+ }
+
+ if (sw->len == 0) {
+ n->flags &= ~TV_NFLAGS_MATCHED;
+ } else {
+ struct treeview_node_entry *entry =
+ (struct treeview_node_entry *)n;
+ bool matched = false;
+
+
+ for (int i = 0; i < sw->tree->n_fields; i++) {
+ struct treeview_field *ef = &(sw->tree->fields[i + 1]);
+ if (ef->flags & TREE_FLAG_SEARCHABLE) {
+ if (strcasestr(entry->fields[i].value.data,
+ sw->text) != NULL) {
+ matched = true;
+ break;
+ }
+ }
+ }
+
+ if (!matched && strcasestr(n->text.data, sw->text) != NULL) {
+ matched = true;
+ }
+
+ if (matched) {
+ n->flags |= TV_NFLAGS_MATCHED;
+ sw->window_height += tree_g.line_height;
+ } else {
+ n->flags &= ~TV_NFLAGS_MATCHED;
+ }
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Search treeview for text.
+ *
+ * \param[in] tree Treeview to search.
+ * \param[in] text UTF-8 string to search for. (NULL-terminated.)
+ * \param[in] len Byte length of UTF-8 string.
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+static nserror treeview__search(
+ treeview *tree,
+ const char *text,
+ unsigned int len)
+{
+ nserror err;
+ uint32_t height;
+ struct treeview_search_walk_data sw = {
+ .len = len,
+ .text = text,
+ .tree = tree,
+ .window_height = 0,
+ };
+
+ assert(text[len] == '\0');
+
+ err = treeview_walk_internal(tree->root, true, NULL,
+ treeview__search_walk_cb, &sw);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ if (len > 0) {
+ tree->search.search = true;
+ height = sw.window_height;
+ } else {
+ tree->search.search = false;
+ height = tree->root->height;
+ }
+
+ treeview__cw_update_size(tree, -1, height);
+
+ return NSERROR_OK;
+}
+
+
+/**
* Callback for textarea_create, in desktop/treeview.h
*
* \param data treeview context
@@ -1577,6 +1693,10 @@ static void treeview_textarea_search_callback(void *data,
treeview *tree = data;
struct rect *r;
+ if (tree->search.active == false) {
+ return;
+ }
+
switch (msg->type) {
case TEXTAREA_MSG_DRAG_REPORT:
if (msg->data.drag == TEXTAREA_DRAG_NONE) {
@@ -1600,6 +1720,13 @@ static void treeview_textarea_search_callback(void *data,
cw_invalidate_area(tree, r);
break;
+ case TEXTAREA_MSG_TEXT_MODIFIED:
+ /* Textarea length includes trailing NULL, so subtract it. */
+ treeview__search(tree,
+ msg->data.modified.text,
+ msg->data.modified.len - 1);
+ break;
+
default:
break;
}
@@ -1701,6 +1828,7 @@ treeview_create(treeview **tree,
(*tree)->search.textarea = NULL;
}
(*tree)->search.active = false;
+ (*tree)->search.search = false;
(*tree)->flags = flags;
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=d627b930f2d70da0c6a8bd7481050a288db628c9
commit d627b930f2d70da0c6a8bd7481050a288db628c9
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Treeview: API: Allow treeview fields to be flagged searchable.
diff --git a/desktop/treeview.h b/desktop/treeview.h
index b9347d2..a8cf29a 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -114,11 +114,12 @@ struct treeview_node_msg {
* treeview field flags
*/
enum treeview_field_flags {
- TREE_FLAG_NONE = 0, /**< No flags set */
- TREE_FLAG_ALLOW_EDIT = (1 << 0), /**< Whether allow edit field */
- TREE_FLAG_DEFAULT = (1 << 1), /**< Whether field is default */
- TREE_FLAG_SHOW_NAME = (1 << 2), /**< Whether field name shown */
- TREE_FLAG_COPY_TEXT = (1 << 3) /**< Whether to copy to clipb */
+ TREE_FLAG_NONE = 0, /**< No flags set */
+ TREE_FLAG_ALLOW_EDIT = (1 << 0), /**< Whether allow edit field */
+ TREE_FLAG_DEFAULT = (1 << 1), /**< Whether field is default */
+ TREE_FLAG_SHOW_NAME = (1 << 2), /**< Whether field name shown */
+ TREE_FLAG_COPY_TEXT = (1 << 3), /**< Whether to copy to clipb */
+ TREE_FLAG_SEARCHABLE = (1 << 4), /**< Whether field is searchable */
};
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=50688cde51ae5f78af59a43d56ad687f62e9bfe5
commit 50688cde51ae5f78af59a43d56ad687f62e9bfe5
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Treeview: Improve some code wrapping.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 2779550..765d927 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -962,7 +962,7 @@ treeview_create_node_entry(treeview *tree,
}
e = malloc(sizeof(struct treeview_node_entry) +
- (tree->n_fields - 1) * sizeof(struct treeview_field));
+ (tree->n_fields - 1) * sizeof(struct treeview_field));
if (e == NULL) {
return NSERROR_NOMEM;
}
@@ -978,8 +978,8 @@ treeview_create_node_entry(treeview *tree,
assert(fields != NULL);
assert(fields[0].field != NULL);
assert(lwc_string_isequal(tree->fields[0].field,
- fields[0].field, &match) == lwc_error_ok &&
- match == true);
+ fields[0].field, &match) == lwc_error_ok &&
+ match == true);
n->text.data = fields[0].value;
n->text.len = fields[0].value_len;
n->text.width = 0;
@@ -994,8 +994,8 @@ treeview_create_node_entry(treeview *tree,
for (i = 1; i < tree->n_fields; i++) {
assert(fields[i].field != NULL);
assert(lwc_string_isequal(tree->fields[i].field,
- fields[i].field, &match) ==
lwc_error_ok &&
- match == true);
+ fields[i].field, &match) == lwc_error_ok &&
+ match == true);
e->fields[i - 1].value.data = fields[i].value;
e->fields[i - 1].value.len = fields[i].value_len;
@@ -1103,11 +1103,10 @@ treeview_walk(treeview *tree,
if (root == NULL)
root = tree->root;
- return treeview_walk_internal(root,
- true,
- (leave_cb != NULL) ? treeview_walk_bwd_cb
: NULL,
- (enter_cb != NULL) ? treeview_walk_fwd_cb
: NULL,
- &tw);
+ return treeview_walk_internal(root, true,
+ (leave_cb != NULL) ? treeview_walk_bwd_cb : NULL,
+ (enter_cb != NULL) ? treeview_walk_fwd_cb : NULL,
+ &tw);
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=37127c4a52b6d85faef379ad6c6e07f63b1ccf46
commit 37127c4a52b6d85faef379ad6c6e07f63b1ccf46
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Treeview: Ensure window extents take account of search bar presence.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index ba1056e..2779550 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -348,8 +348,12 @@ static inline void treeview__cw_update_size(
const struct treeview *tree,
int width, int height)
{
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
+
if (tree->cw_t != NULL) {
- tree->cw_t->update_size(tree->cw_h, width, height);
+ tree->cw_t->update_size(tree->cw_h, width,
+ height + search_height);
}
}
@@ -4151,12 +4155,15 @@ treeview_mouse_action(treeview *tree,
browser_mouse_state mouse, int x, int y)
/* Exported interface, documented in treeview.h */
int treeview_get_height(treeview *tree)
{
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
+
assert(tree != NULL);
assert(tree->root != NULL);
treeview__cw_update_size(tree, -1, tree->root->height);
- return tree->root->height;
+ return tree->root->height + search_height;
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=43cdd742212ae0b47080717bfab028b1c78fbebc
commit 43cdd742212ae0b47080717bfab028b1c78fbebc
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Treeview: Add keypress handling to the search bar.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index a460f4d..ba1056e 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -3281,7 +3281,7 @@ bool treeview_keypress(treeview *tree, uint32_t key)
assert(tree != NULL);
- /* Pass to textarea, if editing in progress */
+ /* Pass to any textarea, if editing in progress */
if (tree->edit.textarea != NULL) {
switch (key) {
case NS_KEY_ESCAPE:
@@ -3294,6 +3294,23 @@ bool treeview_keypress(treeview *tree, uint32_t key)
default:
return textarea_keypress(tree->edit.textarea, key);
}
+ } else if (tree->search.active == true) {
+ switch (key) {
+ case NS_KEY_ESCAPE:
+ textarea_set_text(tree->search.textarea, "");
+ textarea_set_caret(tree->search.textarea, 0);
+ r.x0 = tree_g.window_padding + tree_g.icon_size;
+ r.x1 = 600;
+ r.y0 = 0;
+ r.y1 = tree_g.line_height;
+ cw_invalidate_area(tree, &r);
+ return true;
+ case NS_KEY_NL:
+ case NS_KEY_CR:
+ return true;
+ default:
+ return textarea_keypress(tree->search.textarea, key);
+ }
}
/* Keypress to be handled by treeview */
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=3a02a4ea484685e5fce9c6c77f521670959d926b
commit 3a02a4ea484685e5fce9c6c77f521670959d926b
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Treeview: Handle mouse clicks on search bar.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 5c0d05c..a460f4d 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -3981,6 +3981,23 @@ treeview_mouse_action(treeview *tree,
browser_mouse_state mouse, int x, int y)
textarea_mouse_action(tree->edit.textarea, mouse,
x - tree->edit.x, y - tree->edit.y);
return;
+ } else if (tree->drag.type == TV_DRAG_SEARCH || y < search_height) {
+ if (tree->search.active == false) {
+ tree->search.active = true;
+ if (treeview_clear_selection(tree, &r)) {
+ cw_invalidate_area(tree, &r);
+ }
+ }
+ textarea_mouse_action(tree->search.textarea, mouse,
+ x - tree_g.window_padding - tree_g.icon_size,
+ y);
+ return;
+ } else if (mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2) &&
+ tree->search.active == true) {
+
+ tree->search.active = false;
+ textarea_set_caret(tree->search.textarea, -1);
+ return;
}
/* Handle textarea related mouse action */
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=adbcb7f1b904c1a725fab4be7323a350f9ce02a8
commit adbcb7f1b904c1a725fab4be7323a350f9ce02a8
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Treeview: Update treeview mouse handling to offset for search bar presence.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index acf49ce..5c0d05c 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -2695,7 +2695,8 @@ static bool treeview_clear_selection(treeview *tree,
struct rect *rect)
sw.purpose = TREEVIEW_WALK_CLEAR_SELECTION;
sw.data.redraw.required = false;
sw.data.redraw.rect = rect;
- sw.current_y = 0;
+ sw.current_y = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
treeview_walk_internal(tree->root, false, NULL,
treeview_node_selection_walk_cb, &sw);
@@ -2723,7 +2724,8 @@ static bool treeview_select_all(treeview *tree, struct
rect *rect)
sw.purpose = TREEVIEW_WALK_SELECT_ALL;
sw.data.redraw.required = false;
sw.data.redraw.rect = rect;
- sw.current_y = 0;
+ sw.current_y = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
treeview_walk_internal(tree->root, false, NULL,
treeview_node_selection_walk_cb, &sw);
@@ -2742,7 +2744,8 @@ static void treeview_commit_selection_drag(treeview *tree)
struct treeview_selection_walk_data sw;
sw.purpose = TREEVIEW_WALK_COMMIT_SELECT_DRAG;
- sw.current_y = 0;
+ sw.current_y = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
if (tree->drag.start.y > tree->drag.prev.y) {
sw.data.drag.sel_min = tree->drag.prev.y;
@@ -3967,6 +3970,8 @@ treeview_mouse_action(treeview *tree, browser_mouse_state
mouse, int x, int y)
{
struct rect r;
bool redraw = false;
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
assert(tree != NULL);
assert(tree->root != NULL);
@@ -4023,7 +4028,7 @@ treeview_mouse_action(treeview *tree, browser_mouse_state
mouse, int x, int y)
}
}
- if (y > tree->root->height) {
+ if (y > tree->root->height + search_height) {
/* Below tree */
r.x0 = 0;
@@ -4101,7 +4106,7 @@ treeview_mouse_action(treeview *tree, browser_mouse_state
mouse, int x, int y)
ma.mouse = mouse;
ma.x = x;
ma.y = y;
- ma.current_y = 0;
+ ma.current_y = search_height;
treeview_walk_internal(tree->root, false, NULL,
treeview_node_mouse_action_cb, &ma);
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=f877069399608c8805d871b0ff08852186467490
commit f877069399608c8805d871b0ff08852186467490
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Treeview: Add search bar rendering to redraw function.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index e41fdc4..acf49ce 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -2175,6 +2175,40 @@ treeview_redraw(treeview *tree,
data.repeat_x = false;
data.repeat_y = false;
+ if (tree->flags & TREEVIEW_SEARCHABLE) {
+ if (render_y < r.y1) {
+ enum treeview_resource_id icon = TREE_RES_SEARCH;
+
+ /* Fill the blank area at the bottom */
+ rect.x0 = r.x0;
+ rect.y0 = render_y;
+ rect.x1 = r.x1;
+ rect.y1 = render_y + tree_g.line_height;
+ new_ctx.plot->rectangle(&new_ctx, &plot_style_even.bg,
+ &rect);
+
+ if (treeview_res[icon].ready) {
+ /* Icon resource is available */
+ data.x = tree_g.window_padding;
+ data.y = render_y + ((tree_g.line_height -
+ treeview_res[icon].height + 1) /
+ 2);
+ data.background_colour = plot_style_even.bg.
+ fill_colour;
+
+ content_redraw(treeview_res[icon].c,
+ &data, &r, &new_ctx);
+ }
+
+ textarea_redraw(tree->search.textarea,
+ x + tree_g.window_padding +
+ tree_g.icon_step, y,
+ plot_style_even.bg.fill_colour, 1.0,
+ &r, &new_ctx);
+ }
+ render_y += tree_g.line_height;
+ }
+
while (node != NULL) {
int i;
next = (node->flags & TV_NFLAGS_EXPANDED) ?
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=3d2adf4330851a147763c9d853f00fc914f1b8f9
commit 3d2adf4330851a147763c9d853f00fc914f1b8f9
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Treeview: Create and destroy a textarea for search.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 8b7f8a7..e41fdc4 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -208,6 +208,15 @@ struct treeview_edit {
/**
+ * Treeview search box details
+ */
+struct treeview_search {
+ struct textarea *textarea; /**< Search box. Never NULL. */
+ bool active; /**< Whether the search box is active */
+};
+
+
+/**
* The treeview context
*/
struct treeview {
@@ -225,6 +234,8 @@ struct treeview {
struct treeview_move move; /**< Move drag details */
struct treeview_edit edit; /**< Edit details */
+ struct treeview_search search; /**< Treeview search box */
+
const struct treeview_callback_table *callbacks; /**< For node events */
const struct core_window_callback_table *cw_t; /**< Window cb table */
@@ -1504,6 +1515,94 @@ treeview_delete_node(treeview *tree,
}
+/**
+ * Helper to create a textarea.
+ *
+ * \param[in] tree The treeview we're creating the textarea for.
+ * \param[in] width The width of the textarea.
+ * \param[in] height The height of the textarea.
+ * \param[in] border The border colour to use.
+ * \param[in] background The background colour to use.
+ * \param[in] foreground The foreground colour to use.
+ * \param[in] text The text style to use for the text area.
+ * \param[in] ta_callback The textarea callback function to give the textarea.
+ * \return the textarea pointer on success, or NULL on failure.
+ */
+static struct textarea *treeview__create_textarea(
+ treeview *tree,
+ int width,
+ int height,
+ colour border,
+ colour background,
+ colour foreground,
+ plot_font_style_t text,
+ textarea_client_callback ta_callback)
+{
+ /* Configure the textarea */
+ textarea_flags ta_flags = TEXTAREA_INTERNAL_CARET;
+ textarea_setup ta_setup = {
+ .text = text,
+ .width = width,
+ .height = height,
+ .pad_top = 0,
+ .pad_left = 2,
+ .pad_right = 2,
+ .pad_bottom = 0,
+ .border_width = 1,
+ .border_col = border,
+ .selected_bg = foreground,
+ .selected_text = background,
+ };
+
+ ta_setup.text.foreground = foreground;
+ ta_setup.text.background = background;
+
+ /* Create text area */
+ return textarea_create(ta_flags, &ta_setup, ta_callback, tree);
+}
+
+
+/**
+ * Callback for textarea_create, in desktop/treeview.h
+ *
+ * \param data treeview context
+ * \param msg textarea message
+ */
+static void treeview_textarea_search_callback(void *data,
+ struct textarea_msg *msg)
+{
+ treeview *tree = data;
+ struct rect *r;
+
+ switch (msg->type) {
+ case TEXTAREA_MSG_DRAG_REPORT:
+ if (msg->data.drag == TEXTAREA_DRAG_NONE) {
+ /* Textarea drag finished */
+ tree->drag.type = TV_DRAG_NONE;
+ } else {
+ /* Textarea drag started */
+ tree->drag.type = TV_DRAG_SEARCH;
+ }
+ treeview__cw_drag_status(tree, tree->drag.type);
+ break;
+
+ case TEXTAREA_MSG_REDRAW_REQUEST:
+ r = &msg->data.redraw;
+ r->x0 += tree_g.window_padding + tree_g.icon_size;
+ r->y0 += 0;
+ r->x1 += 600;
+ r->y1 += tree_g.line_height;
+
+ /* Redraw the textarea */
+ cw_invalidate_area(tree, r);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
/* Exported interface, documented in treeview.h */
nserror
treeview_create(treeview **tree,
@@ -1583,6 +1682,23 @@ treeview_create(treeview **tree,
(*tree)->edit.textarea = NULL;
(*tree)->edit.node = NULL;
+ if (flags & TREEVIEW_SEARCHABLE) {
+ (*tree)->search.textarea = treeview__create_textarea(
+ *tree, 600, tree_g.line_height,
+ plot_style_even.text.background,
+ plot_style_even.text.background,
+ plot_style_even.text.foreground,
+ plot_style_odd.text,
+ treeview_textarea_search_callback);
+ if ((*tree)->search.textarea == NULL) {
+ treeview_destroy(*tree);
+ return NSERROR_NOMEM;
+ }
+ } else {
+ (*tree)->search.textarea = NULL;
+ }
+ (*tree)->search.active = false;
+
(*tree)->flags = flags;
(*tree)->cw_t = cw_t;
@@ -1640,6 +1756,10 @@ nserror treeview_destroy(treeview *tree)
}
free(tree->fields);
+ if (tree->search.textarea != NULL) {
+ textarea_destroy(tree->search.textarea);
+ }
+
/* Free treeview */
free(tree);
@@ -3369,47 +3489,6 @@ static void treeview_textarea_callback(void *data,
struct textarea_msg *msg)
/**
- * Helper to create a textarea.
- *
- * \param[in] tree The treeview we're creating the textarea for.
- * \param[in] width The width of the textarea.
- * \param[in] height The height of the textarea.
- * \param[in] text The text style to use for the text area.
- * \param[in] ta_callback The textarea callback function to give the textarea.
- * \return the textarea pointer on success, or NULL on failure.
- */
-static struct textarea *treeview_create_textarea(
- treeview *tree,
- int width,
- int height,
- plot_font_style_t text,
- textarea_client_callback ta_callback)
-{
- /* Configure the textarea */
- textarea_flags ta_flags = TEXTAREA_INTERNAL_CARET;
- textarea_setup ta_setup = {
- .text = text,
- .width = width,
- .height = height,
- .pad_top = 0,
- .pad_left = 2,
- .pad_right = 2,
- .pad_bottom = 0,
- .border_width = 1,
- .border_col = 0x000000,
- .selected_bg = 0x000000,
- .selected_text = 0xffffff,
- };
-
- ta_setup.text.foreground = 0x000000;
- ta_setup.text.background = 0xffffff;
-
- /* Create text area */
- return textarea_create(ta_flags, &ta_setup, ta_callback, tree);
-}
-
-
-/**
* Start edit of node field, at given y-coord, if editable
*
* \param tree Treeview object to consider editing in
@@ -3481,8 +3560,9 @@ treeview_edit_node_at_point(treeview *tree,
height = tree_g.line_height;
/* Create text area */
- tree->edit.textarea = treeview_create_textarea(tree, width, height,
- plot_style_odd.text, treeview_textarea_callback);
+ tree->edit.textarea = treeview__create_textarea(tree, width, height,
+ 0x000000, 0xffffff, 0x000000, plot_style_odd.text,
+ treeview_textarea_callback);
if (tree->edit.textarea == NULL) {
return false;
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=1420d01a2190ef7a4d6ded135c59b697e44194b4
commit 1420d01a2190ef7a4d6ded135c59b697e44194b4
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Treeview: Add search drag type to enumeration.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index df5c5e9..8b7f8a7 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -171,7 +171,8 @@ struct treeview_drag {
TV_DRAG_NONE,
TV_DRAG_SELECTION,
TV_DRAG_MOVE,
- TV_DRAG_TEXTAREA
+ TV_DRAG_TEXTAREA,
+ TV_DRAG_SEARCH,
} type; /**< Drag type */
treeview_node *start_node; /**< Start node */
bool selected; /**< Start node is selected */
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=521651ea5194ec1aac65d95c8e0bd33000b6bad9
commit 521651ea5194ec1aac65d95c8e0bd33000b6bad9
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Treeview: API: Add searchable flag for treeview creation.
diff --git a/desktop/treeview.h b/desktop/treeview.h
index 45469b7..b9347d2 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -76,7 +76,8 @@ typedef enum {
TREEVIEW_NO_MOVES = (1 << 0), /**< No node drags */
TREEVIEW_NO_DELETES = (1 << 1), /**< No node deletes */
TREEVIEW_READ_ONLY = TREEVIEW_NO_MOVES | TREEVIEW_NO_DELETES,
- TREEVIEW_DEL_EMPTY_DIRS = (1 << 2) /**< Delete dirs on empty */
+ TREEVIEW_DEL_EMPTY_DIRS = (1 << 2), /**< Delete dirs on empty */
+ TREEVIEW_SEARCHABLE = (1 << 3), /**< Treeview has search bar */
} treeview_flags;
/**
-----------------------------------------------------------------------
Summary of changes:
desktop/treeview.c | 847 ++++++++++++++++++++++++++++++++++++++++++----------
desktop/treeview.h | 14 +-
2 files changed, 704 insertions(+), 157 deletions(-)
diff --git a/desktop/treeview.c b/desktop/treeview.c
index df5c5e9..85bc61d 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -22,10 +22,13 @@
* Treeview handling implementation.
*/
+#include <string.h>
+
#include "utils/utils.h"
#include "utils/log.h"
#include "utils/nsurl.h"
#include "utils/nsoption.h"
+#include "utils/config.h"
#include "netsurf/bitmap.h"
#include "netsurf/content.h"
#include "netsurf/plotters.h"
@@ -104,7 +107,8 @@ enum treeview_node_flags {
TV_NFLAGS_NONE = 0, /**< No node flags set */
TV_NFLAGS_EXPANDED = (1 << 0), /**< Whether node is expanded */
TV_NFLAGS_SELECTED = (1 << 1), /**< Whether node is selected */
- TV_NFLAGS_SPECIAL = (1 << 2) /**< Render as special node */
+ TV_NFLAGS_SPECIAL = (1 << 2), /**< Render as special node */
+ TV_NFLAGS_MATCHED = (1 << 3), /**< Whether node matches search */
};
@@ -171,7 +175,8 @@ struct treeview_drag {
TV_DRAG_NONE,
TV_DRAG_SELECTION,
TV_DRAG_MOVE,
- TV_DRAG_TEXTAREA
+ TV_DRAG_TEXTAREA,
+ TV_DRAG_SEARCH,
} type; /**< Drag type */
treeview_node *start_node; /**< Start node */
bool selected; /**< Start node is selected */
@@ -207,6 +212,16 @@ struct treeview_edit {
/**
+ * Treeview search box details
+ */
+struct treeview_search {
+ struct textarea *textarea; /**< Search box. */
+ bool active; /**< Whether the search box has focus. */
+ bool search; /**< Whether we have a search term. */
+};
+
+
+/**
* The treeview context
*/
struct treeview {
@@ -224,6 +239,8 @@ struct treeview {
struct treeview_move move; /**< Move drag details */
struct treeview_edit edit; /**< Edit details */
+ struct treeview_search search; /**< Treeview search box */
+
const struct treeview_callback_table *callbacks; /**< For node events */
const struct core_window_callback_table *cw_t; /**< Window cb table */
@@ -336,8 +353,12 @@ static inline void treeview__cw_update_size(
const struct treeview *tree,
int width, int height)
{
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
+
if (tree->cw_t != NULL) {
- tree->cw_t->update_size(tree->cw_h, width, height);
+ tree->cw_t->update_size(tree->cw_h, width,
+ height + search_height);
}
}
@@ -946,7 +967,7 @@ treeview_create_node_entry(treeview *tree,
}
e = malloc(sizeof(struct treeview_node_entry) +
- (tree->n_fields - 1) * sizeof(struct treeview_field));
+ (tree->n_fields - 1) * sizeof(struct treeview_field));
if (e == NULL) {
return NSERROR_NOMEM;
}
@@ -962,8 +983,8 @@ treeview_create_node_entry(treeview *tree,
assert(fields != NULL);
assert(fields[0].field != NULL);
assert(lwc_string_isequal(tree->fields[0].field,
- fields[0].field, &match) == lwc_error_ok &&
- match == true);
+ fields[0].field, &match) == lwc_error_ok &&
+ match == true);
n->text.data = fields[0].value;
n->text.len = fields[0].value_len;
n->text.width = 0;
@@ -978,8 +999,8 @@ treeview_create_node_entry(treeview *tree,
for (i = 1; i < tree->n_fields; i++) {
assert(fields[i].field != NULL);
assert(lwc_string_isequal(tree->fields[i].field,
- fields[i].field, &match) ==
lwc_error_ok &&
- match == true);
+ fields[i].field, &match) == lwc_error_ok &&
+ match == true);
e->fields[i - 1].value.data = fields[i].value;
e->fields[i - 1].value.len = fields[i].value_len;
@@ -1087,11 +1108,10 @@ treeview_walk(treeview *tree,
if (root == NULL)
root = tree->root;
- return treeview_walk_internal(root,
- true,
- (leave_cb != NULL) ? treeview_walk_bwd_cb
: NULL,
- (enter_cb != NULL) ? treeview_walk_fwd_cb
: NULL,
- &tw);
+ return treeview_walk_internal(root, true,
+ (leave_cb != NULL) ? treeview_walk_bwd_cb : NULL,
+ (enter_cb != NULL) ? treeview_walk_fwd_cb : NULL,
+ &tw);
}
@@ -1503,6 +1523,216 @@ treeview_delete_node(treeview *tree,
}
+/**
+ * Helper to create a textarea.
+ *
+ * \param[in] tree The treeview we're creating the textarea for.
+ * \param[in] width The width of the textarea.
+ * \param[in] height The height of the textarea.
+ * \param[in] border The border colour to use.
+ * \param[in] background The background colour to use.
+ * \param[in] foreground The foreground colour to use.
+ * \param[in] text The text style to use for the text area.
+ * \param[in] ta_callback The textarea callback function to give the textarea.
+ * \return the textarea pointer on success, or NULL on failure.
+ */
+static struct textarea *treeview__create_textarea(
+ treeview *tree,
+ int width,
+ int height,
+ colour border,
+ colour background,
+ colour foreground,
+ plot_font_style_t text,
+ textarea_client_callback ta_callback)
+{
+ /* Configure the textarea */
+ textarea_flags ta_flags = TEXTAREA_INTERNAL_CARET;
+ textarea_setup ta_setup = {
+ .text = text,
+ .width = width,
+ .height = height,
+ .pad_top = 0,
+ .pad_left = 2,
+ .pad_right = 2,
+ .pad_bottom = 0,
+ .border_width = 1,
+ .border_col = border,
+ .selected_bg = foreground,
+ .selected_text = background,
+ };
+
+ ta_setup.text.foreground = foreground;
+ ta_setup.text.background = background;
+
+ /* Create text area */
+ return textarea_create(ta_flags, &ta_setup, ta_callback, tree);
+}
+
+
+/**
+ * Data used when doing a treeview walk for search.
+ */
+struct treeview_search_walk_data {
+ treeview *tree; /**< The treeview to search. */
+ const char *text; /**< The string being searched for. */
+ const unsigned int len; /**< Length of string being searched for. */
+ int window_height; /**< Accumulate height for matching entries. */
+};
+
+
+/**
+ * Treewalk node callback for handling search.
+ *
+ * \param[in] n Current node.
+ * \param[in] ctx Treeview search context.
+ * \param[in,out] skip_children Flag to allow children to be skipped.
+ * \param[in,out] end Flag to allow iteration to be finished early.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror treeview__search_walk_cb(
+ treeview_node *n,
+ void *ctx,
+ bool *skip_children,
+ bool *end)
+{
+ struct treeview_search_walk_data *sw = ctx;
+
+ if (n->type != TREE_NODE_ENTRY) {
+ return NSERROR_OK;
+ }
+
+ if (sw->len == 0) {
+ n->flags &= ~TV_NFLAGS_MATCHED;
+ } else {
+ struct treeview_node_entry *entry =
+ (struct treeview_node_entry *)n;
+ bool matched = false;
+
+
+ for (int i = 0; i < sw->tree->n_fields; i++) {
+ struct treeview_field *ef = &(sw->tree->fields[i + 1]);
+ if (ef->flags & TREE_FLAG_SEARCHABLE) {
+ if (strcasestr(entry->fields[i].value.data,
+ sw->text) != NULL) {
+ matched = true;
+ break;
+ }
+ }
+ }
+
+ if (!matched && strcasestr(n->text.data, sw->text) != NULL) {
+ matched = true;
+ }
+
+ if (matched) {
+ n->flags |= TV_NFLAGS_MATCHED;
+ sw->window_height += tree_g.line_height;
+ } else {
+ n->flags &= ~TV_NFLAGS_MATCHED;
+ }
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Search treeview for text.
+ *
+ * \param[in] tree Treeview to search.
+ * \param[in] text UTF-8 string to search for. (NULL-terminated.)
+ * \param[in] len Byte length of UTF-8 string.
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+static nserror treeview__search(
+ treeview *tree,
+ const char *text,
+ unsigned int len)
+{
+ nserror err;
+ uint32_t height;
+ struct treeview_search_walk_data sw = {
+ .len = len,
+ .text = text,
+ .tree = tree,
+ .window_height = 0,
+ };
+
+ assert(text[len] == '\0');
+
+ err = treeview_walk_internal(tree->root, true, NULL,
+ treeview__search_walk_cb, &sw);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ if (len > 0) {
+ tree->search.search = true;
+ height = sw.window_height;
+ } else {
+ tree->search.search = false;
+ height = tree->root->height;
+ }
+
+ treeview__cw_update_size(tree, -1, height);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Callback for textarea_create, in desktop/treeview.h
+ *
+ * \param data treeview context
+ * \param msg textarea message
+ */
+static void treeview_textarea_search_callback(void *data,
+ struct textarea_msg *msg)
+{
+ treeview *tree = data;
+ struct rect *r;
+
+ if (tree->search.active == false) {
+ return;
+ }
+
+ switch (msg->type) {
+ case TEXTAREA_MSG_DRAG_REPORT:
+ if (msg->data.drag == TEXTAREA_DRAG_NONE) {
+ /* Textarea drag finished */
+ tree->drag.type = TV_DRAG_NONE;
+ } else {
+ /* Textarea drag started */
+ tree->drag.type = TV_DRAG_SEARCH;
+ }
+ treeview__cw_drag_status(tree, tree->drag.type);
+ break;
+
+ case TEXTAREA_MSG_REDRAW_REQUEST:
+ r = &msg->data.redraw;
+ r->x0 += tree_g.window_padding + tree_g.icon_size;
+ r->y0 += 0;
+ r->x1 += 600;
+ r->y1 += tree_g.line_height;
+
+ /* Redraw the textarea */
+ cw_invalidate_area(tree, r);
+ break;
+
+ case TEXTAREA_MSG_TEXT_MODIFIED:
+ /* Textarea length includes trailing NULL, so subtract it. */
+ treeview__search(tree,
+ msg->data.modified.text,
+ msg->data.modified.len - 1);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
/* Exported interface, documented in treeview.h */
nserror
treeview_create(treeview **tree,
@@ -1582,6 +1812,24 @@ treeview_create(treeview **tree,
(*tree)->edit.textarea = NULL;
(*tree)->edit.node = NULL;
+ if (flags & TREEVIEW_SEARCHABLE) {
+ (*tree)->search.textarea = treeview__create_textarea(
+ *tree, 600, tree_g.line_height,
+ plot_style_even.text.background,
+ plot_style_even.text.background,
+ plot_style_even.text.foreground,
+ plot_style_odd.text,
+ treeview_textarea_search_callback);
+ if ((*tree)->search.textarea == NULL) {
+ treeview_destroy(*tree);
+ return NSERROR_NOMEM;
+ }
+ } else {
+ (*tree)->search.textarea = NULL;
+ }
+ (*tree)->search.active = false;
+ (*tree)->search.search = false;
+
(*tree)->flags = flags;
(*tree)->cw_t = cw_t;
@@ -1639,6 +1887,10 @@ nserror treeview_destroy(treeview *tree)
}
free(tree->fields);
+ if (tree->search.textarea != NULL) {
+ textarea_destroy(tree->search.textarea);
+ }
+
/* Free treeview */
free(tree);
@@ -1991,38 +2243,40 @@ nserror treeview_expand(treeview *tree, bool
only_folders)
}
-/* Exported interface, documented in treeview.h */
-void
-treeview_redraw(treeview *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_tree(
+ treeview *tree,
const int x,
const int y,
- struct rect *clip,
+ int *render_y_in_out,
+ struct rect *r,
+ struct content_redraw_data *data,
const struct redraw_context *ctx)
{
- struct redraw_context new_ctx = *ctx;
- treeview_node *node, *root, *next;
- struct treeview_node_entry *entry;
struct treeview_node_style *style = &plot_style_odd;
- struct content_redraw_data data;
- struct rect r;
- struct rect rect;
- uint32_t count = 0;
- int render_y = y;
- int inset;
- int x0;
- int baseline = (tree_g.line_height * 3 + 2) / 4;
enum treeview_resource_id res = TREE_RES_CONTENT;
- plot_style_t *bg_style;
- plot_font_style_t *text_style;
+ int baseline = (tree_g.line_height * 3 + 2) / 4;
plot_font_style_t *infotext_style;
- struct bitmap *furniture;
- int height;
+ 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;
- bool invert_selection;
-
- assert(tree != NULL);
- assert(tree->root != NULL);
- assert(tree->root->flags & TV_NFLAGS_EXPANDED);
+ 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;
@@ -2032,30 +2286,14 @@ treeview_redraw(treeview *tree,
sel_max = tree->drag.prev.y;
}
- /* Start knockout rendering if it's available for this plotter */
- if (ctx->plot->option_knockout) {
- knockout_plot_start(ctx, &new_ctx);
- }
-
- /* Set up clip rectangle */
- r.x0 = clip->x0 + x;
- r.y0 = clip->y0 + y;
- r.x1 = clip->x1 + x;
- r.y1 = clip->y1 + y;
- new_ctx.plot->clip(&new_ctx, &r);
-
- /* Draw the tree */
- node = root = tree->root;
-
- /* Setup common content redraw data */
- data.width = tree_g.icon_size;
- data.height = tree_g.icon_size;
- data.scale = 1;
- data.repeat_x = false;
- data.repeat_y = false;
-
while (node != NULL) {
+ struct treeview_node_entry *entry;
+ struct bitmap *furniture;
+ bool invert_selection;
+ treeview_node *next;
+ int height;
int i;
+
next = (node->flags & TV_NFLAGS_EXPANDED) ?
node->children : NULL;
@@ -2088,7 +2326,7 @@ treeview_redraw(treeview *tree,
height = (node->type == TREE_NODE_ENTRY) ? node->height :
tree_g.line_height;
- if ((render_y + height) < r.y0) {
+ if ((render_y + height) < r->y0) {
/* This node's line is above clip region */
render_y += height;
continue;
@@ -2121,21 +2359,243 @@ treeview_redraw(treeview *tree,
}
/* Render background */
- rect.x0 = r.x0;
+ rect.x0 = r->x0;
rect.y0 = render_y;
- rect.x1 = r.x1;
+ 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;
+}
+
+
+/**
+ * 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;
- new_ctx.plot->rectangle(&new_ctx, bg_style, &rect);
+ ctx->plot->rectangle(ctx, bg_style, &rect);
/* Render toggle */
- new_ctx.plot->bitmap(&new_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);
+ 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) {
@@ -2148,26 +2608,25 @@ treeview_redraw(treeview *tree,
if (treeview_res[res].ready) {
/* Icon resource is available */
- data.x = inset + tree_g.step_width;
- data.y = render_y + ((tree_g.line_height -
+ 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;
+ data->background_colour = bg_style->fill_colour;
- content_redraw(treeview_res[res].c,
- &data, &r, &new_ctx);
+ content_redraw(treeview_res[res].c, data, r, ctx);
}
/* Render text */
x0 = inset + tree_g.step_width + tree_g.icon_step;
- new_ctx.plot->text(&new_ctx,
- text_style,
- x0, render_y + baseline,
- node->text.data,
- node->text.len);
+ 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) {
+ if (render_y > r->y1) {
/* Passed the bottom of what's in the clip region.
* Done. */
break;
@@ -2187,25 +2646,25 @@ treeview_redraw(treeview *tree,
if (ef->flags & TREE_FLAG_SHOW_NAME) {
int max_width = tree->field_width;
- new_ctx.plot->text(&new_ctx,
- infotext_style,
- x0 + max_width -
ef->value.width - tree_g.step_width,
- render_y + baseline,
- ef->value.data,
- ef->value.len);
-
- new_ctx.plot->text(&new_ctx,
- infotext_style,
- x0 + max_width,
- render_y + baseline,
- entry->fields[i].value.data,
- entry->fields[i].value.len);
+ 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 {
- new_ctx.plot->text(&new_ctx,
- infotext_style,
- x0, render_y + baseline,
- entry->fields[i].value.data,
- entry->fields[i].value.len);
+ 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 */
@@ -2214,13 +2673,97 @@ treeview_redraw(treeview *tree,
/* Finished rendering expanded entry */
- if (render_y > r.y1) {
+ 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,
+ const int x,
+ const int y,
+ struct rect *clip,
+ const struct redraw_context *ctx)
+{
+ struct redraw_context new_ctx = *ctx;
+ struct content_redraw_data data;
+ struct rect r;
+ struct rect rect;
+ int render_y = y;
+
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+ assert(tree->root->flags & TV_NFLAGS_EXPANDED);
+
+ /* Start knockout rendering if it's available for this plotter */
+ if (ctx->plot->option_knockout) {
+ knockout_plot_start(ctx, &new_ctx);
+ }
+
+ /* Set up clip rectangle */
+ r.x0 = clip->x0 + x;
+ r.y0 = clip->y0 + y;
+ r.x1 = clip->x1 + x;
+ r.y1 = clip->y1 + y;
+ new_ctx.plot->clip(&new_ctx, &r);
+
+ /* Setup common content redraw data */
+ data.width = tree_g.icon_size;
+ data.height = tree_g.icon_size;
+ data.scale = 1;
+ data.repeat_x = false;
+ data.repeat_y = false;
+
+ if (tree->flags & TREEVIEW_SEARCHABLE) {
+ if (render_y < r.y1) {
+ enum treeview_resource_id icon = TREE_RES_SEARCH;
+
+ /* Fill the blank area at the bottom */
+ rect.x0 = r.x0;
+ rect.y0 = render_y;
+ rect.x1 = r.x1;
+ rect.y1 = render_y + tree_g.line_height;
+ new_ctx.plot->rectangle(&new_ctx, &plot_style_even.bg,
+ &rect);
+
+ if (treeview_res[icon].ready) {
+ /* Icon resource is available */
+ data.x = tree_g.window_padding;
+ data.y = render_y + ((tree_g.line_height -
+ treeview_res[icon].height + 1) /
+ 2);
+ data.background_colour = plot_style_even.bg.
+ fill_colour;
+
+ content_redraw(treeview_res[icon].c,
+ &data, &r, &new_ctx);
+ }
+
+ textarea_redraw(tree->search.textarea,
+ x + tree_g.window_padding +
+ tree_g.icon_step, y,
+ plot_style_even.bg.fill_colour, 1.0,
+ &r, &new_ctx);
+ }
+ render_y += tree_g.line_height;
+ }
+
+ /* 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 */
rect.x0 = r.x0;
@@ -2540,7 +3083,8 @@ static bool treeview_clear_selection(treeview *tree,
struct rect *rect)
sw.purpose = TREEVIEW_WALK_CLEAR_SELECTION;
sw.data.redraw.required = false;
sw.data.redraw.rect = rect;
- sw.current_y = 0;
+ sw.current_y = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
treeview_walk_internal(tree->root, false, NULL,
treeview_node_selection_walk_cb, &sw);
@@ -2568,7 +3112,8 @@ static bool treeview_select_all(treeview *tree, struct
rect *rect)
sw.purpose = TREEVIEW_WALK_SELECT_ALL;
sw.data.redraw.required = false;
sw.data.redraw.rect = rect;
- sw.current_y = 0;
+ sw.current_y = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
treeview_walk_internal(tree->root, false, NULL,
treeview_node_selection_walk_cb, &sw);
@@ -2587,7 +3132,8 @@ static void treeview_commit_selection_drag(treeview *tree)
struct treeview_selection_walk_data sw;
sw.purpose = TREEVIEW_WALK_COMMIT_SELECT_DRAG;
- sw.current_y = 0;
+ sw.current_y = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
if (tree->drag.start.y > tree->drag.prev.y) {
sw.data.drag.sel_min = tree->drag.prev.y;
@@ -3123,7 +3669,7 @@ bool treeview_keypress(treeview *tree, uint32_t key)
assert(tree != NULL);
- /* Pass to textarea, if editing in progress */
+ /* Pass to any textarea, if editing in progress */
if (tree->edit.textarea != NULL) {
switch (key) {
case NS_KEY_ESCAPE:
@@ -3136,6 +3682,23 @@ bool treeview_keypress(treeview *tree, uint32_t key)
default:
return textarea_keypress(tree->edit.textarea, key);
}
+ } else if (tree->search.active == true) {
+ switch (key) {
+ case NS_KEY_ESCAPE:
+ textarea_set_text(tree->search.textarea, "");
+ textarea_set_caret(tree->search.textarea, 0);
+ r.x0 = tree_g.window_padding + tree_g.icon_size;
+ r.x1 = 600;
+ r.y0 = 0;
+ r.y1 = tree_g.line_height;
+ cw_invalidate_area(tree, &r);
+ return true;
+ case NS_KEY_NL:
+ case NS_KEY_CR:
+ return true;
+ default:
+ return textarea_keypress(tree->search.textarea, key);
+ }
}
/* Keypress to be handled by treeview */
@@ -3368,47 +3931,6 @@ static void treeview_textarea_callback(void *data,
struct textarea_msg *msg)
/**
- * Helper to create a textarea.
- *
- * \param[in] tree The treeview we're creating the textarea for.
- * \param[in] width The width of the textarea.
- * \param[in] height The height of the textarea.
- * \param[in] text The text style to use for the text area.
- * \param[in] ta_callback The textarea callback function to give the textarea.
- * \return the textarea pointer on success, or NULL on failure.
- */
-static struct textarea *treeview_create_textarea(
- treeview *tree,
- int width,
- int height,
- plot_font_style_t text,
- textarea_client_callback ta_callback)
-{
- /* Configure the textarea */
- textarea_flags ta_flags = TEXTAREA_INTERNAL_CARET;
- textarea_setup ta_setup = {
- .text = text,
- .width = width,
- .height = height,
- .pad_top = 0,
- .pad_left = 2,
- .pad_right = 2,
- .pad_bottom = 0,
- .border_width = 1,
- .border_col = 0x000000,
- .selected_bg = 0x000000,
- .selected_text = 0xffffff,
- };
-
- ta_setup.text.foreground = 0x000000;
- ta_setup.text.background = 0xffffff;
-
- /* Create text area */
- return textarea_create(ta_flags, &ta_setup, ta_callback, tree);
-}
-
-
-/**
* Start edit of node field, at given y-coord, if editable
*
* \param tree Treeview object to consider editing in
@@ -3480,8 +4002,9 @@ treeview_edit_node_at_point(treeview *tree,
height = tree_g.line_height;
/* Create text area */
- tree->edit.textarea = treeview_create_textarea(tree, width, height,
- plot_style_odd.text, treeview_textarea_callback);
+ tree->edit.textarea = treeview__create_textarea(tree, width, height,
+ 0x000000, 0xffffff, 0x000000, plot_style_odd.text,
+ treeview_textarea_callback);
if (tree->edit.textarea == NULL) {
return false;
}
@@ -3852,6 +4375,8 @@ treeview_mouse_action(treeview *tree, browser_mouse_state
mouse, int x, int y)
{
struct rect r;
bool redraw = false;
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
assert(tree != NULL);
assert(tree->root != NULL);
@@ -3861,6 +4386,23 @@ treeview_mouse_action(treeview *tree,
browser_mouse_state mouse, int x, int y)
textarea_mouse_action(tree->edit.textarea, mouse,
x - tree->edit.x, y - tree->edit.y);
return;
+ } else if (tree->drag.type == TV_DRAG_SEARCH || y < search_height) {
+ if (tree->search.active == false) {
+ tree->search.active = true;
+ if (treeview_clear_selection(tree, &r)) {
+ cw_invalidate_area(tree, &r);
+ }
+ }
+ textarea_mouse_action(tree->search.textarea, mouse,
+ x - tree_g.window_padding - tree_g.icon_size,
+ y);
+ return;
+ } else if (mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2) &&
+ tree->search.active == true) {
+
+ tree->search.active = false;
+ textarea_set_caret(tree->search.textarea, -1);
+ return;
}
/* Handle textarea related mouse action */
@@ -3908,7 +4450,7 @@ treeview_mouse_action(treeview *tree, browser_mouse_state
mouse, int x, int y)
}
}
- if (y > tree->root->height) {
+ if (y > tree->root->height + search_height) {
/* Below tree */
r.x0 = 0;
@@ -3986,7 +4528,7 @@ treeview_mouse_action(treeview *tree, browser_mouse_state
mouse, int x, int y)
ma.mouse = mouse;
ma.x = x;
ma.y = y;
- ma.current_y = 0;
+ ma.current_y = search_height;
treeview_walk_internal(tree->root, false, NULL,
treeview_node_mouse_action_cb, &ma);
@@ -3997,12 +4539,15 @@ treeview_mouse_action(treeview *tree,
browser_mouse_state mouse, int x, int y)
/* Exported interface, documented in treeview.h */
int treeview_get_height(treeview *tree)
{
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
+
assert(tree != NULL);
assert(tree->root != NULL);
treeview__cw_update_size(tree, -1, tree->root->height);
- return tree->root->height;
+ return tree->root->height + search_height;
}
diff --git a/desktop/treeview.h b/desktop/treeview.h
index 45469b7..a8cf29a 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -76,7 +76,8 @@ typedef enum {
TREEVIEW_NO_MOVES = (1 << 0), /**< No node drags */
TREEVIEW_NO_DELETES = (1 << 1), /**< No node deletes */
TREEVIEW_READ_ONLY = TREEVIEW_NO_MOVES | TREEVIEW_NO_DELETES,
- TREEVIEW_DEL_EMPTY_DIRS = (1 << 2) /**< Delete dirs on empty */
+ TREEVIEW_DEL_EMPTY_DIRS = (1 << 2), /**< Delete dirs on empty */
+ TREEVIEW_SEARCHABLE = (1 << 3), /**< Treeview has search bar */
} treeview_flags;
/**
@@ -113,11 +114,12 @@ struct treeview_node_msg {
* treeview field flags
*/
enum treeview_field_flags {
- TREE_FLAG_NONE = 0, /**< No flags set */
- TREE_FLAG_ALLOW_EDIT = (1 << 0), /**< Whether allow edit field */
- TREE_FLAG_DEFAULT = (1 << 1), /**< Whether field is default */
- TREE_FLAG_SHOW_NAME = (1 << 2), /**< Whether field name shown */
- TREE_FLAG_COPY_TEXT = (1 << 3) /**< Whether to copy to clipb */
+ TREE_FLAG_NONE = 0, /**< No flags set */
+ TREE_FLAG_ALLOW_EDIT = (1 << 0), /**< Whether allow edit field */
+ TREE_FLAG_DEFAULT = (1 << 1), /**< Whether field is default */
+ TREE_FLAG_SHOW_NAME = (1 << 2), /**< Whether field name shown */
+ TREE_FLAG_COPY_TEXT = (1 << 3), /**< Whether to copy to clipb */
+ TREE_FLAG_SEARCHABLE = (1 << 4), /**< Whether field is searchable */
};
--
NetSurf Browser
_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org