Gitweb links:
...log
http://git.netsurf-browser.org/netsurf.git/shortlog/6e5e741d531ef73249d73...
...commit
http://git.netsurf-browser.org/netsurf.git/commit/6e5e741d531ef73249d7319...
...tree
http://git.netsurf-browser.org/netsurf.git/tree/6e5e741d531ef73249d731949...
The branch, master has been updated
via 6e5e741d531ef73249d7319491d770707730626b (commit)
via b6219f6685036bb474f7b9e1ff625169aafd02d0 (commit)
via c862cd60ad7d7c6f58795dabd1e4e41baa1d62b8 (commit)
via 743ffa2a46cd8f5a52bab88e9ec6e5ba1b962e6a (commit)
via df1667bd58c95517a16109bca9fb1db0a0a518b5 (commit)
via 6599f415f7b31fd09320c02bac1c50247574ace3 (commit)
via 31450767c94ac241e8d96a910c850ff733d883d5 (commit)
via 0c3ac47b0594e5f2f78082242996c00c78bcca10 (commit)
via a1f5272f7871cf337a15fcb3aaeb87f6f48d5762 (commit)
via db83497645eee549aefca3dda6e9a99fcdeabf0b (commit)
via cca6707585253c3ead2f8cc20989a8646b62d038 (commit)
via 060a4485bdda738c3c4a8083dd5d075171681891 (commit)
via 64eab40b1825f7ab34713c295e949d7d21c5835d (commit)
via 4e0f960e3c892569c62cfa10a7b993a79aaef3b3 (commit)
via 7cd0bacaf624502cac27088b2ee4e6d37b3aea00 (commit)
via 8c114cdfd824a7ed2fd02ff13e4fd5def6a443b1 (commit)
via a642cab1b7eab0f68f00835ec463bc4b8270995f (commit)
via 146fea758f664a93380ed25f8273fb4940634aee (commit)
via d6ee11de9365d87fe3e9e4ae94569c8b42136eb3 (commit)
via 99e1246cabc0c79cc7edb64dfd505c4af98607e6 (commit)
via 0b730caf2d1e150e60d61dc93bdf917d79994127 (commit)
via beceec8c8e7074bfe904f534c753ecfab427b7a6 (commit)
via ec02cf9e4c560c38321b594cb95f9f7c22172f8e (commit)
via 1f3265f2a56ccb5de4722351fa0bb7ca8d037dd8 (commit)
via 11d4788c8b8713de5fa06ea64e9999eb57e815fa (commit)
via d064e9ac78e38f3622935092e166c30a8917f043 (commit)
via 55dd0356862293ea22f12791de4aa93e2a363f8f (commit)
via a3c72894b9eb38268d6d61e1f5adc151891107e5 (commit)
via 44e4ca5f05ceff06831dfac9066d35df37d7a830 (commit)
via b04acde22874bb69c5ad8eba41e73fbb39589f0e (commit)
via db62a386bf4a9c4c962e21384c91c425738318e0 (commit)
via d398caf146f35d1bc7386e853ce16e2ef457fbc2 (commit)
via 9919b77f1995e8379870d610aea7a2e227882297 (commit)
via 29185f75cfead8c0794b198be7372b0651110c8c (commit)
via 23a0520b40a35e46aabcce5743603c3e26a74cd6 (commit)
via 8692bb687697a2a5bcbeab84bae7b5d69a64f7f6 (commit)
via add9e7283711ba059d017d1a656c172366bc751a (commit)
via abf5512aff5cf03a764963aaa9dad9e2e570f03e (commit)
via cdf9c9ba72c7588a1e3f503fea9f288c8394af9e (commit)
via a86dd681657ee4d5bd108baaf6825abb47957559 (commit)
via d9a66a7ce86e3798b7e1f8fe112c4a0f5a0f1acb (commit)
via c011f45860a4088ffbaa5896eecac7f40d763f89 (commit)
via a6906394f4c5da184ad647a9033ca8490cc80034 (commit)
via f947259ef22a989af9719e6557d65212b775c8ab (commit)
via abe003cc8d5643f8b27a1f9695fe52d3ee509f90 (commit)
via 8b940b5f11fceb870530c949f9b784dc53c0dec8 (commit)
via aeb09c73299bae6dcbe607d115f078fe0a35905f (commit)
via c7b57ff681513dbceebd22ff13b207331c86c117 (commit)
via 99d85697d2c1a181d34417f2b44cad2ea7ba875c (commit)
via ab39827bd8f5fada435ee5e195bbd7584965cfb1 (commit)
via 8fda149baeaad32fa646522c3562ad806bdaf6a1 (commit)
via 088d60ec9662d2ecc34410fbaf6a7ff05c9e5558 (commit)
via fd453beb9702fd28f8724db969099b2f4463b62e (commit)
via 1726304d72f766777c3e8f6a15f789fdaec5803e (commit)
via dafe9a6208d4160daa9375c405fc637f1dbd3c6d (commit)
via 8747398c98761f37350a47a3e6749c28e462ab49 (commit)
via 8f3b8c8cfa81d850b218b1a49b4e67a8bb10cb95 (commit)
via 27849cb182b308fbc68dce16299c7e98a031f78f (commit)
via b959e6946d4d38a02819536d83b135233ade0df0 (commit)
via d3b8a493af8caac8563685d2094123ba7e2c65bd (commit)
via e684218169c5580795a2a2637f45d58c470189ac (commit)
via 910b31f63ee051f414567f5dc68b4ddcda832aea (commit)
via 03eb4ec30f9e090fece2328c33d6acbd32103f3c (commit)
via ab403b251738c86312dd828ed383b6b2defe1704 (commit)
via 83b9c850746c222907477a10d7888807558e9834 (commit)
via a669a7d12ca5c70c1e3ba3813c490731d36cfc7e (commit)
via cf5782718718bee4788dea315dfdbaeafbc3cbc0 (commit)
via ab9efd19fe88547c305589e518a49961d58028b5 (commit)
via d9394608726224bdaf5678ea634564b9da2b5248 (commit)
via 903122126703e70670131932acb9b5b3eba86e8f (commit)
via f656d8ca04ea2c84878ef270bbab78766065e7f5 (commit)
via 55aa7af80f8e008b1bf5f478948cd3eda3458836 (commit)
via de85b4348a85c20c8cf1553199203c691dec6629 (commit)
via a2c6f90330fe7e1aa757f8dec3f65ebef8646eff (commit)
from a93e32de3767ade3931aaf661a720f53e7a27f90 (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=6e5e741d531ef73249d...
commit 6e5e741d531ef73249d7319491d770707730626b
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Add temporary option to enable test of new treeview in bookmarks window.
diff --git a/desktop/options.h b/desktop/options.h
index 391dfbc..7ed6fc1 100644
--- a/desktop/options.h
+++ b/desktop/options.h
@@ -275,3 +275,6 @@ NSOPTION_COLOUR(sys_colour_ThreeDShadow, 0x00d5d5d5)
NSOPTION_COLOUR(sys_colour_Window, 0x00f1f1f1)
NSOPTION_COLOUR(sys_colour_WindowFrame, 0x004e4e4e)
NSOPTION_COLOUR(sys_colour_WindowText, 0x00000000)
+
+/** Temporary option for enabling test of new treeview */
+NSOPTION_BOOL(temp_treeview_test, false)
diff --git a/desktop/tree.c b/desktop/tree.c
index 2a91c8e..a0640f6 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -212,54 +212,76 @@ struct core_window_callback_table cw_t = {
.get_window_dimensions = treeview_test_get_window_dimensions
};
-static void treeview_test_init(struct tree *tree)
+static bool treeview_test_init(struct tree *tree)
{
nserror err;
- treeview_init();
+ if (nsoption_bool(temp_treeview_test) == false)
+ return false;
+ treeview_init();
err = global_history_init(&cw_t, (struct core_window *)tree);
-
if (err != NSERROR_OK) {
warn_user("Duffed it.", 0);
}
+
+ return true;
}
-static void treeview_test_fini(struct tree *tree)
+static bool treeview_test_fini(struct tree *tree)
{
nserror err;
- err = global_history_fini();
+ if (nsoption_bool(temp_treeview_test) == false)
+ return false;
+ err = global_history_fini();
treeview_fini();
-
if (err != NSERROR_OK) {
warn_user("Duffed it.", 0);
}
+
+ return true;
}
-static void treeview_test_redraw(struct tree *tree, int x, int y,
+static bool treeview_test_redraw(struct tree *tree, int x, int y,
int clip_x, int clip_y, int clip_width, int clip_height,
const struct redraw_context *ctx)
{
struct rect clip;
+
+ if (nsoption_bool(temp_treeview_test) == false)
+ return false;
+
clip.x0 = clip_x;
clip.y0 = clip_y;
clip.x1 = clip_x + clip_width;
clip.y1 = clip_y + clip_height;
global_history_redraw(x, y, &clip, ctx);
+
+ return true;
}
-static void treeview_test_mouse_action(struct tree *tree,
+static bool treeview_test_mouse_action(struct tree *tree,
browser_mouse_state mouse, int x, int y)
{
+ if (nsoption_bool(temp_treeview_test) == false)
+ return false;
+
global_history_mouse_action(mouse, x, y);
+
+ return true;
}
-static void treeview_test_keypress(struct tree *tree, uint32_t key)
+static bool treeview_test_keypress(struct tree *tree, uint32_t key)
{
+ if (nsoption_bool(temp_treeview_test) == false)
+ return false;
+
global_history_keypress(key);
+
+ return true;
}
@@ -2156,9 +2178,10 @@ void tree_draw(struct tree *tree, int x, int y,
assert(tree->root != NULL);
if (tree->flags == TREE_MOVABLE) {
- treeview_test_redraw(tree, x, y, clip_x, clip_y,
- clip_width, clip_height, ctx);
- return;
+ if (treeview_test_redraw(tree, x, y, clip_x, clip_y,
+ clip_width, clip_height, ctx)) {
+ return;
+ }
}
/* Start knockout rendering if it's available for this plotter */
@@ -2526,8 +2549,9 @@ bool tree_mouse_action(struct tree *tree, browser_mouse_state mouse,
int x,
assert(tree->root != NULL);
if (tree->flags == TREE_MOVABLE) {
- treeview_test_mouse_action(tree, mouse, x, y);
- return true;
+ if (treeview_test_mouse_action(tree, mouse, x, y)) {
+ return true;
+ }
}
if (tree->root->child == NULL)
@@ -2937,8 +2961,10 @@ void tree_drag_end(struct tree *tree, browser_mouse_state mouse,
int x0, int y0,
int x, y;
if (tree->flags & TREE_MOVABLE) {
- treeview_test_mouse_action(tree, BROWSER_MOUSE_HOVER, x1, y1);
- return;
+ if (treeview_test_mouse_action(tree, BROWSER_MOUSE_HOVER,
+ x1, y1)) {
+ return;
+ }
}
switch (tree->drag) {
@@ -2982,8 +3008,9 @@ void tree_drag_end(struct tree *tree, browser_mouse_state mouse, int
x0, int y0,
bool tree_keypress(struct tree *tree, uint32_t key)
{
if (tree->flags == TREE_MOVABLE) {
- treeview_test_keypress(tree, key);
- return true;
+ if (treeview_test_keypress(tree, key)) {
+ return true;
+ }
}
if (tree->editing != NULL)
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=b6219f6685036bb474f...
commit b6219f6685036bb474f7b9e1ff625169aafd02d0
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Delete and backspace keys delete selected nodes.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index bca2dea..3035f9e 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -1041,7 +1041,8 @@ struct treeview_selection_walk_data {
TREEVIEW_WALK_HAS_SELECTION,
TREEVIEW_WALK_CLEAR_SELECTION,
TREEVIEW_WALK_SELECT_ALL,
- TREEVIEW_WALK_COMMIT_SELECT_DRAG
+ TREEVIEW_WALK_COMMIT_SELECT_DRAG,
+ TREEVIEW_WALK_DELETE_SELECTION
} purpose;
union {
bool has_selection;
@@ -1055,6 +1056,7 @@ struct treeview_selection_walk_data {
} drag;
} data;
int current_y;
+ struct treeview *tree;
};
/** Treewalk node callback for handling selection related actions. */
static bool treeview_node_selection_walk_cb(struct treeview_node *node,
@@ -1076,6 +1078,13 @@ static bool treeview_node_selection_walk_cb(struct treeview_node
*node,
}
break;
+ case TREEVIEW_WALK_DELETE_SELECTION:
+ if (node->flags & TREE_NODE_SELECTED) {
+ treeview_delete_node(sw->tree, node);
+ changed = true;
+ }
+ break;
+
case TREEVIEW_WALK_CLEAR_SELECTION:
if (node->flags & TREE_NODE_SELECTED) {
node->flags ^= TREE_NODE_SELECTED;
@@ -1196,6 +1205,34 @@ static void treeview_commit_selection_drag(struct treeview *tree)
}
+/**
+ * Commit a current selection drag, modifying the node's selection state.
+ */
+static bool treeview_delete_selection(struct treeview *tree, struct rect *rect)
+{
+ struct treeview_selection_walk_data sw;
+
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+
+ rect->x0 = 0;
+ rect->y0 = 0;
+ rect->x1 = REDRAW_MAX;
+ rect->y1 = tree->root->height;
+
+ sw.purpose = TREEVIEW_WALK_DELETE_SELECTION;
+ sw.data.redraw.required = false;
+ sw.data.redraw.rect = rect;
+ sw.current_y = 0;
+ sw.tree = tree;
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_selection_walk_cb, &sw);
+
+ return sw.data.redraw.required;
+}
+
+
/* Exported interface, documented in treeview.h */
bool treeview_keypress(struct treeview *tree, uint32_t key)
{
@@ -1213,7 +1250,7 @@ bool treeview_keypress(struct treeview *tree, uint32_t key)
break;
case KEY_DELETE_LEFT:
case KEY_DELETE_RIGHT:
- /* TODO: Delete selection */
+ redraw = treeview_delete_selection(tree, &r);
break;
case KEY_CR:
case KEY_NL:
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=c862cd60ad7d7c6f587...
commit c862cd60ad7d7c6f58795dabd1e4e41baa1d62b8
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Make treeview test parasite trap keyboard action too.
diff --git a/desktop/tree.c b/desktop/tree.c
index 780bd6b..2a91c8e 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -257,6 +257,11 @@ static void treeview_test_mouse_action(struct tree *tree,
global_history_mouse_action(mouse, x, y);
}
+static void treeview_test_keypress(struct tree *tree, uint32_t key)
+{
+ global_history_keypress(key);
+}
+
@@ -2976,6 +2981,11 @@ void tree_drag_end(struct tree *tree, browser_mouse_state mouse,
int x0, int y0,
*/
bool tree_keypress(struct tree *tree, uint32_t key)
{
+ if (tree->flags == TREE_MOVABLE) {
+ treeview_test_keypress(tree, key);
+ return true;
+ }
+
if (tree->editing != NULL)
switch (key) {
case KEY_ESCAPE:
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=743ffa2a46cd8f5a52b...
commit 743ffa2a46cd8f5a52bab88e9ec6e5ba1b962e6a
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Pass keypresses on to treeview.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index e49b300..0a1e549 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -740,3 +740,10 @@ void global_history_mouse_action(browser_mouse_state mouse, int x,
int y)
treeview_mouse_action(gh_ctx.tree, mouse, x, y);
}
+
+/* Exported interface, documented in global_history.h */
+void global_history_keypress(uint32_t key)
+{
+ treeview_keypress(gh_ctx.tree, key);
+}
+
diff --git a/desktop/global_history.h b/desktop/global_history.h
index 4564920..591b1fe 100644
--- a/desktop/global_history.h
+++ b/desktop/global_history.h
@@ -70,4 +70,13 @@ void global_history_redraw(int x, int y, struct rect *clip,
*/
void global_history_mouse_action(browser_mouse_state mouse, int x, int y);
+
+/**
+ * Key press handling.
+ *
+ * \param key The ucs4 character codepoint
+ * \return true if the keypress is dealt with, false otherwise.
+ */
+void global_history_keypress(uint32_t key);
+
#endif
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=df1667bd58c95517a16...
commit df1667bd58c95517a16109bca9fb1db0a0a518b5
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Start keypress handling.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 7cf454e..bca2dea 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -1195,6 +1195,54 @@ static void treeview_commit_selection_drag(struct treeview *tree)
treeview_node_selection_walk_cb, &sw);
}
+
+/* Exported interface, documented in treeview.h */
+bool treeview_keypress(struct treeview *tree, uint32_t key)
+{
+ struct rect r; /**< Redraw rectangle */
+ bool redraw = false;
+
+ assert(tree != NULL);
+
+ switch (key) {
+ case KEY_SELECT_ALL:
+ redraw = treeview_select_all(tree, &r);
+ break;
+ case KEY_COPY_SELECTION:
+ /* TODO: Copy selection as text */
+ break;
+ case KEY_DELETE_LEFT:
+ case KEY_DELETE_RIGHT:
+ /* TODO: Delete selection */
+ break;
+ case KEY_CR:
+ case KEY_NL:
+ /* TODO: Launch selection */
+ break;
+ case KEY_ESCAPE:
+ case KEY_CLEAR_SELECTION:
+ redraw = treeview_clear_selection(tree, &r);
+ break;
+ /* TODO: Trivial keyboard navigation */
+ case KEY_LEFT:
+ break;
+ case KEY_RIGHT:
+ break;
+ case KEY_UP:
+ break;
+ case KEY_DOWN:
+ break;
+ default:
+ return false;
+ }
+
+ if (redraw) {
+ tree->cw_t->redraw_request(tree->cw_h, r);
+ }
+
+ return true;
+}
+
struct treeview_mouse_action {
struct treeview *tree;
browser_mouse_state mouse;
diff --git a/desktop/treeview.h b/desktop/treeview.h
index 2579d85..9692d0a 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -27,6 +27,7 @@
#include <stdint.h>
#include "desktop/core_window.h"
+#include "desktop/textinput.h"
#include "utils/types.h"
struct treeview;
@@ -232,6 +233,15 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
const struct redraw_context *ctx);
/**
+ * Key press handling for treeviews.
+ *
+ * \param tree The treeview which got the keypress
+ * \param key The ucs4 character codepoint
+ * \return true if the keypress is dealt with, false otherwise.
+ */
+bool treeview_keypress(struct treeview *tree, uint32_t key);
+
+/**
* Handles all kinds of mouse action
*
* \param tree Treeview object
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=6599f415f7b31fd0932...
commit 6599f415f7b31fd09320c02bac1c50247574ace3
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Handle mouse action below last node.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index c6b09e2..7cf454e 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -1414,7 +1414,10 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node, void *ctx)
void treeview_mouse_action(struct treeview *tree,
browser_mouse_state mouse, int x, int y)
{
- struct treeview_mouse_action ma;
+ bool redraw = false;
+
+ assert(tree != NULL);
+ assert(tree->root != NULL);
if (mouse == BROWSER_MOUSE_HOVER &&
tree->drag.type == TV_DRAG_SELECTION) {
@@ -1424,14 +1427,87 @@ void treeview_mouse_action(struct treeview *tree,
return;
}
- ma.tree = tree;
- ma.mouse = mouse;
- ma.x = x;
- ma.y = y;
- ma.current_y = 0;
+ if (y > tree->root->height) {
+ /* Below tree */
+ struct rect r;
+
+ r.x0 = 0;
+ r.x1 = REDRAW_MAX;
+
+ /* Record what position / section a drag started on */
+ if (mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2) &&
+ tree->drag.type == TV_DRAG_NONE) {
+ tree->drag.selected = false;
+ tree->drag.start_node = NULL;
+ tree->drag.section = TV_NODE_SECTION_NONE;
+ tree->drag.start.x = x;
+ tree->drag.start.y = y;
+ tree->drag.start.node_y = tree->root->height;
+ tree->drag.start.node_h = 0;
+
+ tree->drag.prev.x = x;
+ tree->drag.prev.y = y;
+ tree->drag.prev.node_y = tree->root->height;
+ tree->drag.prev.node_h = 0;
+ }
- treeview_walk_internal(tree->root, false,
- treeview_node_mouse_action_cb, &ma);
+ /* Handle drag start */
+ if (tree->drag.type == TV_DRAG_NONE) {
+ if (mouse & BROWSER_MOUSE_DRAG_1 &&
+ tree->drag.selected == false &&
+ tree->drag.section ==
+ TV_NODE_SECTION_NONE) {
+ tree->drag.type = TV_DRAG_SELECTION;
+ } else if (mouse & BROWSER_MOUSE_DRAG_2) {
+ tree->drag.type = TV_DRAG_SELECTION;
+ }
+
+ if (tree->drag.start_node != NULL &&
+ tree->drag.type == TV_DRAG_SELECTION) {
+ tree->drag.start_node->flags ^=
+ TREE_NODE_SELECTED;
+ }
+ }
+
+ /* Handle selection drags */
+ if (tree->drag.type == TV_DRAG_SELECTION) {
+ int curr_y1 = tree->root->height;
+ int prev_y1 = tree->drag.prev.node_y +
+ tree->drag.prev.node_h;
+
+ r.y0 = tree->drag.prev.node_y;
+ r.y1 = (curr_y1 > prev_y1) ? curr_y1 : prev_y1;
+
+ redraw = true;
+
+ tree->drag.prev.x = x;
+ tree->drag.prev.y = y;
+ tree->drag.prev.node_y = curr_y1;
+ tree->drag.prev.node_h = 0;
+ }
+
+ if (mouse & BROWSER_MOUSE_PRESS_1) {
+ /* Clear any existing selection */
+ redraw |= treeview_clear_selection(tree, &r);
+ }
+
+ if (redraw) {
+ tree->cw_t->redraw_request(tree->cw_h, r);
+ }
+
+ } else {
+ /* On tree */
+ struct treeview_mouse_action ma;
+
+ ma.tree = tree;
+ ma.mouse = mouse;
+ ma.x = x;
+ ma.y = y;
+ ma.current_y = 0;
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_mouse_action_cb, &ma);
+ }
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=31450767c94ac241e8d...
commit 31450767c94ac241e8d96a910c850ff733d883d5
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Update ancestor heights on node deletion.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 725125d..c6b09e2 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -470,6 +470,7 @@ nserror treeview_delete_node(struct treeview *tree, struct
treeview_node *n)
{
struct treeview_node_msg msg;
msg.msg = TREE_MSG_NODE_DELETE;
+ struct treeview_node *p;
/* Destroy children first */
while (n->children != NULL) {
@@ -491,6 +492,13 @@ nserror treeview_delete_node(struct treeview *tree, struct
treeview_node *n)
n->sibling_next->sibling_prev = n->sibling_prev;
}
+ /* Reduce ancestor heights */
+ p = n->parent;
+ while (p != NULL && p->flags & TREE_NODE_EXPANDED) {
+ p->height -= n->height;
+ p = p->parent;
+ }
+
/* Handle any special treatment */
switch (n->type) {
case TREE_NODE_ENTRY:
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=0c3ac47b0594e5f2f78...
commit 0c3ac47b0594e5f2f78082242996c00c78bcca10
Merge: a1f5272 a93e32d
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Merge branch 'master' of
git://git.netsurf-browser.org/netsurf
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=a1f5272f7871cf337a1...
commit a1f5272f7871cf337a15fcb3aaeb87f6f48d5762
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Update treeview test parasite to pass tree height changes on to front end.
diff --git a/desktop/tree.c b/desktop/tree.c
index c33c0f1..780bd6b 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -191,6 +191,9 @@ static void treeview_test_redraw_request(struct core_window *cw,
struct rect r)
static void treeview_test_update_size(struct core_window *cw,
int width, int height)
{
+ struct tree *tree = (struct tree *)cw;
+
+ tree->callbacks->resized(tree, width, height, tree->client_data);
}
static void treeview_test_scroll_visible(struct core_window *cw, struct rect r)
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=db83497645eee549aef...
commit db83497645eee549aefca3dda6e9a99fcdeabf0b
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Inform front end when treeview height changes.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 30d0066..725125d 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -115,7 +115,6 @@ struct treeview_drag {
}; /**< Drag state */
struct treeview {
- uint32_t view_height; /** Viewport size */
uint32_t view_width; /** Viewport size */
struct treeview_node *root; /**< Root node */
@@ -324,6 +323,9 @@ nserror treeview_create_node_folder(struct treeview *tree,
*folder = n;
+ /* Inform front end of change in dimensions */
+ tree->cw_t->update_size(tree->cw_h, -1, tree->root->height);
+
return NSERROR_OK;
}
@@ -456,6 +458,9 @@ nserror treeview_create_node_entry(struct treeview *tree,
*entry = n;
+ /* Inform front end of change in dimensions */
+ tree->cw_t->update_size(tree->cw_h, -1, tree->root->height);
+
return NSERROR_OK;
}
@@ -500,6 +505,9 @@ nserror treeview_delete_node(struct treeview *tree, struct
treeview_node *n)
return NSERROR_BAD_PARAMETER;
}
+ /* Inform front end of change in dimensions */
+ tree->cw_t->update_size(tree->cw_h, -1, tree->root->height);
+
/* Free the node */
free(n);
@@ -737,6 +745,9 @@ nserror treeview_node_expand(struct treeview *tree,
node->height += additional_height;
+ /* Inform front end of change in dimensions */
+ tree->cw_t->update_size(tree->cw_h, -1, tree->root->height);
+
return NSERROR_OK;
}
@@ -762,8 +773,7 @@ static bool treeview_node_contract_cb(struct treeview_node *node, void
*ctx)
do {
node->height -= height_reduction;
node = node->parent;
- } while (node->parent != NULL &&
- node->parent->flags & TREE_NODE_EXPANDED);
+ } while (node != NULL);
return false; /* Don't want to abort tree walk */
}
@@ -785,6 +795,9 @@ nserror treeview_node_contract(struct treeview *tree,
/* Contract node */
treeview_node_contract_cb(node, NULL);
+ /* Inform front end of change in dimensions */
+ tree->cw_t->update_size(tree->cw_h, -1, tree->root->height);
+
return NSERROR_OK;
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=cca6707585253c3ead2...
commit cca6707585253c3ead2f8cc20989a8646b62d038
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Update documentation for update_size callback.
diff --git a/desktop/core_window.h b/desktop/core_window.h
index 9e68e26..ad2319b 100644
--- a/desktop/core_window.h
+++ b/desktop/core_window.h
@@ -32,7 +32,13 @@ struct core_window_callback_table {
/** Request a redraw of the window. */
void (*redraw_request)(struct core_window *cw, struct rect r);
- /** Update the limits of the window */
+ /**
+ * Update the limits of the window
+ *
+ * \param cw the core window object
+ * \param width the width in px, or negative if don't care
+ * \param height the height in px, or negative if don't care
+ */
void (*update_size)(struct core_window *cw, int width, int height);
/** Scroll the window to make area visible */
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=060a4485bdda738c3c4...
commit 060a4485bdda738c3c4a8083dd5d075171681891
Merge: 64eab40 59dc293
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Merge branch 'master' of
git://git.netsurf-browser.org/netsurf
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=64eab40b1825f7ab347...
commit 64eab40b1825f7ab34713c295e949d7d21c5835d
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Fix typo.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index e415c10..e49b300 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -327,7 +327,7 @@ static nserror global_history_entry_insert(struct global_history_entry
*e,
* simplfy sorting the entries.
*
* \param url URL for entry to add to history
- * \param slot Global histroy slot to contain history entry
+ * \param slot Global history slot to contain history entry
* \param data URL data for the entry
* \param got_treeview Whether the treeview has been created already
* \return NSERROR_OK on success, or appropriate error otherwise
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=4e0f960e3c892569c62...
commit 4e0f960e3c892569c62cfa10a7b993a79aaef3b3
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Write up the rest of the fucntion comments.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index c03c254..e415c10 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -105,7 +105,8 @@ static struct global_history_entry *global_history_find(nsurl *url)
/**
* Initialise the treeview directories
*
- * \return true on success, false on memory exhaustion
+ * \param f Ident for folder to create
+ * \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror global_history_create_dir(enum global_history_folders f)
{
@@ -236,6 +237,13 @@ static inline nserror global_history_get_parent_treeview_node(
}
+/**
+ * Set a global history entry's data from the url_data.
+ *
+ * \param e Global history entry to set up
+ * \param url_data Data associated with entry's URL
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
static nserror global_history_create_treeview_field_data(
struct global_history_entry *e,
const struct url_data *data)
@@ -309,6 +317,21 @@ static nserror global_history_entry_insert(struct
global_history_entry *e,
}
+/**
+ * Add an entry to the global history (creates the entry).
+ *
+ * If the treeview has already been created, the entry will be added to the
+ * treeview. Otherwise, the entry will have to be added to the treeview later.
+ *
+ * When we first create the global history we create it without the treeview, to
+ * simplfy sorting the entries.
+ *
+ * \param url URL for entry to add to history
+ * \param slot Global histroy slot to contain history entry
+ * \param data URL data for the entry
+ * \param got_treeview Whether the treeview has been created already
+ * \return NSERROR_OK on success, or appropriate error otherwise
+ */
static nserror global_history_add_entry_internal(nsurl *url, int slot,
const struct url_data *data, bool got_treeview)
{
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=7cd0bacaf624502cac2...
commit 7cd0bacaf624502cac27088b2ee4e6d37b3aea00
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Create folders as they're required when entry is inserted.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index f803b52..c03c254 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -101,6 +101,93 @@ static struct global_history_entry *global_history_find(nsurl *url)
return NULL;
}
+
+/**
+ * Initialise the treeview directories
+ *
+ * \return true on success, false on memory exhaustion
+ */
+static nserror global_history_create_dir(enum global_history_folders f)
+{
+ nserror err;
+ time_t t = gh_ctx.today;
+ struct treeview_node *relation = NULL;
+ enum treeview_relationship rel = TREE_REL_FIRST_CHILD;
+ const char *label;
+ int age;
+ int i;
+
+ switch (f) {
+ case GH_TODAY:
+ label = "DateToday";
+ age = 0;
+ break;
+ case GH_YESTERDAY:
+ label = "DateYesterday";
+ age = 1;
+ break;
+ case GH_2_DAYS_AGO:
+ label = "Date2Days";
+ age = 2;
+ break;
+ case GH_3_DAYS_AGO:
+ label = "Date3Days";
+ age = 3;
+ break;
+ case GH_4_DAYS_AGO:
+ label = "Date4Days";
+ age = 4;
+ break;
+ case GH_5_DAYS_AGO:
+ label = "Date5Days";
+ age = 5;
+ break;
+ case GH_6_DAYS_AGO:
+ label = "Date6Days";
+ age = 6;
+ break;
+ case GH_LAST_WEEK:
+ label = "Date1Week";
+ age = 7;
+ break;
+ case GH_2_WEEKS_AGO:
+ label = "Date2Week";
+ age = 14;
+ break;
+ case GH_3_WEEKS_AGO:
+ label = "Date3Week";
+ age = 21;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ t -= age * N_SEC_PER_DAY;
+
+ label = messages_get(label);
+
+ for (i = f - 1; i >= 0; i--) {
+ if (gh_ctx.folders[i].folder != NULL) {
+ relation = gh_ctx.folders[i].folder;
+ rel = TREE_REL_NEXT_SIBLING;
+ break;
+ }
+ }
+
+ gh_ctx.folders[f].data.field = gh_ctx.fields[N_FIELDS - 1].field;
+ gh_ctx.folders[f].data.value = label;
+ gh_ctx.folders[f].data.value_len = strlen(label);
+ err = treeview_create_node_folder(gh_ctx.tree,
+ &gh_ctx.folders[f].folder,
+ relation, rel,
+ &gh_ctx.folders[f].data,
+ &gh_ctx.folders[f]);
+
+ return err;
+}
+
+
/**
* Get the treeview folder for history entires in a particular slot
*
@@ -113,6 +200,7 @@ static inline nserror global_history_get_parent_treeview_node(
{
int folder_index;
struct global_history_folder *f;
+ nserror err;
if (slot < 7) {
folder_index = slot;
@@ -134,7 +222,13 @@ static inline nserror global_history_get_parent_treeview_node(
/* Get the folder */
f = &(gh_ctx.folders[folder_index]);
- /* TODO: Create the folder if f==NULL */
+ if (f->folder == NULL) {
+ err = global_history_create_dir(folder_index);
+ if (err != NSERROR_OK) {
+ *parent = NULL;
+ return err;
+ }
+ }
/* Return the parent treeview folder */
*parent = f->folder;
@@ -464,84 +558,6 @@ static nserror global_history_initialise_time(void)
/**
- * Initialise the treeview directories
- *
- * \return true on success, false on memory exhaustion
- */
-static nserror global_history_init_dir(enum global_history_folders f,
- const char *label, int age)
-{
- nserror err;
- time_t t = gh_ctx.today;
- struct treeview_node *relation = NULL;
- enum treeview_relationship rel = TREE_REL_FIRST_CHILD;
-
- t -= age * N_SEC_PER_DAY;
-
- label = messages_get(label);
-
- if (f != GH_TODAY) {
- relation = gh_ctx.folders[f - 1].folder;
- rel = TREE_REL_NEXT_SIBLING;
- }
-
- gh_ctx.folders[f].data.field = gh_ctx.fields[N_FIELDS - 1].field;
- gh_ctx.folders[f].data.value = label;
- gh_ctx.folders[f].data.value_len = strlen(label);
- err = treeview_create_node_folder(gh_ctx.tree,
- &gh_ctx.folders[f].folder,
- relation, rel,
- &gh_ctx.folders[f].data,
- &gh_ctx.folders[f]);
-
- return err;
-}
-
-
-/**
- * Initialise the treeview directories
- *
- * \return true on success, false on memory exhaustion
- */
-static nserror global_history_init_dirs(void)
-{
- nserror err;
-
- err = global_history_init_dir(GH_TODAY, "DateToday", 0);
- if (err != NSERROR_OK) return err;
-
- err = global_history_init_dir(GH_YESTERDAY, "DateYesterday", 1);
- if (err != NSERROR_OK) return err;
-
- err = global_history_init_dir(GH_2_DAYS_AGO, "Date2Days", 2);
- if (err != NSERROR_OK) return err;
-
- err = global_history_init_dir(GH_3_DAYS_AGO, "Date3Days", 3);
- if (err != NSERROR_OK) return err;
-
- err = global_history_init_dir(GH_4_DAYS_AGO, "Date4Days", 4);
- if (err != NSERROR_OK) return err;
-
- err = global_history_init_dir(GH_5_DAYS_AGO, "Date5Days", 5);
- if (err != NSERROR_OK) return err;
-
- err = global_history_init_dir(GH_6_DAYS_AGO, "Date6Days", 6);
- if (err != NSERROR_OK) return err;
-
- err = global_history_init_dir(GH_LAST_WEEK, "Date1Week", 7);
- if (err != NSERROR_OK) return err;
-
- err = global_history_init_dir(GH_2_WEEKS_AGO, "Date2Week", 14);
- if (err != NSERROR_OK) return err;
-
- err = global_history_init_dir(GH_3_WEEKS_AGO, "Date3Week", 21);
- if (err != NSERROR_OK) return err;
-
- return NSERROR_OK;
-}
-
-
-/**
* Initialise the treeview entries
*
* \return true on success, false on memory exhaustion
@@ -640,8 +656,8 @@ nserror global_history_init(struct core_window_callback_table *cw_t,
return err;
}
- /* Add the folders to the treeview */
- err = global_history_init_dirs();
+ /* Ensure there is a folder for today */
+ err = global_history_create_dir(GH_TODAY);
if (err != NSERROR_OK) {
return err;
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=8c114cdfd824a7ed2fd...
commit 8c114cdfd824a7ed2fd02ff13e4fd5def6a443b1
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Ensure global_history_delete_internal checks treeview node is NULL. Add various
documentation comments.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index e32f2ba..f803b52 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -76,7 +76,7 @@ struct global_history_entry *gh_list[N_DAYS];
* Find an entry in the global history
*
* \param url The URL to find
- * \return Pointer to node, or NULL if not found
+ * \return Pointer to history entry, or NULL if not found
*/
static struct global_history_entry *global_history_find(nsurl *url)
{
@@ -89,15 +89,25 @@ static struct global_history_entry *global_history_find(nsurl *url)
while (e != NULL) {
if (nsurl_compare(e->url, url,
NSURL_COMPLETE) == true) {
+ /* Got a match */
return e;
}
e = e->next;
}
}
+
+ /* No match found */
return NULL;
}
+/**
+ * Get the treeview folder for history entires in a particular slot
+ *
+ * \param parent Updated to parent folder.
+ * \param slot Global history slot of entry we want folder node for
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
static inline nserror global_history_get_parent_treeview_node(
struct treeview_node **parent, int slot)
{
@@ -124,6 +134,8 @@ static inline nserror global_history_get_parent_treeview_node(
/* Get the folder */
f = &(gh_ctx.folders[folder_index]);
+ /* TODO: Create the folder if f==NULL */
+
/* Return the parent treeview folder */
*parent = f->folder;
return NSERROR_OK;
@@ -266,9 +278,21 @@ static nserror global_history_add_entry_internal(nsurl *url, int
slot,
return NSERROR_OK;
}
+
+/**
+ * Delete a global history entry
+ *
+ * This does not delete the treeview node, rather it should only be called from
+ * the treeview node delete event message.
+ *
+ * \param e Entry to delete
+ */
static void global_history_delete_entry_internal(
struct global_history_entry *e)
{
+ assert(e != NULL);
+ assert(e->entry == NULL);
+
/* Unlink */
if (gh_list[e->slot] == e) {
/* e is first entry */
@@ -564,6 +588,7 @@ static nserror global_history_tree_node_entry_cb(
switch (msg.msg) {
case TREE_MSG_NODE_DELETE:
+ e->entry = NULL;
global_history_delete_entry_internal(e);
break;
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=a642cab1b7eab0f68f0...
commit a642cab1b7eab0f68f00835ec463bc4b8270995f
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Point at header for exported function commentary.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index d159c50..e32f2ba 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -580,13 +580,8 @@ struct treeview_callback_table tree_cb_t = {
.entry = global_history_tree_node_entry_cb
};
-/**
- * Initialises the global history module.
- *
- * \param
- * \param
- * \return true on success, false on memory exhaustion
- */
+
+/* Exported interface, documented in global_history.h */
nserror global_history_init(struct core_window_callback_table *cw_t,
void *core_window_handle)
{
@@ -666,12 +661,16 @@ nserror global_history_fini(void)
return NSERROR_OK;
}
+
+/* Exported interface, documented in global_history.h */
void global_history_redraw(int x, int y, struct rect *clip,
const struct redraw_context *ctx)
{
treeview_redraw(gh_ctx.tree, x, y, clip, ctx);
}
+
+/* Exported interface, documented in global_history.h */
void global_history_mouse_action(browser_mouse_state mouse, int x, int y)
{
treeview_mouse_action(gh_ctx.tree, mouse, x, y);
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=146fea758f664a93380...
commit 146fea758f664a93380ed25f8273fb4940634aee
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Global history finaliser does not need core_window stuff.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index 27b8e47..d159c50 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -644,15 +644,9 @@ nserror global_history_init(struct core_window_callback_table *cw_t,
return NSERROR_OK;
}
-/**
- * Finalises the global history module.
- *
- * \param
- * \param
- * \return true on success, false on memory exhaustion
- */
-nserror global_history_fini(struct core_window_callback_table *cw_t,
- void *core_window_handle)
+
+/* Exported interface, documented in global_history.h */
+nserror global_history_fini(void)
{
int i;
nserror err;
diff --git a/desktop/global_history.h b/desktop/global_history.h
index 7e2376b..4564920 100644
--- a/desktop/global_history.h
+++ b/desktop/global_history.h
@@ -46,12 +46,9 @@ nserror global_history_init(struct core_window_callback_table *cw_t,
* internal data. After calling this if global history is required again,
* global_history_init must be called.
*
- * \param cw_t Callback table for core_window containing the treeview
- * \param cw The core_window in which the treeview is shown
* \return NSERROR_OK on success, appropriate error otherwise
*/
-nserror global_history_fini(struct core_window_callback_table *cw_t,
- void *core_window_handle);
+nserror global_history_fini(void);
/**
* Redraw the global history.
diff --git a/desktop/tree.c b/desktop/tree.c
index d9b0592..c33c0f1 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -226,7 +226,7 @@ static void treeview_test_fini(struct tree *tree)
{
nserror err;
- err = global_history_fini(&cw_t, (struct core_window *)tree);
+ err = global_history_fini();
treeview_fini();
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=d6ee11de9365d87fe3e...
commit d6ee11de9365d87fe3e9e4ae94569c8b42136eb3
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Add documentation comments.
diff --git a/desktop/global_history.h b/desktop/global_history.h
index 960eb1e..7e2376b 100644
--- a/desktop/global_history.h
+++ b/desktop/global_history.h
@@ -23,15 +23,54 @@
#include "desktop/core_window.h"
+
+/**
+ * Initialise the global history.
+ *
+ * This iterates through the URL database, generating the global history data,
+ * and creates a treeview.
+ *
+ * This must be called before any other global_history_* function.
+ *
+ * \param cw_t Callback table for core_window containing the treeview
+ * \param cw The core_window in which the treeview is shown
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
nserror global_history_init(struct core_window_callback_table *cw_t,
void *core_window_handle);
+/**
+ * Finalise the global history.
+ *
+ * This destroys the global history treeview and the global history module's
+ * internal data. After calling this if global history is required again,
+ * global_history_init must be called.
+ *
+ * \param cw_t Callback table for core_window containing the treeview
+ * \param cw The core_window in which the treeview is shown
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
nserror global_history_fini(struct core_window_callback_table *cw_t,
void *core_window_handle);
+/**
+ * Redraw the global history.
+ *
+ * \param x X coordinate to render treeview at
+ * \param x Y coordinate to render treeview at
+ * \param clip Current clip rectangle (wrt tree origin)
+ * \param ctx Current redraw context
+ */
void global_history_redraw(int x, int y, struct rect *clip,
const struct redraw_context *ctx);
+/**
+ * Handles all kinds of mouse action
+ *
+ * \param mouse The current mouse state
+ * \param x X coordinate
+ * \param y Y coordinate
+ */
void global_history_mouse_action(browser_mouse_state mouse, int x, int y);
#endif
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=99e1246cabc0c79cc7e...
commit 99e1246cabc0c79cc7edb64dfd505c4af98607e6
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Document static functions.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index b5b838c..30d0066 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -177,6 +177,12 @@ static struct treeview_text treeview_furn[TREE_FURN_LAST] = {
};
+/**
+ * Create treeview's root node
+ *
+ * \param root Returns root node
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
static nserror treeview_create_node_root(struct treeview_node **root)
{
struct treeview_node *n;
@@ -735,6 +741,7 @@ nserror treeview_node_expand(struct treeview *tree,
}
+/** Treewalk node callback for handling node contraction. */
static bool treeview_node_contract_cb(struct treeview_node *node, void *ctx)
{
int height_reduction;
@@ -781,7 +788,7 @@ nserror treeview_node_contract(struct treeview *tree,
return NSERROR_OK;
}
-/* Exported interface, documented in treeview.h */
+
/* Exported interface, documented in treeview.h */
void treeview_redraw(struct treeview *tree, int x, int y, struct rect *clip,
const struct redraw_context *ctx)
@@ -1028,6 +1035,7 @@ struct treeview_selection_walk_data {
} data;
int current_y;
};
+/** Treewalk node callback for handling selection related actions. */
static bool treeview_node_selection_walk_cb(struct treeview_node *node,
void *ctx)
{
@@ -1143,6 +1151,10 @@ bool treeview_select_all(struct treeview *tree, struct rect *rect)
return sw.data.redraw.required;
}
+
+/**
+ * Commit a current selection drag, modifying the node's selection state.
+ */
static void treeview_commit_selection_drag(struct treeview *tree)
{
struct treeview_selection_walk_data sw;
@@ -1167,8 +1179,9 @@ struct treeview_mouse_action {
browser_mouse_state mouse;
int x;
int y;
- int current_y;
+ int current_y; /* Y coordinate value of top of current node */
};
+/** Treewalk node callback for handling mouse action. */
static bool treeview_node_mouse_action_cb(struct treeview_node *node, void *ctx)
{
struct treeview_mouse_action *ma = ctx;
@@ -1404,8 +1417,8 @@ void treeview_mouse_action(struct treeview *tree,
/* Mix two colours according to the proportion given by p.
* Where 0 <= p <= 255
- * p=0 gives result=c0
- * p=255 gives result=c1
+ * p=0 gives result ==> c1
+ * p=255 gives result ==> c0
*/
#define mix_colour(c0, c1, p) \
((((((c1 & 0xff00ff) * (255 - p)) + \
@@ -1414,6 +1427,9 @@ void treeview_mouse_action(struct treeview *tree,
((c0 & 0x00ff00) * ( p)) ) >> 8) & 0x00ff00))
+/**
+ * Initialise the plot styles from CSS system colour values.
+ */
static void treeview_init_plot_styles(int font_pt_size)
{
/* Background colour */
@@ -1495,6 +1511,9 @@ static nserror treeview_res_cb(hlcache_handle *handle,
}
+/**
+ * Fetch content resources used by treeview.
+ */
static void treeview_init_resources(void)
{
int i;
@@ -1512,6 +1531,9 @@ static void treeview_init_resources(void)
}
+/**
+ * Measures width of characters used to represent treeview furniture.
+ */
static void treeview_init_furniture(void)
{
int i;
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=0b730caf2d1e150e60d...
commit 0b730caf2d1e150e60d61dc93bdf917d79994127
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
More documentation.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index ab77a7b..b5b838c 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -46,15 +46,15 @@ enum treeview_node_type {
};
enum treeview_node_section {
- TV_NODE_SECTION_TOGGLE,
- TV_NODE_SECTION_ON_NODE,
- TV_NODE_SECTION_NONE
-};
+ TV_NODE_SECTION_TOGGLE, /**< Expansion toggle */
+ TV_NODE_SECTION_ON_NODE, /**< Node content (text, icon) */
+ TV_NODE_SECTION_NONE /**< Empty area */
+}; /**< Section type of a treeview at a point */
struct treeview_text {
- const char *data;
- uint32_t len;
- int width;
+ const char *data; /**< Text string */
+ uint32_t len; /**< Lenfth of string in bytes */
+ int width; /**< Width of text in px */
};
struct treeview_field {
@@ -72,33 +72,33 @@ enum treeview_node_flags {
};
struct treeview_node {
- enum treeview_node_flags flags;
- enum treeview_node_type type;
+ enum treeview_node_flags flags; /**< Node flags */
+ enum treeview_node_type type; /**< Node type */
- int height;
- int inset;
+ int height; /**< Includes height of any descendants (pixels) */
+ int inset; /**< Node's inset depending on tree depth (pixels) */
struct treeview_node *parent;
struct treeview_node *sibling_prev;
struct treeview_node *sibling_next;
struct treeview_node *children;
- void *client_data;
+ void *client_data; /**< Passed to client on node event msg callback */
- struct treeview_field text;
-};
+ struct treeview_field text; /** Text to show for node (default field) */
+}; /**< Treeview node */
struct treeview_node_entry {
struct treeview_node base;
struct treeview_field fields[];
-};
+}; /**< Entry class inherits node base class */
struct treeview_pos {
- int x;
- int y;
- int node_y;
- int node_h;
-};
+ int x; /**< Mouse X coordinate */
+ int y; /**< Mouse Y coordinate */
+ int node_y; /**< Top of node at y */
+ int node_h; /**< Height of node at y */
+}; /**< A mouse position wrt treeview */
struct treeview_drag {
enum {
@@ -106,28 +106,29 @@ struct treeview_drag {
TV_DRAG_SELECTION,
TV_DRAG_MOVE,
TV_DRAG_TEXTAREA
- } type;
- struct treeview_node *start_node;
- bool selected; /* Whether start node is selected */
- enum treeview_node_section section;
- struct treeview_pos start;
- struct treeview_pos prev;
-};
+ } type; /**< Drag type */
+ struct treeview_node *start_node; /**< Start node */
+ bool selected; /**< Start node is selected */
+ enum treeview_node_section section; /**< Node section at start */
+ struct treeview_pos start; /**< Start pos */
+ struct treeview_pos prev; /**< Previous pos */
+}; /**< Drag state */
struct treeview {
- uint32_t view_height;
- uint32_t view_width;
+ uint32_t view_height; /** Viewport size */
+ uint32_t view_width; /** Viewport size */
- struct treeview_node *root;
+ struct treeview_node *root; /**< Root node */
- struct treeview_field *fields;
- int n_fields; /* fields[n_fields] is folder, lower are entry fields */
- int field_width;
+ struct treeview_field *fields; /**< Array of fields */
+ 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;
+ struct treeview_drag drag; /**< Drag state */
- const struct treeview_callback_table *callbacks;
- const struct core_window_callback_table *cw_t; /**< Core window callback table */
+ const struct treeview_callback_table *callbacks; /**< For node events */
+
+ const struct core_window_callback_table *cw_t; /**< Window cb table */
struct core_window *cw_h; /**< Core window handle */
};
@@ -142,15 +143,15 @@ struct treeview_node_style {
plot_font_style_t sitext; /**< Selected entry field text */
};
-struct treeview_node_style plot_style_odd;
-struct treeview_node_style plot_style_even;
+struct treeview_node_style plot_style_odd; /**< Plot style for odd rows */
+struct treeview_node_style plot_style_even; /**< Plot style for even rows */
struct treeview_resource {
const char *url;
struct hlcache_handle *c;
int height;
bool ready;
-};
+}; /**< Treeview content resource data */
enum treeview_resource_id {
TREE_RES_CONTENT = 0,
TREE_RES_FOLDER,
@@ -161,7 +162,7 @@ static struct treeview_resource treeview_res[TREE_RES_LAST] = {
{ "resource:icons/content.png", NULL, 0, false },
{ "resource:icons/directory.png", NULL, 0, false },
{ "resource:icons/search.png", NULL, 0, false }
-};
+}; /**< Treeview content resources */
@@ -171,8 +172,8 @@ enum treeview_furniture_id {
TREE_FURN_LAST
};
static struct treeview_text treeview_furn[TREE_FURN_LAST] = {
- { "\xe2\x96\xb8", 3, 0 },
- { "\xe2\x96\xbe", 3, 0 }
+ { "\xe2\x96\xb8", 3, 0 }, /* U+25B8: Right-pointing small triangle */
+ { "\xe2\x96\xbe", 3, 0 } /* U+25BE: Down-pointing small triangle */
};
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=beceec8c8e7074bfe90...
commit beceec8c8e7074bfe904f534c753ecfab427b7a6
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Say which functions are documented in the header.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index b51fd54..ab77a7b 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -209,6 +209,7 @@ static nserror treeview_create_node_root(struct treeview_node **root)
return NSERROR_OK;
}
+
/**
* Insert a treeview node into a treeview
*
@@ -272,6 +273,7 @@ static inline void treeview_insert_node(struct treeview_node *a,
}
+/* Exported interface, documented in treeview.h */
nserror treeview_create_node_folder(struct treeview *tree,
struct treeview_node **folder,
struct treeview_node *relation,
@@ -319,7 +321,7 @@ nserror treeview_create_node_folder(struct treeview *tree,
}
-
+/* Exported interface, documented in treeview.h */
nserror treeview_update_node_entry(struct treeview *tree,
struct treeview_node *entry,
const struct treeview_field_data fields[],
@@ -380,6 +382,7 @@ nserror treeview_update_node_entry(struct treeview *tree,
}
+/* Exported interface, documented in treeview.h */
nserror treeview_create_node_entry(struct treeview *tree,
struct treeview_node **entry,
struct treeview_node *relation,
@@ -450,6 +453,7 @@ nserror treeview_create_node_entry(struct treeview *tree,
}
+/* Exported interface, documented in treeview.h */
nserror treeview_delete_node(struct treeview *tree, struct treeview_node *n)
{
struct treeview_node_msg msg;
@@ -496,6 +500,7 @@ nserror treeview_delete_node(struct treeview *tree, struct
treeview_node *n)
}
+/* Exported interface, documented in treeview.h */
nserror treeview_create(struct treeview **tree,
const struct treeview_callback_table *callbacks,
int n_fields, struct treeview_field_desc fields[],
@@ -571,6 +576,8 @@ nserror treeview_create(struct treeview **tree,
return NSERROR_OK;
}
+
+/* Exported interface, documented in treeview.h */
nserror treeview_destroy(struct treeview *tree)
{
int f;
@@ -645,6 +652,7 @@ static bool treeview_walk_internal(struct treeview_node *root, bool
full,
}
+/* Exported interface, documented in treeview.h */
nserror treeview_node_expand(struct treeview *tree,
struct treeview_node *node)
{
@@ -751,6 +759,7 @@ static bool treeview_node_contract_cb(struct treeview_node *node, void
*ctx)
return false; /* Don't want to abort tree walk */
}
+/* Exported interface, documented in treeview.h */
nserror treeview_node_contract(struct treeview *tree,
struct treeview_node *node)
{
@@ -771,15 +780,8 @@ nserror treeview_node_contract(struct treeview *tree,
return NSERROR_OK;
}
-/**
- * Redraws a treeview.
- *
- * \param tree the tree to draw
- * \param x X coordinate to draw the tree at (wrt plot origin)
- * \param y Y coordinate to draw the tree at (wrt plot origin)
- * \param clip_x clipping rectangle (wrt tree origin)
- * \param ctx current redraw context
- */
+/* Exported interface, documented in treeview.h */
+/* Exported interface, documented in treeview.h */
void treeview_redraw(struct treeview *tree, int x, int y, struct rect *clip,
const struct redraw_context *ctx)
{
@@ -1081,6 +1083,8 @@ static bool treeview_node_selection_walk_cb(struct treeview_node
*node,
return false; /* Don't stop walk */
}
+
+/* Exported interface, documented in treeview.h */
bool treeview_has_selection(struct treeview *tree)
{
struct treeview_selection_walk_data sw;
@@ -1094,6 +1098,8 @@ bool treeview_has_selection(struct treeview *tree)
return sw.data.has_selection;
}
+
+/* Exported interface, documented in treeview.h */
bool treeview_clear_selection(struct treeview *tree, struct rect *rect)
{
struct treeview_selection_walk_data sw;
@@ -1114,6 +1120,8 @@ bool treeview_clear_selection(struct treeview *tree, struct rect
*rect)
return sw.data.redraw.required;
}
+
+/* Exported interface, documented in treeview.h */
bool treeview_select_all(struct treeview *tree, struct rect *rect)
{
struct treeview_selection_walk_data sw;
@@ -1367,6 +1375,7 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node, void *ctx)
return true; /* Reached line with click; stop walking tree */
}
+/* Exported interface, documented in treeview.h */
void treeview_mouse_action(struct treeview *tree,
browser_mouse_state mouse, int x, int y)
{
@@ -1521,6 +1530,7 @@ static void treeview_init_furniture(void)
}
+/* Exported interface, documented in treeview.h */
nserror treeview_init(void)
{
int font_px_size;
@@ -1541,6 +1551,7 @@ nserror treeview_init(void)
}
+/* Exported interface, documented in treeview.h */
nserror treeview_fini(void)
{
int i;
diff --git a/desktop/treeview.h b/desktop/treeview.h
index da6216f..2579d85 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -225,7 +225,7 @@ nserror treeview_node_contract(struct treeview *tree,
* \param tree Treeview object to render
* \param x X coordinate to render treeview at
* \param x Y coordinate to render treeview at
- * \param clip Current clip rectangle
+ * \param clip Current clip rectangle (wrt tree origin)
* \param ctx Current redraw context
*/
void treeview_redraw(struct treeview *tree, int x, int y, struct rect *clip,
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=ec02cf9e4c560c38321...
commit ec02cf9e4c560c38321b594cb95f9f7c22172f8e
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Remove unused function.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 615a76c..b51fd54 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -1551,12 +1551,3 @@ nserror treeview_fini(void)
return NSERROR_OK;
}
-
-
-struct treeview_node * treeview_get_root(struct treeview *tree)
-{
- assert(tree != NULL);
- assert(tree->root != NULL);
-
- return tree->root;
-}
diff --git a/desktop/treeview.h b/desktop/treeview.h
index 0bcd7bc..da6216f 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -242,8 +242,6 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
void treeview_mouse_action(struct treeview *tree,
browser_mouse_state mouse, int x, int y);
-struct treeview_node * treeview_get_root(struct treeview *tree);
-
/**
* Determine whether treeview has a selection
*
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=1f3265f2a56ccb5de47...
commit 1f3265f2a56ccb5de4722351fa0bb7ca8d037dd8
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Add documentation.
diff --git a/desktop/treeview.h b/desktop/treeview.h
index d21a8a4..0bcd7bc 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -35,12 +35,12 @@ struct treeview_node;
enum treeview_relationship {
TREE_REL_FIRST_CHILD,
TREE_REL_NEXT_SIBLING
-};
+}; /**< Relationship between nodes */
enum treeview_msg {
- TREE_MSG_NODE_DELETE,
- TREE_MSG_NODE_EDIT,
- TREE_MSG_NODE_LAUNCH
+ TREE_MSG_NODE_DELETE, /**< Node to be deleted */
+ TREE_MSG_NODE_EDIT, /**< Node to be edited */
+ TREE_MSG_NODE_LAUNCH /**< Node to be launched */
};
struct treeview_node_msg {
enum treeview_msg msg; /**< The message type */
@@ -63,39 +63,108 @@ enum treeview_field_flags {
};
struct treeview_field_desc {
- lwc_string *field;
- enum treeview_field_flags flags;
-};
+ lwc_string *field; /**< A treeview field name */
+ enum treeview_field_flags flags; /**< Flags for field */
+}; /**< Treeview field description */
struct treeview_field_data {
- lwc_string *field;
- const char *value;
- size_t value_len;
+ lwc_string *field; /**< Field name */
+ const char *value; /**< Field value */
+ size_t value_len; /**< Field value length (bytes) */
};
struct treeview_callback_table {
nserror (*folder)(struct treeview_node_msg msg, void *data);
nserror (*entry)(struct treeview_node_msg msg, void *data);
-};
+}; /**< Client callbacks for events concerning nodes */
+/**
+ * Prepare treeview module for treeview usage
+ *
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
nserror treeview_init(void);
+
+/**
+ * Finalise the treeview module (all treeviews must have been destroyed first)
+ *
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
nserror treeview_fini(void);
+/**
+ * Create a treeview
+ *
+ * \param tree Returns created treeview object
+ * \param callbacks Treeview client node event callbacks
+ * \param n_fields Number of treeview fields (see description)
+ * \param fields Array of treeview fields
+ * \param cw_t Callback table for core_window containing the treeview
+ * \param cw The core_window in which the treeview is shown
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * The fields array order is as follows (N = n_fields):
+ *
+ * fields[0] Main field for entries (shown when not expanded)
+ * fields[1]...fields[N-2] Additional fields for entries
+ * fields[N-1] Field for folder nodes
+ *
+ * So fields[0] and fields[N-1] have TREE_FLAG_DEFAULT set.
+ */
nserror treeview_create(struct treeview **tree,
const struct treeview_callback_table *callbacks,
int n_fields, struct treeview_field_desc fields[],
const struct core_window_callback_table *cw_t,
struct core_window *cw);
+/**
+ * Destroy a treeview object
+ *
+ * \param tree Treeview object to destroy
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * Will emit folder and entry deletion msg callbacks for all nodes in treeview.
+ */
nserror treeview_destroy(struct treeview *tree);
+/**
+ * Create a folder node in given treeview
+ *
+ * \param tree Treeview object in which to create folder
+ * \param folder Returns created folder node
+ * \param relation Existing node to insert as relation of, or NULL
+ * \param rel Folder's relationship to relation
+ * \param field Field data
+ * \param data Client data for node event callbacks
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * Field name must match name past in treeview_create fields[N-1].
+ *
+ * If relation is NULL, will insert as child of root node.
+ */
nserror treeview_create_node_folder(struct treeview *tree,
struct treeview_node **folder,
struct treeview_node *relation,
enum treeview_relationship rel,
const struct treeview_field_data *field,
void *data);
+
+/**
+ * Create an entry node in given treeview
+ *
+ * \param tree Treeview object in which to create entry
+ * \param entry Returns created entry node
+ * \param relation Existing node to insert as relation of, or NULL
+ * \param rel Folder's relationship to relation
+ * \param fields Array of field data
+ * \param data Client data for node event callbacks
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * Fields array names must match names past in treeview_create fields[0...N-2].
+ *
+ * If relation is NULL, will insert as child of root node.
+ */
nserror treeview_create_node_entry(struct treeview *tree,
struct treeview_node **entry,
struct treeview_node *relation,
@@ -103,41 +172,91 @@ nserror treeview_create_node_entry(struct treeview *tree,
const struct treeview_field_data fields[],
void *data);
+/**
+ * Update an entry node in given treeview
+ *
+ * \param tree Treeview object in which to create entry
+ * \param entry Entry node to update
+ * \param fields Array of new field data
+ * \param data Client data for node event callbacks
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * Fields array names must match names past in treeview_create fields[0...N-2].
+ */
nserror treeview_update_node_entry(struct treeview *tree,
struct treeview_node *entry,
const struct treeview_field_data fields[],
void *data);
+/**
+ * Delete a treeview node
+ *
+ * \param tree Treeview object to delete node from
+ * \param n Node to delete
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * Will emit folder or entry deletion msg callback.
+ */
nserror treeview_delete_node(struct treeview *tree, struct treeview_node *n);
+/**
+ * Expand a treeview node
+ *
+ * \param tree Treeview object to expande node in
+ * \param node Node to expand
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
nserror treeview_node_expand(struct treeview *tree,
struct treeview_node *node);
+
+/**
+ * Contract a treeview node
+ *
+ * \param tree Treeview object to contract node in
+ * \param node Node to contract
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
nserror treeview_node_contract(struct treeview *tree,
struct treeview_node *node);
+/**
+ * Redraw a treeview object
+ *
+ * \param tree Treeview object to render
+ * \param x X coordinate to render treeview at
+ * \param x Y coordinate to render treeview at
+ * \param clip Current clip rectangle
+ * \param ctx Current redraw context
+ */
void treeview_redraw(struct treeview *tree, int x, int y, struct rect *clip,
const struct redraw_context *ctx);
/**
* Handles all kinds of mouse action
*
- * \param tree Treeview
- * \param mouse the mouse state at action moment
- * \param x X coordinate
- * \param y Y coordinate
+ * \param tree Treeview object
+ * \param mouse The current mouse state
+ * \param x X coordinate
+ * \param y Y coordinate
*/
void treeview_mouse_action(struct treeview *tree,
browser_mouse_state mouse, int x, int y);
struct treeview_node * treeview_get_root(struct treeview *tree);
+/**
+ * Determine whether treeview has a selection
+ *
+ * \param tree Treeview object to delete node from
+ * \return true iff treeview has a selection
+ */
bool treeview_has_selection(struct treeview *tree);
/**
* Clear any selection in a treeview
*
- * \param tree treeview to clear selection in
- * \param rect redraw rectangle (if redraw required)
+ * \param tree Treeview object to clear selection in
+ * \param rect Redraw rectangle (if redraw required)
* \return true iff redraw required
*/
bool treeview_clear_selection(struct treeview *tree, struct rect *rect);
@@ -145,8 +264,8 @@ bool treeview_clear_selection(struct treeview *tree, struct rect
*rect);
/**
* Select all in a treeview
*
- * \param tree treeview to select all in
- * \param rect redraw rectangle (if redraw required)
+ * \param tree Treeview object to select all in
+ * \param rect Redraw rectangle (if redraw required)
* \return true iff redraw required
*/
bool treeview_select_all(struct treeview *tree, struct rect *rect);
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=11d4788c8b8713de5fa...
commit 11d4788c8b8713de5fa06ea64e9999eb57e815fa
Merge: d064e9a 6c17aa7
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Merge branch 'master' of
git://git.netsurf-browser.org/netsurf
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=d064e9ac78e38f36229...
commit d064e9ac78e38f3622935092e166c30a8917f043
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Add support for selection drags. Not yet implemented move drags.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index ae2d030..615a76c 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -45,6 +45,12 @@ enum treeview_node_type {
TREE_NODE_ENTRY
};
+enum treeview_node_section {
+ TV_NODE_SECTION_TOGGLE,
+ TV_NODE_SECTION_ON_NODE,
+ TV_NODE_SECTION_NONE
+};
+
struct treeview_text {
const char *data;
uint32_t len;
@@ -87,6 +93,27 @@ struct treeview_node_entry {
struct treeview_field fields[];
};
+struct treeview_pos {
+ int x;
+ int y;
+ int node_y;
+ int node_h;
+};
+
+struct treeview_drag {
+ enum {
+ TV_DRAG_NONE,
+ TV_DRAG_SELECTION,
+ TV_DRAG_MOVE,
+ TV_DRAG_TEXTAREA
+ } type;
+ struct treeview_node *start_node;
+ bool selected; /* Whether start node is selected */
+ enum treeview_node_section section;
+ struct treeview_pos start;
+ struct treeview_pos prev;
+};
+
struct treeview {
uint32_t view_height;
uint32_t view_width;
@@ -97,6 +124,8 @@ struct treeview {
int n_fields; /* fields[n_fields] is folder, lower are entry fields */
int field_width;
+ struct treeview_drag drag;
+
const struct treeview_callback_table *callbacks;
const struct core_window_callback_table *cw_t; /**< Core window callback table */
struct core_window *cw_h; /**< Core window handle */
@@ -525,6 +554,17 @@ nserror treeview_create(struct treeview **tree,
(*tree)->callbacks = callbacks;
(*tree)->n_fields = n_fields - 1;
+ (*tree)->drag.type = TV_DRAG_NONE;
+ (*tree)->drag.start_node = NULL;
+ (*tree)->drag.start.x = 0;
+ (*tree)->drag.start.y = 0;
+ (*tree)->drag.start.node_y = 0;
+ (*tree)->drag.start.node_h = 0;
+ (*tree)->drag.prev.x = 0;
+ (*tree)->drag.prev.y = 0;
+ (*tree)->drag.prev.node_y = 0;
+ (*tree)->drag.prev.node_h = 0;
+
(*tree)->cw_t = cw_t;
(*tree)->cw_h = cw;
@@ -759,11 +799,21 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct
rect *clip,
plot_font_style_t *text_style;
plot_font_style_t *infotext_style;
int height;
+ int sel_min, sel_max;
+ bool invert_selection;
assert(tree != NULL);
assert(tree->root != NULL);
assert(tree->root->flags & TREE_NODE_EXPANDED);
+ 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;
+ }
+
/* Start knockout rendering if it's available for this plotter */
if (ctx->plot->option_knockout)
knockout_plot_start(ctx, &new_ctx);
@@ -826,7 +876,16 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
}
style = (count & 0x1) ? &plot_style_odd : &plot_style_even;
- if (node->flags & TREE_NODE_SELECTED) {
+ 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 & TREE_NODE_SELECTED && !invert_selection) ||
+ (!(node->flags & TREE_NODE_SELECTED) &&
+ invert_selection)) {
bg_style = &style->sbg;
text_style = &style->stext;
infotext_style = &style->sitext;
@@ -950,7 +1009,8 @@ struct treeview_selection_walk_data {
enum {
TREEVIEW_WALK_HAS_SELECTION,
TREEVIEW_WALK_CLEAR_SELECTION,
- TREEVIEW_WALK_SELECT_ALL
+ TREEVIEW_WALK_SELECT_ALL,
+ TREEVIEW_WALK_COMMIT_SELECT_DRAG
} purpose;
union {
bool has_selection;
@@ -958,6 +1018,10 @@ struct treeview_selection_walk_data {
bool required;
struct rect *rect;
} redraw;
+ struct {
+ int sel_min;
+ int sel_max;
+ } drag;
} data;
int current_y;
};
@@ -993,6 +1057,14 @@ static bool treeview_node_selection_walk_cb(struct treeview_node
*node,
changed = true;
}
break;
+
+ case TREEVIEW_WALK_COMMIT_SELECT_DRAG:
+ if (sw->current_y > sw->data.drag.sel_min &&
+ sw->current_y - height <
+ sw->data.drag.sel_max) {
+ node->flags ^= TREE_NODE_SELECTED;
+ }
+ return false; /* Don't stop walk */
}
if (changed) {
@@ -1062,6 +1134,25 @@ bool treeview_select_all(struct treeview *tree, struct rect *rect)
return sw.data.redraw.required;
}
+static void treeview_commit_selection_drag(struct treeview *tree)
+{
+ struct treeview_selection_walk_data sw;
+
+ sw.purpose = TREEVIEW_WALK_COMMIT_SELECT_DRAG;
+ sw.current_y = 0;
+
+ if (tree->drag.start.y > tree->drag.prev.y) {
+ sw.data.drag.sel_min = tree->drag.prev.y;
+ sw.data.drag.sel_max = tree->drag.start.y;
+ } else {
+ sw.data.drag.sel_min = tree->drag.start.y;
+ sw.data.drag.sel_max = tree->drag.prev.y;
+ }
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_selection_walk_cb, &sw);
+}
+
struct treeview_mouse_action {
struct treeview *tree;
browser_mouse_state mouse;
@@ -1080,10 +1171,7 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node, void *ctx)
TV_NODE_ACTION_NONE = 0,
TV_NODE_ACTION_SELECTION = (1 << 0)
} action = TV_NODE_ACTION_NONE;
- enum {
- TV_NODE_SECTION_TOGGLE,
- TV_NODE_SECTION_NODE
- } section = TV_NODE_SECTION_NODE;
+ enum treeview_node_section section = TV_NODE_SECTION_NONE;
nserror err;
r.x0 = 0;
@@ -1099,9 +1187,112 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node, void *ctx)
}
/* Find where the mouse is */
- if (ma->x >= node->inset - 1 &&
- ma->x < node->inset + tree_g.step_width) {
- section = TV_NODE_SECTION_TOGGLE;
+ if (ma->y <= ma->current_y + tree_g.line_height) {
+ if (ma->x >= node->inset - 1 &&
+ ma->x < node->inset + tree_g.step_width) {
+ /* Over expansion toggle */
+ section = TV_NODE_SECTION_TOGGLE;
+
+ } else if (ma->x >= node->inset + tree_g.step_width &&
+ ma->x < node->inset + tree_g.step_width +
+ tree_g.icon_step + node->text.value.width) {
+ /* On node */
+ section = TV_NODE_SECTION_ON_NODE;
+ }
+ } else if (node->type == TREE_NODE_ENTRY &&
+ height > tree_g.line_height) {
+ /* Expanded entries */
+ int x = node->inset + tree_g.step_width + tree_g.icon_step;
+ int y = ma->current_y + tree_g.line_height;
+ int i;
+ struct treeview_node_entry *entry =
+ (struct treeview_node_entry *)node;
+ for (i = 0; i < ma->tree->n_fields - 1; i++) {
+ struct treeview_field *ef = &(ma->tree->fields[i + 1]);
+
+ if (ma->y > y + tree_g.line_height) {
+ y += tree_g.line_height;
+ continue;
+ }
+
+ if (ef->flags & TREE_FLAG_SHOW_NAME) {
+ int max_width = ma->tree->field_width;
+
+ if (ma->x >= x + max_width - ef->value.width -
+ tree_g.step_width &&
+ ma->x < x + max_width -
+ tree_g.step_width) {
+ /* On a field name */
+ section = TV_NODE_SECTION_ON_NODE;
+
+ } else if (ma->x >= x + max_width &&
+ ma->x < x + max_width +
+ entry->fields[i].value.width) {
+ /* On a field value */
+ section = TV_NODE_SECTION_ON_NODE;
+ }
+ } else {
+ if (ma->x >= x && ma->x < x +
+ entry->fields[i].value.width) {
+ /* On a field value */
+ section = TV_NODE_SECTION_ON_NODE;
+ }
+ }
+
+ break;
+ }
+ }
+
+ /* Record what position / section a drag started on */
+ if (ma->mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2) &&
+ ma->tree->drag.type == TV_DRAG_NONE) {
+ ma->tree->drag.selected = node->flags & TREE_NODE_SELECTED;
+ ma->tree->drag.start_node = node;
+ ma->tree->drag.section = section;
+ ma->tree->drag.start.x = ma->x;
+ ma->tree->drag.start.y = ma->y;
+ ma->tree->drag.start.node_y = ma->current_y;
+ ma->tree->drag.start.node_h = height;
+
+ ma->tree->drag.prev.x = ma->x;
+ ma->tree->drag.prev.y = ma->y;
+ ma->tree->drag.prev.node_y = ma->current_y;
+ ma->tree->drag.prev.node_h = height;
+ }
+
+ /* Handle drag start */
+ if (ma->tree->drag.type == TV_DRAG_NONE) {
+ if (ma->mouse & BROWSER_MOUSE_DRAG_1 &&
+ ma->tree->drag.selected == false &&
+ ma->tree->drag.section ==
+ TV_NODE_SECTION_NONE) {
+ ma->tree->drag.type = TV_DRAG_SELECTION;
+ } else if (ma->mouse & BROWSER_MOUSE_DRAG_2) {
+ ma->tree->drag.type = TV_DRAG_SELECTION;
+ }
+
+ if (ma->tree->drag.start_node != NULL &&
+ ma->tree->drag.type == TV_DRAG_SELECTION) {
+ ma->tree->drag.start_node->flags ^= TREE_NODE_SELECTED;
+ }
+ }
+
+ /* Handle selection drags */
+ if (ma->tree->drag.type == 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;
+
+ r.y0 = (ma->current_y < ma->tree->drag.prev.node_y) ?
+ ma->current_y : ma->tree->drag.prev.node_y;
+ r.y1 = (curr_y1 > prev_y1) ? curr_y1 : prev_y1;
+
+ redraw = true;
+
+ ma->tree->drag.prev.x = ma->x;
+ ma->tree->drag.prev.y = ma->y;
+ ma->tree->drag.prev.node_y = ma->current_y;
+ ma->tree->drag.prev.node_h = height;
}
click = ma->mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2);
@@ -1181,6 +1372,14 @@ void treeview_mouse_action(struct treeview *tree,
{
struct treeview_mouse_action ma;
+ if (mouse == BROWSER_MOUSE_HOVER &&
+ tree->drag.type == TV_DRAG_SELECTION) {
+ treeview_commit_selection_drag(tree);
+ tree->drag.type = TV_DRAG_NONE;
+ tree->drag.start_node = NULL;
+ return;
+ }
+
ma.tree = tree;
ma.mouse = mouse;
ma.x = x;
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=55dd0356862293ea22f...
commit 55dd0356862293ea22f12791de4aa93e2a363f8f
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Add triple click to mouse event logger.
diff --git a/desktop/mouse.c b/desktop/mouse.c
index 372ce2c..c156af8 100644
--- a/desktop/mouse.c
+++ b/desktop/mouse.c
@@ -30,12 +30,13 @@
*/
void browser_mouse_state_dump(browser_mouse_state mouse)
{
- LOG(("mouse state: %s %s %s %s %s %s %s %s %s %s %s %s %s",
+ LOG(("mouse state: %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
mouse & BROWSER_MOUSE_PRESS_1 ? "P1" : " ",
mouse & BROWSER_MOUSE_PRESS_2 ? "P2" : " ",
mouse & BROWSER_MOUSE_CLICK_1 ? "C1" : " ",
mouse & BROWSER_MOUSE_CLICK_2 ? "C2" : " ",
mouse & BROWSER_MOUSE_DOUBLE_CLICK ? "DC" : " ",
+ mouse & BROWSER_MOUSE_TRIPLE_CLICK ? "TC" : " ",
mouse & BROWSER_MOUSE_DRAG_1 ? "D1" : " ",
mouse & BROWSER_MOUSE_DRAG_2 ? "D2" : " ",
mouse & BROWSER_MOUSE_DRAG_ON ? "DO" : " ",
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=a3c72894b9eb38268d6...
commit a3c72894b9eb38268d6d61e1f5adc151891107e5
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Make test parasite pass drag end event to new treeview.
diff --git a/desktop/tree.c b/desktop/tree.c
index 92a2510..d9b0592 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -2928,6 +2928,11 @@ void tree_drag_end(struct tree *tree, browser_mouse_state mouse,
int x0, int y0,
struct node *node;
int x, y;
+ if (tree->flags & TREE_MOVABLE) {
+ treeview_test_mouse_action(tree, BROWSER_MOUSE_HOVER, x1, y1);
+ return;
+ }
+
switch (tree->drag) {
case TREE_NO_DRAG:
case TREE_UNKNOWN_DRAG:
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=44e4ca5f05ceff06831...
commit 44e4ca5f05ceff06831dfac9066d35df37d7a830
Merge: b04acde 4d39d43
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Merge branch 'master' of
git://git.netsurf-browser.org/netsurf
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=b04acde22874bb69c5a...
commit b04acde22874bb69c5ad8eba41e73fbb39589f0e
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Set visits and last visited values.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index a675d83..27b8e47 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -135,22 +135,39 @@ static nserror global_history_create_treeview_field_data(
const struct url_data *data)
{
const char *title = (data->title != NULL) ? data->title : "<No
title>";
+ char buffer[16];
+ const char *last_visited;
+ char *last_visited2;
+ int len;
e->data[0].field = gh_ctx.fields[0].field;
e->data[0].value = strdup(title);
- e->data[0].value_len = strlen(title);
+ e->data[0].value_len = (e->data[0].value != NULL) ? strlen(title) : 0;
e->data[1].field = gh_ctx.fields[1].field;
e->data[1].value = nsurl_access(e->url);
e->data[1].value_len = nsurl_length(e->url);
+ last_visited = ctime(&data->last_visit);
+ last_visited2 = strdup(last_visited);
+ if (last_visited2 != NULL) {
+ assert(last_visited2[24] == '\n');
+ last_visited2[24] = '\0';
+ }
+
e->data[2].field = gh_ctx.fields[2].field;
- e->data[2].value = "Date time";
- e->data[2].value_len = SLEN("Date time");
+ e->data[2].value = last_visited2;
+ e->data[2].value_len = (last_visited2 != NULL) ? 24 : 0;
+
+ len = snprintf(buffer, 16, "%u", data->visits);
+ if (len == 16) {
+ len--;
+ buffer[len] = '\0';
+ }
e->data[3].field = gh_ctx.fields[3].field;
- e->data[3].value = "Count";
- e->data[3].value_len = SLEN("Count");
+ e->data[3].value = strdup(buffer);
+ e->data[3].value_len = len;
return NSERROR_OK;
}
@@ -272,6 +289,8 @@ static void global_history_delete_entry_internal(
/* Destroy */
free((void *)e->data[0].value); /* Eww */
+ free((void *)e->data[2].value); /* Eww */
+ free((void *)e->data[3].value); /* Eww */
nsurl_unref(e->url);
free(e);
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=db62a386bf4a9c4c962...
commit db62a386bf4a9c4c962e21384c91c425738318e0
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Reduce redraw area.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 83ae526..ae2d030 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -1120,10 +1120,10 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node, void *ctx)
}
/* Set up redraw */
- redraw = true;
- if (r.y0 > ma->current_y)
+ if (!redraw || r.y0 > ma->current_y)
r.y0 = ma->current_y;
r.y1 = REDRAW_MAX;
+ redraw = true;
} else if ((node->type == TREE_NODE_ENTRY) &&
(ma->mouse & BROWSER_MOUSE_DOUBLE_CLICK) && click) {
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=d398caf146f35d1bc73...
commit d398caf146f35d1bc7386e853ce16e2ef457fbc2
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Ensure there's a title.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index f8bd180..a675d83 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -134,9 +134,11 @@ static nserror global_history_create_treeview_field_data(
struct global_history_entry *e,
const struct url_data *data)
{
+ const char *title = (data->title != NULL) ? data->title : "<No
title>";
+
e->data[0].field = gh_ctx.fields[0].field;
- e->data[0].value = strdup(data->title);
- e->data[0].value_len = strlen(data->title);
+ e->data[0].value = strdup(title);
+ e->data[0].value_len = strlen(title);
e->data[1].field = gh_ctx.fields[1].field;
e->data[1].value = nsurl_access(e->url);
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=9919b77f1995e837987...
commit 9919b77f1995e8379870d610aea7a2e227882297
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Update for launch msg.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index c2df249..f8bd180 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -546,7 +546,10 @@ static nserror global_history_tree_node_entry_cb(
global_history_delete_entry_internal(e);
break;
- case TREE_MSG_FIELD_EDIT:
+ case TREE_MSG_NODE_EDIT:
+ break;
+
+ case TREE_MSG_NODE_LAUNCH:
break;
}
return NSERROR_OK;
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=29185f75cfead8c0794...
commit 29185f75cfead8c0794b198be7372b0651110c8c
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Fixup and remove unused defines.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 2e360e3..83ae526 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -28,9 +28,6 @@
#include "render/font.h"
#include "utils/log.h"
-#define FIELD_FOLDER 0
-#define FIELD_FIRST_ENTRY 1
-
/* TODO: get rid of REDRAW_MAX -- need to be able to know window size */
#define REDRAW_MAX 8000
@@ -1138,7 +1135,7 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node, void *ctx)
redraw |= treeview_clear_selection(ma->tree, &r);
/* Tell client an entry was launched */
- tree->callbacks->entry(msg, n->client_data);
+ ma->tree->callbacks->entry(msg, node->client_data);
} else if (ma->mouse & BROWSER_MOUSE_PRESS_1 &&
!(node->flags & TREE_NODE_SELECTED) &&
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=23a0520b40a35e46aab...
commit 23a0520b40a35e46aabcce5743603c3e26a74cd6
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Enable double click to launch from treeview.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 2fa65c8..2e360e3 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -428,7 +428,6 @@ nserror treeview_delete_node(struct treeview *tree, struct
treeview_node *n)
{
struct treeview_node_msg msg;
msg.msg = TREE_MSG_NODE_DELETE;
- msg.data.node_delete.node = n;
/* Destroy children first */
while (n->children != NULL) {
@@ -1116,11 +1115,14 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node, void *ctx)
/* Clear any existing selection */
redraw |= treeview_clear_selection(ma->tree, &r);
+ /* Toggle node expansion */
if (node->flags & TREE_NODE_EXPANDED) {
err = treeview_node_contract(ma->tree, node);
} else {
err = treeview_node_expand(ma->tree, node);
}
+
+ /* Set up redraw */
redraw = true;
if (r.y0 > ma->current_y)
r.y0 = ma->current_y;
@@ -1128,11 +1130,15 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node, void *ctx)
} else if ((node->type == TREE_NODE_ENTRY) &&
(ma->mouse & BROWSER_MOUSE_DOUBLE_CLICK) && click) {
+ struct treeview_node_msg msg;
+ msg.msg = TREE_MSG_NODE_LAUNCH;
+ msg.data.node_launch.mouse = ma->mouse;
+
/* Clear any existing selection */
redraw |= treeview_clear_selection(ma->tree, &r);
/* Tell client an entry was launched */
- /* TODO */
+ tree->callbacks->entry(msg, n->client_data);
} else if (ma->mouse & BROWSER_MOUSE_PRESS_1 &&
!(node->flags & TREE_NODE_SELECTED) &&
diff --git a/desktop/treeview.h b/desktop/treeview.h
index 38c22f2..d21a8a4 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -39,19 +39,19 @@ enum treeview_relationship {
enum treeview_msg {
TREE_MSG_NODE_DELETE,
- TREE_MSG_FIELD_EDIT
+ TREE_MSG_NODE_EDIT,
+ TREE_MSG_NODE_LAUNCH
};
struct treeview_node_msg {
enum treeview_msg msg; /**< The message type */
union {
struct {
- struct treeview_node *node;
- } node_delete;
+ lwc_string *feild; /* The field being edited */
+ const char *text; /* The proposed new value */
+ } node_edit; /* Client may call treeview_update_node_* */
struct {
- struct treeview_node *node;
- lwc_string *feild;
- const char *text;
- } field_edit;
+ browser_mouse_state mouse; /* Button / modifier used */
+ } node_launch;
} data; /**< The message data. */
};
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=8692bb687697a2a5bcb...
commit 8692bb687697a2a5bcbeab84bae7b5d69a64f7f6
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Add support for clicking node expansion toggle.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 3b71da0..2fa65c8 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -1078,11 +1078,16 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node, void *ctx)
struct treeview_mouse_action *ma = ctx;
struct rect r;
bool redraw = false;
+ bool click;
int height;
enum {
TV_NODE_ACTION_NONE = 0,
TV_NODE_ACTION_SELECTION = (1 << 0)
} action = TV_NODE_ACTION_NONE;
+ enum {
+ TV_NODE_SECTION_TOGGLE,
+ TV_NODE_SECTION_NODE
+ } section = TV_NODE_SECTION_NODE;
nserror err;
r.x0 = 0;
@@ -1097,24 +1102,41 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node, void *ctx)
return false; /* Don't want to abort tree walk */
}
- if ((ma->mouse & BROWSER_MOUSE_DOUBLE_CLICK) &&
- (ma->mouse & BROWSER_MOUSE_CLICK_1)) {
+ /* Find where the mouse is */
+ if (ma->x >= node->inset - 1 &&
+ ma->x < node->inset + tree_g.step_width) {
+ section = TV_NODE_SECTION_TOGGLE;
+ }
+
+ click = ma->mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2);
+
+ if (((node->type == TREE_NODE_FOLDER) &&
+ (ma->mouse & BROWSER_MOUSE_DOUBLE_CLICK) && click) ||
+ (section == TV_NODE_SECTION_TOGGLE && click)) {
/* Clear any existing selection */
redraw |= treeview_clear_selection(ma->tree, &r);
- /* TODO: launch callback for entry */
- /* TODO: for now expand/collapse both directories and entries */
if (node->flags & TREE_NODE_EXPANDED) {
err = treeview_node_contract(ma->tree, node);
} else {
err = treeview_node_expand(ma->tree, node);
}
redraw = true;
- r.y0 = ma->current_y;
+ if (r.y0 > ma->current_y)
+ r.y0 = ma->current_y;
r.y1 = REDRAW_MAX;
+ } else if ((node->type == TREE_NODE_ENTRY) &&
+ (ma->mouse & BROWSER_MOUSE_DOUBLE_CLICK) && click) {
+ /* Clear any existing selection */
+ redraw |= treeview_clear_selection(ma->tree, &r);
+
+ /* Tell client an entry was launched */
+ /* TODO */
+
} else if (ma->mouse & BROWSER_MOUSE_PRESS_1 &&
- !(node->flags & TREE_NODE_SELECTED)) {
+ !(node->flags & TREE_NODE_SELECTED) &&
+ section != TV_NODE_SECTION_TOGGLE) {
/* Clear any existing selection */
redraw |= treeview_clear_selection(ma->tree, &r);
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=add9e7283711ba059d0...
commit add9e7283711ba059d017d1a656c172366bc751a
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Allow ctrl + select to toggle selection.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 8fee9fc..3b71da0 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -1121,7 +1121,9 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node, void *ctx)
/* Select node */
action |= TV_NODE_ACTION_SELECTION;
- } else if (ma->mouse & BROWSER_MOUSE_PRESS_2) {
+ } else if (ma->mouse & BROWSER_MOUSE_PRESS_2 ||
+ (ma->mouse & BROWSER_MOUSE_PRESS_1 &&
+ ma->mouse & BROWSER_MOUSE_MOD_2)) {
/* Toggle selection of node */
action |= TV_NODE_ACTION_SELECTION;
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=abf5512aff5cf03a764...
commit abf5512aff5cf03a764963aaa9dad9e2e570f03e
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Make releationship enum meanings clearer.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index 5ebc1ec..c2df249 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -175,7 +175,7 @@ static nserror global_history_entry_insert(struct global_history_entry
*e,
}
err = treeview_create_node_entry(gh_ctx.tree, &(e->entry),
- parent, TREE_REL_CHILD, e->data, e);
+ parent, TREE_REL_FIRST_CHILD, e->data, e);
if (err != NSERROR_OK) {
return err;
}
@@ -429,7 +429,7 @@ static nserror global_history_init_dir(enum global_history_folders f,
nserror err;
time_t t = gh_ctx.today;
struct treeview_node *relation = NULL;
- enum treeview_relationship rel = TREE_REL_CHILD;
+ enum treeview_relationship rel = TREE_REL_FIRST_CHILD;
t -= age * N_SEC_PER_DAY;
@@ -437,7 +437,7 @@ static nserror global_history_init_dir(enum global_history_folders f,
if (f != GH_TODAY) {
relation = gh_ctx.folders[f - 1].folder;
- rel = TREE_REL_SIBLING_NEXT;
+ rel = TREE_REL_NEXT_SIBLING;
}
gh_ctx.folders[f].data.field = gh_ctx.fields[N_FIELDS - 1].field;
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 1959c0c..8fee9fc 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -199,7 +199,7 @@ static inline void treeview_insert_node(struct treeview_node *a,
assert(b != NULL);
switch (rel) {
- case TREE_REL_CHILD:
+ case TREE_REL_FIRST_CHILD:
assert(b->type != TREE_NODE_ENTRY);
a->parent = b;
a->sibling_next = b->children;
@@ -208,7 +208,7 @@ static inline void treeview_insert_node(struct treeview_node *a,
b->children = a;
break;
- case TREE_REL_SIBLING_NEXT:
+ case TREE_REL_NEXT_SIBLING:
assert(b->type != TREE_NODE_ROOT);
a->sibling_prev = b;
a->sibling_next = b->sibling_next;
@@ -261,7 +261,7 @@ nserror treeview_create_node_folder(struct treeview *tree,
if (relation == NULL) {
relation = tree->root;
- rel = TREE_REL_CHILD;
+ rel = TREE_REL_FIRST_CHILD;
}
n = malloc(sizeof(struct treeview_node));
@@ -372,7 +372,7 @@ nserror treeview_create_node_entry(struct treeview *tree,
if (relation == NULL) {
relation = tree->root;
- rel = TREE_REL_CHILD;
+ rel = TREE_REL_FIRST_CHILD;
}
e = malloc(sizeof(struct treeview_node_entry) +
diff --git a/desktop/treeview.h b/desktop/treeview.h
index 21ecfe8..38c22f2 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -33,8 +33,8 @@ struct treeview;
struct treeview_node;
enum treeview_relationship {
- TREE_REL_CHILD,
- TREE_REL_SIBLING_NEXT
+ TREE_REL_FIRST_CHILD,
+ TREE_REL_NEXT_SIBLING
};
enum treeview_msg {
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=cdf9c9ba72c7588a1e3...
commit cdf9c9ba72c7588a1e3f503fea9f288c8394af9e
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Sort so newest at top.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index f479e75..5ebc1ec 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -508,14 +508,22 @@ static nserror global_history_init_entries(void)
/* Itterate over all global history data, inserting it into treeview */
for (i = 0; i < N_DAYS; i++) {
+ struct global_history_entry *l = NULL;
struct global_history_entry *e = gh_list[i];
-
+
+ /* Insert in reverse order; find last */
while (e != NULL) {
- err = global_history_entry_insert(e, i);
+ l = e;
+ e = e->next;
+ }
+
+ /* Insert the entries into the treeview */
+ while (l != NULL) {
+ err = global_history_entry_insert(l, i);
if (err != NSERROR_OK) {
return err;
}
- e = e->next;
+ l = l->prev;
}
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=a86dd681657ee4d5bd1...
commit a86dd681657ee4d5bd108baaf6825abb47957559
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Lose excess logging.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index 2e4a9b5..f479e75 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -594,8 +594,6 @@ nserror global_history_init(struct core_window_callback_table *cw_t,
return err;
}
- LOG(("Building global history treeview"));
-
/* Add the history to the treeview */
err = global_history_init_entries();
if (err != NSERROR_OK) {
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=d9a66a7ce86e3798b7e...
commit d9a66a7ce86e3798b7e1f8fe112c4a0f5a0f1acb
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Different text colour for an expanded entries' fields.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 2ebdaa2..1959c0c 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -109,9 +109,11 @@ struct treeview {
struct treeview_node_style {
plot_style_t bg; /**< Background */
plot_font_style_t text; /**< Text */
+ plot_font_style_t itext; /**< Entry field text */
plot_style_t sbg; /**< Selected background */
plot_font_style_t stext; /**< Selected text */
+ plot_font_style_t sitext; /**< Selected entry field text */
};
struct treeview_node_style plot_style_odd;
@@ -757,8 +759,9 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
int x0, y0, y1;
int baseline = (tree_g.line_height * 3 + 2) / 4;
enum treeview_resource_id res = TREE_RES_CONTENT;
- plot_style_t *bg;
- plot_font_style_t *text;
+ plot_style_t *bg_style;
+ plot_font_style_t *text_style;
+ plot_font_style_t *infotext_style;
int height;
assert(tree != NULL);
@@ -828,29 +831,31 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct
rect *clip,
style = (count & 0x1) ? &plot_style_odd : &plot_style_even;
if (node->flags & TREE_NODE_SELECTED) {
- bg = &style->sbg;
- text = &style->stext;
+ bg_style = &style->sbg;
+ text_style = &style->stext;
+ infotext_style = &style->sitext;
} else {
- bg = &style->bg;
- text = &style->text;
+ bg_style = &style->bg;
+ text_style = &style->text;
+ infotext_style = &style->itext;
}
/* Render background */
y0 = render_y;
y1 = render_y + height;
- new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, bg);
+ new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, bg_style);
/* Render toggle */
if (node->flags & TREE_NODE_EXPANDED) {
new_ctx.plot->text(inset, render_y + baseline,
treeview_furn[TREE_FURN_CONTRACT].data,
treeview_furn[TREE_FURN_CONTRACT].len,
- text);
+ text_style);
} else {
new_ctx.plot->text(inset, render_y + baseline,
treeview_furn[TREE_FURN_EXPAND].data,
treeview_furn[TREE_FURN_EXPAND].len,
- text);
+ text_style);
}
/* Render icon */
@@ -864,7 +869,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
data.x = inset + tree_g.step_width;
data.y = render_y + ((tree_g.line_height -
treeview_res[res].height + 1) / 2);
- data.background_colour = style->bg.fill_colour;
+ data.background_colour = bg_style->fill_colour;
content_redraw(treeview_res[res].c,
&data, &r, &new_ctx);
@@ -874,7 +879,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
x0 = inset + tree_g.step_width + tree_g.icon_step;
new_ctx.plot->text(x0, render_y + baseline,
node->text.value.data, node->text.value.len,
- text);
+ text_style);
/* Rendered the node */
render_y += tree_g.line_height;
@@ -904,18 +909,18 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct
rect *clip,
render_y + baseline,
ef->value.data,
ef->value.len,
- text);
+ infotext_style);
new_ctx.plot->text(x0 + max_width,
render_y + baseline,
entry->fields[i].value.data,
entry->fields[i].value.len,
- text);
+ infotext_style);
} else {
new_ctx.plot->text(x0, render_y + baseline,
entry->fields[i].value.data,
entry->fields[i].value.len,
- text);
+ infotext_style);
}
@@ -1190,6 +1195,12 @@ static void treeview_init_plot_styles(int font_pt_size)
plot_style_even.text.foreground = gui_system_colour_char("WindowText");
plot_style_even.text.background = gui_system_colour_char("Window");
+ /* Entry field text colour */
+ plot_style_even.itext = plot_style_even.text;
+ plot_style_even.itext.foreground = mix_colour(
+ plot_style_even.text.foreground,
+ plot_style_even.text.background, 255 * 10 / 16);
+
/* Selected background colour */
plot_style_even.sbg = plot_style_even.bg;
plot_style_even.sbg.fill_colour = gui_system_colour_char("Highlight");
@@ -1200,6 +1211,12 @@ static void treeview_init_plot_styles(int font_pt_size)
gui_system_colour_char("HighlightText");
plot_style_even.stext.background = gui_system_colour_char("Highlight");
+ /* Selected entry field text colour */
+ plot_style_even.sitext = plot_style_even.stext;
+ plot_style_even.sitext.foreground = mix_colour(
+ plot_style_even.stext.foreground,
+ plot_style_even.stext.background, 255 * 25 / 32);
+
/* Odd numbered node styles */
plot_style_odd.bg = plot_style_even.bg;
@@ -1208,9 +1225,14 @@ static void treeview_init_plot_styles(int font_pt_size)
plot_style_even.text.foreground, 255 * 15 / 16);
plot_style_odd.text = plot_style_even.text;
plot_style_odd.text.background = plot_style_odd.bg.fill_colour;
+ plot_style_odd.itext = plot_style_odd.text;
+ plot_style_odd.itext.foreground = mix_colour(
+ plot_style_odd.text.foreground,
+ plot_style_odd.text.background, 255 * 10 / 16);
plot_style_odd.sbg = plot_style_even.sbg;
plot_style_odd.stext = plot_style_even.stext;
+ plot_style_odd.sitext = plot_style_even.sitext;
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=c011f45860a4088ffba...
commit c011f45860a4088ffbaa5896eecac7f40d763f89
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Store inset on node.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index d5d7b0e..2ebdaa2 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -73,6 +73,7 @@ struct treeview_node {
enum treeview_node_type type;
int height;
+ int inset;
struct treeview_node *parent;
struct treeview_node *sibling_prev;
@@ -160,6 +161,7 @@ static nserror treeview_create_node_root(struct treeview_node **root)
n->type = TREE_NODE_ROOT;
n->height = 0;
+ n->inset = tree_g.window_padding - tree_g.step_width;
n->text.flags = TREE_FLAG_NONE;
n->text.field = NULL;
@@ -221,6 +223,8 @@ static inline void treeview_insert_node(struct treeview_node *a,
assert(a->parent != NULL);
+ a->inset = a->parent->inset + tree_g.step_width;
+
if (a->parent->flags & TREE_NODE_EXPANDED) {
/* Parent is expanded, so inserted node will be visible and
* affect layout */
@@ -560,12 +564,10 @@ nserror treeview_destroy(struct treeview *tree)
* \return true iff callback caused premature abort
*/
static bool treeview_walk_internal(struct treeview_node *root, bool full,
- bool (*callback)(struct treeview_node *node,
- int inset, void *ctx),
+ bool (*callback)(struct treeview_node *node, void *ctx),
void *ctx)
{
struct treeview_node *node, *next;
- int inset = tree_g.window_padding - tree_g.step_width;
node = root;
@@ -576,7 +578,6 @@ static bool treeview_walk_internal(struct treeview_node *root, bool
full,
if (next != NULL) {
/* Down to children */
node = next;
- inset += tree_g.step_width;
} else {
/* No children. As long as we're not at the root,
* go to next sibling if present, or nearest ancestor
@@ -585,7 +586,6 @@ static bool treeview_walk_internal(struct treeview_node *root, bool
full,
while (node != root &&
node->sibling_next == NULL) {
node = node->parent;
- inset -= tree_g.step_width;
}
if (node == root)
@@ -597,7 +597,7 @@ static bool treeview_walk_internal(struct treeview_node *root, bool
full,
assert(node != NULL);
assert(node != root);
- if (callback(node, inset, ctx)) {
+ if (callback(node, ctx)) {
/* callback caused early termination */
return true;
}
@@ -688,8 +688,7 @@ nserror treeview_node_expand(struct treeview *tree,
}
-static bool treeview_node_contract_cb(struct treeview_node *node, int inset,
- void *ctx)
+static bool treeview_node_contract_cb(struct treeview_node *node, void *ctx)
{
int height_reduction;
@@ -729,7 +728,7 @@ nserror treeview_node_contract(struct treeview *tree,
treeview_walk_internal(node, false, treeview_node_contract_cb, NULL);
/* Contract node */
- treeview_node_contract_cb(node, 0, NULL);
+ treeview_node_contract_cb(node, NULL);
return NSERROR_OK;
}
@@ -752,9 +751,9 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
struct treeview_node_style *style = &plot_style_odd;
struct content_redraw_data data;
struct rect r;
- int inset = tree_g.window_padding - tree_g.step_width;
uint32_t count = 0;
int render_y = y;
+ int inset;
int x0, y0, y1;
int baseline = (tree_g.line_height * 3 + 2) / 4;
enum treeview_resource_id res = TREE_RES_CONTENT;
@@ -795,7 +794,6 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
if (next != NULL) {
/* down to children */
node = next;
- inset += tree_g.step_width;
} else {
/* No children. As long as we're not at the root,
* go to next sibling if present, or nearest ancestor
@@ -804,7 +802,6 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
while (node != root &&
node->sibling_next == NULL) {
node = node->parent;
- inset -= tree_g.step_width;
}
if (node == root)
@@ -819,6 +816,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
node->type == TREE_NODE_ENTRY);
count++;
+ inset = node->inset;
height = (node->type == TREE_NODE_ENTRY) ? node->height :
tree_g.line_height;
@@ -963,7 +961,7 @@ struct treeview_selection_walk_data {
int current_y;
};
static bool treeview_node_selection_walk_cb(struct treeview_node *node,
- int inset, void *ctx)
+ void *ctx)
{
struct treeview_selection_walk_data *sw = ctx;
int height;
@@ -1070,8 +1068,7 @@ struct treeview_mouse_action {
int y;
int current_y;
};
-static bool treeview_node_mouse_action_cb(struct treeview_node *node,
- int inset, void *ctx)
+static bool treeview_node_mouse_action_cb(struct treeview_node *node, void *ctx)
{
struct treeview_mouse_action *ma = ctx;
struct rect r;
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=a6906394f4c5da184ad...
commit a6906394f4c5da184ad647a9033ca8490cc80034
Merge: f947259 ccb0c1c
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Merge branch 'master' of
git://git.netsurf-browser.org/netsurf
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=f947259ef22a989af97...
commit f947259ef22a989af9719e6557d65212b775c8ab
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Get line height from font size.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index abf06f3..d5d7b0e 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -20,6 +20,7 @@
* Treeview handling (implementation).
*/
+#include "css/utils.h"
#include "desktop/gui.h"
#include "desktop/knockout.h"
#include "desktop/plotters.h"
@@ -1175,7 +1176,7 @@ void treeview_mouse_action(struct treeview *tree,
((c0 & 0x00ff00) * ( p)) ) >> 8) & 0x00ff00))
-static void treeview_init_plot_styles(void)
+static void treeview_init_plot_styles(int font_pt_size)
{
/* Background colour */
plot_style_even.bg.stroke_type = PLOT_OP_TYPE_NONE;
@@ -1186,7 +1187,7 @@ static void treeview_init_plot_styles(void)
/* Text colour */
plot_style_even.text.family = PLOT_FONT_FAMILY_SANS_SERIF;
- plot_style_even.text.size = 11 * FONT_SIZE_SCALE;
+ plot_style_even.text.size = font_pt_size * FONT_SIZE_SCALE;
plot_style_even.text.weight = 400;
plot_style_even.text.flags = FONTF_NONE;
plot_style_even.text.foreground = gui_system_colour_char("WindowText");
@@ -1277,11 +1278,16 @@ static void treeview_init_furniture(void)
nserror treeview_init(void)
{
- treeview_init_plot_styles();
+ int font_px_size;
+ int font_pt_size = 11;
+
+ treeview_init_plot_styles(font_pt_size);
treeview_init_resources();
treeview_init_furniture();
- tree_g.line_height = 20;
+ font_px_size = (font_pt_size * FIXTOINT(nscss_screen_dpi) + 36) / 72;
+
+ tree_g.line_height = (font_px_size * 8 + 3) / 6;
tree_g.step_width = tree_g.furniture_width;
tree_g.window_padding = 6;
tree_g.icon_step = 23;
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=abe003cc8d5643f8b27...
commit abe003cc8d5643f8b27a1f9695fe52d3ee509f90
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Remove selected area styles.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 01c8fbc..abf06f3 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -110,9 +110,6 @@ struct treeview_node_style {
plot_style_t sbg; /**< Selected background */
plot_font_style_t stext; /**< Selected text */
-
- plot_style_t sabg; /**< Selection area background */
- plot_font_style_t satext; /**< Selection area text */
};
struct treeview_node_style plot_style_odd;
@@ -1205,16 +1202,6 @@ static void treeview_init_plot_styles(void)
gui_system_colour_char("HighlightText");
plot_style_even.stext.background = gui_system_colour_char("Highlight");
- /* Selection area background colour */
- plot_style_even.sabg = plot_style_even.bg;
- plot_style_even.sabg.fill_colour = mix_colour(
- plot_style_even.bg.fill_colour,
- plot_style_even.sbg.fill_colour, 255 * 3 / 4);
-
- /* Selection area text colour */
- plot_style_even.satext = plot_style_even.text;
- plot_style_even.satext.background = plot_style_even.sabg.fill_colour;
-
/* Odd numbered node styles */
plot_style_odd.bg = plot_style_even.bg;
@@ -1226,13 +1213,6 @@ static void treeview_init_plot_styles(void)
plot_style_odd.sbg = plot_style_even.sbg;
plot_style_odd.stext = plot_style_even.stext;
-
- plot_style_odd.sabg = plot_style_even.sabg;
- plot_style_odd.sabg.fill_colour = mix_colour(
- plot_style_even.sabg.fill_colour,
- plot_style_even.satext.foreground, 255 * 15 / 16);
- plot_style_odd.satext = plot_style_even.satext;
- plot_style_odd.satext.background = plot_style_odd.sabg.fill_colour;
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=8b940b5f11fceb87053...
commit 8b940b5f11fceb870530c949f9b784dc53c0dec8
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Don't pass INT_MAX to redraw_request. RO WIMP doesn't like it.
TODO: Make treeview aware of the window size.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index d430f30..01c8fbc 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -30,6 +30,9 @@
#define FIELD_FOLDER 0
#define FIELD_FIRST_ENTRY 1
+/* TODO: get rid of REDRAW_MAX -- need to be able to know window size */
+#define REDRAW_MAX 8000
+
struct treeview_globals {
int line_height;
int furniture_width;
@@ -1028,7 +1031,7 @@ bool treeview_clear_selection(struct treeview *tree, struct rect
*rect)
rect->x0 = 0;
rect->y0 = 0;
- rect->x1 = INT_MAX;
+ rect->x1 = REDRAW_MAX;
rect->y1 = 0;
sw.purpose = TREEVIEW_WALK_CLEAR_SELECTION;
@@ -1048,7 +1051,7 @@ bool treeview_select_all(struct treeview *tree, struct rect *rect)
rect->x0 = 0;
rect->y0 = 0;
- rect->x1 = INT_MAX;
+ rect->x1 = REDRAW_MAX;
rect->y1 = 0;
sw.purpose = TREEVIEW_WALK_SELECT_ALL;
@@ -1083,7 +1086,7 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node,
nserror err;
r.x0 = 0;
- r.x1 = INT_MAX;
+ r.x1 = REDRAW_MAX;
height = (node->type == TREE_NODE_ENTRY) ? node->height :
tree_g.line_height;
@@ -1108,7 +1111,7 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node,
}
redraw = true;
r.y0 = ma->current_y;
- r.y1 = INT_MAX;
+ r.y1 = REDRAW_MAX;
} else if (ma->mouse & BROWSER_MOUSE_PRESS_1 &&
!(node->flags & TREE_NODE_SELECTED)) {
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=aeb09c73299bae6dcbe...
commit aeb09c73299bae6dcbe607d115f078fe0a35905f
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Remove logging.
diff --git a/desktop/tree.c b/desktop/tree.c
index 07a69f3..92a2510 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -244,8 +244,7 @@ static void treeview_test_redraw(struct tree *tree, int x, int y,
clip.y0 = clip_y;
clip.x1 = clip_x + clip_width;
clip.y1 = clip_y + clip_height;
-LOG(("x:%i, y:%i, clip x0:%i, clip y0:%i, clip x1:%i, clip y1:%i\n",
- x, y, clip.x0, clip.y0, clip.x1, clip.y1));
+
global_history_redraw(x, y, &clip, ctx);
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=c7b57ff681513dbceeb...
commit c7b57ff681513dbceebd22ff13b207331c86c117
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Include full expanded entry height in clip test.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index dc1ed23..d430f30 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -821,7 +821,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
height = (node->type == TREE_NODE_ENTRY) ? node->height :
tree_g.line_height;
- if ((render_y + tree_g.line_height) < r.y0) {
+ if ((render_y + height) < r.y0) {
/* This node's line is above clip region */
render_y += height;
continue;
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=99d85697d2c1a181d34...
commit 99d85697d2c1a181d34417f2b44cad2ea7ba875c
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Use plot coordinate correctly and use the shifted offset clip rect.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index cc0e682..dc1ed23 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -753,7 +753,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
struct rect r;
int inset = tree_g.window_padding - tree_g.step_width;
uint32_t count = 0;
- int render_y = 0;
+ int render_y = y;
int x0, y0, y1;
int baseline = (tree_g.line_height * 3 + 2) / 4;
enum treeview_resource_id res = TREE_RES_CONTENT;
@@ -821,7 +821,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
height = (node->type == TREE_NODE_ENTRY) ? node->height :
tree_g.line_height;
- if ((render_y + tree_g.line_height) < clip->y0) {
+ if ((render_y + tree_g.line_height) < r.y0) {
/* This node's line is above clip region */
render_y += height;
continue;
@@ -879,7 +879,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
/* Rendered the node */
render_y += tree_g.line_height;
- if (render_y > clip->y1) {
+ if (render_y > r.y1) {
/* Passed the bottom of what's in the clip region.
* Done. */
break;
@@ -926,14 +926,14 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct
rect *clip,
/* Finshed rendering expanded entry */
- if (render_y > clip->y1) {
+ if (render_y > r.y1) {
/* Passed the bottom of what's in the clip region.
* Done. */
break;
}
}
- if (render_y < clip->y1) {
+ if (render_y < r.y1) {
/* Fill the blank area at the bottom */
y0 = render_y;
new_ctx.plot->rectangle(r.x0, y0, r.x1, r.y1,
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=ab39827bd8f5fada435...
commit ab39827bd8f5fada435ee5e195bbd7584965cfb1
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Fix use of wrong enum value.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 48f6655..cc0e682 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -858,7 +858,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
if (node->type == TREE_NODE_ENTRY)
res = TREE_RES_CONTENT;
else if (node->type == TREE_NODE_FOLDER)
- res = TREE_NODE_FOLDER;
+ res = TREE_RES_FOLDER;
if (treeview_res[res].ready) {
/* Icon resource is available */
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=8fda149baeaad32fa64...
commit 8fda149baeaad32fa646522c3562ad806bdaf6a1
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Make heights signed, to simplify comparison with struct rect values, which are
signed.
diff --git a/desktop/tree.c b/desktop/tree.c
index 92a2510..07a69f3 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -244,7 +244,8 @@ static void treeview_test_redraw(struct tree *tree, int x, int y,
clip.y0 = clip_y;
clip.x1 = clip_x + clip_width;
clip.y1 = clip_y + clip_height;
-
+LOG(("x:%i, y:%i, clip x0:%i, clip y0:%i, clip x1:%i, clip y1:%i\n",
+ x, y, clip.x0, clip.y0, clip.x1, clip.y1));
global_history_redraw(x, y, &clip, ctx);
}
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 812b3b3..48f6655 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -31,7 +31,7 @@
#define FIELD_FIRST_ENTRY 1
struct treeview_globals {
- uint32_t line_height;
+ int line_height;
int furniture_width;
int step_width;
int window_padding;
@@ -68,7 +68,7 @@ struct treeview_node {
enum treeview_node_flags flags;
enum treeview_node_type type;
- uint32_t height;
+ int height;
struct treeview_node *parent;
struct treeview_node *sibling_prev;
@@ -821,9 +821,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
height = (node->type == TREE_NODE_ENTRY) ? node->height :
tree_g.line_height;
- if (clip->y0 >= 0 &&
- render_y + tree_g.line_height <
- (unsigned)clip->y0) {
+ if ((render_y + tree_g.line_height) < clip->y0) {
/* This node's line is above clip region */
render_y += height;
continue;
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=088d60ec9662d2ecc34...
commit 088d60ec9662d2ecc34410fbaf6a7ff05c9e5558
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Simplify redraw node walk.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index dfa4ea3..812b3b3 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -796,29 +796,20 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct
rect *clip,
node = next;
inset += tree_g.step_width;
} else {
- /* no children */
- next = node->sibling_next;
-
- if (next != NULL) {
- /* on to next sibling */
- node = next;
- } else {
- /* no next sibling */
- while (node != root) {
- next = node->sibling_next;
+ /* No children. As long as we're not at the root,
+ * go to next sibling if present, or nearest ancestor
+ * with a next sibling. */
- if (next != NULL) {
- break;
- }
- node = node->parent;
- inset -= tree_g.step_width;
- }
+ while (node != root &&
+ node->sibling_next == NULL) {
+ node = node->parent;
+ inset -= tree_g.step_width;
+ }
- if (node == root)
- break;
+ if (node == root)
+ break;
- node = node->sibling_next;
- }
+ node = node->sibling_next;
}
assert(node != NULL);
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=fd453beb9702fd28f87...
commit fd453beb9702fd28f8724db969099b2f4463b62e
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Squash warnings for things that can't happen.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 02dd7e2..dfa4ea3 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -756,7 +756,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
int render_y = 0;
int x0, y0, y1;
int baseline = (tree_g.line_height * 3 + 2) / 4;
- enum treeview_resource_id res;
+ enum treeview_resource_id res = TREE_RES_CONTENT;
plot_style_t *bg;
plot_font_style_t *text;
int height;
@@ -823,6 +823,8 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
assert(node != NULL);
assert(node != root);
+ assert(node->type == TREE_NODE_FOLDER ||
+ node->type == TREE_NODE_ENTRY);
count++;
height = (node->type == TREE_NODE_ENTRY) ? node->height :
@@ -945,7 +947,8 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
if (render_y < clip->y1) {
/* Fill the blank area at the bottom */
y0 = render_y;
- new_ctx.plot->rectangle(r.x0, y0, r.x1, r.y1, bg);
+ new_ctx.plot->rectangle(r.x0, y0, r.x1, r.y1,
+ &plot_style_even.bg);
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=1726304d72f766777c3...
commit 1726304d72f766777c3e8f6a15f789fdaec5803e
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Simplify tree walker.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 9d3dce5..02dd7e2 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -573,34 +573,24 @@ static bool treeview_walk_internal(struct treeview_node *root, bool
full,
node->children : NULL;
if (next != NULL) {
- /* down to children */
+ /* Down to children */
node = next;
inset += tree_g.step_width;
} else {
- /* no children */
- next = node->sibling_next;
-
- if (next != NULL && node != root) {
- /* on to next sibling */
- node = next;
- } else {
- /* no next sibling */
- while (node != root) {
- next = node->sibling_next;
-
- if (next != NULL) {
- break;
- }
-
- node = node->parent;
- inset -= tree_g.step_width;
- }
+ /* 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->sibling_next == NULL) {
+ node = node->parent;
+ inset -= tree_g.step_width;
+ }
- if (node == root)
- break;
+ if (node == root)
+ break;
- node = node->sibling_next;
- }
+ node = node->sibling_next;
}
assert(node != NULL);
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=dafe9a6208d4160daa9...
commit dafe9a6208d4160daa9375c405fc637f1dbd3c6d
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Fix string length.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index 36f2880..2e4a9b5 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -144,7 +144,7 @@ static nserror global_history_create_treeview_field_data(
e->data[2].field = gh_ctx.fields[2].field;
e->data[2].value = "Date time";
- e->data[2].value_len = SLEN("Last visited");
+ e->data[2].value_len = SLEN("Date time");
e->data[3].field = gh_ctx.fields[3].field;
e->data[3].value = "Count";
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=8747398c98761f37350...
commit 8747398c98761f37350a47a3e6749c28e462ab49
Merge: 8f3b8c8 3aba4b7
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Merge branch 'master' of
git://git.netsurf-browser.org/netsurf
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=8f3b8c8cfa81d850b21...
commit 8f3b8c8cfa81d850b218b1a49b4e67a8bb10cb95
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Clean up history node deletion -- now treeview driven. Add select all, selection
clear, has selection functions. Improve selection handling. Enable double click to
toggle node expansion. Improve redraw behaviour. Make treeview call node callback for
deletion. Fix redraw issues.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index 17fabb0..36f2880 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -60,6 +60,7 @@ struct global_history_ctx {
struct global_history_ctx gh_ctx;
struct global_history_entry {
+ int slot;
nsurl *url;
time_t t;
struct treeview_node *entry;
@@ -77,8 +78,7 @@ struct global_history_entry *gh_list[N_DAYS];
* \param url The URL to find
* \return Pointer to node, or NULL if not found
*/
-static struct global_history_entry *global_history_find(nsurl *url,
- int *slot)
+static struct global_history_entry *global_history_find(nsurl *url)
{
int i;
struct global_history_entry *e;
@@ -89,7 +89,6 @@ static struct global_history_entry *global_history_find(nsurl *url,
while (e != NULL) {
if (nsurl_compare(e->url, url,
NSURL_COMPLETE) == true) {
- *slot = i;
return e;
}
e = e->next;
@@ -136,20 +135,20 @@ static nserror global_history_create_treeview_field_data(
const struct url_data *data)
{
e->data[0].field = gh_ctx.fields[0].field;
+ e->data[0].value = strdup(data->title);
e->data[0].value_len = strlen(data->title);
- e->data[0].value = data->title;
e->data[1].field = gh_ctx.fields[1].field;
e->data[1].value = nsurl_access(e->url);
- e->data[1].value_len = strlen(nsurl_access(e->url));
+ e->data[1].value_len = nsurl_length(e->url);
e->data[2].field = gh_ctx.fields[2].field;
- e->data[2].value = "node last visit data";
- e->data[2].value_len = SLEN("node last visit data");
+ e->data[2].value = "Date time";
+ e->data[2].value_len = SLEN("Last visited");
e->data[3].field = gh_ctx.fields[3].field;
- e->data[3].value = "node visi count data";
- e->data[3].value_len = SLEN("node visi count data");
+ e->data[3].value = "Count";
+ e->data[3].value_len = SLEN("Count");
return NSERROR_OK;
}
@@ -197,6 +196,7 @@ static nserror global_history_add_entry_internal(nsurl *url, int
slot,
return false;
}
+ e->slot = slot;
e->url = nsurl_ref(url);
e->t = data->last_visit;
e->entry = NULL;
@@ -215,6 +215,7 @@ static nserror global_history_add_entry_internal(nsurl *url, int
slot,
} else if (gh_list[slot]->t < e->t) {
/* Insert at list head */
e->next = gh_list[slot];
+ gh_list[slot]->prev = e;
gh_list[slot] = e;
} else {
struct global_history_entry *prev = gh_list[slot];
@@ -247,12 +248,12 @@ static nserror global_history_add_entry_internal(nsurl *url, int
slot,
}
static void global_history_delete_entry_internal(
- struct global_history_entry *e,
- int slot)
+ struct global_history_entry *e)
{
- if (gh_list[slot] == e) {
+ /* Unlink */
+ if (gh_list[e->slot] == e) {
/* e is first entry */
- gh_list[slot] = e->next;
+ gh_list[e->slot] = e->next;
if (e->next != NULL)
e->next->prev = NULL;
@@ -267,8 +268,9 @@ static void global_history_delete_entry_internal(
e->next->prev = e->prev;
}
- /* TODO: Delete treeview node */
-
+ /* Destroy */
+ free((void *)e->data[0].value); /* Eww */
+ nsurl_unref(e->url);
free(e);
}
@@ -283,7 +285,6 @@ static bool global_history_add_entry(nsurl *url,
const struct url_data *data)
{
int slot;
- int existing_slot;
struct global_history_entry *e;
time_t visit_date;
time_t earliest_date = gh_ctx.today - (N_DAYS - 1) * N_SEC_PER_DAY;
@@ -307,10 +308,10 @@ static bool global_history_add_entry(nsurl *url,
/* The treeview for global history already exists */
/* See if there's already an entry for this URL */
- e = global_history_find(url, &existing_slot);
+ e = global_history_find(url);
if (e != NULL) {
/* Existing entry. Delete it. */
- global_history_delete_entry_internal(e, existing_slot);
+ treeview_delete_node(gh_ctx.tree, e->entry);
return true;
}
}
@@ -374,7 +375,7 @@ static nserror global_history_initialise_entry_fields(void)
return NSERROR_OK;
error:
- for (i = 0; i < N_FIELDS - 1; i++)
+ for (i = 0; i < N_FIELDS; i++)
if (gh_ctx.fields[i].field != NULL)
lwc_string_unref(gh_ctx.fields[i].field);
@@ -422,8 +423,8 @@ static nserror global_history_initialise_time(void)
*
* \return true on success, false on memory exhaustion
*/
-static nserror global_history_init_dir(
- enum global_history_folders f, const char *label, int age)
+static nserror global_history_init_dir(enum global_history_folders f,
+ const char *label, int age)
{
nserror err;
time_t t = gh_ctx.today;
@@ -439,7 +440,7 @@ static nserror global_history_init_dir(
rel = TREE_REL_SIBLING_NEXT;
}
- gh_ctx.folders[f].data.field = gh_ctx.fields[4].field;
+ gh_ctx.folders[f].data.field = gh_ctx.fields[N_FIELDS - 1].field;
gh_ctx.folders[f].data.value = label;
gh_ctx.folders[f].data.value_len = strlen(label);
err = treeview_create_node_folder(gh_ctx.tree,
@@ -530,6 +531,16 @@ static nserror global_history_tree_node_folder_cb(
static nserror global_history_tree_node_entry_cb(
struct treeview_node_msg msg, void *data)
{
+ struct global_history_entry *e = (struct global_history_entry *)data;
+
+ switch (msg.msg) {
+ case TREE_MSG_NODE_DELETE:
+ global_history_delete_entry_internal(e);
+ break;
+
+ case TREE_MSG_FIELD_EDIT:
+ break;
+ }
return NSERROR_OK;
}
struct treeview_callback_table tree_cb_t = {
@@ -583,6 +594,8 @@ nserror global_history_init(struct core_window_callback_table *cw_t,
return err;
}
+ LOG(("Building global history treeview"));
+
/* Add the history to the treeview */
err = global_history_init_entries();
if (err != NSERROR_OK) {
@@ -614,26 +627,18 @@ nserror global_history_fini(struct core_window_callback_table
*cw_t,
int i;
nserror err;
+ LOG(("Finalising global history"));
+
/* Destroy the global history treeview */
err = treeview_destroy(gh_ctx.tree);
- /* Free global history entry data */
- for (i = 0; i < N_DAYS; i++) {
- struct global_history_entry *t;
- struct global_history_entry *e = gh_list[i];
- while (e != NULL) {
- t = e;
- e = e->next;
- nsurl_unref(t->url);
- free(t);
- }
- }
-
/* Free global history treeview entry fields */
for (i = 0; i < N_FIELDS; i++)
if (gh_ctx.fields[i].field != NULL)
lwc_string_unref(gh_ctx.fields[i].field);
+ LOG(("Finalised global history"));
+
return NSERROR_OK;
}
diff --git a/desktop/treeview.c b/desktop/treeview.c
index de731f2..9d3dce5 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -31,7 +31,7 @@
#define FIELD_FIRST_ENTRY 1
struct treeview_globals {
- int line_height;
+ uint32_t line_height;
int furniture_width;
int step_width;
int window_padding;
@@ -81,7 +81,7 @@ struct treeview_node {
};
struct treeview_node_entry {
- struct treeview_node *base;
+ struct treeview_node base;
struct treeview_field fields[];
};
@@ -328,18 +328,18 @@ nserror treeview_update_node_entry(struct treeview *tree,
fields[i].field, &match) == lwc_error_ok &&
match == true);
- e->fields[i].value.data = fields[i].value;
- e->fields[i].value.len = fields[i].value_len;
+ e->fields[i - 1].value.data = fields[i].value;
+ e->fields[i - 1].value.len = fields[i].value_len;
if (entry->flags & TREE_NODE_EXPANDED) {
/* Text will be seen, get its width */
nsfont.font_width(&plot_style_odd.text,
- e->fields[i].value.data,
- e->fields[i].value.len,
- &(e->fields[i].value.width));
+ e->fields[i - 1].value.data,
+ e->fields[i - 1].value.len,
+ &(e->fields[i - 1].value.width));
} else {
/* Invalidate the width, since it's not needed yet */
- entry->text.value.width = 0;
+ e->fields[i - 1].value.width = 0;
}
}
@@ -369,11 +369,12 @@ nserror treeview_create_node_entry(struct treeview *tree,
}
e = malloc(sizeof(struct treeview_node_entry) +
- tree->n_fields * sizeof(struct treeview_field));
+ (tree->n_fields - 1) * sizeof(struct treeview_field));
if (e == NULL) {
return NSERROR_NOMEM;
}
+
n = (struct treeview_node *) e;
n->flags = TREE_NODE_NONE;
@@ -403,9 +404,9 @@ nserror treeview_create_node_entry(struct treeview *tree,
fields[i].field, &match) == lwc_error_ok &&
match == true);
- e->fields[i].value.data = fields[i].value;
- e->fields[i].value.len = fields[i].value_len;
- e->fields[i].value.width = 0;
+ e->fields[i - 1].value.data = fields[i].value;
+ e->fields[i - 1].value.len = fields[i].value_len;
+ e->fields[i - 1].value.width = 0;
}
treeview_insert_node(n, relation, rel);
@@ -416,11 +417,15 @@ nserror treeview_create_node_entry(struct treeview *tree,
}
-nserror treeview_delete_node(struct treeview_node *n)
+nserror treeview_delete_node(struct treeview *tree, struct treeview_node *n)
{
+ struct treeview_node_msg msg;
+ msg.msg = TREE_MSG_NODE_DELETE;
+ msg.data.node_delete.node = n;
+
/* Destroy children first */
while (n->children != NULL) {
- treeview_delete_node(n->children);
+ treeview_delete_node(tree, n->children);
}
/* Unlink node from tree */
@@ -441,8 +446,10 @@ nserror treeview_delete_node(struct treeview_node *n)
/* Handle any special treatment */
switch (n->type) {
case TREE_NODE_ENTRY:
+ tree->callbacks->entry(msg, n->client_data);
break;
case TREE_NODE_FOLDER:
+ tree->callbacks->folder(msg, n->client_data);
break;
case TREE_NODE_ROOT:
break;
@@ -528,7 +535,7 @@ nserror treeview_destroy(struct treeview *tree)
assert(tree != NULL);
/* Destroy nodes */
- treeview_delete_node(tree->root);
+ treeview_delete_node(tree, tree->root);
/* Destroy feilds */
for (f = 0; f <= tree->n_fields; f++) {
@@ -573,7 +580,7 @@ static bool treeview_walk_internal(struct treeview_node *root, bool
full,
/* no children */
next = node->sibling_next;
- if (next != NULL) {
+ if (next != NULL && node != root) {
/* on to next sibling */
node = next;
} else {
@@ -655,7 +662,7 @@ nserror treeview_node_expand(struct treeview *tree,
e = (struct treeview_node_entry *)node;
- for (i = 1; i < tree->n_fields; i++) {
+ for (i = 0; i < tree->n_fields - 1; i++) {
if (e->fields[i].value.width == 0) {
nsfont.font_width(&plot_style_odd.text,
@@ -703,7 +710,7 @@ static bool treeview_node_contract_cb(struct treeview_node *node, int
inset,
return false;
}
- node->flags |= ~TREE_NODE_EXPANDED;
+ node->flags ^= TREE_NODE_EXPANDED;
height_reduction = node->height - tree_g.line_height;
assert(height_reduction >= 0);
@@ -711,7 +718,8 @@ static bool treeview_node_contract_cb(struct treeview_node *node, int
inset,
do {
node->height -= height_reduction;
node = node->parent;
- } while (node->parent != NULL);
+ } while (node->parent != NULL &&
+ node->parent->flags & TREE_NODE_EXPANDED);
return false; /* Don't want to abort tree walk */
}
@@ -761,6 +769,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
enum treeview_resource_id res;
plot_style_t *bg;
plot_font_style_t *text;
+ int height;
assert(tree != NULL);
assert(tree->root != NULL);
@@ -826,10 +835,14 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct
rect *clip,
assert(node != root);
count++;
+ height = (node->type == TREE_NODE_ENTRY) ? node->height :
+ tree_g.line_height;
- if (render_y + tree_g.line_height < clip->y0) {
+ if (clip->y0 >= 0 &&
+ render_y + tree_g.line_height <
+ (unsigned)clip->y0) {
/* This node's line is above clip region */
- render_y += tree_g.line_height;
+ render_y += height;
continue;
}
@@ -844,7 +857,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
/* Render background */
y0 = render_y;
- y1 = render_y + tree_g.line_height;
+ y1 = render_y + height;
new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, bg);
/* Render toggle */
@@ -897,19 +910,14 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct
rect *clip,
/* Done everything for this node */
continue;
-
- /* Reneder expanded entry background */
- y0 = render_y;
- y1 = render_y + tree_g.line_height * tree->n_fields;
- new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, bg);
-
/* Render expanded entry fields */
entry = (struct treeview_node_entry *)node;
- for (i = 0; i < tree->n_fields; i++) {
- struct treeview_field *ef = &(tree->fields[i]);
- int max_width = tree->field_width;
+ 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;
+
new_ctx.plot->text(x0 + max_width -
ef->value.width -
tree_g.step_width,
@@ -956,6 +964,122 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct
rect *clip,
knockout_plot_end();
}
+struct treeview_selection_walk_data {
+ enum {
+ TREEVIEW_WALK_HAS_SELECTION,
+ TREEVIEW_WALK_CLEAR_SELECTION,
+ TREEVIEW_WALK_SELECT_ALL
+ } purpose;
+ union {
+ bool has_selection;
+ struct {
+ bool required;
+ struct rect *rect;
+ } redraw;
+ } data;
+ int current_y;
+};
+static bool treeview_node_selection_walk_cb(struct treeview_node *node,
+ int inset, void *ctx)
+{
+ struct treeview_selection_walk_data *sw = ctx;
+ int height;
+ bool changed = false;
+
+ height = (node->type == TREE_NODE_ENTRY) ? node->height :
+ tree_g.line_height;
+ sw->current_y += height;
+
+ switch (sw->purpose) {
+ case TREEVIEW_WALK_HAS_SELECTION:
+ if (node->flags & TREE_NODE_SELECTED) {
+ sw->data.has_selection = true;
+ return true; /* Can abort tree walk */
+ }
+ break;
+
+ case TREEVIEW_WALK_CLEAR_SELECTION:
+ if (node->flags & TREE_NODE_SELECTED) {
+ node->flags ^= TREE_NODE_SELECTED;
+ changed = true;
+ }
+ break;
+
+ case TREEVIEW_WALK_SELECT_ALL:
+ if (!(node->flags & TREE_NODE_SELECTED)) {
+ node->flags ^= TREE_NODE_SELECTED;
+ changed = true;
+ }
+ break;
+ }
+
+ if (changed) {
+ if (sw->data.redraw.required == false) {
+ sw->data.redraw.required = true;
+ sw->data.redraw.rect->y0 = sw->current_y - height;
+ }
+
+ if (sw->current_y > sw->data.redraw.rect->y1) {
+ sw->data.redraw.rect->y1 = sw->current_y;
+ }
+ }
+
+ return false; /* Don't stop walk */
+}
+
+bool treeview_has_selection(struct treeview *tree)
+{
+ struct treeview_selection_walk_data sw;
+
+ sw.purpose = TREEVIEW_WALK_HAS_SELECTION;
+ sw.data.has_selection = false;
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_selection_walk_cb, &sw);
+
+ return sw.data.has_selection;
+}
+
+bool treeview_clear_selection(struct treeview *tree, struct rect *rect)
+{
+ struct treeview_selection_walk_data sw;
+
+ rect->x0 = 0;
+ rect->y0 = 0;
+ rect->x1 = INT_MAX;
+ rect->y1 = 0;
+
+ sw.purpose = TREEVIEW_WALK_CLEAR_SELECTION;
+ sw.data.redraw.required = false;
+ sw.data.redraw.rect = rect;
+ sw.current_y = 0;
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_selection_walk_cb, &sw);
+
+ return sw.data.redraw.required;
+}
+
+bool treeview_select_all(struct treeview *tree, struct rect *rect)
+{
+ struct treeview_selection_walk_data sw;
+
+ rect->x0 = 0;
+ rect->y0 = 0;
+ rect->x1 = INT_MAX;
+ rect->y1 = 0;
+
+ sw.purpose = TREEVIEW_WALK_SELECT_ALL;
+ sw.data.redraw.required = false;
+ sw.data.redraw.rect = rect;
+ sw.current_y = 0;
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_selection_walk_cb, &sw);
+
+ return sw.data.redraw.required;
+}
+
struct treeview_mouse_action {
struct treeview *tree;
browser_mouse_state mouse;
@@ -968,20 +1092,73 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node,
{
struct treeview_mouse_action *ma = ctx;
struct rect r;
+ bool redraw = false;
+ int height;
+ enum {
+ TV_NODE_ACTION_NONE = 0,
+ TV_NODE_ACTION_SELECTION = (1 << 0)
+ } action = TV_NODE_ACTION_NONE;
+ nserror err;
+
+ r.x0 = 0;
+ r.x1 = INT_MAX;
+
+ height = (node->type == TREE_NODE_ENTRY) ? node->height :
+ tree_g.line_height;
/* Skip line if we've not reached mouse y */
- if (ma->y > ma->current_y + tree_g.line_height) {
- ma->current_y += tree_g.line_height;
+ if (ma->y > ma->current_y + height) {
+ ma->current_y += height;
return false; /* Don't want to abort tree walk */
}
- if (ma->mouse & BROWSER_MOUSE_CLICK_1) {
- node->flags ^= TREE_NODE_SELECTED;
+ if ((ma->mouse & BROWSER_MOUSE_DOUBLE_CLICK) &&
+ (ma->mouse & BROWSER_MOUSE_CLICK_1)) {
+ /* Clear any existing selection */
+ redraw |= treeview_clear_selection(ma->tree, &r);
- r.x0 = 0;
+ /* TODO: launch callback for entry */
+ /* TODO: for now expand/collapse both directories and entries */
+ if (node->flags & TREE_NODE_EXPANDED) {
+ err = treeview_node_contract(ma->tree, node);
+ } else {
+ err = treeview_node_expand(ma->tree, node);
+ }
+ redraw = true;
r.y0 = ma->current_y;
- r.x1 = INT_MAX;
- r.y1 = ma->current_y + tree_g.line_height;
+ r.y1 = INT_MAX;
+
+ } else if (ma->mouse & BROWSER_MOUSE_PRESS_1 &&
+ !(node->flags & TREE_NODE_SELECTED)) {
+ /* Clear any existing selection */
+ redraw |= treeview_clear_selection(ma->tree, &r);
+
+ /* Select node */
+ action |= TV_NODE_ACTION_SELECTION;
+
+ } else if (ma->mouse & BROWSER_MOUSE_PRESS_2) {
+ /* Toggle selection of node */
+ action |= TV_NODE_ACTION_SELECTION;
+ }
+
+ if (action & TV_NODE_ACTION_SELECTION) {
+ /* Handle change in selection */
+ node->flags ^= TREE_NODE_SELECTED;
+
+ /* Redraw */
+ if (!redraw) {
+ r.y0 = ma->current_y;
+ r.y1 = ma->current_y + height;
+ redraw = true;
+ } else {
+ if (r.y0 > ma->current_y)
+ r.y0 = ma->current_y;
+ if (r.y1 < ma->current_y + height)
+ r.y1 = ma->current_y + height;
+ }
+ }
+
+ if (redraw) {
ma->tree->cw_t->redraw_request(ma->tree->cw_h, r);
}
diff --git a/desktop/treeview.h b/desktop/treeview.h
index 2f4e0c8..21ecfe8 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -108,7 +108,7 @@ nserror treeview_update_node_entry(struct treeview *tree,
const struct treeview_field_data fields[],
void *data);
-nserror treeview_delete_node(struct treeview_node *n);
+nserror treeview_delete_node(struct treeview *tree, struct treeview_node *n);
nserror treeview_node_expand(struct treeview *tree,
struct treeview_node *node);
@@ -131,4 +131,24 @@ void treeview_mouse_action(struct treeview *tree,
struct treeview_node * treeview_get_root(struct treeview *tree);
+bool treeview_has_selection(struct treeview *tree);
+
+/**
+ * Clear any selection in a treeview
+ *
+ * \param tree treeview to clear selection in
+ * \param rect redraw rectangle (if redraw required)
+ * \return true iff redraw required
+ */
+bool treeview_clear_selection(struct treeview *tree, struct rect *rect);
+
+/**
+ * Select all in a treeview
+ *
+ * \param tree treeview to select all in
+ * \param rect redraw rectangle (if redraw required)
+ * \return true iff redraw required
+ */
+bool treeview_select_all(struct treeview *tree, struct rect *rect);
+
#endif
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=27849cb182b308fbc68...
commit 27849cb182b308fbc68dce16299c7e98a031f78f
Merge: b959e69 8b586b2
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Merge branch 'master' of
git://git.netsurf-browser.org/netsurf
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=b959e6946d4d38a0281...
commit b959e6946d4d38a02819536d83b135233ade0df0
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Squash warning.
diff --git a/desktop/tree.c b/desktop/tree.c
index ed75604..92a2510 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -181,7 +181,7 @@ struct tree {
static void treeview_test_redraw_request(struct core_window *cw, struct rect r)
{
- struct tree *tree = cw;
+ struct tree *tree = (struct tree *)cw;
tree->callbacks->redraw_request(r.x0, r.y0,
r.x1 - r.x0, r.y1 - r.y0,
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=d3b8a493af8caac8563...
commit d3b8a493af8caac8563685d2094123ba7e2c65bd
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
cw handle can't be const.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index bf36a60..de731f2 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -97,7 +97,7 @@ struct treeview {
const struct treeview_callback_table *callbacks;
const struct core_window_callback_table *cw_t; /**< Core window callback table */
- const struct core_window *cw_h; /**< Core window handle */
+ struct core_window *cw_h; /**< Core window handle */
};
@@ -461,7 +461,7 @@ nserror treeview_create(struct treeview **tree,
const struct treeview_callback_table *callbacks,
int n_fields, struct treeview_field_desc fields[],
const struct core_window_callback_table *cw_t,
- const struct core_window *cw)
+ struct core_window *cw)
{
nserror error;
int i;
diff --git a/desktop/treeview.h b/desktop/treeview.h
index 6969ea6..2f4e0c8 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -86,7 +86,7 @@ nserror treeview_create(struct treeview **tree,
const struct treeview_callback_table *callbacks,
int n_fields, struct treeview_field_desc fields[],
const struct core_window_callback_table *cw_t,
- const struct core_window *cw);
+ struct core_window *cw);
nserror treeview_destroy(struct treeview *tree);
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=e684218169c5580795a...
commit e684218169c5580795a2a2637f45d58c470189ac
Merge: 910b31f 864762c
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Merge branch 'master' of
git://git.netsurf-browser.org/netsurf
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=910b31f63ee051f4145...
commit 910b31f63ee051f414567f5dc68b4ddcda832aea
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Rename treeview_walk --> treeview_walk_internal.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index daae6d3..bf36a60 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -551,7 +551,7 @@ nserror treeview_destroy(struct treeview *tree)
* \param ctx Context to pass to callback
* \return true iff callback caused premature abort
*/
-static bool treeview_walk(struct treeview_node *root, bool full,
+static bool treeview_walk_internal(struct treeview_node *root, bool full,
bool (*callback)(struct treeview_node *node,
int inset, void *ctx),
void *ctx)
@@ -727,7 +727,7 @@ nserror treeview_node_contract(struct treeview *tree,
}
/* Contract children. */
- treeview_walk(node, false, treeview_node_contract_cb, NULL);
+ treeview_walk_internal(node, false, treeview_node_contract_cb, NULL);
/* Contract node */
treeview_node_contract_cb(node, 0, NULL);
@@ -998,7 +998,8 @@ void treeview_mouse_action(struct treeview *tree,
ma.y = y;
ma.current_y = 0;
- treeview_walk(tree->root, false, treeview_node_mouse_action_cb, &ma);
+ treeview_walk_internal(tree->root, false,
+ treeview_node_mouse_action_cb, &ma);
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=03eb4ec30f9e090fece...
commit 03eb4ec30f9e090fece2328c33d6acbd32103f3c
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Implement redraw request hander for treeview test parsite.
diff --git a/desktop/tree.c b/desktop/tree.c
index edc1f97..adee7bf 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -181,6 +181,11 @@ struct tree {
static void treeview_test_redraw_request(struct core_window *cw, struct rect r)
{
+ struct tree *tree = cw;
+
+ tree->callbacks->redraw_request(r.x0, r.y0,
+ r.x1 - r.x0, r.y1 - r.y0,
+ tree->client_data);
}
static void treeview_test_update_size(struct core_window *cw,
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=ab403b251738c86312d...
commit ab403b251738c86312dd828ed383b6b2defe1704
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Call redraw function on clicks. Enable treewalker to skip the children of collapsed
nodes.
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 2a56006..daae6d3 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -546,22 +546,24 @@ nserror treeview_destroy(struct treeview *tree)
/* 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)
+ * \param full Iff true, visit children of collapsed nodes
* \param callback Function to call on each node
* \param ctx Context to pass to callback
* \return true iff callback caused premature abort
*/
-static bool treeview_walk(struct treeview_node *root,
+static bool treeview_walk(struct treeview_node *root, bool full,
bool (*callback)(struct treeview_node *node,
int inset, void *ctx),
void *ctx)
{
- struct treeview_node *node;
+ struct treeview_node *node, *next;
int inset = tree_g.window_padding - tree_g.step_width;
node = root;
while (node != NULL) {
- struct treeview_node *next = node->children;
+ next = (full || (node->flags & TREE_NODE_EXPANDED)) ?
+ node->children : NULL;
if (next != NULL) {
/* down to children */
@@ -674,7 +676,7 @@ nserror treeview_node_expand(struct treeview *tree,
}
/* Update the node */
- node->flags &= TREE_NODE_EXPANDED;
+ node->flags |= TREE_NODE_EXPANDED;
/* And parent's heights */
do {
@@ -725,7 +727,7 @@ nserror treeview_node_contract(struct treeview *tree,
}
/* Contract children. */
- treeview_walk(node, treeview_node_contract_cb, NULL);
+ treeview_walk(node, false, treeview_node_contract_cb, NULL);
/* Contract node */
treeview_node_contract_cb(node, 0, NULL);
@@ -746,7 +748,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
const struct redraw_context *ctx)
{
struct redraw_context new_ctx = *ctx;
- struct treeview_node *node, *root;
+ struct treeview_node *node, *root, *next;
struct treeview_node_entry *entry;
struct treeview_node_style *style = &plot_style_odd;
struct content_redraw_data data;
@@ -787,7 +789,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
while (node != NULL) {
int i;
- struct treeview_node *next = node->flags & TREE_NODE_EXPANDED ?
+ next = (node->flags & TREE_NODE_EXPANDED) ?
node->children : NULL;
if (next != NULL) {
@@ -883,7 +885,6 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
/* Rendered the node */
render_y += tree_g.line_height;
-
if (render_y > clip->y1) {
/* Passed the bottom of what's in the clip region.
* Done. */
@@ -956,6 +957,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
}
struct treeview_mouse_action {
+ struct treeview *tree;
browser_mouse_state mouse;
int x;
int y;
@@ -965,6 +967,7 @@ static bool treeview_node_mouse_action_cb(struct treeview_node *node,
int inset, void *ctx)
{
struct treeview_mouse_action *ma = ctx;
+ struct rect r;
/* Skip line if we've not reached mouse y */
if (ma->y > ma->current_y + tree_g.line_height) {
@@ -972,9 +975,16 @@ static bool treeview_node_mouse_action_cb(struct treeview_node
*node,
return false; /* Don't want to abort tree walk */
}
- if (ma->mouse & BROWSER_MOUSE_CLICK_1)
+ if (ma->mouse & BROWSER_MOUSE_CLICK_1) {
node->flags ^= TREE_NODE_SELECTED;
+ r.x0 = 0;
+ r.y0 = ma->current_y;
+ r.x1 = INT_MAX;
+ r.y1 = ma->current_y + tree_g.line_height;
+ ma->tree->cw_t->redraw_request(ma->tree->cw_h, r);
+ }
+
return true; /* Reached line with click; stop walking tree */
}
void treeview_mouse_action(struct treeview *tree,
@@ -982,12 +992,13 @@ void treeview_mouse_action(struct treeview *tree,
{
struct treeview_mouse_action ma;
+ ma.tree = tree;
ma.mouse = mouse;
ma.x = x;
ma.y = y;
ma.current_y = 0;
- treeview_walk(tree->root, treeview_node_mouse_action_cb, &ma);
+ treeview_walk(tree->root, false, treeview_node_mouse_action_cb, &ma);
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=83b9c850746c2229074...
commit 83b9c850746c222907477a10d7888807558e9834
Merge: a669a7d b2aa0c1
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Merge branch 'master' of
git://git.netsurf-browser.org/netsurf
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=a669a7d12ca5c70c1e3...
commit a669a7d12ca5c70c1e3ba3813c490731d36cfc7e
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Make treeview test parasite sit on mouse input too.
diff --git a/desktop/tree.c b/desktop/tree.c
index 64ba91f..edc1f97 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -243,6 +243,12 @@ static void treeview_test_redraw(struct tree *tree, int x, int y,
global_history_redraw(x, y, &clip, ctx);
}
+static void treeview_test_mouse_action(struct tree *tree,
+ browser_mouse_state mouse, int x, int y)
+{
+ global_history_mouse_action(mouse, x, y);
+}
+
@@ -2495,6 +2501,11 @@ bool tree_mouse_action(struct tree *tree, browser_mouse_state
mouse, int x,
assert(tree != NULL);
assert(tree->root != NULL);
+ if (tree->flags == TREE_MOVABLE) {
+ treeview_test_mouse_action(tree, mouse, x, y);
+ return true;
+ }
+
if (tree->root->child == NULL)
return true;
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=cf5782718718bee4788...
commit cf5782718718bee4788dea315dfdbaeafbc3cbc0
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Add function to pass mouse input to treeview.
diff --git a/desktop/global_history.c b/desktop/global_history.c
index bad24f4..17fabb0 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -643,3 +643,8 @@ void global_history_redraw(int x, int y, struct rect *clip,
treeview_redraw(gh_ctx.tree, x, y, clip, ctx);
}
+void global_history_mouse_action(browser_mouse_state mouse, int x, int y)
+{
+ treeview_mouse_action(gh_ctx.tree, mouse, x, y);
+}
+
diff --git a/desktop/global_history.h b/desktop/global_history.h
index 5253f06..960eb1e 100644
--- a/desktop/global_history.h
+++ b/desktop/global_history.h
@@ -31,4 +31,7 @@ nserror global_history_fini(struct core_window_callback_table *cw_t,
void global_history_redraw(int x, int y, struct rect *clip,
const struct redraw_context *ctx);
+
+void global_history_mouse_action(browser_mouse_state mouse, int x, int y);
+
#endif
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=ab9efd19fe88547c305...
commit ab9efd19fe88547c305589e518a49961d58028b5
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Make node flags for expanded and selected. Start mouse action support. (Little more
than a stub.)
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 10925b1..2a56006 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -57,8 +57,15 @@ struct treeview_field {
struct treeview_text value;
};
+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 {
- bool expanded;
+ enum treeview_node_flags flags;
enum treeview_node_type type;
uint32_t height;
@@ -148,7 +155,7 @@ static nserror treeview_create_node_root(struct treeview_node **root)
return NSERROR_NOMEM;
}
- n->expanded = true;
+ n->flags = TREE_NODE_EXPANDED;
n->type = TREE_NODE_ROOT;
n->height = 0;
@@ -213,7 +220,7 @@ static inline void treeview_insert_node(struct treeview_node *a,
assert(a->parent != NULL);
- if (a->parent->expanded) {
+ if (a->parent->flags & TREE_NODE_EXPANDED) {
/* Parent is expanded, so inserted node will be visible and
* affect layout */
b = a;
@@ -255,7 +262,7 @@ nserror treeview_create_node_folder(struct treeview *tree,
return NSERROR_NOMEM;
}
- n->expanded = false;
+ n->flags = TREE_NODE_NONE;
n->type = TREE_NODE_FOLDER;
n->height = tree_g.line_height;
@@ -304,7 +311,7 @@ nserror treeview_update_node_entry(struct treeview *tree,
entry->text.value.len = fields[0].value_len;
entry->text.value.width = 0;
- if (entry->parent->expanded) {
+ if (entry->parent->flags & TREE_NODE_EXPANDED) {
/* Text will be seen, get its width */
nsfont.font_width(&plot_style_odd.text,
entry->text.value.data,
@@ -324,7 +331,7 @@ nserror treeview_update_node_entry(struct treeview *tree,
e->fields[i].value.data = fields[i].value;
e->fields[i].value.len = fields[i].value_len;
- if (entry->expanded) {
+ if (entry->flags & TREE_NODE_EXPANDED) {
/* Text will be seen, get its width */
nsfont.font_width(&plot_style_odd.text,
e->fields[i].value.data,
@@ -369,7 +376,7 @@ nserror treeview_create_node_entry(struct treeview *tree,
n = (struct treeview_node *) e;
- n->expanded = false;
+ n->flags = TREE_NODE_NONE;
n->type = TREE_NODE_ENTRY;
n->height = tree_g.line_height;
@@ -549,7 +556,7 @@ static bool treeview_walk(struct treeview_node *root,
void *ctx)
{
struct treeview_node *node;
- int inset = tree_g.window_padding;
+ int inset = tree_g.window_padding - tree_g.step_width;
node = root;
@@ -611,7 +618,7 @@ nserror treeview_node_expand(struct treeview *tree,
assert(tree != NULL);
assert(node != NULL);
- if (node->expanded) {
+ if (node->flags & TREE_NODE_EXPANDED) {
/* What madness is this? */
LOG(("Tried to expand an expanded node."));
return NSERROR_OK;
@@ -626,7 +633,7 @@ nserror treeview_node_expand(struct treeview *tree,
}
do {
- assert(child->expanded == false);
+ assert((child->flags & TREE_NODE_EXPANDED) == false);
if (child->text.value.width == 0) {
nsfont.font_width(&plot_style_odd.text,
child->text.value.data,
@@ -667,7 +674,7 @@ nserror treeview_node_expand(struct treeview *tree,
}
/* Update the node */
- node->expanded = true;
+ node->flags &= TREE_NODE_EXPANDED;
/* And parent's heights */
do {
@@ -689,11 +696,12 @@ static bool treeview_node_contract_cb(struct treeview_node *node,
int inset,
assert(node != NULL);
assert(node->type != TREE_NODE_ROOT);
- if (node->expanded == false) {
+ if ((node->flags & TREE_NODE_EXPANDED) == false) {
/* Nothing to do. */
return false;
}
+ node->flags |= ~TREE_NODE_EXPANDED;
height_reduction = node->height - tree_g.line_height;
assert(height_reduction >= 0);
@@ -710,7 +718,7 @@ nserror treeview_node_contract(struct treeview *tree,
{
assert(node != NULL);
- if (node->expanded == false) {
+ if ((node->flags & TREE_NODE_EXPANDED) == false) {
/* What madness is this? */
LOG(("Tried to contract a contracted node."));
return NSERROR_OK;
@@ -749,10 +757,12 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct
rect *clip,
int x0, y0, y1;
int baseline = (tree_g.line_height * 3 + 2) / 4;
enum treeview_resource_id res;
+ plot_style_t *bg;
+ plot_font_style_t *text;
assert(tree != NULL);
assert(tree->root != NULL);
- assert(tree->root->expanded == true);
+ assert(tree->root->flags & TREE_NODE_EXPANDED);
/* Start knockout rendering if it's available for this plotter */
if (ctx->plot->option_knockout)
@@ -777,7 +787,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
while (node != NULL) {
int i;
- struct treeview_node *next = node->expanded ?
+ struct treeview_node *next = node->flags & TREE_NODE_EXPANDED ?
node->children : NULL;
if (next != NULL) {
@@ -822,23 +832,30 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct
rect *clip,
}
style = (count & 0x1) ? &plot_style_odd : &plot_style_even;
+ if (node->flags & TREE_NODE_SELECTED) {
+ bg = &style->sbg;
+ text = &style->stext;
+ } else {
+ bg = &style->bg;
+ text = &style->text;
+ }
/* Render background */
y0 = render_y;
y1 = render_y + tree_g.line_height;
- new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, &(style->bg));
+ new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, bg);
/* Render toggle */
- if (node->expanded) {
+ if (node->flags & TREE_NODE_EXPANDED) {
new_ctx.plot->text(inset, render_y + baseline,
treeview_furn[TREE_FURN_CONTRACT].data,
treeview_furn[TREE_FURN_CONTRACT].len,
- &(style->text));
+ text);
} else {
new_ctx.plot->text(inset, render_y + baseline,
treeview_furn[TREE_FURN_EXPAND].data,
treeview_furn[TREE_FURN_EXPAND].len,
- &(style->text));
+ text);
}
/* Render icon */
@@ -862,7 +879,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
x0 = inset + tree_g.step_width + tree_g.icon_step;
new_ctx.plot->text(x0, render_y + baseline,
node->text.value.data, node->text.value.len,
- &(style->text));
+ text);
/* Rendered the node */
render_y += tree_g.line_height;
@@ -874,7 +891,8 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
}
- if (node->type != TREE_NODE_ENTRY || !node->expanded)
+ if (node->type != TREE_NODE_ENTRY ||
+ !(node->flags & TREE_NODE_EXPANDED))
/* Done everything for this node */
continue;
@@ -882,7 +900,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
/* Reneder expanded entry background */
y0 = render_y;
y1 = render_y + tree_g.line_height * tree->n_fields;
- new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, &(style->bg));
+ new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, bg);
/* Render expanded entry fields */
entry = (struct treeview_node_entry *)node;
@@ -897,18 +915,18 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct
rect *clip,
render_y + baseline,
ef->value.data,
ef->value.len,
- &(style->text));
+ text);
new_ctx.plot->text(x0 + max_width,
render_y + baseline,
entry->fields[i].value.data,
entry->fields[i].value.len,
- &(style->text));
+ text);
} else {
new_ctx.plot->text(x0, render_y + baseline,
entry->fields[i].value.data,
entry->fields[i].value.len,
- &(style->text));
+ text);
}
@@ -928,7 +946,7 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
if (render_y < clip->y1) {
/* Fill the blank area at the bottom */
y0 = render_y;
- new_ctx.plot->rectangle(r.x0, y0, r.x1, r.y1, &(style->bg));
+ new_ctx.plot->rectangle(r.x0, y0, r.x1, r.y1, bg);
}
@@ -937,6 +955,41 @@ void treeview_redraw(struct treeview *tree, int x, int y, struct rect
*clip,
knockout_plot_end();
}
+struct treeview_mouse_action {
+ browser_mouse_state mouse;
+ int x;
+ int y;
+ int current_y;
+};
+static bool treeview_node_mouse_action_cb(struct treeview_node *node,
+ int inset, void *ctx)
+{
+ struct treeview_mouse_action *ma = ctx;
+
+ /* Skip line if we've not reached mouse y */
+ if (ma->y > ma->current_y + tree_g.line_height) {
+ ma->current_y += tree_g.line_height;
+ return false; /* Don't want to abort tree walk */
+ }
+
+ if (ma->mouse & BROWSER_MOUSE_CLICK_1)
+ node->flags ^= TREE_NODE_SELECTED;
+
+ return true; /* Reached line with click; stop walking tree */
+}
+void treeview_mouse_action(struct treeview *tree,
+ browser_mouse_state mouse, int x, int y)
+{
+ struct treeview_mouse_action ma;
+
+ ma.mouse = mouse;
+ ma.x = x;
+ ma.y = y;
+ ma.current_y = 0;
+
+ treeview_walk(tree->root, treeview_node_mouse_action_cb, &ma);
+}
+
/* Mix two colours according to the proportion given by p.
diff --git a/desktop/treeview.h b/desktop/treeview.h
index 91383d3..6969ea6 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -118,6 +118,17 @@ nserror treeview_node_contract(struct treeview *tree,
void treeview_redraw(struct treeview *tree, int x, int y, struct rect *clip,
const struct redraw_context *ctx);
+/**
+ * Handles all kinds of mouse action
+ *
+ * \param tree Treeview
+ * \param mouse the mouse state at action moment
+ * \param x X coordinate
+ * \param y Y coordinate
+ */
+void treeview_mouse_action(struct treeview *tree,
+ browser_mouse_state mouse, int x, int y);
+
struct treeview_node * treeview_get_root(struct treeview *tree);
#endif
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=d9394608726224bdaf5...
commit d9394608726224bdaf5678ea634564b9da2b5248
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Add parasitic hack to allow the new treeview to be tested in the Hotlist window.
(Tested with GTK front end only, so far.)
diff --git a/desktop/tree.c b/desktop/tree.c
index 25bd948..64ba91f 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -173,6 +173,90 @@ struct tree {
struct node *def_folder; /* Node to be used for additions by default */
};
+
+
+
+#include "desktop/treeview.h"
+#include "desktop/global_history.h"
+
+static void treeview_test_redraw_request(struct core_window *cw, struct rect r)
+{
+}
+
+static void treeview_test_update_size(struct core_window *cw,
+ int width, int height)
+{
+}
+
+static void treeview_test_scroll_visible(struct core_window *cw, struct rect r)
+{
+}
+
+static void treeview_test_get_window_dimensions(struct core_window *cw,
+ int *width, int *height)
+{
+}
+
+struct core_window_callback_table cw_t = {
+ .redraw_request = treeview_test_redraw_request,
+ .update_size = treeview_test_update_size,
+ .scroll_visible = treeview_test_scroll_visible,
+ .get_window_dimensions = treeview_test_get_window_dimensions
+};
+
+static void treeview_test_init(struct tree *tree)
+{
+ nserror err;
+
+ treeview_init();
+
+ err = global_history_init(&cw_t, (struct core_window *)tree);
+
+ if (err != NSERROR_OK) {
+ warn_user("Duffed it.", 0);
+ }
+}
+
+static void treeview_test_fini(struct tree *tree)
+{
+ nserror err;
+
+ err = global_history_fini(&cw_t, (struct core_window *)tree);
+
+ treeview_fini();
+
+ if (err != NSERROR_OK) {
+ warn_user("Duffed it.", 0);
+ }
+}
+
+static void treeview_test_redraw(struct tree *tree, int x, int y,
+ int clip_x, int clip_y, int clip_width, int clip_height,
+ const struct redraw_context *ctx)
+{
+ struct rect clip;
+ clip.x0 = clip_x;
+ clip.y0 = clip_y;
+ clip.x1 = clip_x + clip_width;
+ clip.y1 = clip_y + clip_height;
+
+ global_history_redraw(x, y, &clip, ctx);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
void tree_set_icon_dir(char *icon_dir)
{
LOG(("Tree icon directory set to %s", icon_dir));
@@ -276,6 +360,10 @@ struct tree *tree_create(unsigned int flags,
tree_setup_colours();
+ if (flags == TREE_MOVABLE) {
+ treeview_test_init(tree);
+ }
+
return tree;
}
@@ -1119,6 +1207,10 @@ void tree_delete(struct tree *tree)
{
tree->redraw = false;
+ if (tree->flags == TREE_MOVABLE) {
+ treeview_test_fini(tree);
+ }
+
if (tree->root->child != NULL)
tree_delete_node_internal(tree, tree->root->child, true);
@@ -2033,6 +2125,12 @@ void tree_draw(struct tree *tree, int x, int y,
assert(tree != NULL);
assert(tree->root != NULL);
+ if (tree->flags == TREE_MOVABLE) {
+ treeview_test_redraw(tree, x, y, clip_x, clip_y,
+ clip_width, clip_height, ctx);
+ return;
+ }
+
/* Start knockout rendering if it's available for this plotter */
if (ctx->plot->option_knockout)
knockout_plot_start(ctx, &new_ctx);
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=903122126703e706701...
commit 903122126703e70670131932acb9b5b3eba86e8f
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Build the new treeview and global history.
diff --git a/desktop/Makefile b/desktop/Makefile
index f91754e..f787fd2 100644
--- a/desktop/Makefile
+++ b/desktop/Makefile
@@ -3,7 +3,7 @@
S_DESKTOP := cookies.c history_global_core.c hotlist.c knockout.c \
mouse.c plot_style.c print.c search.c searchweb.c \
scrollbar.c sslcert.c textarea.c thumbnail.c tree.c \
- tree_url_node.c version.c system_colour.c
+ tree_url_node.c version.c system_colour.c global_history.c treeview.c
S_DESKTOP := $(addprefix desktop/,$(S_DESKTOP))
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=f656d8ca04ea2c84878...
commit f656d8ca04ea2c84878ef270bbab78766065e7f5
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Add global history client for new treeview.
Loads from urldb. Much faster load than old treeview based history.
TODO: Keep it up-to-date as you browse.
diff --git a/desktop/global_history.c b/desktop/global_history.c
new file mode 100644
index 0000000..bad24f4
--- /dev/null
+++ b/desktop/global_history.c
@@ -0,0 +1,645 @@
+/*
+ * Copyright 2012 - 2013 Michael Drake <tlsa(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf,
http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <
http://www.gnu.org/licenses/>.
+ */
+
+
+#include <stdlib.h>
+
+#include "content/urldb.h"
+#include "desktop/browser.h"
+#include "desktop/global_history.h"
+#include "desktop/treeview.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "utils/log.h"
+
+#define N_FIELDS 5
+#define N_DAYS 28
+#define N_SEC_PER_DAY (60 * 60 * 24)
+
+enum global_history_folders {
+ GH_TODAY = 0,
+ GH_YESTERDAY,
+ GH_2_DAYS_AGO,
+ GH_3_DAYS_AGO,
+ GH_4_DAYS_AGO,
+ GH_5_DAYS_AGO,
+ GH_6_DAYS_AGO,
+ GH_LAST_WEEK,
+ GH_2_WEEKS_AGO,
+ GH_3_WEEKS_AGO,
+ GH_N_FOLDERS
+};
+
+struct global_history_folder {
+ struct treeview_node *folder;
+ struct treeview_field_data data;
+};
+
+struct global_history_ctx {
+ struct treeview *tree;
+ struct treeview_field_desc fields[N_FIELDS];
+ struct global_history_folder folders[GH_N_FOLDERS];
+ time_t today;
+ int weekday;
+};
+struct global_history_ctx gh_ctx;
+
+struct global_history_entry {
+ nsurl *url;
+ time_t t;
+ struct treeview_node *entry;
+ struct global_history_entry *next;
+ struct global_history_entry *prev;
+
+ struct treeview_field_data data[N_FIELDS - 1];
+};
+struct global_history_entry *gh_list[N_DAYS];
+
+
+/**
+ * Find an entry in the global history
+ *
+ * \param url The URL to find
+ * \return Pointer to node, or NULL if not found
+ */
+static struct global_history_entry *global_history_find(nsurl *url,
+ int *slot)
+{
+ int i;
+ struct global_history_entry *e;
+
+ for (i = 0; i < N_DAYS; i++) {
+ e = gh_list[i];
+
+ while (e != NULL) {
+ if (nsurl_compare(e->url, url,
+ NSURL_COMPLETE) == true) {
+ *slot = i;
+ return e;
+ }
+ e = e->next;
+ }
+
+ }
+ return NULL;
+}
+
+static inline nserror global_history_get_parent_treeview_node(
+ struct treeview_node **parent, int slot)
+{
+ int folder_index;
+ struct global_history_folder *f;
+
+ if (slot < 7) {
+ folder_index = slot;
+
+ } else if (slot < 14) {
+ folder_index = GH_LAST_WEEK;
+
+ } else if (slot < 21) {
+ folder_index = GH_2_WEEKS_AGO;
+
+ } else if (slot < N_DAYS) {
+ folder_index = GH_3_WEEKS_AGO;
+
+ } else {
+ /* Slot value is invalid */
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ /* Get the folder */
+ f = &(gh_ctx.folders[folder_index]);
+
+ /* Return the parent treeview folder */
+ *parent = f->folder;
+ return NSERROR_OK;
+}
+
+
+static nserror global_history_create_treeview_field_data(
+ struct global_history_entry *e,
+ const struct url_data *data)
+{
+ e->data[0].field = gh_ctx.fields[0].field;
+ e->data[0].value_len = strlen(data->title);
+ e->data[0].value = data->title;
+
+ e->data[1].field = gh_ctx.fields[1].field;
+ e->data[1].value = nsurl_access(e->url);
+ e->data[1].value_len = strlen(nsurl_access(e->url));
+
+ e->data[2].field = gh_ctx.fields[2].field;
+ e->data[2].value = "node last visit data";
+ e->data[2].value_len = SLEN("node last visit data");
+
+ e->data[3].field = gh_ctx.fields[3].field;
+ e->data[3].value = "node visi count data";
+ e->data[3].value_len = SLEN("node visi count data");
+
+ return NSERROR_OK;
+}
+
+/**
+ * Add a global history entry to the treeview
+ *
+ * \param e entry to add to treeview
+ * \param slot global history slot containing entry
+ * \return NSERROR_OK on success, or appropriate error otherwise
+ *
+ * It is assumed that the entry is unique (for its URL) in the global
+ * history table
+ */
+static nserror global_history_entry_insert(struct global_history_entry *e,
+ int slot)
+{
+ nserror err;
+
+ struct treeview_node *parent;
+ err = global_history_get_parent_treeview_node(&parent, slot);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ err = treeview_create_node_entry(gh_ctx.tree, &(e->entry),
+ parent, TREE_REL_CHILD, e->data, e);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ return NSERROR_OK;
+}
+
+
+static nserror global_history_add_entry_internal(nsurl *url, int slot,
+ const struct url_data *data, bool got_treeview)
+{
+ nserror err;
+ struct global_history_entry *e;
+
+ /* Create new local history entry */
+ e = malloc(sizeof(struct global_history_entry));
+ if (e == NULL) {
+ return false;
+ }
+
+ e->url = nsurl_ref(url);
+ e->t = data->last_visit;
+ e->entry = NULL;
+ e->next = NULL;
+ e->prev = NULL;
+
+ err = global_history_create_treeview_field_data(e, data);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ if (gh_list[slot] == NULL) {
+ /* list empty */
+ gh_list[slot] = e;
+
+ } else if (gh_list[slot]->t < e->t) {
+ /* Insert at list head */
+ e->next = gh_list[slot];
+ gh_list[slot] = e;
+ } else {
+ struct global_history_entry *prev = gh_list[slot];
+ struct global_history_entry *curr = prev->next;
+ while (curr != NULL) {
+ if (curr->t < e->t) {
+ break;
+ }
+ prev = curr;
+ curr = curr->next;
+ }
+
+ /* insert after prev */
+ e->next = curr;
+ e->prev = prev;
+ prev->next = e;
+
+ if (curr != NULL)
+ curr->prev = e;
+ }
+
+ if (got_treeview) {
+ err = global_history_entry_insert(e, slot);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+ }
+
+ return NSERROR_OK;
+}
+
+static void global_history_delete_entry_internal(
+ struct global_history_entry *e,
+ int slot)
+{
+ if (gh_list[slot] == e) {
+ /* e is first entry */
+ gh_list[slot] = e->next;
+
+ if (e->next != NULL)
+ e->next->prev = NULL;
+
+ } else if (e->next == NULL) {
+ /* e is last entry */
+ e->prev->next = NULL;
+
+ } else {
+ /* e has an entry before and after */
+ e->prev->next = e->next;
+ e->next->prev = e->prev;
+ }
+
+ /* TODO: Delete treeview node */
+
+ free(e);
+}
+
+/**
+ * Internal routine to actually perform global history addition
+ *
+ * \param url The URL to add
+ * \param data URL data associated with URL
+ * \return true (for urldb_iterate_entries)
+ */
+static bool global_history_add_entry(nsurl *url,
+ const struct url_data *data)
+{
+ int slot;
+ int existing_slot;
+ struct global_history_entry *e;
+ time_t visit_date;
+ time_t earliest_date = gh_ctx.today - (N_DAYS - 1) * N_SEC_PER_DAY;
+ bool got_treeview = gh_ctx.tree != NULL;
+
+ assert((url != NULL) && (data != NULL));
+
+ visit_date = data->last_visit;
+
+ /* Find day array slot for entry */
+ if (visit_date >= gh_ctx.today) {
+ slot = 0;
+ } else if (visit_date >= earliest_date) {
+ slot = (gh_ctx.today - visit_date) / N_SEC_PER_DAY + 1;
+ } else {
+ /* too old */
+ return true;
+ }
+
+ if (got_treeview == true) {
+ /* The treeview for global history already exists */
+
+ /* See if there's already an entry for this URL */
+ e = global_history_find(url, &existing_slot);
+ if (e != NULL) {
+ /* Existing entry. Delete it. */
+ global_history_delete_entry_internal(e, existing_slot);
+ return true;
+ }
+ }
+
+ if (global_history_add_entry_internal(url, slot, data,
+ got_treeview) != NSERROR_OK) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Initialise the treeview entry feilds
+ *
+ * \return true on success, false on memory exhaustion
+ */
+static nserror global_history_initialise_entry_fields(void)
+{
+ int i;
+
+ for (i = 0; i < N_FIELDS; i++)
+ gh_ctx.fields[i].field = NULL;
+
+ /* TODO: use messages */
+ gh_ctx.fields[0].flags = TREE_FLAG_DEFAULT;
+ if (lwc_intern_string("Title", SLEN("Title"),
+ &gh_ctx.fields[0].field) !=
+ lwc_error_ok) {
+ goto error;
+ }
+
+ gh_ctx.fields[1].flags = TREE_FLAG_NONE;
+ if (lwc_intern_string("URL", SLEN("URL"),
+ &gh_ctx.fields[1].field) !=
+ lwc_error_ok) {
+ goto error;
+ }
+
+ gh_ctx.fields[2].flags = TREE_FLAG_SHOW_NAME;
+ if (lwc_intern_string("Last visit", SLEN("Last visit"),
+ &gh_ctx.fields[2].field) !=
+ lwc_error_ok) {
+ goto error;
+ }
+
+ gh_ctx.fields[3].flags = TREE_FLAG_SHOW_NAME;
+ if (lwc_intern_string("Visits", SLEN("Visits"),
+ &gh_ctx.fields[3].field) !=
+ lwc_error_ok) {
+ goto error;
+ }
+
+ gh_ctx.fields[4].flags = TREE_FLAG_DEFAULT;
+ if (lwc_intern_string("Period", SLEN("Period"),
+ &gh_ctx.fields[4].field) !=
+ lwc_error_ok) {
+ return false;
+ }
+
+ return NSERROR_OK;
+
+error:
+ for (i = 0; i < N_FIELDS - 1; i++)
+ if (gh_ctx.fields[i].field != NULL)
+ lwc_string_unref(gh_ctx.fields[i].field);
+
+ return NSERROR_UNKNOWN;
+}
+
+
+/**
+ * Initialise the time
+ *
+ * \return true on success, false on memory exhaustion
+ */
+static nserror global_history_initialise_time(void)
+{
+ struct tm *full_time;
+ time_t t;
+
+ /* get the current time */
+ t = time(NULL);
+ if (t == -1) {
+ LOG(("time info unaviable"));
+ return NSERROR_UNKNOWN;
+ }
+
+ /* get the time at the start of today */
+ full_time = localtime(&t);
+ full_time->tm_sec = 0;
+ full_time->tm_min = 0;
+ full_time->tm_hour = 0;
+ t = mktime(full_time);
+ if (t == -1) {
+ LOG(("mktime failed"));
+ return NSERROR_UNKNOWN;
+ }
+
+ gh_ctx.today = t;
+ gh_ctx.weekday = full_time->tm_wday;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Initialise the treeview directories
+ *
+ * \return true on success, false on memory exhaustion
+ */
+static nserror global_history_init_dir(
+ enum global_history_folders f, const char *label, int age)
+{
+ nserror err;
+ time_t t = gh_ctx.today;
+ struct treeview_node *relation = NULL;
+ enum treeview_relationship rel = TREE_REL_CHILD;
+
+ t -= age * N_SEC_PER_DAY;
+
+ label = messages_get(label);
+
+ if (f != GH_TODAY) {
+ relation = gh_ctx.folders[f - 1].folder;
+ rel = TREE_REL_SIBLING_NEXT;
+ }
+
+ gh_ctx.folders[f].data.field = gh_ctx.fields[4].field;
+ gh_ctx.folders[f].data.value = label;
+ gh_ctx.folders[f].data.value_len = strlen(label);
+ err = treeview_create_node_folder(gh_ctx.tree,
+ &gh_ctx.folders[f].folder,
+ relation, rel,
+ &gh_ctx.folders[f].data,
+ &gh_ctx.folders[f]);
+
+ return err;
+}
+
+
+/**
+ * Initialise the treeview directories
+ *
+ * \return true on success, false on memory exhaustion
+ */
+static nserror global_history_init_dirs(void)
+{
+ nserror err;
+
+ err = global_history_init_dir(GH_TODAY, "DateToday", 0);
+ if (err != NSERROR_OK) return err;
+
+ err = global_history_init_dir(GH_YESTERDAY, "DateYesterday", 1);
+ if (err != NSERROR_OK) return err;
+
+ err = global_history_init_dir(GH_2_DAYS_AGO, "Date2Days", 2);
+ if (err != NSERROR_OK) return err;
+
+ err = global_history_init_dir(GH_3_DAYS_AGO, "Date3Days", 3);
+ if (err != NSERROR_OK) return err;
+
+ err = global_history_init_dir(GH_4_DAYS_AGO, "Date4Days", 4);
+ if (err != NSERROR_OK) return err;
+
+ err = global_history_init_dir(GH_5_DAYS_AGO, "Date5Days", 5);
+ if (err != NSERROR_OK) return err;
+
+ err = global_history_init_dir(GH_6_DAYS_AGO, "Date6Days", 6);
+ if (err != NSERROR_OK) return err;
+
+ err = global_history_init_dir(GH_LAST_WEEK, "Date1Week", 7);
+ if (err != NSERROR_OK) return err;
+
+ err = global_history_init_dir(GH_2_WEEKS_AGO, "Date2Week", 14);
+ if (err != NSERROR_OK) return err;
+
+ err = global_history_init_dir(GH_3_WEEKS_AGO, "Date3Week", 21);
+ if (err != NSERROR_OK) return err;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Initialise the treeview entries
+ *
+ * \return true on success, false on memory exhaustion
+ */
+static nserror global_history_init_entries(void)
+{
+ int i;
+ nserror err;
+
+ /* Itterate over all global history data, inserting it into treeview */
+ for (i = 0; i < N_DAYS; i++) {
+ struct global_history_entry *e = gh_list[i];
+
+ while (e != NULL) {
+ err = global_history_entry_insert(e, i);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+ e = e->next;
+ }
+ }
+
+ return NSERROR_OK;
+}
+
+
+static nserror global_history_tree_node_folder_cb(
+ struct treeview_node_msg msg, void *data)
+{
+ return NSERROR_OK;
+}
+static nserror global_history_tree_node_entry_cb(
+ struct treeview_node_msg msg, void *data)
+{
+ return NSERROR_OK;
+}
+struct treeview_callback_table tree_cb_t = {
+ .folder = global_history_tree_node_folder_cb,
+ .entry = global_history_tree_node_entry_cb
+};
+
+/**
+ * Initialises the global history module.
+ *
+ * \param
+ * \param
+ * \return true on success, false on memory exhaustion
+ */
+nserror global_history_init(struct core_window_callback_table *cw_t,
+ void *core_window_handle)
+{
+ nserror err;
+
+ LOG(("Loading global history"));
+
+ /* Init. global history treeview time */
+ err = global_history_initialise_time();
+ if (err != NSERROR_OK) {
+ gh_ctx.tree = NULL;
+ return err;
+ }
+
+ /* Init. global history treeview entry fields */
+ err = global_history_initialise_entry_fields();
+ if (err != NSERROR_OK) {
+ gh_ctx.tree = NULL;
+ return err;
+ }
+
+ /* Load the entries */
+ urldb_iterate_entries(global_history_add_entry);
+
+ /* Create the global history treeview */
+ err = treeview_create(&gh_ctx.tree, &tree_cb_t,
+ N_FIELDS, gh_ctx.fields,
+ cw_t, core_window_handle);
+ if (err != NSERROR_OK) {
+ gh_ctx.tree = NULL;
+ return err;
+ }
+
+ /* Add the folders to the treeview */
+ err = global_history_init_dirs();
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ /* Add the history to the treeview */
+ err = global_history_init_entries();
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ /* Expand the "Today" folder node */
+ err = treeview_node_expand(gh_ctx.tree,
+ gh_ctx.folders[GH_TODAY].folder);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ LOG(("Loaded global history"));
+
+ return NSERROR_OK;
+}
+
+/**
+ * Finalises the global history module.
+ *
+ * \param
+ * \param
+ * \return true on success, false on memory exhaustion
+ */
+nserror global_history_fini(struct core_window_callback_table *cw_t,
+ void *core_window_handle)
+{
+ int i;
+ nserror err;
+
+ /* Destroy the global history treeview */
+ err = treeview_destroy(gh_ctx.tree);
+
+ /* Free global history entry data */
+ for (i = 0; i < N_DAYS; i++) {
+ struct global_history_entry *t;
+ struct global_history_entry *e = gh_list[i];
+ while (e != NULL) {
+ t = e;
+ e = e->next;
+ nsurl_unref(t->url);
+ free(t);
+ }
+ }
+
+ /* Free global history treeview entry fields */
+ for (i = 0; i < N_FIELDS; i++)
+ if (gh_ctx.fields[i].field != NULL)
+ lwc_string_unref(gh_ctx.fields[i].field);
+
+ return NSERROR_OK;
+}
+
+void global_history_redraw(int x, int y, struct rect *clip,
+ const struct redraw_context *ctx)
+{
+ treeview_redraw(gh_ctx.tree, x, y, clip, ctx);
+}
+
diff --git a/desktop/global_history.h b/desktop/global_history.h
new file mode 100644
index 0000000..5253f06
--- /dev/null
+++ b/desktop/global_history.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012 - 2013 Michael Drake <tlsa(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf,
http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <
http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NETSURF_DESKTOP_GLOBAL_HISTORY_H_
+#define _NETSURF_DESKTOP_GLOBAL_HISTORY_H_
+
+#include <stdbool.h>
+
+#include "desktop/core_window.h"
+
+nserror global_history_init(struct core_window_callback_table *cw_t,
+ void *core_window_handle);
+
+nserror global_history_fini(struct core_window_callback_table *cw_t,
+ void *core_window_handle);
+
+void global_history_redraw(int x, int y, struct rect *clip,
+ const struct redraw_context *ctx);
+#endif
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=55aa7af80f8e008b1bf...
commit 55aa7af80f8e008b1bf5f478948cd3eda3458836
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Add first pass at new treeview.
Only supports creation, destruction, and redraw atm.
TODO: input handling (mouse, keyboard), editing, using the node callbacks.
Also includes new core_window.h.
diff --git a/desktop/core_window.h b/desktop/core_window.h
new file mode 100644
index 0000000..9e68e26
--- /dev/null
+++ b/desktop/core_window.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2012 Michael Drake <tlsa(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf,
http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <
http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Core window handling (interface).
+ */
+
+#ifndef _NETSURF_DESKTOP_CORE_WINDOW_H_
+#define _NETSURF_DESKTOP_CORE_WINDOW_H_
+
+#include "utils/types.h"
+
+struct core_window;
+
+/** Callbacks to achieve various core window functionality. */
+struct core_window_callback_table {
+ /** Request a redraw of the window. */
+ void (*redraw_request)(struct core_window *cw, struct rect r);
+
+ /** Update the limits of the window */
+ void (*update_size)(struct core_window *cw, int width, int height);
+
+ /** Scroll the window to make area visible */
+ void (*scroll_visible)(struct core_window *cw, struct rect r);
+
+ /** Get window viewport dimensions */
+ void (*get_window_dimensions)(struct core_window *cw,
+ int *width, int *height);
+};
+
+
+void core_window_draw(struct core_window *cw, int x, int y, struct rect r,
+ const struct redraw_context *ctx);
+
+
+#endif
diff --git a/desktop/treeview.c b/desktop/treeview.c
new file mode 100644
index 0000000..10925b1
--- /dev/null
+++ b/desktop/treeview.c
@@ -0,0 +1,1104 @@
+/*
+ * Copyright 2012 - 2013 Michael Drake <tlsa(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf,
http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <
http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Treeview handling (implementation).
+ */
+
+#include "desktop/gui.h"
+#include "desktop/knockout.h"
+#include "desktop/plotters.h"
+#include "desktop/treeview.h"
+#include "render/font.h"
+#include "utils/log.h"
+
+#define FIELD_FOLDER 0
+#define FIELD_FIRST_ENTRY 1
+
+struct treeview_globals {
+ int line_height;
+ int furniture_width;
+ int step_width;
+ int window_padding;
+ int icon_step;
+} tree_g;
+
+enum treeview_node_type {
+ TREE_NODE_ROOT,
+ TREE_NODE_FOLDER,
+ TREE_NODE_ENTRY
+};
+
+struct treeview_text {
+ const char *data;
+ uint32_t len;
+ int width;
+};
+
+struct treeview_field {
+ enum treeview_field_flags flags;
+
+ lwc_string *field;
+ struct treeview_text value;
+};
+
+struct treeview_node {
+ bool expanded;
+ enum treeview_node_type type;
+
+ uint32_t height;
+
+ struct treeview_node *parent;
+ struct treeview_node *sibling_prev;
+ struct treeview_node *sibling_next;
+ struct treeview_node *children;
+
+ void *client_data;
+
+ struct treeview_field text;
+};
+
+struct treeview_node_entry {
+ struct treeview_node *base;
+ struct treeview_field fields[];
+};
+
+struct treeview {
+ uint32_t view_height;
+ uint32_t view_width;
+
+ struct treeview_node *root;
+
+ struct treeview_field *fields;
+ int n_fields; /* fields[n_fields] is folder, lower are entry fields */
+ int field_width;
+
+ const struct treeview_callback_table *callbacks;
+ const struct core_window_callback_table *cw_t; /**< Core window callback table */
+ const struct core_window *cw_h; /**< Core window handle */
+};
+
+
+struct treeview_node_style {
+ plot_style_t bg; /**< Background */
+ plot_font_style_t text; /**< Text */
+
+ plot_style_t sbg; /**< Selected background */
+ plot_font_style_t stext; /**< Selected text */
+
+ plot_style_t sabg; /**< Selection area background */
+ plot_font_style_t satext; /**< Selection area text */
+};
+
+struct treeview_node_style plot_style_odd;
+struct treeview_node_style plot_style_even;
+
+struct treeview_resource {
+ const char *url;
+ struct hlcache_handle *c;
+ int height;
+ bool ready;
+};
+enum treeview_resource_id {
+ TREE_RES_CONTENT = 0,
+ TREE_RES_FOLDER,
+ TREE_RES_SEARCH,
+ TREE_RES_LAST
+};
+static struct treeview_resource treeview_res[TREE_RES_LAST] = {
+ { "resource:icons/content.png", NULL, 0, false },
+ { "resource:icons/directory.png", NULL, 0, false },
+ { "resource:icons/search.png", NULL, 0, false }
+};
+
+
+
+enum treeview_furniture_id {
+ TREE_FURN_EXPAND = 0,
+ TREE_FURN_CONTRACT,
+ TREE_FURN_LAST
+};
+static struct treeview_text treeview_furn[TREE_FURN_LAST] = {
+ { "\xe2\x96\xb8", 3, 0 },
+ { "\xe2\x96\xbe", 3, 0 }
+};
+
+
+static nserror treeview_create_node_root(struct treeview_node **root)
+{
+ struct treeview_node *n;
+
+ n = malloc(sizeof(struct treeview_node));
+ if (n == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ n->expanded = true;
+ n->type = TREE_NODE_ROOT;
+
+ n->height = 0;
+
+ n->text.flags = TREE_FLAG_NONE;
+ n->text.field = NULL;
+ n->text.value.data = NULL;
+ n->text.value.len = 0;
+ n->text.value.width = 0;
+
+ n->parent = NULL;
+ n->sibling_next = NULL;
+ n->sibling_prev = NULL;
+ n->children = NULL;
+
+ n->client_data = NULL;
+
+ *root = n;
+
+ return NSERROR_OK;
+}
+
+/**
+ * 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 rel a's relationship to b
+ */
+static inline void treeview_insert_node(struct treeview_node *a,
+ struct treeview_node *b,
+ enum treeview_relationship rel)
+{
+ assert(a != NULL);
+ assert(a->parent == NULL);
+ assert(b != NULL);
+
+ switch (rel) {
+ case TREE_REL_CHILD:
+ assert(b->type != TREE_NODE_ENTRY);
+ a->parent = b;
+ a->sibling_next = b->children;
+ if (a->sibling_next)
+ a->sibling_next->sibling_prev = a;
+ b->children = a;
+ break;
+
+ case TREE_REL_SIBLING_NEXT:
+ assert(b->type != TREE_NODE_ROOT);
+ a->sibling_prev = b;
+ a->sibling_next = b->sibling_next;
+ a->parent = b->parent;
+ b->sibling_next = a;
+ if (a->sibling_next)
+ a->sibling_next->sibling_prev = a;
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ assert(a->parent != NULL);
+
+ if (a->parent->expanded) {
+ /* Parent is expanded, so inserted node will be visible and
+ * affect layout */
+ b = a;
+ do {
+ b->parent->height += b->height;
+ b = b->parent;
+ } while (b->parent != NULL);
+
+ if (a->text.value.width == 0) {
+ nsfont.font_width(&plot_style_odd.text,
+ a->text.value.data,
+ a->text.value.len,
+ &(a->text.value.width));
+ }
+ }
+}
+
+
+nserror treeview_create_node_folder(struct treeview *tree,
+ struct treeview_node **folder,
+ struct treeview_node *relation,
+ enum treeview_relationship rel,
+ const struct treeview_field_data *field,
+ void *data)
+{
+ struct treeview_node *n;
+
+ assert(data != NULL);
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+
+ if (relation == NULL) {
+ relation = tree->root;
+ rel = TREE_REL_CHILD;
+ }
+
+ n = malloc(sizeof(struct treeview_node));
+ if (n == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ n->expanded = false;
+ n->type = TREE_NODE_FOLDER;
+
+ n->height = tree_g.line_height;
+
+ n->text.value.data = field->value;
+ n->text.value.len = field->value_len;
+ n->text.value.width = 0;
+
+ n->parent = NULL;
+ n->sibling_next = NULL;
+ n->sibling_prev = NULL;
+ n->children = NULL;
+
+ n->client_data = data;
+
+ treeview_insert_node(n, relation, rel);
+
+ *folder = n;
+
+ return NSERROR_OK;
+}
+
+
+
+nserror treeview_update_node_entry(struct treeview *tree,
+ struct treeview_node *entry,
+ const struct treeview_field_data fields[],
+ void *data)
+{
+ bool match;
+ struct treeview_node_entry *e = (struct treeview_node_entry *)entry;
+ int i;
+
+ assert(data != NULL);
+ assert(tree != NULL);
+ assert(entry != NULL);
+ assert(data == entry->client_data);
+ assert(entry->parent != NULL);
+
+ 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);
+ entry->text.value.data = fields[0].value;
+ entry->text.value.len = fields[0].value_len;
+ entry->text.value.width = 0;
+
+ if (entry->parent->expanded) {
+ /* Text will be seen, get its width */
+ nsfont.font_width(&plot_style_odd.text,
+ entry->text.value.data,
+ entry->text.value.len,
+ &(entry->text.value.width));
+ } else {
+ /* Just invalidate the width, since it's not needed now */
+ entry->text.value.width = 0;
+ }
+
+ 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);
+
+ e->fields[i].value.data = fields[i].value;
+ e->fields[i].value.len = fields[i].value_len;
+
+ if (entry->expanded) {
+ /* Text will be seen, get its width */
+ nsfont.font_width(&plot_style_odd.text,
+ e->fields[i].value.data,
+ e->fields[i].value.len,
+ &(e->fields[i].value.width));
+ } else {
+ /* Invalidate the width, since it's not needed yet */
+ entry->text.value.width = 0;
+ }
+ }
+
+ return NSERROR_OK;
+}
+
+
+nserror treeview_create_node_entry(struct treeview *tree,
+ struct treeview_node **entry,
+ struct treeview_node *relation,
+ enum treeview_relationship rel,
+ const struct treeview_field_data fields[],
+ void *data)
+{
+ bool match;
+ struct treeview_node_entry *e;
+ struct treeview_node *n;
+ int i;
+
+ assert(data != NULL);
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+
+ if (relation == NULL) {
+ relation = tree->root;
+ rel = TREE_REL_CHILD;
+ }
+
+ e = malloc(sizeof(struct treeview_node_entry) +
+ tree->n_fields * sizeof(struct treeview_field));
+ if (e == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ n = (struct treeview_node *) e;
+
+ n->expanded = false;
+ n->type = TREE_NODE_ENTRY;
+
+ n->height = tree_g.line_height;
+
+ 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);
+ n->text.value.data = fields[0].value;
+ n->text.value.len = fields[0].value_len;
+ n->text.value.width = 0;
+
+ n->parent = NULL;
+ n->sibling_next = NULL;
+ n->sibling_prev = NULL;
+ n->children = NULL;
+
+ n->client_data = data;
+
+ 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);
+
+ e->fields[i].value.data = fields[i].value;
+ e->fields[i].value.len = fields[i].value_len;
+ e->fields[i].value.width = 0;
+ }
+
+ treeview_insert_node(n, relation, rel);
+
+ *entry = n;
+
+ return NSERROR_OK;
+}
+
+
+nserror treeview_delete_node(struct treeview_node *n)
+{
+ /* Destroy children first */
+ while (n->children != NULL) {
+ treeview_delete_node(n->children);
+ }
+
+ /* Unlink node from tree */
+ if (n->parent != NULL && n->parent->children == n) {
+ /* Node is a first child */
+ n->parent->children = n->sibling_next;
+
+ } else if (n->sibling_prev != NULL) {
+ /* Node is not first child */
+ n->sibling_prev->sibling_next = n->sibling_next;
+ }
+
+ if (n->sibling_next != NULL) {
+ /* Always need to do this */
+ n->sibling_next->sibling_prev = n->sibling_prev;
+ }
+
+ /* Handle any special treatment */
+ switch (n->type) {
+ case TREE_NODE_ENTRY:
+ break;
+ case TREE_NODE_FOLDER:
+ break;
+ case TREE_NODE_ROOT:
+ break;
+ default:
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ /* Free the node */
+ free(n);
+
+ return NSERROR_OK;
+}
+
+
+nserror treeview_create(struct treeview **tree,
+ const struct treeview_callback_table *callbacks,
+ int n_fields, struct treeview_field_desc fields[],
+ const struct core_window_callback_table *cw_t,
+ const struct core_window *cw)
+{
+ nserror error;
+ int i;
+
+ assert(cw_t != NULL);
+ assert(cw != NULL);
+ assert(callbacks != NULL);
+
+ assert(fields != NULL);
+ assert(fields[0].flags & TREE_FLAG_DEFAULT);
+ assert(fields[n_fields - 1].flags & TREE_FLAG_DEFAULT);
+ assert(n_fields >= 2);
+
+ *tree = malloc(sizeof(struct treeview));
+ if (*tree == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ (*tree)->fields = malloc(sizeof(struct treeview_field) * n_fields);
+ if ((*tree)->fields == NULL) {
+ free(tree);
+ return NSERROR_NOMEM;
+ }
+
+ error = treeview_create_node_root(&((*tree)->root));
+ if (error != NSERROR_OK) {
+ free((*tree)->fields);
+ free(*tree);
+ return error;
+ }
+
+ (*tree)->field_width = 0;
+ for (i = 0; i < n_fields; i++) {
+ struct treeview_field *f = &((*tree)->fields[i]);
+
+ f->flags = fields[i].flags;
+ f->field = lwc_string_ref(fields[i].field);
+ f->value.data = lwc_string_data(fields[i].field);
+ f->value.len = lwc_string_length(fields[i].field);
+
+ nsfont.font_width(&plot_style_odd.text, f->value.data,
+ f->value.len, &(f->value.width));
+
+ if (f->flags & TREE_FLAG_SHOW_NAME)
+ if ((*tree)->field_width < f->value.width)
+ (*tree)->field_width = f->value.width;
+ }
+
+ (*tree)->field_width += tree_g.step_width;
+
+ (*tree)->callbacks = callbacks;
+ (*tree)->n_fields = n_fields - 1;
+
+ (*tree)->cw_t = cw_t;
+ (*tree)->cw_h = cw;
+
+ return NSERROR_OK;
+}
+
+nserror treeview_destroy(struct treeview *tree)
+{
+ int f;
+
+ assert(tree != NULL);
+
+ /* Destroy nodes */
+ treeview_delete_node(tree->root);
+
+ /* Destroy feilds */
+ for (f = 0; f <= tree->n_fields; f++) {
+ lwc_string_unref(tree->fields[f].field);
+ }
+ free(tree->fields);
+
+ /* Free treeview */
+ free(tree);
+
+ return NSERROR_OK;
+}
+
+
+/* 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)
+ * \param callback Function to call on each node
+ * \param ctx Context to pass to callback
+ * \return true iff callback caused premature abort
+ */
+static bool treeview_walk(struct treeview_node *root,
+ bool (*callback)(struct treeview_node *node,
+ int inset, void *ctx),
+ void *ctx)
+{
+ struct treeview_node *node;
+ int inset = tree_g.window_padding;
+
+ node = root;
+
+ while (node != NULL) {
+ struct treeview_node *next = node->children;
+
+ if (next != NULL) {
+ /* down to children */
+ node = next;
+ inset += tree_g.step_width;
+ } else {
+ /* no children */
+ next = node->sibling_next;
+
+ if (next != NULL) {
+ /* on to next sibling */
+ node = next;
+ } else {
+ /* no next sibling */
+ while (node != root) {
+ next = node->sibling_next;
+
+ if (next != NULL) {
+ break;
+ }
+
+ node = node->parent;
+ inset -= tree_g.step_width;
+ }
+
+ if (node == root)
+ break;
+
+ node = node->sibling_next;
+ }
+ }
+
+ assert(node != NULL);
+ assert(node != root);
+
+ if (callback(node, inset, ctx)) {
+ /* callback caused early termination */
+ return true;
+ }
+
+ }
+ return false;
+}
+
+
+nserror treeview_node_expand(struct treeview *tree,
+ struct treeview_node *node)
+{
+ struct treeview_node *child;
+ struct treeview_node_entry *e;
+ int additional_height = 0;
+ int i;
+
+ assert(tree != NULL);
+ assert(node != NULL);
+
+ if (node->expanded) {
+ /* What madness is this? */
+ LOG(("Tried to expand an expanded node."));
+ return NSERROR_OK;
+ }
+
+ switch (node->type) {
+ case TREE_NODE_FOLDER:
+ child = node->children;
+ if (child == NULL) {
+ /* Can't expand an empty node */
+ return NSERROR_OK;
+ }
+
+ do {
+ assert(child->expanded == false);
+ if (child->text.value.width == 0) {
+ nsfont.font_width(&plot_style_odd.text,
+ child->text.value.data,
+ child->text.value.len,
+ &(child->text.value.width));
+ }
+
+ additional_height += child->height;
+
+ child = child->sibling_next;
+ } while (child != NULL);
+
+ break;
+
+ case TREE_NODE_ENTRY:
+ assert(node->children == NULL);
+
+ e = (struct treeview_node_entry *)node;
+
+ for (i = 1; i < tree->n_fields; i++) {
+
+ if (e->fields[i].value.width == 0) {
+ nsfont.font_width(&plot_style_odd.text,
+ e->fields[i].value.data,
+ e->fields[i].value.len,
+ &(e->fields[i].value.width));
+ }
+
+ /* Add height for field */
+ additional_height += tree_g.line_height;
+ }
+
+ break;
+
+ case TREE_NODE_ROOT:
+ assert(node->type != TREE_NODE_ROOT);
+ break;
+ }
+
+ /* Update the node */
+ node->expanded = true;
+
+ /* And parent's heights */
+ do {
+ node->height += additional_height;
+ node = node->parent;
+ } while (node->parent != NULL);
+
+ node->height += additional_height;
+
+ return NSERROR_OK;
+}
+
+
+static bool treeview_node_contract_cb(struct treeview_node *node, int inset,
+ void *ctx)
+{
+ int height_reduction;
+
+ assert(node != NULL);
+ assert(node->type != TREE_NODE_ROOT);
+
+ if (node->expanded == false) {
+ /* Nothing to do. */
+ return false;
+ }
+
+ height_reduction = node->height - tree_g.line_height;
+
+ assert(height_reduction >= 0);
+
+ do {
+ node->height -= height_reduction;
+ node = node->parent;
+ } while (node->parent != NULL);
+
+ return false; /* Don't want to abort tree walk */
+}
+nserror treeview_node_contract(struct treeview *tree,
+ struct treeview_node *node)
+{
+ assert(node != NULL);
+
+ if (node->expanded == false) {
+ /* What madness is this? */
+ LOG(("Tried to contract a contracted node."));
+ return NSERROR_OK;
+ }
+
+ /* Contract children. */
+ treeview_walk(node, treeview_node_contract_cb, NULL);
+
+ /* Contract node */
+ treeview_node_contract_cb(node, 0, NULL);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Redraws a treeview.
+ *
+ * \param tree the tree to draw
+ * \param x X coordinate to draw the tree at (wrt plot origin)
+ * \param y Y coordinate to draw the tree at (wrt plot origin)
+ * \param clip_x clipping rectangle (wrt tree origin)
+ * \param ctx current redraw context
+ */
+void treeview_redraw(struct treeview *tree, int x, int y, struct rect *clip,
+ const struct redraw_context *ctx)
+{
+ struct redraw_context new_ctx = *ctx;
+ struct treeview_node *node, *root;
+ struct treeview_node_entry *entry;
+ struct treeview_node_style *style = &plot_style_odd;
+ struct content_redraw_data data;
+ struct rect r;
+ int inset = tree_g.window_padding - tree_g.step_width;
+ uint32_t count = 0;
+ int render_y = 0;
+ int x0, y0, y1;
+ int baseline = (tree_g.line_height * 3 + 2) / 4;
+ enum treeview_resource_id res;
+
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+ assert(tree->root->expanded == true);
+
+ /* 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(&r);
+
+ /* Draw the tree */
+ node = root = tree->root;
+
+ /* Setup common content redraw data */
+ data.width = 17;
+ data.height = 17;
+ data.scale = 1;
+ data.repeat_x = false;
+ data.repeat_y = false;
+
+ while (node != NULL) {
+ int i;
+ struct treeview_node *next = node->expanded ?
+ node->children : NULL;
+
+ if (next != NULL) {
+ /* down to children */
+ node = next;
+ inset += tree_g.step_width;
+ } else {
+ /* no children */
+ next = node->sibling_next;
+
+ if (next != NULL) {
+ /* on to next sibling */
+ node = next;
+ } else {
+ /* no next sibling */
+ while (node != root) {
+ next = node->sibling_next;
+
+ if (next != NULL) {
+ break;
+ }
+ node = node->parent;
+ inset -= tree_g.step_width;
+ }
+
+ if (node == root)
+ break;
+
+ node = node->sibling_next;
+ }
+ }
+
+ assert(node != NULL);
+ assert(node != root);
+
+ count++;
+
+ if (render_y + tree_g.line_height < clip->y0) {
+ /* This node's line is above clip region */
+ render_y += tree_g.line_height;
+ continue;
+ }
+
+ style = (count & 0x1) ? &plot_style_odd : &plot_style_even;
+
+ /* Render background */
+ y0 = render_y;
+ y1 = render_y + tree_g.line_height;
+ new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, &(style->bg));
+
+ /* Render toggle */
+ if (node->expanded) {
+ new_ctx.plot->text(inset, render_y + baseline,
+ treeview_furn[TREE_FURN_CONTRACT].data,
+ treeview_furn[TREE_FURN_CONTRACT].len,
+ &(style->text));
+ } else {
+ new_ctx.plot->text(inset, render_y + baseline,
+ treeview_furn[TREE_FURN_EXPAND].data,
+ treeview_furn[TREE_FURN_EXPAND].len,
+ &(style->text));
+ }
+
+ /* Render icon */
+ if (node->type == TREE_NODE_ENTRY)
+ res = TREE_RES_CONTENT;
+ else if (node->type == TREE_NODE_FOLDER)
+ res = TREE_NODE_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 = style->bg.fill_colour;
+
+ content_redraw(treeview_res[res].c,
+ &data, &r, &new_ctx);
+ }
+
+ /* Render text */
+ x0 = inset + tree_g.step_width + tree_g.icon_step;
+ new_ctx.plot->text(x0, render_y + baseline,
+ node->text.value.data, node->text.value.len,
+ &(style->text));
+
+ /* Rendered the node */
+ render_y += tree_g.line_height;
+
+ if (render_y > clip->y1) {
+ /* Passed the bottom of what's in the clip region.
+ * Done. */
+ break;
+ }
+
+
+ if (node->type != TREE_NODE_ENTRY || !node->expanded)
+ /* Done everything for this node */
+ continue;
+
+
+ /* Reneder expanded entry background */
+ y0 = render_y;
+ y1 = render_y + tree_g.line_height * tree->n_fields;
+ new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, &(style->bg));
+
+ /* Render expanded entry fields */
+ entry = (struct treeview_node_entry *)node;
+ for (i = 0; i < tree->n_fields; i++) {
+ struct treeview_field *ef = &(tree->fields[i]);
+ int max_width = tree->field_width;
+
+ if (ef->flags & TREE_FLAG_SHOW_NAME) {
+ new_ctx.plot->text(x0 + max_width -
+ ef->value.width -
+ tree_g.step_width,
+ render_y + baseline,
+ ef->value.data,
+ ef->value.len,
+ &(style->text));
+
+ new_ctx.plot->text(x0 + max_width,
+ render_y + baseline,
+ entry->fields[i].value.data,
+ entry->fields[i].value.len,
+ &(style->text));
+ } else {
+ new_ctx.plot->text(x0, render_y + baseline,
+ entry->fields[i].value.data,
+ entry->fields[i].value.len,
+ &(style->text));
+
+ }
+
+ /* Rendered the expanded entry field */
+ render_y += tree_g.line_height;
+ }
+
+ /* Finshed rendering expanded entry */
+
+ if (render_y > clip->y1) {
+ /* Passed the bottom of what's in the clip region.
+ * Done. */
+ break;
+ }
+ }
+
+ if (render_y < clip->y1) {
+ /* Fill the blank area at the bottom */
+ y0 = render_y;
+ new_ctx.plot->rectangle(r.x0, y0, r.x1, r.y1, &(style->bg));
+
+ }
+
+ /* Rendering complete */
+ if (ctx->plot->option_knockout)
+ knockout_plot_end();
+}
+
+
+
+/* Mix two colours according to the proportion given by p.
+ * Where 0 <= p <= 255
+ * p=0 gives result=c0
+ * p=255 gives result=c1
+ */
+#define mix_colour(c0, c1, p) \
+ ((((((c1 & 0xff00ff) * (255 - p)) + \
+ ((c0 & 0xff00ff) * ( p)) ) >> 8) & 0xff00ff) | \
+ (((((c1 & 0x00ff00) * (255 - p)) + \
+ ((c0 & 0x00ff00) * ( p)) ) >> 8) & 0x00ff00))
+
+
+static void treeview_init_plot_styles(void)
+{
+ /* Background colour */
+ plot_style_even.bg.stroke_type = PLOT_OP_TYPE_NONE;
+ plot_style_even.bg.stroke_width = 0;
+ plot_style_even.bg.stroke_colour = 0;
+ plot_style_even.bg.fill_type = PLOT_OP_TYPE_SOLID;
+ plot_style_even.bg.fill_colour = gui_system_colour_char("Window");
+
+ /* Text colour */
+ plot_style_even.text.family = PLOT_FONT_FAMILY_SANS_SERIF;
+ plot_style_even.text.size = 11 * FONT_SIZE_SCALE;
+ plot_style_even.text.weight = 400;
+ plot_style_even.text.flags = FONTF_NONE;
+ plot_style_even.text.foreground = gui_system_colour_char("WindowText");
+ plot_style_even.text.background = gui_system_colour_char("Window");
+
+ /* Selected background colour */
+ plot_style_even.sbg = plot_style_even.bg;
+ plot_style_even.sbg.fill_colour = gui_system_colour_char("Highlight");
+
+ /* Selected text colour */
+ plot_style_even.stext = plot_style_even.text;
+ plot_style_even.stext.foreground =
+ gui_system_colour_char("HighlightText");
+ plot_style_even.stext.background = gui_system_colour_char("Highlight");
+
+ /* Selection area background colour */
+ plot_style_even.sabg = plot_style_even.bg;
+ plot_style_even.sabg.fill_colour = mix_colour(
+ plot_style_even.bg.fill_colour,
+ plot_style_even.sbg.fill_colour, 255 * 3 / 4);
+
+ /* Selection area text colour */
+ plot_style_even.satext = plot_style_even.text;
+ plot_style_even.satext.background = plot_style_even.sabg.fill_colour;
+
+
+ /* Odd numbered node styles */
+ plot_style_odd.bg = plot_style_even.bg;
+ plot_style_odd.bg.fill_colour = mix_colour(
+ plot_style_even.bg.fill_colour,
+ plot_style_even.text.foreground, 255 * 15 / 16);
+ plot_style_odd.text = plot_style_even.text;
+ plot_style_odd.text.background = plot_style_odd.bg.fill_colour;
+
+ plot_style_odd.sbg = plot_style_even.sbg;
+ plot_style_odd.stext = plot_style_even.stext;
+
+ plot_style_odd.sabg = plot_style_even.sabg;
+ plot_style_odd.sabg.fill_colour = mix_colour(
+ plot_style_even.sabg.fill_colour,
+ plot_style_even.satext.foreground, 255 * 15 / 16);
+ plot_style_odd.satext = plot_style_even.satext;
+ plot_style_odd.satext.background = plot_style_odd.sabg.fill_colour;
+}
+
+
+/**
+ * Callback for hlcache.
+ */
+static nserror treeview_res_cb(hlcache_handle *handle,
+ const hlcache_event *event, void *pw)
+{
+ struct treeview_resource *r = pw;
+
+ switch (event->type) {
+ case CONTENT_MSG_READY:
+ case CONTENT_MSG_DONE:
+ r->ready = true;
+ r->height = content_get_height(handle);
+ break;
+
+ default:
+ break;
+ }
+
+ return NSERROR_OK;
+}
+
+
+static void treeview_init_resources(void)
+{
+ int i;
+
+ for (i = 0; i < TREE_RES_LAST; i++) {
+ nsurl *url;
+ if (nsurl_create(treeview_res[i].url, &url) == NSERROR_OK) {
+ hlcache_handle_retrieve(url, 0, NULL, NULL,
+ treeview_res_cb,
+ &(treeview_res[i]), NULL,
+ CONTENT_IMAGE, &(treeview_res[i].c));
+ nsurl_unref(url);
+ }
+ }
+}
+
+
+static void treeview_init_furniture(void)
+{
+ int i;
+ tree_g.furniture_width = 0;
+
+ for (i = 0; i < TREE_FURN_LAST; i++) {
+ nsfont.font_width(&plot_style_odd.text,
+ treeview_furn[i].data,
+ treeview_furn[i].len,
+ &(treeview_furn[i].width));
+
+ if (treeview_furn[i].width > tree_g.furniture_width)
+ tree_g.furniture_width = treeview_furn[i].width;
+ }
+
+ tree_g.furniture_width += 5;
+}
+
+
+nserror treeview_init(void)
+{
+ treeview_init_plot_styles();
+ treeview_init_resources();
+ treeview_init_furniture();
+
+ tree_g.line_height = 20;
+ tree_g.step_width = tree_g.furniture_width;
+ tree_g.window_padding = 6;
+ tree_g.icon_step = 23;
+
+ return NSERROR_OK;
+}
+
+
+nserror treeview_fini(void)
+{
+ int i;
+
+ for (i = 0; i < TREE_RES_LAST; i++) {
+ hlcache_handle_release(treeview_res[i].c);
+ }
+
+ return NSERROR_OK;
+}
+
+
+struct treeview_node * treeview_get_root(struct treeview *tree)
+{
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+
+ return tree->root;
+}
diff --git a/desktop/treeview.h b/desktop/treeview.h
new file mode 100644
index 0000000..91383d3
--- /dev/null
+++ b/desktop/treeview.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2012 - 2013 Michael Drake <tlsa(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf,
http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <
http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Treeview handling (interface).
+ */
+
+#ifndef _NETSURF_DESKTOP_TREEVIEW_H_
+#define _NETSURF_DESKTOP_TREEVIEW_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "desktop/core_window.h"
+#include "utils/types.h"
+
+struct treeview;
+struct treeview_node;
+
+enum treeview_relationship {
+ TREE_REL_CHILD,
+ TREE_REL_SIBLING_NEXT
+};
+
+enum treeview_msg {
+ TREE_MSG_NODE_DELETE,
+ TREE_MSG_FIELD_EDIT
+};
+struct treeview_node_msg {
+ enum treeview_msg msg; /**< The message type */
+ union {
+ struct {
+ struct treeview_node *node;
+ } node_delete;
+ struct {
+ struct treeview_node *node;
+ lwc_string *feild;
+ const char *text;
+ } field_edit;
+ } data; /**< The message data. */
+};
+
+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 */
+
+};
+struct treeview_field_desc {
+ lwc_string *field;
+ enum treeview_field_flags flags;
+};
+
+struct treeview_field_data {
+ lwc_string *field;
+ const char *value;
+ size_t value_len;
+};
+
+
+struct treeview_callback_table {
+ nserror (*folder)(struct treeview_node_msg msg, void *data);
+ nserror (*entry)(struct treeview_node_msg msg, void *data);
+};
+
+nserror treeview_init(void);
+nserror treeview_fini(void);
+
+nserror treeview_create(struct treeview **tree,
+ const struct treeview_callback_table *callbacks,
+ int n_fields, struct treeview_field_desc fields[],
+ const struct core_window_callback_table *cw_t,
+ const struct core_window *cw);
+
+nserror treeview_destroy(struct treeview *tree);
+
+nserror treeview_create_node_folder(struct treeview *tree,
+ struct treeview_node **folder,
+ struct treeview_node *relation,
+ enum treeview_relationship rel,
+ const struct treeview_field_data *field,
+ void *data);
+nserror treeview_create_node_entry(struct treeview *tree,
+ struct treeview_node **entry,
+ struct treeview_node *relation,
+ enum treeview_relationship rel,
+ const struct treeview_field_data fields[],
+ void *data);
+
+nserror treeview_update_node_entry(struct treeview *tree,
+ struct treeview_node *entry,
+ const struct treeview_field_data fields[],
+ void *data);
+
+nserror treeview_delete_node(struct treeview_node *n);
+
+nserror treeview_node_expand(struct treeview *tree,
+ struct treeview_node *node);
+nserror treeview_node_contract(struct treeview *tree,
+ struct treeview_node *node);
+
+void treeview_redraw(struct treeview *tree, int x, int y, struct rect *clip,
+ const struct redraw_context *ctx);
+
+struct treeview_node * treeview_get_root(struct treeview *tree);
+
+#endif
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=de85b4348a85c20c8cf...
commit de85b4348a85c20c8cf1553199203c691dec6629
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Include stdbool.h.
diff --git a/utils/types.h b/utils/types.h
index 617b493..e3f2e83 100644
--- a/utils/types.h
+++ b/utils/types.h
@@ -23,6 +23,8 @@
#ifndef _NETSURF_UTILS_TYPES_H_
#define _NETSURF_UTILS_TYPES_H_
+#include <stdbool.h>
+
struct plotter_table;
struct hlcache_handle;
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=a2c6f90330fe7e1aa75...
commit a2c6f90330fe7e1aa757f8dec3f65ebef8646eff
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Add icons to resource space.
diff --git a/content/fetchers/resource.c b/content/fetchers/resource.c
index 4afd443..2c31da2 100644
--- a/content/fetchers/resource.c
+++ b/content/fetchers/resource.c
@@ -81,7 +81,10 @@ static const char *fetch_resource_paths[] = {
"licence.html",
"welcome.html",
"favicon.ico",
- "netsurf.png"
+ "netsurf.png",
+ "icons/content.png",
+ "icons/directory.png",
+ "icons/search.png"
};
static struct fetch_resource_map_entry {
lwc_string *path;
-----------------------------------------------------------------------
Summary of changes:
content/fetchers/resource.c | 5 +-
desktop/Makefile | 2 +-
desktop/core_window.h | 57 ++
desktop/global_history.c | 749 ++++++++++++++++++
desktop/global_history.h | 82 ++
desktop/mouse.c | 3 +-
desktop/options.h | 3 +
desktop/tree.c | 159 ++++
desktop/treeview.c | 1769 +++++++++++++++++++++++++++++++++++++++++++
desktop/treeview.h | 281 +++++++
utils/types.h | 2 +
11 files changed, 3109 insertions(+), 3 deletions(-)
create mode 100644 desktop/core_window.h
create mode 100644 desktop/global_history.c
create mode 100644 desktop/global_history.h
create mode 100644 desktop/treeview.c
create mode 100644 desktop/treeview.h
diff --git a/content/fetchers/resource.c b/content/fetchers/resource.c
index 4afd443..2c31da2 100644
--- a/content/fetchers/resource.c
+++ b/content/fetchers/resource.c
@@ -81,7 +81,10 @@ static const char *fetch_resource_paths[] = {
"licence.html",
"welcome.html",
"favicon.ico",
- "netsurf.png"
+ "netsurf.png",
+ "icons/content.png",
+ "icons/directory.png",
+ "icons/search.png"
};
static struct fetch_resource_map_entry {
lwc_string *path;
diff --git a/desktop/Makefile b/desktop/Makefile
index f91754e..f787fd2 100644
--- a/desktop/Makefile
+++ b/desktop/Makefile
@@ -3,7 +3,7 @@
S_DESKTOP := cookies.c history_global_core.c hotlist.c knockout.c \
mouse.c plot_style.c print.c search.c searchweb.c \
scrollbar.c sslcert.c textarea.c thumbnail.c tree.c \
- tree_url_node.c version.c system_colour.c
+ tree_url_node.c version.c system_colour.c global_history.c treeview.c
S_DESKTOP := $(addprefix desktop/,$(S_DESKTOP))
diff --git a/desktop/core_window.h b/desktop/core_window.h
new file mode 100644
index 0000000..ad2319b
--- /dev/null
+++ b/desktop/core_window.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012 Michael Drake <tlsa(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf,
http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <
http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Core window handling (interface).
+ */
+
+#ifndef _NETSURF_DESKTOP_CORE_WINDOW_H_
+#define _NETSURF_DESKTOP_CORE_WINDOW_H_
+
+#include "utils/types.h"
+
+struct core_window;
+
+/** Callbacks to achieve various core window functionality. */
+struct core_window_callback_table {
+ /** Request a redraw of the window. */
+ void (*redraw_request)(struct core_window *cw, struct rect r);
+
+ /**
+ * Update the limits of the window
+ *
+ * \param cw the core window object
+ * \param width the width in px, or negative if don't care
+ * \param height the height in px, or negative if don't care
+ */
+ void (*update_size)(struct core_window *cw, int width, int height);
+
+ /** Scroll the window to make area visible */
+ void (*scroll_visible)(struct core_window *cw, struct rect r);
+
+ /** Get window viewport dimensions */
+ void (*get_window_dimensions)(struct core_window *cw,
+ int *width, int *height);
+};
+
+
+void core_window_draw(struct core_window *cw, int x, int y, struct rect r,
+ const struct redraw_context *ctx);
+
+
+#endif
diff --git a/desktop/global_history.c b/desktop/global_history.c
new file mode 100644
index 0000000..0a1e549
--- /dev/null
+++ b/desktop/global_history.c
@@ -0,0 +1,749 @@
+/*
+ * Copyright 2012 - 2013 Michael Drake <tlsa(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf,
http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <
http://www.gnu.org/licenses/>.
+ */
+
+
+#include <stdlib.h>
+
+#include "content/urldb.h"
+#include "desktop/browser.h"
+#include "desktop/global_history.h"
+#include "desktop/treeview.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "utils/log.h"
+
+#define N_FIELDS 5
+#define N_DAYS 28
+#define N_SEC_PER_DAY (60 * 60 * 24)
+
+enum global_history_folders {
+ GH_TODAY = 0,
+ GH_YESTERDAY,
+ GH_2_DAYS_AGO,
+ GH_3_DAYS_AGO,
+ GH_4_DAYS_AGO,
+ GH_5_DAYS_AGO,
+ GH_6_DAYS_AGO,
+ GH_LAST_WEEK,
+ GH_2_WEEKS_AGO,
+ GH_3_WEEKS_AGO,
+ GH_N_FOLDERS
+};
+
+struct global_history_folder {
+ struct treeview_node *folder;
+ struct treeview_field_data data;
+};
+
+struct global_history_ctx {
+ struct treeview *tree;
+ struct treeview_field_desc fields[N_FIELDS];
+ struct global_history_folder folders[GH_N_FOLDERS];
+ time_t today;
+ int weekday;
+};
+struct global_history_ctx gh_ctx;
+
+struct global_history_entry {
+ int slot;
+ nsurl *url;
+ time_t t;
+ struct treeview_node *entry;
+ struct global_history_entry *next;
+ struct global_history_entry *prev;
+
+ struct treeview_field_data data[N_FIELDS - 1];
+};
+struct global_history_entry *gh_list[N_DAYS];
+
+
+/**
+ * Find an entry in the global history
+ *
+ * \param url The URL to find
+ * \return Pointer to history entry, or NULL if not found
+ */
+static struct global_history_entry *global_history_find(nsurl *url)
+{
+ int i;
+ struct global_history_entry *e;
+
+ for (i = 0; i < N_DAYS; i++) {
+ e = gh_list[i];
+
+ while (e != NULL) {
+ if (nsurl_compare(e->url, url,
+ NSURL_COMPLETE) == true) {
+ /* Got a match */
+ return e;
+ }
+ e = e->next;
+ }
+
+ }
+
+ /* No match found */
+ return NULL;
+}
+
+
+/**
+ * Initialise the treeview directories
+ *
+ * \param f Ident for folder to create
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror global_history_create_dir(enum global_history_folders f)
+{
+ nserror err;
+ time_t t = gh_ctx.today;
+ struct treeview_node *relation = NULL;
+ enum treeview_relationship rel = TREE_REL_FIRST_CHILD;
+ const char *label;
+ int age;
+ int i;
+
+ switch (f) {
+ case GH_TODAY:
+ label = "DateToday";
+ age = 0;
+ break;
+ case GH_YESTERDAY:
+ label = "DateYesterday";
+ age = 1;
+ break;
+ case GH_2_DAYS_AGO:
+ label = "Date2Days";
+ age = 2;
+ break;
+ case GH_3_DAYS_AGO:
+ label = "Date3Days";
+ age = 3;
+ break;
+ case GH_4_DAYS_AGO:
+ label = "Date4Days";
+ age = 4;
+ break;
+ case GH_5_DAYS_AGO:
+ label = "Date5Days";
+ age = 5;
+ break;
+ case GH_6_DAYS_AGO:
+ label = "Date6Days";
+ age = 6;
+ break;
+ case GH_LAST_WEEK:
+ label = "Date1Week";
+ age = 7;
+ break;
+ case GH_2_WEEKS_AGO:
+ label = "Date2Week";
+ age = 14;
+ break;
+ case GH_3_WEEKS_AGO:
+ label = "Date3Week";
+ age = 21;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ t -= age * N_SEC_PER_DAY;
+
+ label = messages_get(label);
+
+ for (i = f - 1; i >= 0; i--) {
+ if (gh_ctx.folders[i].folder != NULL) {
+ relation = gh_ctx.folders[i].folder;
+ rel = TREE_REL_NEXT_SIBLING;
+ break;
+ }
+ }
+
+ gh_ctx.folders[f].data.field = gh_ctx.fields[N_FIELDS - 1].field;
+ gh_ctx.folders[f].data.value = label;
+ gh_ctx.folders[f].data.value_len = strlen(label);
+ err = treeview_create_node_folder(gh_ctx.tree,
+ &gh_ctx.folders[f].folder,
+ relation, rel,
+ &gh_ctx.folders[f].data,
+ &gh_ctx.folders[f]);
+
+ return err;
+}
+
+
+/**
+ * Get the treeview folder for history entires in a particular slot
+ *
+ * \param parent Updated to parent folder.
+ * \param slot Global history slot of entry we want folder node for
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static inline nserror global_history_get_parent_treeview_node(
+ struct treeview_node **parent, int slot)
+{
+ int folder_index;
+ struct global_history_folder *f;
+ nserror err;
+
+ if (slot < 7) {
+ folder_index = slot;
+
+ } else if (slot < 14) {
+ folder_index = GH_LAST_WEEK;
+
+ } else if (slot < 21) {
+ folder_index = GH_2_WEEKS_AGO;
+
+ } else if (slot < N_DAYS) {
+ folder_index = GH_3_WEEKS_AGO;
+
+ } else {
+ /* Slot value is invalid */
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ /* Get the folder */
+ f = &(gh_ctx.folders[folder_index]);
+
+ if (f->folder == NULL) {
+ err = global_history_create_dir(folder_index);
+ if (err != NSERROR_OK) {
+ *parent = NULL;
+ return err;
+ }
+ }
+
+ /* Return the parent treeview folder */
+ *parent = f->folder;
+ return NSERROR_OK;
+}
+
+
+/**
+ * Set a global history entry's data from the url_data.
+ *
+ * \param e Global history entry to set up
+ * \param url_data Data associated with entry's URL
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror global_history_create_treeview_field_data(
+ struct global_history_entry *e,
+ const struct url_data *data)
+{
+ const char *title = (data->title != NULL) ? data->title : "<No
title>";
+ char buffer[16];
+ const char *last_visited;
+ char *last_visited2;
+ int len;
+
+ e->data[0].field = gh_ctx.fields[0].field;
+ e->data[0].value = strdup(title);
+ e->data[0].value_len = (e->data[0].value != NULL) ? strlen(title) : 0;
+
+ e->data[1].field = gh_ctx.fields[1].field;
+ e->data[1].value = nsurl_access(e->url);
+ e->data[1].value_len = nsurl_length(e->url);
+
+ last_visited = ctime(&data->last_visit);
+ last_visited2 = strdup(last_visited);
+ if (last_visited2 != NULL) {
+ assert(last_visited2[24] == '\n');
+ last_visited2[24] = '\0';
+ }
+
+ e->data[2].field = gh_ctx.fields[2].field;
+ e->data[2].value = last_visited2;
+ e->data[2].value_len = (last_visited2 != NULL) ? 24 : 0;
+
+ len = snprintf(buffer, 16, "%u", data->visits);
+ if (len == 16) {
+ len--;
+ buffer[len] = '\0';
+ }
+
+ e->data[3].field = gh_ctx.fields[3].field;
+ e->data[3].value = strdup(buffer);
+ e->data[3].value_len = len;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Add a global history entry to the treeview
+ *
+ * \param e entry to add to treeview
+ * \param slot global history slot containing entry
+ * \return NSERROR_OK on success, or appropriate error otherwise
+ *
+ * It is assumed that the entry is unique (for its URL) in the global
+ * history table
+ */
+static nserror global_history_entry_insert(struct global_history_entry *e,
+ int slot)
+{
+ nserror err;
+
+ struct treeview_node *parent;
+ err = global_history_get_parent_treeview_node(&parent, slot);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ err = treeview_create_node_entry(gh_ctx.tree, &(e->entry),
+ parent, TREE_REL_FIRST_CHILD, e->data, e);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Add an entry to the global history (creates the entry).
+ *
+ * If the treeview has already been created, the entry will be added to the
+ * treeview. Otherwise, the entry will have to be added to the treeview later.
+ *
+ * When we first create the global history we create it without the treeview, to
+ * simplfy sorting the entries.
+ *
+ * \param url URL for entry to add to history
+ * \param slot Global history slot to contain history entry
+ * \param data URL data for the entry
+ * \param got_treeview Whether the treeview has been created already
+ * \return NSERROR_OK on success, or appropriate error otherwise
+ */
+static nserror global_history_add_entry_internal(nsurl *url, int slot,
+ const struct url_data *data, bool got_treeview)
+{
+ nserror err;
+ struct global_history_entry *e;
+
+ /* Create new local history entry */
+ e = malloc(sizeof(struct global_history_entry));
+ if (e == NULL) {
+ return false;
+ }
+
+ e->slot = slot;
+ e->url = nsurl_ref(url);
+ e->t = data->last_visit;
+ e->entry = NULL;
+ e->next = NULL;
+ e->prev = NULL;
+
+ err = global_history_create_treeview_field_data(e, data);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ if (gh_list[slot] == NULL) {
+ /* list empty */
+ gh_list[slot] = e;
+
+ } else if (gh_list[slot]->t < e->t) {
+ /* Insert at list head */
+ e->next = gh_list[slot];
+ gh_list[slot]->prev = e;
+ gh_list[slot] = e;
+ } else {
+ struct global_history_entry *prev = gh_list[slot];
+ struct global_history_entry *curr = prev->next;
+ while (curr != NULL) {
+ if (curr->t < e->t) {
+ break;
+ }
+ prev = curr;
+ curr = curr->next;
+ }
+
+ /* insert after prev */
+ e->next = curr;
+ e->prev = prev;
+ prev->next = e;
+
+ if (curr != NULL)
+ curr->prev = e;
+ }
+
+ if (got_treeview) {
+ err = global_history_entry_insert(e, slot);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Delete a global history entry
+ *
+ * This does not delete the treeview node, rather it should only be called from
+ * the treeview node delete event message.
+ *
+ * \param e Entry to delete
+ */
+static void global_history_delete_entry_internal(
+ struct global_history_entry *e)
+{
+ assert(e != NULL);
+ assert(e->entry == NULL);
+
+ /* Unlink */
+ if (gh_list[e->slot] == e) {
+ /* e is first entry */
+ gh_list[e->slot] = e->next;
+
+ if (e->next != NULL)
+ e->next->prev = NULL;
+
+ } else if (e->next == NULL) {
+ /* e is last entry */
+ e->prev->next = NULL;
+
+ } else {
+ /* e has an entry before and after */
+ e->prev->next = e->next;
+ e->next->prev = e->prev;
+ }
+
+ /* Destroy */
+ free((void *)e->data[0].value); /* Eww */
+ free((void *)e->data[2].value); /* Eww */
+ free((void *)e->data[3].value); /* Eww */
+ nsurl_unref(e->url);
+ free(e);
+}
+
+/**
+ * Internal routine to actually perform global history addition
+ *
+ * \param url The URL to add
+ * \param data URL data associated with URL
+ * \return true (for urldb_iterate_entries)
+ */
+static bool global_history_add_entry(nsurl *url,
+ const struct url_data *data)
+{
+ int slot;
+ struct global_history_entry *e;
+ time_t visit_date;
+ time_t earliest_date = gh_ctx.today - (N_DAYS - 1) * N_SEC_PER_DAY;
+ bool got_treeview = gh_ctx.tree != NULL;
+
+ assert((url != NULL) && (data != NULL));
+
+ visit_date = data->last_visit;
+
+ /* Find day array slot for entry */
+ if (visit_date >= gh_ctx.today) {
+ slot = 0;
+ } else if (visit_date >= earliest_date) {
+ slot = (gh_ctx.today - visit_date) / N_SEC_PER_DAY + 1;
+ } else {
+ /* too old */
+ return true;
+ }
+
+ if (got_treeview == true) {
+ /* The treeview for global history already exists */
+
+ /* See if there's already an entry for this URL */
+ e = global_history_find(url);
+ if (e != NULL) {
+ /* Existing entry. Delete it. */
+ treeview_delete_node(gh_ctx.tree, e->entry);
+ return true;
+ }
+ }
+
+ if (global_history_add_entry_internal(url, slot, data,
+ got_treeview) != NSERROR_OK) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Initialise the treeview entry feilds
+ *
+ * \return true on success, false on memory exhaustion
+ */
+static nserror global_history_initialise_entry_fields(void)
+{
+ int i;
+
+ for (i = 0; i < N_FIELDS; i++)
+ gh_ctx.fields[i].field = NULL;
+
+ /* TODO: use messages */
+ gh_ctx.fields[0].flags = TREE_FLAG_DEFAULT;
+ if (lwc_intern_string("Title", SLEN("Title"),
+ &gh_ctx.fields[0].field) !=
+ lwc_error_ok) {
+ goto error;
+ }
+
+ gh_ctx.fields[1].flags = TREE_FLAG_NONE;
+ if (lwc_intern_string("URL", SLEN("URL"),
+ &gh_ctx.fields[1].field) !=
+ lwc_error_ok) {
+ goto error;
+ }
+
+ gh_ctx.fields[2].flags = TREE_FLAG_SHOW_NAME;
+ if (lwc_intern_string("Last visit", SLEN("Last visit"),
+ &gh_ctx.fields[2].field) !=
+ lwc_error_ok) {
+ goto error;
+ }
+
+ gh_ctx.fields[3].flags = TREE_FLAG_SHOW_NAME;
+ if (lwc_intern_string("Visits", SLEN("Visits"),
+ &gh_ctx.fields[3].field) !=
+ lwc_error_ok) {
+ goto error;
+ }
+
+ gh_ctx.fields[4].flags = TREE_FLAG_DEFAULT;
+ if (lwc_intern_string("Period", SLEN("Period"),
+ &gh_ctx.fields[4].field) !=
+ lwc_error_ok) {
+ return false;
+ }
+
+ return NSERROR_OK;
+
+error:
+ for (i = 0; i < N_FIELDS; i++)
+ if (gh_ctx.fields[i].field != NULL)
+ lwc_string_unref(gh_ctx.fields[i].field);
+
+ return NSERROR_UNKNOWN;
+}
+
+
+/**
+ * Initialise the time
+ *
+ * \return true on success, false on memory exhaustion
+ */
+static nserror global_history_initialise_time(void)
+{
+ struct tm *full_time;
+ time_t t;
+
+ /* get the current time */
+ t = time(NULL);
+ if (t == -1) {
+ LOG(("time info unaviable"));
+ return NSERROR_UNKNOWN;
+ }
+
+ /* get the time at the start of today */
+ full_time = localtime(&t);
+ full_time->tm_sec = 0;
+ full_time->tm_min = 0;
+ full_time->tm_hour = 0;
+ t = mktime(full_time);
+ if (t == -1) {
+ LOG(("mktime failed"));
+ return NSERROR_UNKNOWN;
+ }
+
+ gh_ctx.today = t;
+ gh_ctx.weekday = full_time->tm_wday;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Initialise the treeview entries
+ *
+ * \return true on success, false on memory exhaustion
+ */
+static nserror global_history_init_entries(void)
+{
+ int i;
+ nserror err;
+
+ /* Itterate over all global history data, inserting it into treeview */
+ for (i = 0; i < N_DAYS; i++) {
+ struct global_history_entry *l = NULL;
+ struct global_history_entry *e = gh_list[i];
+
+ /* Insert in reverse order; find last */
+ while (e != NULL) {
+ l = e;
+ e = e->next;
+ }
+
+ /* Insert the entries into the treeview */
+ while (l != NULL) {
+ err = global_history_entry_insert(l, i);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+ l = l->prev;
+ }
+ }
+
+ return NSERROR_OK;
+}
+
+
+static nserror global_history_tree_node_folder_cb(
+ struct treeview_node_msg msg, void *data)
+{
+ return NSERROR_OK;
+}
+static nserror global_history_tree_node_entry_cb(
+ struct treeview_node_msg msg, void *data)
+{
+ struct global_history_entry *e = (struct global_history_entry *)data;
+
+ switch (msg.msg) {
+ case TREE_MSG_NODE_DELETE:
+ e->entry = NULL;
+ global_history_delete_entry_internal(e);
+ break;
+
+ case TREE_MSG_NODE_EDIT:
+ break;
+
+ case TREE_MSG_NODE_LAUNCH:
+ break;
+ }
+ return NSERROR_OK;
+}
+struct treeview_callback_table tree_cb_t = {
+ .folder = global_history_tree_node_folder_cb,
+ .entry = global_history_tree_node_entry_cb
+};
+
+
+/* Exported interface, documented in global_history.h */
+nserror global_history_init(struct core_window_callback_table *cw_t,
+ void *core_window_handle)
+{
+ nserror err;
+
+ LOG(("Loading global history"));
+
+ /* Init. global history treeview time */
+ err = global_history_initialise_time();
+ if (err != NSERROR_OK) {
+ gh_ctx.tree = NULL;
+ return err;
+ }
+
+ /* Init. global history treeview entry fields */
+ err = global_history_initialise_entry_fields();
+ if (err != NSERROR_OK) {
+ gh_ctx.tree = NULL;
+ return err;
+ }
+
+ /* Load the entries */
+ urldb_iterate_entries(global_history_add_entry);
+
+ /* Create the global history treeview */
+ err = treeview_create(&gh_ctx.tree, &tree_cb_t,
+ N_FIELDS, gh_ctx.fields,
+ cw_t, core_window_handle);
+ if (err != NSERROR_OK) {
+ gh_ctx.tree = NULL;
+ return err;
+ }
+
+ /* Ensure there is a folder for today */
+ err = global_history_create_dir(GH_TODAY);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ /* Add the history to the treeview */
+ err = global_history_init_entries();
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ /* Expand the "Today" folder node */
+ err = treeview_node_expand(gh_ctx.tree,
+ gh_ctx.folders[GH_TODAY].folder);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ LOG(("Loaded global history"));
+
+ return NSERROR_OK;
+}
+
+
+/* Exported interface, documented in global_history.h */
+nserror global_history_fini(void)
+{
+ int i;
+ nserror err;
+
+ LOG(("Finalising global history"));
+
+ /* Destroy the global history treeview */
+ err = treeview_destroy(gh_ctx.tree);
+
+ /* Free global history treeview entry fields */
+ for (i = 0; i < N_FIELDS; i++)
+ if (gh_ctx.fields[i].field != NULL)
+ lwc_string_unref(gh_ctx.fields[i].field);
+
+ LOG(("Finalised global history"));
+
+ return NSERROR_OK;
+}
+
+
+/* Exported interface, documented in global_history.h */
+void global_history_redraw(int x, int y, struct rect *clip,
+ const struct redraw_context *ctx)
+{
+ treeview_redraw(gh_ctx.tree, x, y, clip, ctx);
+}
+
+
+/* Exported interface, documented in global_history.h */
+void global_history_mouse_action(browser_mouse_state mouse, int x, int y)
+{
+ treeview_mouse_action(gh_ctx.tree, mouse, x, y);
+}
+
+
+/* Exported interface, documented in global_history.h */
+void global_history_keypress(uint32_t key)
+{
+ treeview_keypress(gh_ctx.tree, key);
+}
+
diff --git a/desktop/global_history.h b/desktop/global_history.h
new file mode 100644
index 0000000..591b1fe
--- /dev/null
+++ b/desktop/global_history.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012 - 2013 Michael Drake <tlsa(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf,
http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <
http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NETSURF_DESKTOP_GLOBAL_HISTORY_H_
+#define _NETSURF_DESKTOP_GLOBAL_HISTORY_H_
+
+#include <stdbool.h>
+
+#include "desktop/core_window.h"
+
+
+/**
+ * Initialise the global history.
+ *
+ * This iterates through the URL database, generating the global history data,
+ * and creates a treeview.
+ *
+ * This must be called before any other global_history_* function.
+ *
+ * \param cw_t Callback table for core_window containing the treeview
+ * \param cw The core_window in which the treeview is shown
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror global_history_init(struct core_window_callback_table *cw_t,
+ void *core_window_handle);
+
+/**
+ * Finalise the global history.
+ *
+ * This destroys the global history treeview and the global history module's
+ * internal data. After calling this if global history is required again,
+ * global_history_init must be called.
+ *
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror global_history_fini(void);
+
+/**
+ * Redraw the global history.
+ *
+ * \param x X coordinate to render treeview at
+ * \param x Y coordinate to render treeview at
+ * \param clip Current clip rectangle (wrt tree origin)
+ * \param ctx Current redraw context
+ */
+void global_history_redraw(int x, int y, struct rect *clip,
+ const struct redraw_context *ctx);
+
+/**
+ * Handles all kinds of mouse action
+ *
+ * \param mouse The current mouse state
+ * \param x X coordinate
+ * \param y Y coordinate
+ */
+void global_history_mouse_action(browser_mouse_state mouse, int x, int y);
+
+
+/**
+ * Key press handling.
+ *
+ * \param key The ucs4 character codepoint
+ * \return true if the keypress is dealt with, false otherwise.
+ */
+void global_history_keypress(uint32_t key);
+
+#endif
diff --git a/desktop/mouse.c b/desktop/mouse.c
index 372ce2c..c156af8 100644
--- a/desktop/mouse.c
+++ b/desktop/mouse.c
@@ -30,12 +30,13 @@
*/
void browser_mouse_state_dump(browser_mouse_state mouse)
{
- LOG(("mouse state: %s %s %s %s %s %s %s %s %s %s %s %s %s",
+ LOG(("mouse state: %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
mouse & BROWSER_MOUSE_PRESS_1 ? "P1" : " ",
mouse & BROWSER_MOUSE_PRESS_2 ? "P2" : " ",
mouse & BROWSER_MOUSE_CLICK_1 ? "C1" : " ",
mouse & BROWSER_MOUSE_CLICK_2 ? "C2" : " ",
mouse & BROWSER_MOUSE_DOUBLE_CLICK ? "DC" : " ",
+ mouse & BROWSER_MOUSE_TRIPLE_CLICK ? "TC" : " ",
mouse & BROWSER_MOUSE_DRAG_1 ? "D1" : " ",
mouse & BROWSER_MOUSE_DRAG_2 ? "D2" : " ",
mouse & BROWSER_MOUSE_DRAG_ON ? "DO" : " ",
diff --git a/desktop/options.h b/desktop/options.h
index 391dfbc..7ed6fc1 100644
--- a/desktop/options.h
+++ b/desktop/options.h
@@ -275,3 +275,6 @@ NSOPTION_COLOUR(sys_colour_ThreeDShadow, 0x00d5d5d5)
NSOPTION_COLOUR(sys_colour_Window, 0x00f1f1f1)
NSOPTION_COLOUR(sys_colour_WindowFrame, 0x004e4e4e)
NSOPTION_COLOUR(sys_colour_WindowText, 0x00000000)
+
+/** Temporary option for enabling test of new treeview */
+NSOPTION_BOOL(temp_treeview_test, false)
diff --git a/desktop/tree.c b/desktop/tree.c
index 2e35b5b..a0640f6 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -173,6 +173,131 @@ struct tree {
struct node *def_folder; /* Node to be used for additions by default */
};
+
+
+
+#include "desktop/treeview.h"
+#include "desktop/global_history.h"
+
+static void treeview_test_redraw_request(struct core_window *cw, struct rect r)
+{
+ struct tree *tree = (struct tree *)cw;
+
+ tree->callbacks->redraw_request(r.x0, r.y0,
+ r.x1 - r.x0, r.y1 - r.y0,
+ tree->client_data);
+}
+
+static void treeview_test_update_size(struct core_window *cw,
+ int width, int height)
+{
+ struct tree *tree = (struct tree *)cw;
+
+ tree->callbacks->resized(tree, width, height, tree->client_data);
+}
+
+static void treeview_test_scroll_visible(struct core_window *cw, struct rect r)
+{
+}
+
+static void treeview_test_get_window_dimensions(struct core_window *cw,
+ int *width, int *height)
+{
+}
+
+struct core_window_callback_table cw_t = {
+ .redraw_request = treeview_test_redraw_request,
+ .update_size = treeview_test_update_size,
+ .scroll_visible = treeview_test_scroll_visible,
+ .get_window_dimensions = treeview_test_get_window_dimensions
+};
+
+static bool treeview_test_init(struct tree *tree)
+{
+ nserror err;
+
+ if (nsoption_bool(temp_treeview_test) == false)
+ return false;
+
+ treeview_init();
+ err = global_history_init(&cw_t, (struct core_window *)tree);
+ if (err != NSERROR_OK) {
+ warn_user("Duffed it.", 0);
+ }
+
+ return true;
+}
+
+static bool treeview_test_fini(struct tree *tree)
+{
+ nserror err;
+
+ if (nsoption_bool(temp_treeview_test) == false)
+ return false;
+
+ err = global_history_fini();
+ treeview_fini();
+ if (err != NSERROR_OK) {
+ warn_user("Duffed it.", 0);
+ }
+
+ return true;
+}
+
+static bool treeview_test_redraw(struct tree *tree, int x, int y,
+ int clip_x, int clip_y, int clip_width, int clip_height,
+ const struct redraw_context *ctx)
+{
+ struct rect clip;
+
+ if (nsoption_bool(temp_treeview_test) == false)
+ return false;
+
+ clip.x0 = clip_x;
+ clip.y0 = clip_y;
+ clip.x1 = clip_x + clip_width;
+ clip.y1 = clip_y + clip_height;
+
+ global_history_redraw(x, y, &clip, ctx);
+
+ return true;
+}
+
+static bool treeview_test_mouse_action(struct tree *tree,
+ browser_mouse_state mouse, int x, int y)
+{
+ if (nsoption_bool(temp_treeview_test) == false)
+ return false;
+
+ global_history_mouse_action(mouse, x, y);
+
+ return true;
+}
+
+static bool treeview_test_keypress(struct tree *tree, uint32_t key)
+{
+ if (nsoption_bool(temp_treeview_test) == false)
+ return false;
+
+ global_history_keypress(key);
+
+ return true;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
void tree_set_icon_dir(char *icon_dir)
{
LOG(("Tree icon directory set to %s", icon_dir));
@@ -276,6 +401,10 @@ struct tree *tree_create(unsigned int flags,
tree_setup_colours();
+ if (flags == TREE_MOVABLE) {
+ treeview_test_init(tree);
+ }
+
return tree;
}
@@ -1119,6 +1248,10 @@ void tree_delete(struct tree *tree)
{
tree->redraw = false;
+ if (tree->flags == TREE_MOVABLE) {
+ treeview_test_fini(tree);
+ }
+
if (tree->root->child != NULL)
tree_delete_node_internal(tree, tree->root->child, true);
@@ -2044,6 +2177,13 @@ void tree_draw(struct tree *tree, int x, int y,
assert(tree != NULL);
assert(tree->root != NULL);
+ if (tree->flags == TREE_MOVABLE) {
+ if (treeview_test_redraw(tree, x, y, clip_x, clip_y,
+ clip_width, clip_height, ctx)) {
+ return;
+ }
+ }
+
/* Start knockout rendering if it's available for this plotter */
if (ctx->plot->option_knockout)
knockout_plot_start(ctx, &new_ctx);
@@ -2408,6 +2548,12 @@ bool tree_mouse_action(struct tree *tree, browser_mouse_state
mouse, int x,
assert(tree != NULL);
assert(tree->root != NULL);
+ if (tree->flags == TREE_MOVABLE) {
+ if (treeview_test_mouse_action(tree, mouse, x, y)) {
+ return true;
+ }
+ }
+
if (tree->root->child == NULL)
return true;
@@ -2814,6 +2960,13 @@ void tree_drag_end(struct tree *tree, browser_mouse_state mouse,
int x0, int y0,
struct node *node;
int x, y;
+ if (tree->flags & TREE_MOVABLE) {
+ if (treeview_test_mouse_action(tree, BROWSER_MOUSE_HOVER,
+ x1, y1)) {
+ return;
+ }
+ }
+
switch (tree->drag) {
case TREE_NO_DRAG:
case TREE_UNKNOWN_DRAG:
@@ -2854,6 +3007,12 @@ void tree_drag_end(struct tree *tree, browser_mouse_state mouse,
int x0, int y0,
*/
bool tree_keypress(struct tree *tree, uint32_t key)
{
+ if (tree->flags == TREE_MOVABLE) {
+ if (treeview_test_keypress(tree, key)) {
+ return true;
+ }
+ }
+
if (tree->editing != NULL)
switch (key) {
case KEY_ESCAPE:
diff --git a/desktop/treeview.c b/desktop/treeview.c
new file mode 100644
index 0000000..3035f9e
--- /dev/null
+++ b/desktop/treeview.c
@@ -0,0 +1,1769 @@
+/*
+ * Copyright 2012 - 2013 Michael Drake <tlsa(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf,
http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <
http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Treeview handling (implementation).
+ */
+
+#include "css/utils.h"
+#include "desktop/gui.h"
+#include "desktop/knockout.h"
+#include "desktop/plotters.h"
+#include "desktop/treeview.h"
+#include "render/font.h"
+#include "utils/log.h"
+
+/* TODO: get rid of REDRAW_MAX -- need to be able to know window size */
+#define REDRAW_MAX 8000
+
+struct treeview_globals {
+ int line_height;
+ int furniture_width;
+ int step_width;
+ int window_padding;
+ int icon_step;
+} tree_g;
+
+enum treeview_node_type {
+ TREE_NODE_ROOT,
+ TREE_NODE_FOLDER,
+ TREE_NODE_ENTRY
+};
+
+enum treeview_node_section {
+ TV_NODE_SECTION_TOGGLE, /**< Expansion toggle */
+ TV_NODE_SECTION_ON_NODE, /**< Node content (text, icon) */
+ TV_NODE_SECTION_NONE /**< Empty area */
+}; /**< Section type of a treeview at a point */
+
+struct treeview_text {
+ const char *data; /**< Text string */
+ uint32_t len; /**< Lenfth of string in bytes */
+ int width; /**< Width of text in px */
+};
+
+struct treeview_field {
+ enum treeview_field_flags flags;
+
+ lwc_string *field;
+ struct treeview_text value;
+};
+
+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 {
+ enum treeview_node_flags flags; /**< Node flags */
+ enum treeview_node_type type; /**< Node type */
+
+ int height; /**< Includes height of any descendants (pixels) */
+ int inset; /**< Node's inset depending on tree depth (pixels) */
+
+ struct treeview_node *parent;
+ struct treeview_node *sibling_prev;
+ struct treeview_node *sibling_next;
+ struct treeview_node *children;
+
+ void *client_data; /**< Passed to client on node event msg callback */
+
+ struct treeview_field text; /** Text to show for node (default field) */
+}; /**< Treeview node */
+
+struct treeview_node_entry {
+ struct treeview_node base;
+ struct treeview_field fields[];
+}; /**< Entry class inherits node base class */
+
+struct treeview_pos {
+ int x; /**< Mouse X coordinate */
+ int y; /**< Mouse Y coordinate */
+ int node_y; /**< Top of node at y */
+ int node_h; /**< Height of node at y */
+}; /**< A mouse position wrt treeview */
+
+struct treeview_drag {
+ enum {
+ TV_DRAG_NONE,
+ TV_DRAG_SELECTION,
+ TV_DRAG_MOVE,
+ TV_DRAG_TEXTAREA
+ } type; /**< Drag type */
+ struct treeview_node *start_node; /**< Start node */
+ bool selected; /**< Start node is selected */
+ enum treeview_node_section section; /**< Node section at start */
+ struct treeview_pos start; /**< Start pos */
+ struct treeview_pos prev; /**< Previous pos */
+}; /**< Drag state */
+
+struct treeview {
+ uint32_t view_width; /** Viewport size */
+
+ struct treeview_node *root; /**< Root node */
+
+ struct treeview_field *fields; /**< Array of fields */
+ 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 */
+
+ const struct treeview_callback_table *callbacks; /**< For node events */
+
+ const struct core_window_callback_table *cw_t; /**< Window cb table */
+ struct core_window *cw_h; /**< Core window handle */
+};
+
+
+struct treeview_node_style {
+ plot_style_t bg; /**< Background */
+ plot_font_style_t text; /**< Text */
+ plot_font_style_t itext; /**< Entry field text */
+
+ plot_style_t sbg; /**< Selected background */
+ plot_font_style_t stext; /**< Selected text */
+ plot_font_style_t sitext; /**< Selected entry field text */
+};
+
+struct treeview_node_style plot_style_odd; /**< Plot style for odd rows */
+struct treeview_node_style plot_style_even; /**< Plot style for even rows */
+
+struct treeview_resource {
+ const char *url;
+ struct hlcache_handle *c;
+ int height;
+ bool ready;
+}; /**< Treeview content resource data */
+enum treeview_resource_id {
+ TREE_RES_CONTENT = 0,
+ TREE_RES_FOLDER,
+ TREE_RES_SEARCH,
+ TREE_RES_LAST
+};
+static struct treeview_resource treeview_res[TREE_RES_LAST] = {
+ { "resource:icons/content.png", NULL, 0, false },
+ { "resource:icons/directory.png", NULL, 0, false },
+ { "resource:icons/search.png", NULL, 0, false }
+}; /**< Treeview content resources */
+
+
+
+enum treeview_furniture_id {
+ TREE_FURN_EXPAND = 0,
+ TREE_FURN_CONTRACT,
+ TREE_FURN_LAST
+};
+static struct treeview_text treeview_furn[TREE_FURN_LAST] = {
+ { "\xe2\x96\xb8", 3, 0 }, /* U+25B8: Right-pointing small triangle */
+ { "\xe2\x96\xbe", 3, 0 } /* U+25BE: Down-pointing small triangle */
+};
+
+
+/**
+ * Create treeview's root node
+ *
+ * \param root Returns root node
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror treeview_create_node_root(struct treeview_node **root)
+{
+ struct treeview_node *n;
+
+ n = malloc(sizeof(struct treeview_node));
+ if (n == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ n->flags = TREE_NODE_EXPANDED;
+ n->type = TREE_NODE_ROOT;
+
+ n->height = 0;
+ n->inset = tree_g.window_padding - tree_g.step_width;
+
+ n->text.flags = TREE_FLAG_NONE;
+ n->text.field = NULL;
+ n->text.value.data = NULL;
+ n->text.value.len = 0;
+ n->text.value.width = 0;
+
+ n->parent = NULL;
+ n->sibling_next = NULL;
+ n->sibling_prev = NULL;
+ n->children = NULL;
+
+ n->client_data = NULL;
+
+ *root = n;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * 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 rel a's relationship to b
+ */
+static inline void treeview_insert_node(struct treeview_node *a,
+ struct treeview_node *b,
+ enum treeview_relationship rel)
+{
+ assert(a != NULL);
+ assert(a->parent == NULL);
+ assert(b != NULL);
+
+ switch (rel) {
+ case TREE_REL_FIRST_CHILD:
+ assert(b->type != TREE_NODE_ENTRY);
+ a->parent = b;
+ a->sibling_next = b->children;
+ if (a->sibling_next)
+ a->sibling_next->sibling_prev = a;
+ b->children = a;
+ break;
+
+ case TREE_REL_NEXT_SIBLING:
+ assert(b->type != TREE_NODE_ROOT);
+ a->sibling_prev = b;
+ a->sibling_next = b->sibling_next;
+ a->parent = b->parent;
+ b->sibling_next = a;
+ if (a->sibling_next)
+ a->sibling_next->sibling_prev = a;
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ assert(a->parent != NULL);
+
+ a->inset = a->parent->inset + tree_g.step_width;
+
+ if (a->parent->flags & TREE_NODE_EXPANDED) {
+ /* Parent is expanded, so inserted node will be visible and
+ * affect layout */
+ b = a;
+ do {
+ b->parent->height += b->height;
+ b = b->parent;
+ } while (b->parent != NULL);
+
+ if (a->text.value.width == 0) {
+ nsfont.font_width(&plot_style_odd.text,
+ a->text.value.data,
+ a->text.value.len,
+ &(a->text.value.width));
+ }
+ }
+}
+
+
+/* Exported interface, documented in treeview.h */
+nserror treeview_create_node_folder(struct treeview *tree,
+ struct treeview_node **folder,
+ struct treeview_node *relation,
+ enum treeview_relationship rel,
+ const struct treeview_field_data *field,
+ void *data)
+{
+ struct treeview_node *n;
+
+ assert(data != NULL);
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+
+ if (relation == NULL) {
+ relation = tree->root;
+ rel = TREE_REL_FIRST_CHILD;
+ }
+
+ n = malloc(sizeof(struct treeview_node));
+ if (n == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ n->flags = TREE_NODE_NONE;
+ n->type = TREE_NODE_FOLDER;
+
+ n->height = tree_g.line_height;
+
+ n->text.value.data = field->value;
+ n->text.value.len = field->value_len;
+ n->text.value.width = 0;
+
+ n->parent = NULL;
+ n->sibling_next = NULL;
+ n->sibling_prev = NULL;
+ n->children = NULL;
+
+ n->client_data = data;
+
+ treeview_insert_node(n, relation, rel);
+
+ *folder = n;
+
+ /* Inform front end of change in dimensions */
+ tree->cw_t->update_size(tree->cw_h, -1, tree->root->height);
+
+ return NSERROR_OK;
+}
+
+
+/* Exported interface, documented in treeview.h */
+nserror treeview_update_node_entry(struct treeview *tree,
+ struct treeview_node *entry,
+ const struct treeview_field_data fields[],
+ void *data)
+{
+ bool match;
+ struct treeview_node_entry *e = (struct treeview_node_entry *)entry;
+ int i;
+
+ assert(data != NULL);
+ assert(tree != NULL);
+ assert(entry != NULL);
+ assert(data == entry->client_data);
+ assert(entry->parent != NULL);
+
+ 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);
+ entry->text.value.data = fields[0].value;
+ entry->text.value.len = fields[0].value_len;
+ entry->text.value.width = 0;
+
+ if (entry->parent->flags & TREE_NODE_EXPANDED) {
+ /* Text will be seen, get its width */
+ nsfont.font_width(&plot_style_odd.text,
+ entry->text.value.data,
+ entry->text.value.len,
+ &(entry->text.value.width));
+ } else {
+ /* Just invalidate the width, since it's not needed now */
+ entry->text.value.width = 0;
+ }
+
+ 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);
+
+ e->fields[i - 1].value.data = fields[i].value;
+ e->fields[i - 1].value.len = fields[i].value_len;
+
+ if (entry->flags & TREE_NODE_EXPANDED) {
+ /* Text will be seen, get its width */
+ nsfont.font_width(&plot_style_odd.text,
+ e->fields[i - 1].value.data,
+ e->fields[i - 1].value.len,
+ &(e->fields[i - 1].value.width));
+ } else {
+ /* Invalidate the width, since it's not needed yet */
+ e->fields[i - 1].value.width = 0;
+ }
+ }
+
+ return NSERROR_OK;
+}
+
+
+/* Exported interface, documented in treeview.h */
+nserror treeview_create_node_entry(struct treeview *tree,
+ struct treeview_node **entry,
+ struct treeview_node *relation,
+ enum treeview_relationship rel,
+ const struct treeview_field_data fields[],
+ void *data)
+{
+ bool match;
+ struct treeview_node_entry *e;
+ struct treeview_node *n;
+ int i;
+
+ assert(data != NULL);
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+
+ if (relation == NULL) {
+ relation = tree->root;
+ rel = TREE_REL_FIRST_CHILD;
+ }
+
+ e = malloc(sizeof(struct treeview_node_entry) +
+ (tree->n_fields - 1) * sizeof(struct treeview_field));
+ if (e == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+
+ n = (struct treeview_node *) e;
+
+ n->flags = TREE_NODE_NONE;
+ n->type = TREE_NODE_ENTRY;
+
+ n->height = tree_g.line_height;
+
+ 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);
+ n->text.value.data = fields[0].value;
+ n->text.value.len = fields[0].value_len;
+ n->text.value.width = 0;
+
+ n->parent = NULL;
+ n->sibling_next = NULL;
+ n->sibling_prev = NULL;
+ n->children = NULL;
+
+ n->client_data = data;
+
+ 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);
+
+ e->fields[i - 1].value.data = fields[i].value;
+ e->fields[i - 1].value.len = fields[i].value_len;
+ e->fields[i - 1].value.width = 0;
+ }
+
+ treeview_insert_node(n, relation, rel);
+
+ *entry = n;
+
+ /* Inform front end of change in dimensions */
+ tree->cw_t->update_size(tree->cw_h, -1, tree->root->height);
+
+ return NSERROR_OK;
+}
+
+
+/* Exported interface, documented in treeview.h */
+nserror treeview_delete_node(struct treeview *tree, struct treeview_node *n)
+{
+ struct treeview_node_msg msg;
+ msg.msg = TREE_MSG_NODE_DELETE;
+ struct treeview_node *p;
+
+ /* Destroy children first */
+ while (n->children != NULL) {
+ treeview_delete_node(tree, n->children);
+ }
+
+ /* Unlink node from tree */
+ if (n->parent != NULL && n->parent->children == n) {
+ /* Node is a first child */
+ n->parent->children = n->sibling_next;
+
+ } else if (n->sibling_prev != NULL) {
+ /* Node is not first child */
+ n->sibling_prev->sibling_next = n->sibling_next;
+ }
+
+ if (n->sibling_next != NULL) {
+ /* Always need to do this */
+ n->sibling_next->sibling_prev = n->sibling_prev;
+ }
+
+ /* Reduce ancestor heights */
+ p = n->parent;
+ while (p != NULL && p->flags & TREE_NODE_EXPANDED) {
+ p->height -= n->height;
+ p = p->parent;
+ }
+
+ /* Handle any special treatment */
+ switch (n->type) {
+ case TREE_NODE_ENTRY:
+ tree->callbacks->entry(msg, n->client_data);
+ break;
+ case TREE_NODE_FOLDER:
+ tree->callbacks->folder(msg, n->client_data);
+ break;
+ case TREE_NODE_ROOT:
+ break;
+ default:
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ /* Inform front end of change in dimensions */
+ tree->cw_t->update_size(tree->cw_h, -1, tree->root->height);
+
+ /* Free the node */
+ free(n);
+
+ return NSERROR_OK;
+}
+
+
+/* Exported interface, documented in treeview.h */
+nserror treeview_create(struct treeview **tree,
+ const struct treeview_callback_table *callbacks,
+ int n_fields, struct treeview_field_desc fields[],
+ const struct core_window_callback_table *cw_t,
+ struct core_window *cw)
+{
+ nserror error;
+ int i;
+
+ assert(cw_t != NULL);
+ assert(cw != NULL);
+ assert(callbacks != NULL);
+
+ assert(fields != NULL);
+ assert(fields[0].flags & TREE_FLAG_DEFAULT);
+ assert(fields[n_fields - 1].flags & TREE_FLAG_DEFAULT);
+ assert(n_fields >= 2);
+
+ *tree = malloc(sizeof(struct treeview));
+ if (*tree == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ (*tree)->fields = malloc(sizeof(struct treeview_field) * n_fields);
+ if ((*tree)->fields == NULL) {
+ free(tree);
+ return NSERROR_NOMEM;
+ }
+
+ error = treeview_create_node_root(&((*tree)->root));
+ if (error != NSERROR_OK) {
+ free((*tree)->fields);
+ free(*tree);
+ return error;
+ }
+
+ (*tree)->field_width = 0;
+ for (i = 0; i < n_fields; i++) {
+ struct treeview_field *f = &((*tree)->fields[i]);
+
+ f->flags = fields[i].flags;
+ f->field = lwc_string_ref(fields[i].field);
+ f->value.data = lwc_string_data(fields[i].field);
+ f->value.len = lwc_string_length(fields[i].field);
+
+ nsfont.font_width(&plot_style_odd.text, f->value.data,
+ f->value.len, &(f->value.width));
+
+ if (f->flags & TREE_FLAG_SHOW_NAME)
+ if ((*tree)->field_width < f->value.width)
+ (*tree)->field_width = f->value.width;
+ }
+
+ (*tree)->field_width += tree_g.step_width;
+
+ (*tree)->callbacks = callbacks;
+ (*tree)->n_fields = n_fields - 1;
+
+ (*tree)->drag.type = TV_DRAG_NONE;
+ (*tree)->drag.start_node = NULL;
+ (*tree)->drag.start.x = 0;
+ (*tree)->drag.start.y = 0;
+ (*tree)->drag.start.node_y = 0;
+ (*tree)->drag.start.node_h = 0;
+ (*tree)->drag.prev.x = 0;
+ (*tree)->drag.prev.y = 0;
+ (*tree)->drag.prev.node_y = 0;
+ (*tree)->drag.prev.node_h = 0;
+
+ (*tree)->cw_t = cw_t;
+ (*tree)->cw_h = cw;
+
+ return NSERROR_OK;
+}
+
+
+/* Exported interface, documented in treeview.h */
+nserror treeview_destroy(struct treeview *tree)
+{
+ int f;
+
+ assert(tree != NULL);
+
+ /* Destroy nodes */
+ treeview_delete_node(tree, tree->root);
+
+ /* Destroy feilds */
+ for (f = 0; f <= tree->n_fields; f++) {
+ lwc_string_unref(tree->fields[f].field);
+ }
+ free(tree->fields);
+
+ /* Free treeview */
+ free(tree);
+
+ return NSERROR_OK;
+}
+
+
+/* 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)
+ * \param full Iff true, visit children of collapsed nodes
+ * \param callback Function to call on each node
+ * \param ctx Context to pass to callback
+ * \return true iff callback caused premature abort
+ */
+static bool treeview_walk_internal(struct treeview_node *root, bool full,
+ bool (*callback)(struct treeview_node *node, void *ctx),
+ void *ctx)
+{
+ struct treeview_node *node, *next;
+
+ node = root;
+
+ while (node != NULL) {
+ next = (full || (node->flags & TREE_NODE_EXPANDED)) ?
+ node->children : NULL;
+
+ 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->sibling_next == NULL) {
+ node = node->parent;
+ }
+
+ if (node == root)
+ break;
+
+ node = node->sibling_next;
+ }
+
+ assert(node != NULL);
+ assert(node != root);
+
+ if (callback(node, ctx)) {
+ /* callback caused early termination */
+ return true;
+ }
+
+ }
+ return false;
+}
+
+
+/* Exported interface, documented in treeview.h */
+nserror treeview_node_expand(struct treeview *tree,
+ struct treeview_node *node)
+{
+ struct treeview_node *child;
+ struct treeview_node_entry *e;
+ int additional_height = 0;
+ int i;
+
+ assert(tree != NULL);
+ assert(node != NULL);
+
+ if (node->flags & TREE_NODE_EXPANDED) {
+ /* What madness is this? */
+ LOG(("Tried to expand an expanded node."));
+ return NSERROR_OK;
+ }
+
+ switch (node->type) {
+ case TREE_NODE_FOLDER:
+ child = node->children;
+ if (child == NULL) {
+ /* Can't expand an empty node */
+ return NSERROR_OK;
+ }
+
+ do {
+ assert((child->flags & TREE_NODE_EXPANDED) == false);
+ if (child->text.value.width == 0) {
+ nsfont.font_width(&plot_style_odd.text,
+ child->text.value.data,
+ child->text.value.len,
+ &(child->text.value.width));
+ }
+
+ additional_height += child->height;
+
+ child = child->sibling_next;
+ } while (child != NULL);
+
+ break;
+
+ case TREE_NODE_ENTRY:
+ assert(node->children == NULL);
+
+ e = (struct treeview_node_entry *)node;
+
+ for (i = 0; i < tree->n_fields - 1; i++) {
+
+ if (e->fields[i].value.width == 0) {
+ nsfont.font_width(&plot_style_odd.text,
+ e->fields[i].value.data,
+ e->fields[i].value.len,
+ &(e->fields[i].value.width));
+ }
+
+ /* Add height for field */
+ additional_height += tree_g.line_height;
+ }
+
+ break;
+
+ case TREE_NODE_ROOT:
+ assert(node->type != TREE_NODE_ROOT);
+ break;
+ }
+
+ /* Update the node */
+ node->flags |= TREE_NODE_EXPANDED;
+
+ /* And parent's heights */
+ do {
+ node->height += additional_height;
+ node = node->parent;
+ } while (node->parent != NULL);
+
+ node->height += additional_height;
+
+ /* Inform front end of change in dimensions */
+ tree->cw_t->update_size(tree->cw_h, -1, tree->root->height);
+
+ return NSERROR_OK;
+}
+
+
+/** Treewalk node callback for handling node contraction. */
+static bool treeview_node_contract_cb(struct treeview_node *node, void *ctx)
+{
+ int height_reduction;
+
+ assert(node != NULL);
+ assert(node->type != TREE_NODE_ROOT);
+
+ if ((node->flags & TREE_NODE_EXPANDED) == false) {
+ /* Nothing to do. */
+ return false;
+ }
+
+ node->flags ^= TREE_NODE_EXPANDED;
+ height_reduction = node->height - tree_g.line_height;
+
+ assert(height_reduction >= 0);
+
+ do {
+ node->height -= height_reduction;
+ node = node->parent;
+ } while (node != NULL);
+
+ return false; /* Don't want to abort tree walk */
+}
+/* Exported interface, documented in treeview.h */
+nserror treeview_node_contract(struct treeview *tree,
+ struct treeview_node *node)
+{
+ assert(node != NULL);
+
+ if ((node->flags & TREE_NODE_EXPANDED) == false) {
+ /* What madness is this? */
+ LOG(("Tried to contract a contracted node."));
+ return NSERROR_OK;
+ }
+
+ /* Contract children. */
+ treeview_walk_internal(node, false, treeview_node_contract_cb, NULL);
+
+ /* Contract node */
+ treeview_node_contract_cb(node, NULL);
+
+ /* Inform front end of change in dimensions */
+ tree->cw_t->update_size(tree->cw_h, -1, tree->root->height);
+
+ return NSERROR_OK;
+}
+
+
+/* Exported interface, documented in treeview.h */
+void treeview_redraw(struct treeview *tree, int x, int y, struct rect *clip,
+ const struct redraw_context *ctx)
+{
+ struct redraw_context new_ctx = *ctx;
+ struct 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;
+ uint32_t count = 0;
+ int render_y = y;
+ int inset;
+ int x0, y0, y1;
+ 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;
+ plot_font_style_t *infotext_style;
+ int height;
+ int sel_min, sel_max;
+ bool invert_selection;
+
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+ assert(tree->root->flags & TREE_NODE_EXPANDED);
+
+ 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;
+ }
+
+ /* 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(&r);
+
+ /* Draw the tree */
+ node = root = tree->root;
+
+ /* Setup common content redraw data */
+ data.width = 17;
+ data.height = 17;
+ data.scale = 1;
+ data.repeat_x = false;
+ data.repeat_y = false;
+
+ while (node != NULL) {
+ int i;
+ next = (node->flags & TREE_NODE_EXPANDED) ?
+ node->children : NULL;
+
+ 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->sibling_next == NULL) {
+ node = node->parent;
+ }
+
+ if (node == root)
+ break;
+
+ node = node->sibling_next;
+ }
+
+ assert(node != NULL);
+ assert(node != root);
+ assert(node->type == TREE_NODE_FOLDER ||
+ node->type == TREE_NODE_ENTRY);
+
+ count++;
+ inset = node->inset;
+ height = (node->type == TREE_NODE_ENTRY) ? node->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 & TREE_NODE_SELECTED && !invert_selection) ||
+ (!(node->flags & TREE_NODE_SELECTED) &&
+ invert_selection)) {
+ bg_style = &style->sbg;
+ text_style = &style->stext;
+ infotext_style = &style->sitext;
+ } else {
+ bg_style = &style->bg;
+ text_style = &style->text;
+ infotext_style = &style->itext;
+ }
+
+ /* Render background */
+ y0 = render_y;
+ y1 = render_y + height;
+ new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, bg_style);
+
+ /* Render toggle */
+ if (node->flags & TREE_NODE_EXPANDED) {
+ new_ctx.plot->text(inset, render_y + baseline,
+ treeview_furn[TREE_FURN_CONTRACT].data,
+ treeview_furn[TREE_FURN_CONTRACT].len,
+ text_style);
+ } else {
+ new_ctx.plot->text(inset, render_y + baseline,
+ treeview_furn[TREE_FURN_EXPAND].data,
+ treeview_furn[TREE_FURN_EXPAND].len,
+ text_style);
+ }
+
+ /* Render icon */
+ if (node->type == TREE_NODE_ENTRY)
+ res = TREE_RES_CONTENT;
+ else if (node->type == TREE_NODE_FOLDER)
+ 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, &new_ctx);
+ }
+
+ /* Render text */
+ x0 = inset + tree_g.step_width + tree_g.icon_step;
+ new_ctx.plot->text(x0, render_y + baseline,
+ node->text.value.data, node->text.value.len,
+ text_style);
+
+ /* 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 & TREE_NODE_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;
+
+ new_ctx.plot->text(x0 + max_width -
+ ef->value.width -
+ tree_g.step_width,
+ render_y + baseline,
+ ef->value.data,
+ ef->value.len,
+ infotext_style);
+
+ new_ctx.plot->text(x0 + max_width,
+ render_y + baseline,
+ entry->fields[i].value.data,
+ entry->fields[i].value.len,
+ infotext_style);
+ } else {
+ new_ctx.plot->text(x0, render_y + baseline,
+ entry->fields[i].value.data,
+ entry->fields[i].value.len,
+ infotext_style);
+
+ }
+
+ /* Rendered the expanded entry field */
+ render_y += tree_g.line_height;
+ }
+
+ /* Finshed rendering expanded entry */
+
+ if (render_y > r.y1) {
+ /* Passed the bottom of what's in the clip region.
+ * Done. */
+ break;
+ }
+ }
+
+ if (render_y < r.y1) {
+ /* Fill the blank area at the bottom */
+ y0 = render_y;
+ new_ctx.plot->rectangle(r.x0, y0, r.x1, r.y1,
+ &plot_style_even.bg);
+
+ }
+
+ /* Rendering complete */
+ if (ctx->plot->option_knockout)
+ knockout_plot_end();
+}
+
+struct treeview_selection_walk_data {
+ enum {
+ TREEVIEW_WALK_HAS_SELECTION,
+ TREEVIEW_WALK_CLEAR_SELECTION,
+ TREEVIEW_WALK_SELECT_ALL,
+ TREEVIEW_WALK_COMMIT_SELECT_DRAG,
+ TREEVIEW_WALK_DELETE_SELECTION
+ } purpose;
+ union {
+ bool has_selection;
+ struct {
+ bool required;
+ struct rect *rect;
+ } redraw;
+ struct {
+ int sel_min;
+ int sel_max;
+ } drag;
+ } data;
+ int current_y;
+ struct treeview *tree;
+};
+/** Treewalk node callback for handling selection related actions. */
+static bool treeview_node_selection_walk_cb(struct treeview_node *node,
+ void *ctx)
+{
+ struct treeview_selection_walk_data *sw = ctx;
+ int height;
+ bool changed = false;
+
+ height = (node->type == TREE_NODE_ENTRY) ? node->height :
+ tree_g.line_height;
+ sw->current_y += height;
+
+ switch (sw->purpose) {
+ case TREEVIEW_WALK_HAS_SELECTION:
+ if (node->flags & TREE_NODE_SELECTED) {
+ sw->data.has_selection = true;
+ return true; /* Can abort tree walk */
+ }
+ break;
+
+ case TREEVIEW_WALK_DELETE_SELECTION:
+ if (node->flags & TREE_NODE_SELECTED) {
+ treeview_delete_node(sw->tree, node);
+ changed = true;
+ }
+ break;
+
+ case TREEVIEW_WALK_CLEAR_SELECTION:
+ if (node->flags & TREE_NODE_SELECTED) {
+ node->flags ^= TREE_NODE_SELECTED;
+ changed = true;
+ }
+ break;
+
+ case TREEVIEW_WALK_SELECT_ALL:
+ if (!(node->flags & TREE_NODE_SELECTED)) {
+ node->flags ^= TREE_NODE_SELECTED;
+ changed = true;
+ }
+ break;
+
+ case TREEVIEW_WALK_COMMIT_SELECT_DRAG:
+ if (sw->current_y > sw->data.drag.sel_min &&
+ sw->current_y - height <
+ sw->data.drag.sel_max) {
+ node->flags ^= TREE_NODE_SELECTED;
+ }
+ return false; /* Don't stop walk */
+ }
+
+ if (changed) {
+ if (sw->data.redraw.required == false) {
+ sw->data.redraw.required = true;
+ sw->data.redraw.rect->y0 = sw->current_y - height;
+ }
+
+ if (sw->current_y > sw->data.redraw.rect->y1) {
+ sw->data.redraw.rect->y1 = sw->current_y;
+ }
+ }
+
+ return false; /* Don't stop walk */
+}
+
+
+/* Exported interface, documented in treeview.h */
+bool treeview_has_selection(struct treeview *tree)
+{
+ struct treeview_selection_walk_data sw;
+
+ sw.purpose = TREEVIEW_WALK_HAS_SELECTION;
+ sw.data.has_selection = false;
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_selection_walk_cb, &sw);
+
+ return sw.data.has_selection;
+}
+
+
+/* Exported interface, documented in treeview.h */
+bool treeview_clear_selection(struct treeview *tree, struct rect *rect)
+{
+ struct treeview_selection_walk_data sw;
+
+ rect->x0 = 0;
+ rect->y0 = 0;
+ rect->x1 = REDRAW_MAX;
+ rect->y1 = 0;
+
+ sw.purpose = TREEVIEW_WALK_CLEAR_SELECTION;
+ sw.data.redraw.required = false;
+ sw.data.redraw.rect = rect;
+ sw.current_y = 0;
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_selection_walk_cb, &sw);
+
+ return sw.data.redraw.required;
+}
+
+
+/* Exported interface, documented in treeview.h */
+bool treeview_select_all(struct treeview *tree, struct rect *rect)
+{
+ struct treeview_selection_walk_data sw;
+
+ rect->x0 = 0;
+ rect->y0 = 0;
+ rect->x1 = REDRAW_MAX;
+ rect->y1 = 0;
+
+ sw.purpose = TREEVIEW_WALK_SELECT_ALL;
+ sw.data.redraw.required = false;
+ sw.data.redraw.rect = rect;
+ sw.current_y = 0;
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_selection_walk_cb, &sw);
+
+ return sw.data.redraw.required;
+}
+
+
+/**
+ * Commit a current selection drag, modifying the node's selection state.
+ */
+static void treeview_commit_selection_drag(struct treeview *tree)
+{
+ struct treeview_selection_walk_data sw;
+
+ sw.purpose = TREEVIEW_WALK_COMMIT_SELECT_DRAG;
+ sw.current_y = 0;
+
+ if (tree->drag.start.y > tree->drag.prev.y) {
+ sw.data.drag.sel_min = tree->drag.prev.y;
+ sw.data.drag.sel_max = tree->drag.start.y;
+ } else {
+ sw.data.drag.sel_min = tree->drag.start.y;
+ sw.data.drag.sel_max = tree->drag.prev.y;
+ }
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_selection_walk_cb, &sw);
+}
+
+
+/**
+ * Commit a current selection drag, modifying the node's selection state.
+ */
+static bool treeview_delete_selection(struct treeview *tree, struct rect *rect)
+{
+ struct treeview_selection_walk_data sw;
+
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+
+ rect->x0 = 0;
+ rect->y0 = 0;
+ rect->x1 = REDRAW_MAX;
+ rect->y1 = tree->root->height;
+
+ sw.purpose = TREEVIEW_WALK_DELETE_SELECTION;
+ sw.data.redraw.required = false;
+ sw.data.redraw.rect = rect;
+ sw.current_y = 0;
+ sw.tree = tree;
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_selection_walk_cb, &sw);
+
+ return sw.data.redraw.required;
+}
+
+
+/* Exported interface, documented in treeview.h */
+bool treeview_keypress(struct treeview *tree, uint32_t key)
+{
+ struct rect r; /**< Redraw rectangle */
+ bool redraw = false;
+
+ assert(tree != NULL);
+
+ switch (key) {
+ case KEY_SELECT_ALL:
+ redraw = treeview_select_all(tree, &r);
+ break;
+ case KEY_COPY_SELECTION:
+ /* TODO: Copy selection as text */
+ break;
+ case KEY_DELETE_LEFT:
+ case KEY_DELETE_RIGHT:
+ redraw = treeview_delete_selection(tree, &r);
+ break;
+ case KEY_CR:
+ case KEY_NL:
+ /* TODO: Launch selection */
+ break;
+ case KEY_ESCAPE:
+ case KEY_CLEAR_SELECTION:
+ redraw = treeview_clear_selection(tree, &r);
+ break;
+ /* TODO: Trivial keyboard navigation */
+ case KEY_LEFT:
+ break;
+ case KEY_RIGHT:
+ break;
+ case KEY_UP:
+ break;
+ case KEY_DOWN:
+ break;
+ default:
+ return false;
+ }
+
+ if (redraw) {
+ tree->cw_t->redraw_request(tree->cw_h, r);
+ }
+
+ return true;
+}
+
+struct treeview_mouse_action {
+ struct treeview *tree;
+ browser_mouse_state mouse;
+ int x;
+ int y;
+ int current_y; /* Y coordinate value of top of current node */
+};
+/** Treewalk node callback for handling mouse action. */
+static bool treeview_node_mouse_action_cb(struct treeview_node *node, void *ctx)
+{
+ struct treeview_mouse_action *ma = ctx;
+ struct rect r;
+ bool redraw = false;
+ bool click;
+ int height;
+ enum {
+ TV_NODE_ACTION_NONE = 0,
+ TV_NODE_ACTION_SELECTION = (1 << 0)
+ } action = TV_NODE_ACTION_NONE;
+ enum treeview_node_section section = TV_NODE_SECTION_NONE;
+ nserror err;
+
+ r.x0 = 0;
+ r.x1 = REDRAW_MAX;
+
+ height = (node->type == TREE_NODE_ENTRY) ? node->height :
+ tree_g.line_height;
+
+ /* Skip line if we've not reached mouse y */
+ if (ma->y > ma->current_y + height) {
+ ma->current_y += height;
+ return false; /* Don't want to abort tree walk */
+ }
+
+ /* Find where the mouse is */
+ if (ma->y <= ma->current_y + tree_g.line_height) {
+ if (ma->x >= node->inset - 1 &&
+ ma->x < node->inset + tree_g.step_width) {
+ /* Over expansion toggle */
+ section = TV_NODE_SECTION_TOGGLE;
+
+ } else if (ma->x >= node->inset + tree_g.step_width &&
+ ma->x < node->inset + tree_g.step_width +
+ tree_g.icon_step + node->text.value.width) {
+ /* On node */
+ section = TV_NODE_SECTION_ON_NODE;
+ }
+ } else if (node->type == TREE_NODE_ENTRY &&
+ height > tree_g.line_height) {
+ /* Expanded entries */
+ int x = node->inset + tree_g.step_width + tree_g.icon_step;
+ int y = ma->current_y + tree_g.line_height;
+ int i;
+ struct treeview_node_entry *entry =
+ (struct treeview_node_entry *)node;
+ for (i = 0; i < ma->tree->n_fields - 1; i++) {
+ struct treeview_field *ef = &(ma->tree->fields[i + 1]);
+
+ if (ma->y > y + tree_g.line_height) {
+ y += tree_g.line_height;
+ continue;
+ }
+
+ if (ef->flags & TREE_FLAG_SHOW_NAME) {
+ int max_width = ma->tree->field_width;
+
+ if (ma->x >= x + max_width - ef->value.width -
+ tree_g.step_width &&
+ ma->x < x + max_width -
+ tree_g.step_width) {
+ /* On a field name */
+ section = TV_NODE_SECTION_ON_NODE;
+
+ } else if (ma->x >= x + max_width &&
+ ma->x < x + max_width +
+ entry->fields[i].value.width) {
+ /* On a field value */
+ section = TV_NODE_SECTION_ON_NODE;
+ }
+ } else {
+ if (ma->x >= x && ma->x < x +
+ entry->fields[i].value.width) {
+ /* On a field value */
+ section = TV_NODE_SECTION_ON_NODE;
+ }
+ }
+
+ break;
+ }
+ }
+
+ /* Record what position / section a drag started on */
+ if (ma->mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2) &&
+ ma->tree->drag.type == TV_DRAG_NONE) {
+ ma->tree->drag.selected = node->flags & TREE_NODE_SELECTED;
+ ma->tree->drag.start_node = node;
+ ma->tree->drag.section = section;
+ ma->tree->drag.start.x = ma->x;
+ ma->tree->drag.start.y = ma->y;
+ ma->tree->drag.start.node_y = ma->current_y;
+ ma->tree->drag.start.node_h = height;
+
+ ma->tree->drag.prev.x = ma->x;
+ ma->tree->drag.prev.y = ma->y;
+ ma->tree->drag.prev.node_y = ma->current_y;
+ ma->tree->drag.prev.node_h = height;
+ }
+
+ /* Handle drag start */
+ if (ma->tree->drag.type == TV_DRAG_NONE) {
+ if (ma->mouse & BROWSER_MOUSE_DRAG_1 &&
+ ma->tree->drag.selected == false &&
+ ma->tree->drag.section ==
+ TV_NODE_SECTION_NONE) {
+ ma->tree->drag.type = TV_DRAG_SELECTION;
+ } else if (ma->mouse & BROWSER_MOUSE_DRAG_2) {
+ ma->tree->drag.type = TV_DRAG_SELECTION;
+ }
+
+ if (ma->tree->drag.start_node != NULL &&
+ ma->tree->drag.type == TV_DRAG_SELECTION) {
+ ma->tree->drag.start_node->flags ^= TREE_NODE_SELECTED;
+ }
+ }
+
+ /* Handle selection drags */
+ if (ma->tree->drag.type == 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;
+
+ r.y0 = (ma->current_y < ma->tree->drag.prev.node_y) ?
+ ma->current_y : ma->tree->drag.prev.node_y;
+ r.y1 = (curr_y1 > prev_y1) ? curr_y1 : prev_y1;
+
+ redraw = true;
+
+ ma->tree->drag.prev.x = ma->x;
+ ma->tree->drag.prev.y = ma->y;
+ ma->tree->drag.prev.node_y = ma->current_y;
+ ma->tree->drag.prev.node_h = height;
+ }
+
+ click = ma->mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2);
+
+ if (((node->type == TREE_NODE_FOLDER) &&
+ (ma->mouse & BROWSER_MOUSE_DOUBLE_CLICK) && click) ||
+ (section == TV_NODE_SECTION_TOGGLE && click)) {
+ /* Clear any existing selection */
+ redraw |= treeview_clear_selection(ma->tree, &r);
+
+ /* Toggle node expansion */
+ if (node->flags & TREE_NODE_EXPANDED) {
+ err = treeview_node_contract(ma->tree, node);
+ } else {
+ err = treeview_node_expand(ma->tree, node);
+ }
+
+ /* Set up redraw */
+ if (!redraw || r.y0 > ma->current_y)
+ r.y0 = ma->current_y;
+ r.y1 = REDRAW_MAX;
+ redraw = true;
+
+ } else if ((node->type == TREE_NODE_ENTRY) &&
+ (ma->mouse & BROWSER_MOUSE_DOUBLE_CLICK) && click) {
+ struct treeview_node_msg msg;
+ msg.msg = TREE_MSG_NODE_LAUNCH;
+ msg.data.node_launch.mouse = ma->mouse;
+
+ /* Clear any existing selection */
+ redraw |= treeview_clear_selection(ma->tree, &r);
+
+ /* Tell client an entry was launched */
+ ma->tree->callbacks->entry(msg, node->client_data);
+
+ } else if (ma->mouse & BROWSER_MOUSE_PRESS_1 &&
+ !(node->flags & TREE_NODE_SELECTED) &&
+ section != TV_NODE_SECTION_TOGGLE) {
+ /* Clear any existing selection */
+ redraw |= treeview_clear_selection(ma->tree, &r);
+
+ /* Select node */
+ action |= TV_NODE_ACTION_SELECTION;
+
+ } else if (ma->mouse & BROWSER_MOUSE_PRESS_2 ||
+ (ma->mouse & BROWSER_MOUSE_PRESS_1 &&
+ ma->mouse & BROWSER_MOUSE_MOD_2)) {
+ /* Toggle selection of node */
+ action |= TV_NODE_ACTION_SELECTION;
+ }
+
+ if (action & TV_NODE_ACTION_SELECTION) {
+ /* Handle change in selection */
+ node->flags ^= TREE_NODE_SELECTED;
+
+ /* Redraw */
+ if (!redraw) {
+ r.y0 = ma->current_y;
+ r.y1 = ma->current_y + height;
+ redraw = true;
+ } else {
+ if (r.y0 > ma->current_y)
+ r.y0 = ma->current_y;
+ if (r.y1 < ma->current_y + height)
+ r.y1 = ma->current_y + height;
+ }
+ }
+
+ if (redraw) {
+ ma->tree->cw_t->redraw_request(ma->tree->cw_h, r);
+ }
+
+ return true; /* Reached line with click; stop walking tree */
+}
+/* Exported interface, documented in treeview.h */
+void treeview_mouse_action(struct treeview *tree,
+ browser_mouse_state mouse, int x, int y)
+{
+ bool redraw = false;
+
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+
+ if (mouse == BROWSER_MOUSE_HOVER &&
+ tree->drag.type == TV_DRAG_SELECTION) {
+ treeview_commit_selection_drag(tree);
+ tree->drag.type = TV_DRAG_NONE;
+ tree->drag.start_node = NULL;
+ return;
+ }
+
+ if (y > tree->root->height) {
+ /* Below tree */
+ struct rect r;
+
+ r.x0 = 0;
+ r.x1 = REDRAW_MAX;
+
+ /* Record what position / section a drag started on */
+ if (mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2) &&
+ tree->drag.type == TV_DRAG_NONE) {
+ tree->drag.selected = false;
+ tree->drag.start_node = NULL;
+ tree->drag.section = TV_NODE_SECTION_NONE;
+ tree->drag.start.x = x;
+ tree->drag.start.y = y;
+ tree->drag.start.node_y = tree->root->height;
+ tree->drag.start.node_h = 0;
+
+ tree->drag.prev.x = x;
+ tree->drag.prev.y = y;
+ tree->drag.prev.node_y = tree->root->height;
+ tree->drag.prev.node_h = 0;
+ }
+
+ /* Handle drag start */
+ if (tree->drag.type == TV_DRAG_NONE) {
+ if (mouse & BROWSER_MOUSE_DRAG_1 &&
+ tree->drag.selected == false &&
+ tree->drag.section ==
+ TV_NODE_SECTION_NONE) {
+ tree->drag.type = TV_DRAG_SELECTION;
+ } else if (mouse & BROWSER_MOUSE_DRAG_2) {
+ tree->drag.type = TV_DRAG_SELECTION;
+ }
+
+ if (tree->drag.start_node != NULL &&
+ tree->drag.type == TV_DRAG_SELECTION) {
+ tree->drag.start_node->flags ^=
+ TREE_NODE_SELECTED;
+ }
+ }
+
+ /* Handle selection drags */
+ if (tree->drag.type == TV_DRAG_SELECTION) {
+ int curr_y1 = tree->root->height;
+ int prev_y1 = tree->drag.prev.node_y +
+ tree->drag.prev.node_h;
+
+ r.y0 = tree->drag.prev.node_y;
+ r.y1 = (curr_y1 > prev_y1) ? curr_y1 : prev_y1;
+
+ redraw = true;
+
+ tree->drag.prev.x = x;
+ tree->drag.prev.y = y;
+ tree->drag.prev.node_y = curr_y1;
+ tree->drag.prev.node_h = 0;
+ }
+
+ if (mouse & BROWSER_MOUSE_PRESS_1) {
+ /* Clear any existing selection */
+ redraw |= treeview_clear_selection(tree, &r);
+ }
+
+ if (redraw) {
+ tree->cw_t->redraw_request(tree->cw_h, r);
+ }
+
+ } else {
+ /* On tree */
+ struct treeview_mouse_action ma;
+
+ ma.tree = tree;
+ ma.mouse = mouse;
+ ma.x = x;
+ ma.y = y;
+ ma.current_y = 0;
+
+ treeview_walk_internal(tree->root, false,
+ treeview_node_mouse_action_cb, &ma);
+ }
+}
+
+
+
+/* Mix two colours according to the proportion given by p.
+ * Where 0 <= p <= 255
+ * p=0 gives result ==> c1
+ * p=255 gives result ==> c0
+ */
+#define mix_colour(c0, c1, p) \
+ ((((((c1 & 0xff00ff) * (255 - p)) + \
+ ((c0 & 0xff00ff) * ( p)) ) >> 8) & 0xff00ff) | \
+ (((((c1 & 0x00ff00) * (255 - p)) + \
+ ((c0 & 0x00ff00) * ( p)) ) >> 8) & 0x00ff00))
+
+
+/**
+ * Initialise the plot styles from CSS system colour values.
+ */
+static void treeview_init_plot_styles(int font_pt_size)
+{
+ /* Background colour */
+ plot_style_even.bg.stroke_type = PLOT_OP_TYPE_NONE;
+ plot_style_even.bg.stroke_width = 0;
+ plot_style_even.bg.stroke_colour = 0;
+ plot_style_even.bg.fill_type = PLOT_OP_TYPE_SOLID;
+ plot_style_even.bg.fill_colour = gui_system_colour_char("Window");
+
+ /* Text colour */
+ plot_style_even.text.family = PLOT_FONT_FAMILY_SANS_SERIF;
+ plot_style_even.text.size = font_pt_size * FONT_SIZE_SCALE;
+ plot_style_even.text.weight = 400;
+ plot_style_even.text.flags = FONTF_NONE;
+ plot_style_even.text.foreground = gui_system_colour_char("WindowText");
+ plot_style_even.text.background = gui_system_colour_char("Window");
+
+ /* Entry field text colour */
+ plot_style_even.itext = plot_style_even.text;
+ plot_style_even.itext.foreground = mix_colour(
+ plot_style_even.text.foreground,
+ plot_style_even.text.background, 255 * 10 / 16);
+
+ /* Selected background colour */
+ plot_style_even.sbg = plot_style_even.bg;
+ plot_style_even.sbg.fill_colour = gui_system_colour_char("Highlight");
+
+ /* Selected text colour */
+ plot_style_even.stext = plot_style_even.text;
+ plot_style_even.stext.foreground =
+ gui_system_colour_char("HighlightText");
+ plot_style_even.stext.background = gui_system_colour_char("Highlight");
+
+ /* Selected entry field text colour */
+ plot_style_even.sitext = plot_style_even.stext;
+ plot_style_even.sitext.foreground = mix_colour(
+ plot_style_even.stext.foreground,
+ plot_style_even.stext.background, 255 * 25 / 32);
+
+
+ /* Odd numbered node styles */
+ plot_style_odd.bg = plot_style_even.bg;
+ plot_style_odd.bg.fill_colour = mix_colour(
+ plot_style_even.bg.fill_colour,
+ plot_style_even.text.foreground, 255 * 15 / 16);
+ plot_style_odd.text = plot_style_even.text;
+ plot_style_odd.text.background = plot_style_odd.bg.fill_colour;
+ plot_style_odd.itext = plot_style_odd.text;
+ plot_style_odd.itext.foreground = mix_colour(
+ plot_style_odd.text.foreground,
+ plot_style_odd.text.background, 255 * 10 / 16);
+
+ plot_style_odd.sbg = plot_style_even.sbg;
+ plot_style_odd.stext = plot_style_even.stext;
+ plot_style_odd.sitext = plot_style_even.sitext;
+}
+
+
+/**
+ * Callback for hlcache.
+ */
+static nserror treeview_res_cb(hlcache_handle *handle,
+ const hlcache_event *event, void *pw)
+{
+ struct treeview_resource *r = pw;
+
+ switch (event->type) {
+ case CONTENT_MSG_READY:
+ case CONTENT_MSG_DONE:
+ r->ready = true;
+ r->height = content_get_height(handle);
+ break;
+
+ default:
+ break;
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Fetch content resources used by treeview.
+ */
+static void treeview_init_resources(void)
+{
+ int i;
+
+ for (i = 0; i < TREE_RES_LAST; i++) {
+ nsurl *url;
+ if (nsurl_create(treeview_res[i].url, &url) == NSERROR_OK) {
+ hlcache_handle_retrieve(url, 0, NULL, NULL,
+ treeview_res_cb,
+ &(treeview_res[i]), NULL,
+ CONTENT_IMAGE, &(treeview_res[i].c));
+ nsurl_unref(url);
+ }
+ }
+}
+
+
+/**
+ * Measures width of characters used to represent treeview furniture.
+ */
+static void treeview_init_furniture(void)
+{
+ int i;
+ tree_g.furniture_width = 0;
+
+ for (i = 0; i < TREE_FURN_LAST; i++) {
+ nsfont.font_width(&plot_style_odd.text,
+ treeview_furn[i].data,
+ treeview_furn[i].len,
+ &(treeview_furn[i].width));
+
+ if (treeview_furn[i].width > tree_g.furniture_width)
+ tree_g.furniture_width = treeview_furn[i].width;
+ }
+
+ tree_g.furniture_width += 5;
+}
+
+
+/* Exported interface, documented in treeview.h */
+nserror treeview_init(void)
+{
+ int font_px_size;
+ int font_pt_size = 11;
+
+ treeview_init_plot_styles(font_pt_size);
+ treeview_init_resources();
+ treeview_init_furniture();
+
+ font_px_size = (font_pt_size * FIXTOINT(nscss_screen_dpi) + 36) / 72;
+
+ tree_g.line_height = (font_px_size * 8 + 3) / 6;
+ tree_g.step_width = tree_g.furniture_width;
+ tree_g.window_padding = 6;
+ tree_g.icon_step = 23;
+
+ return NSERROR_OK;
+}
+
+
+/* Exported interface, documented in treeview.h */
+nserror treeview_fini(void)
+{
+ int i;
+
+ for (i = 0; i < TREE_RES_LAST; i++) {
+ hlcache_handle_release(treeview_res[i].c);
+ }
+
+ return NSERROR_OK;
+}
diff --git a/desktop/treeview.h b/desktop/treeview.h
new file mode 100644
index 0000000..9692d0a
--- /dev/null
+++ b/desktop/treeview.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2012 - 2013 Michael Drake <tlsa(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf,
http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <
http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Treeview handling (interface).
+ */
+
+#ifndef _NETSURF_DESKTOP_TREEVIEW_H_
+#define _NETSURF_DESKTOP_TREEVIEW_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "desktop/core_window.h"
+#include "desktop/textinput.h"
+#include "utils/types.h"
+
+struct treeview;
+struct treeview_node;
+
+enum treeview_relationship {
+ TREE_REL_FIRST_CHILD,
+ TREE_REL_NEXT_SIBLING
+}; /**< Relationship between nodes */
+
+enum treeview_msg {
+ TREE_MSG_NODE_DELETE, /**< Node to be deleted */
+ TREE_MSG_NODE_EDIT, /**< Node to be edited */
+ TREE_MSG_NODE_LAUNCH /**< Node to be launched */
+};
+struct treeview_node_msg {
+ enum treeview_msg msg; /**< The message type */
+ union {
+ struct {
+ lwc_string *feild; /* The field being edited */
+ const char *text; /* The proposed new value */
+ } node_edit; /* Client may call treeview_update_node_* */
+ struct {
+ browser_mouse_state mouse; /* Button / modifier used */
+ } node_launch;
+ } data; /**< The message data. */
+};
+
+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 */
+
+};
+struct treeview_field_desc {
+ lwc_string *field; /**< A treeview field name */
+ enum treeview_field_flags flags; /**< Flags for field */
+}; /**< Treeview field description */
+
+struct treeview_field_data {
+ lwc_string *field; /**< Field name */
+ const char *value; /**< Field value */
+ size_t value_len; /**< Field value length (bytes) */
+};
+
+
+struct treeview_callback_table {
+ nserror (*folder)(struct treeview_node_msg msg, void *data);
+ nserror (*entry)(struct treeview_node_msg msg, void *data);
+}; /**< Client callbacks for events concerning nodes */
+
+/**
+ * Prepare treeview module for treeview usage
+ *
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror treeview_init(void);
+
+/**
+ * Finalise the treeview module (all treeviews must have been destroyed first)
+ *
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror treeview_fini(void);
+
+/**
+ * Create a treeview
+ *
+ * \param tree Returns created treeview object
+ * \param callbacks Treeview client node event callbacks
+ * \param n_fields Number of treeview fields (see description)
+ * \param fields Array of treeview fields
+ * \param cw_t Callback table for core_window containing the treeview
+ * \param cw The core_window in which the treeview is shown
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * The fields array order is as follows (N = n_fields):
+ *
+ * fields[0] Main field for entries (shown when not expanded)
+ * fields[1]...fields[N-2] Additional fields for entries
+ * fields[N-1] Field for folder nodes
+ *
+ * So fields[0] and fields[N-1] have TREE_FLAG_DEFAULT set.
+ */
+nserror treeview_create(struct treeview **tree,
+ const struct treeview_callback_table *callbacks,
+ int n_fields, struct treeview_field_desc fields[],
+ const struct core_window_callback_table *cw_t,
+ struct core_window *cw);
+
+/**
+ * Destroy a treeview object
+ *
+ * \param tree Treeview object to destroy
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * Will emit folder and entry deletion msg callbacks for all nodes in treeview.
+ */
+nserror treeview_destroy(struct treeview *tree);
+
+/**
+ * Create a folder node in given treeview
+ *
+ * \param tree Treeview object in which to create folder
+ * \param folder Returns created folder node
+ * \param relation Existing node to insert as relation of, or NULL
+ * \param rel Folder's relationship to relation
+ * \param field Field data
+ * \param data Client data for node event callbacks
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * Field name must match name past in treeview_create fields[N-1].
+ *
+ * If relation is NULL, will insert as child of root node.
+ */
+nserror treeview_create_node_folder(struct treeview *tree,
+ struct treeview_node **folder,
+ struct treeview_node *relation,
+ enum treeview_relationship rel,
+ const struct treeview_field_data *field,
+ void *data);
+
+/**
+ * Create an entry node in given treeview
+ *
+ * \param tree Treeview object in which to create entry
+ * \param entry Returns created entry node
+ * \param relation Existing node to insert as relation of, or NULL
+ * \param rel Folder's relationship to relation
+ * \param fields Array of field data
+ * \param data Client data for node event callbacks
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * Fields array names must match names past in treeview_create fields[0...N-2].
+ *
+ * If relation is NULL, will insert as child of root node.
+ */
+nserror treeview_create_node_entry(struct treeview *tree,
+ struct treeview_node **entry,
+ struct treeview_node *relation,
+ enum treeview_relationship rel,
+ const struct treeview_field_data fields[],
+ void *data);
+
+/**
+ * Update an entry node in given treeview
+ *
+ * \param tree Treeview object in which to create entry
+ * \param entry Entry node to update
+ * \param fields Array of new field data
+ * \param data Client data for node event callbacks
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * Fields array names must match names past in treeview_create fields[0...N-2].
+ */
+nserror treeview_update_node_entry(struct treeview *tree,
+ struct treeview_node *entry,
+ const struct treeview_field_data fields[],
+ void *data);
+
+/**
+ * Delete a treeview node
+ *
+ * \param tree Treeview object to delete node from
+ * \param n Node to delete
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * Will emit folder or entry deletion msg callback.
+ */
+nserror treeview_delete_node(struct treeview *tree, struct treeview_node *n);
+
+/**
+ * Expand a treeview node
+ *
+ * \param tree Treeview object to expande node in
+ * \param node Node to expand
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror treeview_node_expand(struct treeview *tree,
+ struct treeview_node *node);
+
+/**
+ * Contract a treeview node
+ *
+ * \param tree Treeview object to contract node in
+ * \param node Node to contract
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror treeview_node_contract(struct treeview *tree,
+ struct treeview_node *node);
+
+/**
+ * Redraw a treeview object
+ *
+ * \param tree Treeview object to render
+ * \param x X coordinate to render treeview at
+ * \param x Y coordinate to render treeview at
+ * \param clip Current clip rectangle (wrt tree origin)
+ * \param ctx Current redraw context
+ */
+void treeview_redraw(struct treeview *tree, int x, int y, struct rect *clip,
+ const struct redraw_context *ctx);
+
+/**
+ * Key press handling for treeviews.
+ *
+ * \param tree The treeview which got the keypress
+ * \param key The ucs4 character codepoint
+ * \return true if the keypress is dealt with, false otherwise.
+ */
+bool treeview_keypress(struct treeview *tree, uint32_t key);
+
+/**
+ * Handles all kinds of mouse action
+ *
+ * \param tree Treeview object
+ * \param mouse The current mouse state
+ * \param x X coordinate
+ * \param y Y coordinate
+ */
+void treeview_mouse_action(struct treeview *tree,
+ browser_mouse_state mouse, int x, int y);
+
+/**
+ * Determine whether treeview has a selection
+ *
+ * \param tree Treeview object to delete node from
+ * \return true iff treeview has a selection
+ */
+bool treeview_has_selection(struct treeview *tree);
+
+/**
+ * Clear any selection in a treeview
+ *
+ * \param tree Treeview object to clear selection in
+ * \param rect Redraw rectangle (if redraw required)
+ * \return true iff redraw required
+ */
+bool treeview_clear_selection(struct treeview *tree, struct rect *rect);
+
+/**
+ * Select all in a treeview
+ *
+ * \param tree Treeview object to select all in
+ * \param rect Redraw rectangle (if redraw required)
+ * \return true iff redraw required
+ */
+bool treeview_select_all(struct treeview *tree, struct rect *rect);
+
+#endif
diff --git a/utils/types.h b/utils/types.h
index 617b493..e3f2e83 100644
--- a/utils/types.h
+++ b/utils/types.h
@@ -23,6 +23,8 @@
#ifndef _NETSURF_UTILS_TYPES_H_
#define _NETSURF_UTILS_TYPES_H_
+#include <stdbool.h>
+
struct plotter_table;
struct hlcache_handle;
--
NetSurf Browser