mirror of
https://github.com/netsurf-browser/netsurf
synced 2025-01-02 01:04:33 +03:00
Treeview: Update treeview walker to handle walking the filtered display.
This commit is contained in:
parent
f142b3684c
commit
283fb36339
@ -552,11 +552,36 @@ static int treeview_node_y(treeview *tree, treeview_node *node)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The treeview walk mode. Controls which nodes are visited in a walk.
|
||||
*/
|
||||
enum treeview_walk_mode {
|
||||
/**
|
||||
* Walk to all nodes in the (sub)tree.
|
||||
*/
|
||||
TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
|
||||
|
||||
/**
|
||||
* Walk to expanded nodes in the (sub)tree only. Children of
|
||||
* collapsed nodes are not visited.
|
||||
*/
|
||||
TREEVIEW_WALK_MODE_LOGICAL_EXPANDED,
|
||||
|
||||
/**
|
||||
* Walk displayed nodes. This differs from the
|
||||
* `TREEVIEW_WALK_MODE_LOGICAL_EXPANDED` mode when there is
|
||||
* an active search filter display.
|
||||
*/
|
||||
TREEVIEW_WALK_MODE_DISPLAY,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Walk a treeview subtree, calling a callback at each node (depth first)
|
||||
*
|
||||
* \param tree Treeview being walked.
|
||||
* \param root Root to walk tree from (doesn't get a callback call)
|
||||
* \param full Iff true, visit children of collapsed nodes
|
||||
* \param mode The treeview walk mode to use.
|
||||
* \param callback_bwd Function to call on each node in backwards order
|
||||
* \param callback_fwd Function to call on each node in forwards order
|
||||
* \param ctx Context to pass to callback
|
||||
@ -564,20 +589,37 @@ static int treeview_node_y(treeview *tree, treeview_node *node)
|
||||
*
|
||||
* \note Any node deletion must happen in callback_bwd.
|
||||
*/
|
||||
static nserror
|
||||
treeview_walk_internal(treeview_node *root,
|
||||
bool full,
|
||||
nserror (*callback_bwd)(treeview_node *n, void *ctx, bool *end),
|
||||
nserror (*callback_fwd)(treeview_node *n, void *ctx, bool *skip_children, bool *end),
|
||||
void *ctx)
|
||||
static nserror treeview_walk_internal(
|
||||
treeview *tree,
|
||||
treeview_node *root,
|
||||
enum treeview_walk_mode mode,
|
||||
nserror (*callback_bwd)(
|
||||
treeview_node *n,
|
||||
void *ctx,
|
||||
bool *end),
|
||||
nserror (*callback_fwd)(
|
||||
treeview_node *n,
|
||||
void *ctx,
|
||||
bool *skip_children,
|
||||
bool *end),
|
||||
void *ctx)
|
||||
{
|
||||
treeview_node *node, *child, *parent, *next_sibling;
|
||||
bool abort = false;
|
||||
bool walking_search = (mode == TREEVIEW_WALK_MODE_DISPLAY &&
|
||||
tree->search.search == true);
|
||||
bool skip_children = false;
|
||||
bool abort = false;
|
||||
bool full = false;
|
||||
nserror err;
|
||||
bool entry;
|
||||
|
||||
assert(root != NULL);
|
||||
|
||||
if (mode == TREEVIEW_WALK_MODE_LOGICAL_COMPLETE || walking_search) {
|
||||
/* We need to visit children of collapsed folders. */
|
||||
full = true;
|
||||
}
|
||||
|
||||
node = root;
|
||||
parent = node->parent;
|
||||
next_sibling = node->next_sib;
|
||||
@ -594,9 +636,10 @@ treeview_walk_internal(treeview_node *root,
|
||||
* go to next sibling if present, or nearest ancestor
|
||||
* with a next sibling. */
|
||||
|
||||
while (node != root &&
|
||||
next_sibling == NULL) {
|
||||
if (callback_bwd != NULL) {
|
||||
while (node != root && next_sibling == NULL) {
|
||||
entry = (node->type == TREE_NODE_ENTRY);
|
||||
if (callback_bwd != NULL &&
|
||||
(entry || !walking_search)) {
|
||||
/* Backwards callback */
|
||||
err = callback_bwd(node, ctx, &abort);
|
||||
|
||||
@ -636,11 +679,18 @@ treeview_walk_internal(treeview_node *root,
|
||||
assert(node != NULL);
|
||||
assert(node != root);
|
||||
|
||||
entry = (node->type == TREE_NODE_ENTRY);
|
||||
|
||||
parent = node->parent;
|
||||
next_sibling = node->next_sib;
|
||||
child = (full || (node->flags & TV_NFLAGS_EXPANDED)) ?
|
||||
node->children : NULL;
|
||||
|
||||
if (walking_search && (!entry ||
|
||||
!(node->flags & TV_NFLAGS_MATCHED))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (callback_fwd != NULL) {
|
||||
/* Forwards callback */
|
||||
err = callback_fwd(node, ctx, &skip_children, &abort);
|
||||
@ -723,14 +773,17 @@ treeview_set_inset_from_parent(treeview_node *n,
|
||||
/**
|
||||
* Insert a treeview node into a treeview
|
||||
*
|
||||
* \param a parentless node to insert
|
||||
* \param b tree node to insert a as a relation of
|
||||
* \param tree the treeview to insert node into.
|
||||
* \param a parentless node to insert
|
||||
* \param b tree node to insert a as a relation of
|
||||
* \param rel The relationship between \a a and \a b
|
||||
*/
|
||||
static inline void
|
||||
treeview_insert_node(treeview_node *a,
|
||||
treeview_node *b,
|
||||
enum treeview_relationship rel)
|
||||
treeview_insert_node(
|
||||
treeview *tree,
|
||||
treeview_node *a,
|
||||
treeview_node *b,
|
||||
enum treeview_relationship rel)
|
||||
{
|
||||
assert(a != NULL);
|
||||
assert(a->parent == NULL);
|
||||
@ -765,8 +818,9 @@ treeview_insert_node(treeview_node *a,
|
||||
|
||||
a->inset = a->parent->inset + tree_g.step_width;
|
||||
if (a->children != NULL) {
|
||||
treeview_walk_internal(a, true, NULL,
|
||||
treeview_set_inset_from_parent, NULL);
|
||||
treeview_walk_internal(tree, a,
|
||||
TREEVIEW_WALK_MODE_LOGICAL_COMPLETE, NULL,
|
||||
treeview_set_inset_from_parent, NULL);
|
||||
}
|
||||
|
||||
if (a->parent->flags & TV_NFLAGS_EXPANDED) {
|
||||
@ -831,7 +885,7 @@ treeview_create_node_folder(treeview *tree,
|
||||
|
||||
n->client_data = data;
|
||||
|
||||
treeview_insert_node(n, relation, rel);
|
||||
treeview_insert_node(tree, n, relation, rel);
|
||||
|
||||
if (n->parent->flags & TV_NFLAGS_EXPANDED) {
|
||||
/* Inform front end of change in dimensions */
|
||||
@ -1041,7 +1095,7 @@ treeview_create_node_entry(treeview *tree,
|
||||
e->fields[i - 1].value.width = 0;
|
||||
}
|
||||
|
||||
treeview_insert_node(n, relation, rel);
|
||||
treeview_insert_node(tree, n, relation, rel);
|
||||
|
||||
if (n->parent->flags & TV_NFLAGS_EXPANDED) {
|
||||
/* Inform front end of change in dimensions */
|
||||
@ -1142,7 +1196,8 @@ treeview_walk(treeview *tree,
|
||||
if (root == NULL)
|
||||
root = tree->root;
|
||||
|
||||
return treeview_walk_internal(root, true,
|
||||
return treeview_walk_internal(tree, root,
|
||||
TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
|
||||
(leave_cb != NULL) ? treeview_walk_bwd_cb : NULL,
|
||||
(enter_cb != NULL) ? treeview_walk_fwd_cb : NULL,
|
||||
&tw);
|
||||
@ -1370,8 +1425,9 @@ treeview_delete_node_internal(treeview *tree,
|
||||
}
|
||||
|
||||
/* Delete any children first */
|
||||
err = treeview_walk_internal(n, true, treeview_delete_node_walk_cb,
|
||||
NULL, &nd);
|
||||
err = treeview_walk_internal(tree, n,
|
||||
TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
|
||||
treeview_delete_node_walk_cb, NULL, &nd);
|
||||
if (err != NSERROR_OK) {
|
||||
return err;
|
||||
}
|
||||
@ -1702,7 +1758,8 @@ static nserror treeview__search(
|
||||
|
||||
assert(text[len] == '\0');
|
||||
|
||||
err = treeview_walk_internal(tree->root, true, NULL,
|
||||
err = treeview_walk_internal(tree, tree->root,
|
||||
TREEVIEW_WALK_MODE_LOGICAL_COMPLETE, NULL,
|
||||
treeview__search_walk_cb, &sw);
|
||||
if (err != NSERROR_OK) {
|
||||
return err;
|
||||
@ -2129,8 +2186,8 @@ treeview_node_contract_internal(treeview *tree, treeview_node *node)
|
||||
selected = node->flags & TV_NFLAGS_SELECTED;
|
||||
|
||||
/* Contract children. */
|
||||
treeview_walk_internal(node, false, treeview_node_contract_cb,
|
||||
NULL, &data);
|
||||
treeview_walk_internal(tree, node, TREEVIEW_WALK_MODE_LOGICAL_EXPANDED,
|
||||
treeview_node_contract_cb, NULL, &data);
|
||||
|
||||
/* Contract node */
|
||||
treeview_node_contract_cb(node, &data, false);
|
||||
@ -2194,8 +2251,9 @@ nserror treeview_contract(treeview *tree, bool all)
|
||||
selected = n->flags & TV_NFLAGS_SELECTED;
|
||||
|
||||
/* Contract children. */
|
||||
treeview_walk_internal(n, false,
|
||||
treeview_node_contract_cb, NULL, &data);
|
||||
treeview_walk_internal(tree, n,
|
||||
TREEVIEW_WALK_MODE_LOGICAL_EXPANDED,
|
||||
treeview_node_contract_cb, NULL, &data);
|
||||
|
||||
/* Contract node */
|
||||
treeview_node_contract_cb(n, &data, false);
|
||||
@ -2269,11 +2327,9 @@ nserror treeview_expand(treeview *tree, bool only_folders)
|
||||
data.tree = tree;
|
||||
data.only_folders = only_folders;
|
||||
|
||||
res = treeview_walk_internal(tree->root,
|
||||
true,
|
||||
NULL,
|
||||
treeview_expand_cb,
|
||||
&data);
|
||||
res = treeview_walk_internal(tree, tree->root,
|
||||
TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
|
||||
NULL, treeview_expand_cb, &data);
|
||||
if (res == NSERROR_OK) {
|
||||
/* expansion succeeded, schedule redraw */
|
||||
|
||||
@ -3062,8 +3118,9 @@ bool treeview_has_selection(treeview *tree)
|
||||
sw.purpose = TREEVIEW_WALK_HAS_SELECTION;
|
||||
sw.data.has_selection = false;
|
||||
|
||||
treeview_walk_internal(tree->root, false, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
treeview_walk_internal(tree, tree->root,
|
||||
TREEVIEW_WALK_MODE_DISPLAY, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
|
||||
return sw.data.has_selection;
|
||||
}
|
||||
@ -3082,8 +3139,9 @@ static treeview_node * treeview_get_first_selected(treeview *tree)
|
||||
sw.purpose = TREEVIEW_WALK_GET_FIRST_SELECTED;
|
||||
sw.data.first.n = NULL;
|
||||
|
||||
treeview_walk_internal(tree->root, false, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
treeview_walk_internal(tree, tree->root,
|
||||
TREEVIEW_WALK_MODE_DISPLAY, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
|
||||
return sw.data.first.n;
|
||||
}
|
||||
@ -3131,8 +3189,9 @@ static bool treeview_clear_selection(treeview *tree, struct rect *rect)
|
||||
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);
|
||||
treeview_walk_internal(tree, tree->root,
|
||||
TREEVIEW_WALK_MODE_DISPLAY, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
|
||||
return sw.data.redraw.required;
|
||||
}
|
||||
@ -3160,8 +3219,9 @@ static bool treeview_select_all(treeview *tree, struct rect *rect)
|
||||
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);
|
||||
treeview_walk_internal(tree, tree->root,
|
||||
TREEVIEW_WALK_MODE_DISPLAY, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
|
||||
return sw.data.redraw.required;
|
||||
}
|
||||
@ -3188,8 +3248,9 @@ static void treeview_commit_selection_drag(treeview *tree)
|
||||
sw.data.drag.sel_max = tree->drag.prev.y;
|
||||
}
|
||||
|
||||
treeview_walk_internal(tree->root, false, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
treeview_walk_internal(tree, tree->root,
|
||||
TREEVIEW_WALK_MODE_DISPLAY, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
}
|
||||
|
||||
|
||||
@ -3206,8 +3267,9 @@ static void treeview_move_yank_selection(treeview *tree)
|
||||
sw.data.yank.prev = NULL;
|
||||
sw.tree = tree;
|
||||
|
||||
treeview_walk_internal(tree->root, false, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
treeview_walk_internal(tree, tree->root,
|
||||
TREEVIEW_WALK_MODE_DISPLAY, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
}
|
||||
|
||||
|
||||
@ -3226,8 +3288,9 @@ static void treeview_copy_selection(treeview *tree)
|
||||
sw.data.copy.len = 0;
|
||||
sw.tree = tree;
|
||||
|
||||
err = treeview_walk_internal(tree->root, false, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
err = treeview_walk_internal(tree, tree->root,
|
||||
TREEVIEW_WALK_MODE_DISPLAY, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
if (err != NSERROR_OK) {
|
||||
return;
|
||||
}
|
||||
@ -3265,8 +3328,9 @@ static bool treeview_delete_selection(treeview *tree, struct rect *rect)
|
||||
sw.current_y = 0;
|
||||
sw.tree = tree;
|
||||
|
||||
treeview_walk_internal(tree->root, false, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
treeview_walk_internal(tree, tree->root,
|
||||
TREEVIEW_WALK_MODE_DISPLAY, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
|
||||
return sw.data.redraw.required;
|
||||
}
|
||||
@ -3297,8 +3361,9 @@ static bool treeview_propagate_selection(treeview *tree, struct rect *rect)
|
||||
sw.current_y = 0;
|
||||
sw.tree = tree;
|
||||
|
||||
treeview_walk_internal(tree->root, false, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
treeview_walk_internal(tree, tree->root,
|
||||
TREEVIEW_WALK_MODE_DISPLAY, NULL,
|
||||
treeview_node_selection_walk_cb, &sw);
|
||||
|
||||
return sw.data.redraw.required;
|
||||
}
|
||||
@ -3388,7 +3453,7 @@ static nserror treeview_move_selection(treeview *tree, struct rect *rect)
|
||||
node->flags &= ~TV_NFLAGS_SELECTED;
|
||||
}
|
||||
|
||||
treeview_insert_node(node, relation, relationship);
|
||||
treeview_insert_node(tree, node, relation, relationship);
|
||||
|
||||
relation = node;
|
||||
relationship = TREE_REL_NEXT_SIBLING;
|
||||
@ -3487,9 +3552,10 @@ static nserror treeview_launch_selection(treeview *tree)
|
||||
lw.selected_depth = 0;
|
||||
lw.tree = tree;
|
||||
|
||||
return treeview_walk_internal(tree->root, true,
|
||||
treeview_node_launch_walk_bwd_cb,
|
||||
treeview_node_launch_walk_fwd_cb, &lw);
|
||||
return treeview_walk_internal(tree, tree->root,
|
||||
TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
|
||||
treeview_node_launch_walk_bwd_cb,
|
||||
treeview_node_launch_walk_fwd_cb, &lw);
|
||||
}
|
||||
|
||||
|
||||
@ -3624,18 +3690,25 @@ treeview_keyboard_navigation(treeview *tree, uint32_t key, struct rect *rect)
|
||||
|
||||
/* Fill out the nav. state struct, by examining the current selection
|
||||
* state */
|
||||
treeview_walk_internal(tree->root, false, NULL,
|
||||
treeview_node_nav_cb, &ns);
|
||||
if (ns.next == NULL)
|
||||
ns.next = tree->root->children;
|
||||
if (ns.prev == NULL)
|
||||
ns.prev = ns.last;
|
||||
treeview_walk_internal(tree, tree->root,
|
||||
TREEVIEW_WALK_MODE_DISPLAY, NULL,
|
||||
treeview_node_nav_cb, &ns);
|
||||
|
||||
if (tree->search.search == false) {
|
||||
if (ns.next == NULL)
|
||||
ns.next = tree->root->children;
|
||||
if (ns.prev == NULL)
|
||||
ns.prev = ns.last;
|
||||
}
|
||||
|
||||
/* Clear any existing selection */
|
||||
redraw = treeview_clear_selection(tree, rect);
|
||||
|
||||
switch (key) {
|
||||
case NS_KEY_LEFT:
|
||||
if (tree->search.search == true) {
|
||||
break;
|
||||
}
|
||||
if (ns.curr != NULL &&
|
||||
ns.curr->parent != NULL &&
|
||||
ns.curr->parent->type != TREE_NODE_ROOT) {
|
||||
@ -4575,8 +4648,9 @@ treeview_mouse_action(treeview *tree, browser_mouse_state mouse, int x, int y)
|
||||
ma.y = y;
|
||||
ma.current_y = search_height;
|
||||
|
||||
treeview_walk_internal(tree->root, false, NULL,
|
||||
treeview_node_mouse_action_cb, &ma);
|
||||
treeview_walk_internal(tree, tree->root,
|
||||
TREEVIEW_WALK_MODE_DISPLAY, NULL,
|
||||
treeview_node_mouse_action_cb, &ma);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user