Begin move handling. Currently only moves the drop target indicator during drags. Nothing actually gets moved.

This commit is contained in:
Michael Drake 2013-08-16 20:06:08 +01:00
parent 7169b2fb01
commit a9cad3cfa8
1 changed files with 175 additions and 8 deletions

View File

@ -37,6 +37,7 @@ struct treeview_globals {
int step_width;
int window_padding;
int icon_step;
int move_offset;
} tree_g;
enum treeview_node_part {
@ -62,7 +63,6 @@ enum treeview_node_flags {
TREE_NODE_NONE = 0, /**< No node flags set */
TREE_NODE_EXPANDED = (1 << 0), /**< Whether node is expanded */
TREE_NODE_SELECTED = (1 << 1) /**< Whether node is selected */
};
struct treeview_node {
@ -119,7 +119,15 @@ struct treeview {
int n_fields; /**< fields[n_fields] is folder, lower are entry fields */
int field_width; /**< Max width of shown field names */
struct treeview_drag drag; /**< Drag state */
struct treeview_drag drag; /**< Drag state */
treeview_node *target; /**< Move target */
treeview_node *target_display; /**< Target indicator render node */
enum {
TV_TARGET_ABOVE,
TV_TARGET_INSIDE,
TV_TARGET_BELOW,
TV_TARGET_NONE
} target_pos; /**< Drag type */
const struct treeview_callback_table *callbacks; /**< For node events */
@ -465,6 +473,43 @@ nserror treeview_create_node_entry(treeview *tree,
}
/* Find the next node in depth first tree order
*
* \param node Start node
* \param full Iff true, visit children of collapsed nodes
* \param next Updated to next node, or NULL if 'node' is last node
* \return NSERROR_OK on success, or appropriate error otherwise
*/
static inline treeview_node * treeview_node_next(treeview_node *node, bool full)
{
assert(node != NULL);
if ((full || (node->flags & TREE_NODE_EXPANDED)) &&
node->children != NULL) {
/* Next node is child */
node = node->children;
} 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 != NULL && node->type != TREE_NODE_ROOT &&
node->sibling_next == NULL) {
node = node->parent;
}
if (node->type == TREE_NODE_ROOT) {
node = NULL;
} else if (node != NULL) {
node = node->sibling_next;
}
}
return node;
}
/* Walk a treeview subtree, calling a callback at each node (depth first)
*
* \param root Root to walk tree from (doesn't get a callback call)
@ -896,6 +941,10 @@ nserror treeview_create(treeview **tree,
(*tree)->drag.prev.node_y = 0;
(*tree)->drag.prev.node_h = 0;
(*tree)->target = NULL;
(*tree)->target_display = NULL;
(*tree)->target_pos = TV_TARGET_NONE;
(*tree)->flags = flags;
(*tree)->cw_t = cw_t;
@ -1222,6 +1271,23 @@ void treeview_redraw(treeview *tree, int x, int y, struct rect *clip,
node->text.value.data, node->text.value.len,
text_style);
/* Render move indicator arrow */
if (tree->target_display == node &&
treeview_res[TREE_RES_ARROW].ready) {
assert(tree->target != NULL);
data.x = tree->target->inset + tree_g.move_offset;
data.y = render_y + ((tree_g.line_height -
treeview_res[res].height + 1) / 2);
data.background_colour = bg_style->fill_colour;
if (tree->target_pos != TV_TARGET_INSIDE) {
data.y -= (tree_g.line_height + 1) / 2;
}
content_redraw(treeview_res[TREE_RES_ARROW].c,
&data, &r, &new_ctx);
}
/* Rendered the node */
render_y += tree_g.line_height;
if (render_y > r.y1) {
@ -1467,6 +1533,18 @@ static void treeview_commit_selection_drag(treeview *tree)
}
/**
* Move a selection according to the current move drag.
*
* \param tree Treeview object to move selected nodes in
*/
static nserror treeview_move_selection(treeview *tree)
{
/* TODO */
return NSERROR_OK;
}
/**
* Delete a selection.
*
@ -1703,6 +1781,66 @@ static bool treeview_keyboard_navigation(treeview *tree, uint32_t key,
}
/**
* Set the drag&drop drop indicator
*
* \param tree Treeview object to set node indicator in
* \param mouse The current mouse state
* \param node The treeview node with mouse pointer over it
* \param node_height The height of node
* \param mouse_pos Distanct in px from top of node to mouse pos
* \param rect Redraw rectangle (if redraw required)
* \return true iff redraw required
*/
static bool treeview_set_move_indicator(treeview *tree,
browser_mouse_state mouse, treeview_node *node,
int node_height, int mouse_pos, struct rect *rect)
{
switch (node->type) {
case TREE_NODE_FOLDER:
if (mouse_pos <= node_height / 4) {
tree->target = node;
tree->target_display = node;
tree->target_pos = TV_TARGET_ABOVE;
} else if (mouse_pos <= (3 * node_height) / 4 ||
node->flags & TREE_NODE_EXPANDED) {
tree->target = node;
tree->target_display = node;
tree->target_pos = TV_TARGET_INSIDE;
} else {
tree->target = node;
tree->target_display = treeview_node_next(node, false);
tree->target_pos = TV_TARGET_BELOW;
}
break;
case TREE_NODE_ENTRY:
if (mouse_pos <= node_height / 2) {
tree->target = node;
tree->target_display = node;
tree->target_pos = TV_TARGET_ABOVE;
} else {
tree->target = node;
tree->target_display = treeview_node_next(node, false);
tree->target_pos = TV_TARGET_BELOW;
}
break;
default:
assert(node->type != TREE_NODE_ROOT);
return false;
}
/* TODO: proper values */
rect->x0 = 0;
rect->y0 = 0;
rect->x1 = 9000;
rect->y1 = 9000;
return true;
}
/* Exported interface, documented in treeview.h */
bool treeview_keypress(treeview *tree, uint32_t key)
{
@ -1868,12 +2006,19 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
if (ma->tree->drag.type == TV_DRAG_NONE) {
if (ma->mouse & BROWSER_MOUSE_DRAG_1 &&
ma->tree->drag.selected == false &&
ma->tree->drag.part ==
TV_NODE_PART_NONE) {
ma->tree->drag.part == TV_NODE_PART_NONE) {
ma->tree->drag.type = TV_DRAG_SELECTION;
ma->tree->cw_t->drag_status(ma->tree->cw_h,
CORE_WINDOW_DRAG_SELECTION);
} else if (!(ma->tree->flags & TREEVIEW_NO_MOVES) &&
ma->mouse & BROWSER_MOUSE_DRAG_1 &&
(ma->tree->drag.selected == true ||
ma->tree->drag.part == TV_NODE_PART_ON_NODE)) {
ma->tree->drag.type = TV_DRAG_MOVE;
ma->tree->cw_t->drag_status(ma->tree->cw_h,
CORE_WINDOW_DRAG_MOVE);
} else if (ma->mouse & BROWSER_MOUSE_DRAG_2) {
ma->tree->drag.type = TV_DRAG_SELECTION;
ma->tree->cw_t->drag_status(ma->tree->cw_h,
@ -1886,8 +2031,10 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
}
}
/* Handle selection drags */
if (ma->tree->drag.type == TV_DRAG_SELECTION) {
/* Handle active drags */
switch (ma->tree->drag.type) {
case TV_DRAG_SELECTION:
{
int curr_y1 = ma->current_y + height;
int prev_y1 = ma->tree->drag.prev.node_y +
ma->tree->drag.prev.node_h;
@ -1903,6 +2050,16 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
ma->tree->drag.prev.node_y = ma->current_y;
ma->tree->drag.prev.node_h = height;
}
break;
case TV_DRAG_MOVE:
redraw |= treeview_set_move_indicator(ma->tree, ma->mouse,
node, height, ma->y - ma->current_y, &r);
break;
default:
break;
}
click = ma->mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2);
@ -2001,8 +2158,17 @@ void treeview_mouse_action(treeview *tree,
CORE_WINDOW_DRAG_NONE);
return;
case TV_DRAG_MOVE:
/* TODO */
break;
treeview_move_selection(tree);
tree->drag.type = TV_DRAG_NONE;
tree->drag.start_node = NULL;
tree->target = NULL;
tree->target_display = NULL;
tree->target_pos = TV_TARGET_NONE;
tree->cw_t->drag_status(tree->cw_h,
CORE_WINDOW_DRAG_NONE);
return;
default:
/* No drag to end */
break;
@ -2238,6 +2404,7 @@ nserror treeview_init(void)
tree_g.step_width = tree_g.furniture_width;
tree_g.window_padding = 6;
tree_g.icon_step = 23;
tree_g.move_offset = 18;
return NSERROR_OK;
}