summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x!NetSurf/Resources/Sprites,ff9bin2996 -> 2140 bytes
-rw-r--r--!NetSurf/Resources/de/Messages22
-rw-r--r--!NetSurf/Resources/en/Messages28
-rw-r--r--!NetSurf/Resources/fr/Messages22
-rw-r--r--content/fetchcache.c5
-rw-r--r--desktop/options.c376
-rw-r--r--desktop/options.h6
-rw-r--r--desktop/tree.c1113
-rw-r--r--desktop/tree.h137
-rw-r--r--gtk/gtk_treeview.c96
-rw-r--r--image/gif.c53
-rw-r--r--image/gif.h1
-rw-r--r--image/gifread.c2
-rw-r--r--image/mng.c4
-rw-r--r--makefile11
-rw-r--r--riscos/401login.c13
-rw-r--r--riscos/gui.c123
-rw-r--r--riscos/gui.h24
-rw-r--r--riscos/help.c2
-rw-r--r--riscos/hotlist.c2567
-rw-r--r--riscos/menus.c307
-rw-r--r--riscos/options.h3
-rw-r--r--riscos/save.c7
-rw-r--r--riscos/treeview.c1183
-rw-r--r--riscos/treeview.h45
-rw-r--r--riscos/wimp.c12
-rw-r--r--riscos/wimp.h1
-rw-r--r--riscos/window.c44
28 files changed, 3573 insertions, 2634 deletions
diff --git a/!NetSurf/Resources/Sprites,ff9 b/!NetSurf/Resources/Sprites,ff9
index abe992290..be6f0bf3d 100755
--- a/!NetSurf/Resources/Sprites,ff9
+++ b/!NetSurf/Resources/Sprites,ff9
Binary files differ
diff --git a/!NetSurf/Resources/de/Messages b/!NetSurf/Resources/de/Messages
index 9b6de49d2..c26fd02f1 100644
--- a/!NetSurf/Resources/de/Messages
+++ b/!NetSurf/Resources/de/Messages
@@ -119,9 +119,9 @@ Folder:Verzeichnis
Links:Einträge
Link:Eintrag
SaveSelect:Sichern
-Launch:Öffnen
+Launch:Öffnen RETURN
Edit:Bearbeiten
-Delete:Löschen
+Delete:Löschen ^X
ResetUsage:Statistik zurücksetzen
# Hotlist sub-window titles
@@ -130,11 +130,17 @@ NewFolder:Verzeichnis anlegen
EditLink:Eintrag bearbeiten
EditFolder:Verzeichnis umbenennen
-# Hotlist window
-HotlistURL:URL: %s
-HotlistAdded:eingetragen am: %s
-HotlistLast:letzter Besuch: %s
-HotlistVisits:Besuche gesamt: %i
+# Default hotlist
+HotlistHomepage:NetSurf homepage
+HotlistTestBuild:NetSurf test builds
+
+# Tree URL text
+TreeAdded:eingetragen am: %s
+TreeLast:letzter Besuch: %s
+TreeVisits:Besuche gesamt: %i
+TreeUnknown:Unknown
+TreeImport:Imported URL
+TreeNewFolder:New directory
# Download window
Download:%s von %s %s/s noch %s
@@ -372,7 +378,7 @@ HelpHotlist5:Klicken mit AUSWAHL markiert diesen Eintrag.|MDoppelklicken öffnet
HelpHotlist6:Maustasten loslassen, um die Auswahl abzuschließen.
HelpHotlist7:Maustasten loslassen, um das Verschieben auszuführen.
-HelpHotToolbar0:Erzeugt neue Einträge oder Verzeichnisse.|MKlicken mit AUSWAHL erstellt ein neues Verzeichnis.|MKlicken mit SPEZIAL erstellt einen neuen Eintrag.
+HelpHotToolbar0:Erzeugt neue Einträge oder Verzeichnisse.|MKlicken mit AUSWAHL erstellt ein neues Verzeichnis.
HelpHotToolbar1:Löscht die markierten Einträge und Verzeichnisse.
HelpHotToolbar2:Expandiert Einträge.|MKlicken mit AUSWAHL expandiert alle / alle markierten Einträge.|MKlicken mit SPEZIAL faltet alle / alle markierten Einträge zusammen.|MBei expandierten Einträgen werden zusätzliche Informationen angezeigt.
HelpHotToolbar3:Öffnet Verzeichnisse.|MKlicken mit AUSWAHL öffnet alle / alle markierten Verzeichnisse.|MKlicken mit SPEZIAL schließt alle / alle markierten Verzeichnisse.
diff --git a/!NetSurf/Resources/en/Messages b/!NetSurf/Resources/en/Messages
index dd3bb0b80..6ff639879 100644
--- a/!NetSurf/Resources/en/Messages
+++ b/!NetSurf/Resources/en/Messages
@@ -116,25 +116,31 @@ Collapse:Collapse
All:All
Folders:Directories
Folder:Directory
-Links:Entries
-Link:Entry
+Links:Addresses
+Link:Address
SaveSelect:Save
-Launch:Launch
+Launch:Launch RETURN
Edit:Edit
-Delete:Delete
+Delete:Delete ^X
ResetUsage:Reset statistics
# Hotlist sub-window titles
NewLink:Create new address
NewFolder:Create new directory
-EditLink:Edit entry
+EditLink:Edit address
EditFolder:Rename directory
-# Hotlist window
-HotlistURL:URL: %s
-HotlistAdded:Added: %s
-HotlistLast:Last visited: %s
-HotlistVisits:Visits: %i
+# Default hotlist
+HotlistHomepage:NetSurf homepage
+HotlistTestBuild:NetSurf test builds
+
+# Tree URL text
+TreeAdded:Added: %s
+TreeLast:Last visited: %s
+TreeVisits:Visits: %i
+TreeUnknown:Unknown
+TreeImport:Imported URL
+TreeNewFolder:New directory
# Download window
Download:%s of %s %s/s %s remaining
@@ -372,7 +378,7 @@ HelpHotlist5:\Sselect this entry.|MDouble-click \s to launch this URL.
HelpHotlist6:Release the mouse buttons to complete your selection.
HelpHotlist7:Release the mouse buttons to move the selection.
-HelpHotToolbar0:\Tcreate button.|M\Screate a new directory.|M\Acreate a new entry.
+HelpHotToolbar0:\Tcreate button.|M\Screate a new directory.
HelpHotToolbar1:\Tdelete button.|M\Sdelete the current selection.
HelpHotToolbar2:\Texpand entries button.|M\Sexpand all entries or entries within the current selection.|M\Acollapse all entries or entries within the current selection.|MExpanded entries show additional details, such as a visit counter.
HelpHotToolbar3:\Topen directories button.|M\Sopen all directories or directories within the current selection.|M\Aclose all directories or directories within the current selection.
diff --git a/!NetSurf/Resources/fr/Messages b/!NetSurf/Resources/fr/Messages
index aca7bb4ca..e2a9af949 100644
--- a/!NetSurf/Resources/fr/Messages
+++ b/!NetSurf/Resources/fr/Messages
@@ -119,9 +119,9 @@ Folder:Dossier
Links:Adresses
Link:Adresses
SaveSelect:Sauver
-Launch:Lancer
+Launch:Lancer RETURN
Edit:Éditer
-Delete:Supprimer
+Delete:Supprimer ^X
ResetUsage:RAZ des statistiques
# Hotlist sub-window titles
@@ -130,11 +130,17 @@ NewFolder:Créer un nouveau dossier
EditLink:Éditer l'adresse
EditFolder:Éditer le dossier
-# Hotlist window
-HotlistURL:URL: %s
-HotlistAdded:Ajoutée: %s
-HotlistLast:Dernière visitée: %s
-HotlistVisits:Visites: %i
+# Default hotlist
+HotlistHomepage:NetSurf homepage
+HotlistTestBuild:NetSurf test builds
+
+# Tree URL text
+TreeAdded:Ajoutée: %s
+TreeLast:Dernière visitée: %s
+TreeVisits:Visites: %i
+TreeUnknown:Unknown
+TreeImport:Imported URL
+TreeNewFolder:New directory
# Download window
Download:%s de %s %s/s %s restants
@@ -372,7 +378,7 @@ HelpHotlist5:\Ssélectionner cette entrée.|MDouble-cliquer \s pour lancer cette U
HelpHotlist6:Lâcher les boutons de souris pour terminer votre sélection.
HelpHotlist7:Lâcher les boutons de souris pour déplacer votre sélection.
-HelpHotToolbar0:\Tle bouton Créer.|M\Scréer un nouveau répertoire.|M\Acréer une nouvelle entrée.
+HelpHotToolbar0:\Tle bouton Créer.|M\Scréer un nouveau répertoire.
HelpHotToolbar1:\Tle bouton Supprimer.|M\Ssupprimer la sélection courante.
HelpHotToolbar2:\Tle bouton de déploiement des entrées.|M\Sdéployer toutes les entrées ou seulement celle de la sélection courante.|M\ARegrouper toutes les entrées ou seulement celles de la sélection courante.|MLes entrées déployées affichent des infos supplémentaires, comme un compteur de visite.
HelpHotToolbar3:\Tle bouton d'ouverture de répertoires.|M\Souvrir tous les répertoires ou seulement ceux de la sélection courante.|M\Afermer tous les répertoires ou seulement ceux de la sélection courante.
diff --git a/content/fetchcache.c b/content/fetchcache.c
index 54fd7e1c8..192da6cd4 100644
--- a/content/fetchcache.c
+++ b/content/fetchcache.c
@@ -85,6 +85,11 @@ struct content * fetchcache(const char *url,
if ((c = content_get(url1)) != NULL) {
free(url1);
content_add_user(c, callback, p1, p2);
+ /* resize HTML content to the required size */
+ if (c->type == CONTENT_HTML) {
+ c->width = width;
+ c->height = height;
+ }
return c;
}
}
diff --git a/desktop/options.c b/desktop/options.c
index a777f6d12..3ad212a14 100644
--- a/desktop/options.c
+++ b/desktop/options.c
@@ -5,6 +5,7 @@
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
*/
/** \file
@@ -14,11 +15,16 @@
* value is "0" or "1".
*/
+#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
+#include "libxml/HTMLparser.h"
+#include "libxml/HTMLtree.h"
#include "netsurf/desktop/options.h"
+#include "netsurf/desktop/tree.h"
#include "netsurf/utils/log.h"
+#include "netsurf/utils/messages.h"
#include "netsurf/utils/utils.h"
#ifdef riscos
@@ -57,6 +63,9 @@ bool option_block_ads = false;
int option_minimum_gif_delay = 10;
/** Whether to send the referer HTTP header */
bool option_send_referer = true;
+/** Whether to animate images */
+bool option_animate_images = true;
+
EXTRA_OPTION_DEFINE
@@ -80,12 +89,21 @@ struct {
{ "block_advertisements", OPTION_BOOL, &option_block_ads },
{ "minimum_gif_delay", OPTION_INTEGER, &option_minimum_gif_delay },
{ "send_referer", OPTION_BOOL, &option_send_referer },
+ { "animate_images", OPTION_BOOL, &option_animate_images }, \
EXTRA_OPTION_TABLE
};
#define option_table_entries (sizeof option_table / sizeof option_table[0])
+static void options_load_hotlist_directory(xmlNode *ul, struct node *directory);
+static void options_load_hotlist_entry(xmlNode *li, struct node *directory);
+xmlNode *options_find_hotlist_element(xmlNode *node, const char *name);
+bool options_save_hotlist_directory(struct node *directory, xmlNode *node);
+bool options_save_hotlist_entry(struct node *entry, xmlNode *node);
+bool options_save_hotlist_entry_comment(xmlNode *node, const char *name, int value);
+
+
/**
* Read options from a file.
*
@@ -201,3 +219,361 @@ void options_write(const char *path)
fclose(fp);
}
+
+
+/**
+ * Loads a hotlist as a tree from a specified file.
+ *
+ * \param filename name of file to read
+ * \return the hotlist file represented as a tree, or NULL on failure
+ */
+struct tree *options_load_hotlist(const char *filename) {
+ xmlDoc *doc;
+ xmlNode *html, *body, *ul;
+ struct tree *tree;
+
+ doc = htmlParseFile(filename, "iso-8859-1");
+ if (!doc) {
+ warn_user("HotlistLoadError", messages_get("ParsingFail"));
+ return NULL;
+ }
+
+ html = options_find_hotlist_element((xmlNode *) doc, "html");
+ body = options_find_hotlist_element(html, "body");
+ ul = options_find_hotlist_element(body, "ul");
+ if (!ul) {
+ xmlFreeDoc(doc);
+ warn_user("HotlistLoadError",
+ "(<html>...<body>...<ul> not found.)");
+ return NULL;
+ }
+
+ tree = calloc(sizeof(struct tree), 1);
+ if (!tree) {
+ xmlFreeDoc(doc);
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ tree->root = tree_create_folder_node(NULL, "Root");
+ if (!tree->root) return NULL;
+
+ options_load_hotlist_directory(ul, tree->root);
+ tree->root->expanded = true;
+ tree_initialise(tree);
+
+ xmlFreeDoc(doc);
+ return tree;
+}
+
+
+/**
+ * Parse a directory represented as a ul.
+ *
+ * \param ul xmlNode for parsed ul
+ * \param directory directory to add this directory to
+ */
+void options_load_hotlist_directory(xmlNode *ul, struct node *directory) {
+ char *title;
+ struct node *dir;
+ xmlNode *n;
+
+ assert(ul);
+ assert(directory);
+
+ for (n = ul->children; n; n = n->next) {
+ /* The ul may contain entries as a li, or directories as
+ * an h4 followed by a ul. Non-element nodes may be present
+ * (eg. text, comments), and are ignored. */
+
+ if (n->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (strcmp(n->name, "li") == 0) {
+ /* entry */
+ options_load_hotlist_entry(n, directory);
+
+ } else if (strcmp(n->name, "h4") == 0) {
+ /* directory */
+ title = (char *) xmlNodeGetContent(n);
+ if (!title) {
+ warn_user("HotlistLoadError", "(Empty <h4> "
+ "or memory exhausted.)");
+ return;
+ }
+
+ for (n = n->next;
+ n && n->type != XML_ELEMENT_NODE;
+ n = n->next)
+ ;
+ if (!n || strcmp(n->name, "ul") != 0) {
+ /* next element isn't expected ul */
+ free(title);
+ warn_user("HotlistLoadError", "(Expected "
+ "<ul> not present.)");
+ return;
+ }
+
+ dir = tree_create_folder_node(directory, title);
+ if (!dir)
+ return;
+ options_load_hotlist_directory(n, dir);
+ }
+ }
+}
+
+
+/**
+ * Parse an entry represented as a li.
+ *
+ * \param li xmlNode for parsed li
+ * \param directory directory to add this entry to
+ */
+void options_load_hotlist_entry(xmlNode *li, struct node *directory) {
+ char *url = 0;
+ char *title = 0;
+ int filetype = 0xfaf;
+ int add_date = -1;
+ int last_date = -1;
+ int visits = 0;
+ char *comment;
+ struct node *entry;
+ xmlNode *n;
+
+ for (n = li->children; n; n = n->next) {
+ /* The li must contain an "a" element, and may contain
+ * some additional data as comments. */
+
+ if (n->type == XML_ELEMENT_NODE &&
+ strcmp(n->name, "a") == 0) {
+ url = (char *) xmlGetProp(n, (const xmlChar *) "href");
+ title = (char *) xmlNodeGetContent(n);
+
+ } else if (n->type == XML_COMMENT_NODE) {
+ comment = (char *) xmlNodeGetContent(n);
+ if (!comment)
+ continue;
+ if (strncmp("Type:", comment, 5) == 0)
+ filetype = atoi(comment + 5);
+ else if (strncmp("Added:", comment, 6) == 0)
+ add_date = atoi(comment + 6);
+ else if (strncmp("LastVisit:", comment, 10) == 0)
+ last_date = atoi(comment + 10);
+ else if (strncmp("Visits:", comment, 7) == 0)
+ visits = atoi(comment + 7);
+ }
+ }
+
+ if (!url || !title) {
+ warn_user("HotlistLoadError", "(Missing <a> in <li> or "
+ "memory exhausted.)");
+ return;
+ }
+
+ entry = tree_create_URL_node(directory, title, url, filetype, add_date,
+ last_date, visits);
+}
+
+
+/**
+ * Search the children of an xmlNode for an element.
+ *
+ * \param node xmlNode to search children of, or 0
+ * \param name name of element to find
+ * \return first child of node which is an element and matches name, or
+ * 0 if not found or parameter node is 0
+ */
+xmlNode *options_find_hotlist_element(xmlNode *node, const char *name) {
+ xmlNode *n;
+ if (!node)
+ return 0;
+ for (n = node->children;
+ n && !(n->type == XML_ELEMENT_NODE &&
+ strcmp(n->name, name) == 0);
+ n = n->next)
+ ;
+ return n;
+}
+
+
+/**
+ * Perform a save to a specified file
+ *
+ * /param filename the file to save to
+ */
+bool options_save_hotlist(struct tree *tree, const char *filename) {
+ int res;
+ xmlDoc *doc;
+ xmlNode *html, *head, *title, *body;
+
+ /* Unfortunately the Browse Hotlist format is invalid HTML,
+ * so this is a lie. */
+ doc = htmlNewDoc("http://www.w3.org/TR/html4/strict.dtd",
+ "-//W3C//DTD HTML 4.01//EN");
+ if (!doc) {
+ warn_user("NoMemory", 0);
+ return false;
+ }
+
+ html = xmlNewNode(NULL, "html");
+ if (!html) {
+ warn_user("NoMemory", 0);
+ xmlFreeDoc(doc);
+ return false;
+ }
+ xmlDocSetRootElement(doc, html);
+
+ head = xmlNewChild(html, NULL, "head", NULL);
+ if (!head) {
+ warn_user("NoMemory", 0);
+ xmlFreeDoc(doc);
+ return false;
+ }
+
+ title = xmlNewTextChild(head, NULL, "title", "NetSurf Hotlist");
+ if (!title) {
+ warn_user("NoMemory", 0);
+ xmlFreeDoc(doc);
+ return false;
+ }
+
+ body = xmlNewChild(html, NULL, "body", NULL);
+ if (!body) {
+ warn_user("NoMemory", 0);
+ xmlFreeDoc(doc);
+ return false;
+ }
+
+ if (!options_save_hotlist_directory(tree->root, body)) {
+ warn_user("NoMemory", 0);
+ xmlFreeDoc(doc);
+ return false;
+ }
+
+ doc->charset = XML_CHAR_ENCODING_UTF8;
+ res = htmlSaveFileEnc(filename, doc, "iso-8859-1");
+ if (res == -1) {
+ warn_user("HotlistSaveError", 0);
+ xmlFreeDoc(doc);
+ return false;
+ }
+
+ xmlFreeDoc(doc);
+ return true;
+}
+
+
+/**
+ * Add a directory to the HTML tree for saving.
+ *
+ * \param directory hotlist directory to add
+ * \param node node to add ul to
+ * \return true on success, false on memory exhaustion
+ */
+bool options_save_hotlist_directory(struct node *directory, xmlNode *node) {
+ struct node *child;
+ xmlNode *ul, *h4;
+
+ ul = xmlNewChild(node, NULL, "ul", NULL);
+ if (!ul)
+ return false;
+
+ for (child = directory->child; child; child = child->next) {
+ if (!child->folder) {
+ /* entry */
+ if (!options_save_hotlist_entry(child, ul))
+ return false;
+ } else {
+ /* directory */
+ /* invalid HTML */
+ h4 = xmlNewTextChild(ul, NULL, "h4", child->data.text);
+ if (!h4)
+ return false;
+
+ if (!options_save_hotlist_directory(child, ul))
+ return false;
+ } }
+
+ return true;
+}
+
+
+/**
+ * Add an entry to the HTML tree for saving.
+ *
+ * The node must contain a sequence of node_elements in the following order:
+ *
+ * \param entry hotlist entry to add
+ * \param node node to add li to
+ * \return true on success, false on memory exhaustion
+ */
+bool options_save_hotlist_entry(struct node *entry, xmlNode *node) {
+ xmlNode *li, *a;
+ xmlAttr *href;
+ struct node_element *element;
+
+ li = xmlNewChild(node, NULL, "li", NULL);
+ if (!li)
+ return false;
+
+ a = xmlNewTextChild(li, NULL, "a", entry->data.text);
+ if (!a)
+ return false;
+
+ element = tree_find_element(entry, TREE_ELEMENT_URL);
+ if (!element)
+ return false;
+ href = xmlNewProp(a, "href", element->text);
+ if (!href)
+ return false;
+
+ if (element->user_data != 0xfaf)
+ if (!options_save_hotlist_entry_comment(li,
+ "Type", element->user_data))
+ return false;
+
+ element = tree_find_element(entry, TREE_ELEMENT_ADDED);
+ if ((element) && (element->user_data != -1))
+ if (!options_save_hotlist_entry_comment(li,
+ "Added", element->user_data))
+ return false;
+
+ element = tree_find_element(entry, TREE_ELEMENT_LAST_VISIT);
+ if ((element) && (element->user_data != -1))
+ if (!options_save_hotlist_entry_comment(li,
+ "LastVisit", element->user_data))
+ return false;
+
+ element = tree_find_element(entry, TREE_ELEMENT_VISITS);
+ if ((element) && (element->user_data != 0))
+ if (!options_save_hotlist_entry_comment(li,
+ "Visits", element->user_data))
+ return false;
+ return true;
+}
+
+
+/**
+ * Add a special comment node to the HTML tree for saving.
+ *
+ * \param node node to add comment to
+ * \param name name of special comment
+ * \param value value of special comment
+ * \return true on success, false on memory exhaustion
+ */
+bool options_save_hotlist_entry_comment(xmlNode *node, const char *name, int value) {
+ char s[40];
+ xmlNode *comment;
+
+ snprintf(s, sizeof s, "%s:%i", name, value);
+ s[sizeof s - 1] = 0;
+
+ comment = xmlNewComment(s);
+ if (!comment)
+ return false;
+ if (!xmlAddChild(node, comment)) {
+ xmlFreeNode(comment);
+ return false;
+ }
+
+ return true;
+}
diff --git a/desktop/options.h b/desktop/options.h
index 0724f8c65..d811ffb7e 100644
--- a/desktop/options.h
+++ b/desktop/options.h
@@ -24,6 +24,8 @@
#ifndef _NETSURF_DESKTOP_OPTIONS_H_
#define _NETSURF_DESKTOP_OPTIONS_H_
+#include "netsurf/desktop/tree.h"
+
enum { OPTION_HTTP_PROXY_AUTH_NONE = 0, OPTION_HTTP_PROXY_AUTH_BASIC = 1,
OPTION_HTTP_PROXY_AUTH_NTLM = 2 };
@@ -41,8 +43,12 @@ extern int option_memory_cache_size;
extern bool option_block_ads;
extern int option_minimum_gif_delay;
extern bool option_send_referer;
+extern bool option_animate_images;
void options_read(const char *path);
void options_write(const char *path);
+struct tree *options_load_hotlist(const char *filename);
+bool options_save_hotlist(struct tree *tree, const char *filename);
+
#endif
diff --git a/desktop/tree.c b/desktop/tree.c
new file mode 100644
index 000000000..d504ddcba
--- /dev/null
+++ b/desktop/tree.c
@@ -0,0 +1,1113 @@
+/*
+ * This file is part of NetSurf, http://netsurf.sourceforge.net/
+ * Licensed under the GNU General Public License,
+ * http://www.opensource.org/licenses/gpl-license
+ * Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
+ */
+
+/** \file
+ * Generic tree handling (implementation).
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "netsurf/desktop/tree.h"
+#include "netsurf/desktop/options.h"
+#include "netsurf/utils/log.h"
+#include "netsurf/utils/utils.h"
+
+static void tree_recalculate_node(struct node *node, bool recalculate_sizes);
+static void tree_recalculate_node_positions(struct node *root);
+static void tree_draw_node(struct tree *tree, struct node *node, int clip_x, int clip_y,
+ int clip_width, int clip_height);
+static struct node_element *tree_create_node_element(struct node *parent, int user_type);
+static int tree_get_node_width(struct node *node);
+static int tree_get_node_height(struct node *node);
+static void tree_reset_URL_node(struct tree *tree, struct node *node);
+static void tree_handle_selection_area_node(struct tree *tree, struct node *node, int x, int y,
+ int width, int height, bool invert);
+static void tree_selected_to_processing(struct node *node);
+struct node *tree_move_processing_node(struct node *node, struct node *link, bool before,
+ bool first);
+
+static int tree_initialising = 0;
+
+
+/**
+ * Initialises a user-created tree
+ *
+ * \param tree the tree to initialise
+ */
+void tree_initialise(struct tree *tree) {
+
+ assert(tree);
+
+ tree_set_node_expanded(tree->root, true);
+ tree_initialise_nodes(tree->root);
+ tree_recalculate_node_positions(tree->root);
+ tree_set_node_expanded(tree->root, false);
+ tree->root->expanded = true;
+ tree_recalculate_node_positions(tree->root);
+ tree_recalculate_size(tree);
+}
+
+
+/**
+ * Initialises a user-created node structure
+ *
+ * \param root the root node to update from
+ */
+void tree_initialise_nodes(struct node *root) {
+ struct node *node;
+
+ assert(root);
+
+ tree_initialising++;
+ for (node = root; node; node = node->next) {
+ tree_recalculate_node(node, true);
+ if (node->child) {
+ tree_initialise_nodes(node->child);
+ }
+ }
+ tree_initialising--;
+
+ if (tree_initialising == 0)
+ tree_recalculate_node_positions(root);
+}
+
+
+/**
+ * Recalculate the node data and redraw the relevant section of the tree.
+ *
+ * \param tree the tree to redraw
+ * \param node the node to update
+ * \param recalculate_sizes whether the elements have changed
+ * \param expansion the request is the result of a node expansion
+ */
+void tree_handle_node_changed(struct tree *tree, struct node *node,
+ bool recalculate_sizes, bool expansion) {
+ int width, height;
+
+ assert(node);
+
+ if ((expansion) && (node->expanded) && (node->child)) {
+ tree_set_node_expanded(node->child, false);
+ tree_set_node_selected(tree, node->child, false);
+ }
+
+ width = node->box.width;
+ height = node->box.height;
+ if (recalculate_sizes)
+ tree_recalculate_node(node, true);
+ else if (expansion)
+ tree_recalculate_node(node, false);
+ if ((node->box.height != height) || (expansion)) {
+ tree_recalculate_node_positions(tree->root);
+ tree_redraw_area(tree, 0, node->box.y, 16384, 16384);
+ } else {
+ width = (width > node->box.width) ? width : node->box.width;
+ tree_redraw_area(tree, node->box.x, node->box.y, width, node->box.height);
+ }
+ if ((recalculate_sizes) || (expansion))
+ tree_recalculate_size(tree);
+}
+
+
+/**
+ * Recalculate the node element and redraw the relevant section of the tree.
+ * The tree size is not updated.
+ *
+ * \param tree the tree to redraw
+ * \param element the node element to update
+ */
+void tree_handle_node_element_changed(struct tree *tree, struct node_element *element) {
+ int width, height;
+
+ assert(element);
+
+ width = element->box.width;
+ height = element->box.height;
+ tree_recalculate_node_element(element);
+
+ if (element->box.height != height) {
+ tree_recalculate_node(element->parent, false);
+ tree_redraw_area(tree, 0, element->box.y, 16384, 16384);
+ } else {
+ if (element->box.width != width)
+ tree_recalculate_node(element->parent, false);
+ width = (width > element->box.width) ? width :
+ element->box.width;
+ tree_redraw_area(tree, element->box.x, element->box.y, width, element->box.height);
+ }
+}
+
+
+/**
+ * Recalculates the size of a node.
+ *
+ * \param node the node to update
+ * \param recalculate_sizes whether the node elements have changed
+ */
+void tree_recalculate_node(struct node *node, bool recalculate_sizes) {
+ struct node_element *element;
+ int width, height;
+
+ assert(node);
+
+ width = node->box.width;
+ height = node->box.height;
+ node->box.width = 0;
+ node->box.height = 0;
+ if (node->expanded) {
+ for (element = &node->data; element; element = element->next) {
+ if (recalculate_sizes)
+ tree_recalculate_node_element(element);
+ node->box.width = (node->box.width >
+ element->box.x + element->box.width - node->box.x) ?
+ node->box.width :
+ element->box.width + element->box.x - node->box.x;
+ node->box.height += element->box.height;
+ }
+ } else {
+ if (recalculate_sizes)
+ tree_recalculate_node_element(&node->data);
+ node->box.width = node->data.box.width;
+ node->box.height = node->data.box.height;
+ }
+
+ if (height != node->box.height) {
+ for (; node->parent; node = node->parent);
+ if (tree_initialising == 0)
+ tree_recalculate_node_positions(node);
+ }
+}
+
+
+/**
+ * Recalculates the position of a node, its siblings and children.
+ *
+ * \param root the root node to update from
+ */
+void tree_recalculate_node_positions(struct node *root) {
+ struct node *parent;
+ struct node *node;
+ struct node *child;
+ struct node_element *element;
+ int y;
+
+ for (node = root; node; node = node->next) {
+ if (node->previous) {
+ node->box.x = node->previous->box.x;
+ node->box.y = node->previous->box.y +
+ tree_get_node_height(node->previous);
+ } else if ((parent = node->parent)) {
+ node->box.x = parent->box.x + NODE_INSTEP;
+ node->box.y = parent->box.y +
+ parent->box.height;
+ for (child = parent->child; child != node;
+ child = child->next)
+ node->box.y += child->box.height;
+ } else {
+ node->box.x = 0;
+ node->box.y = -40;
+ }
+ if (node->expanded) {
+ if (node->folder) {
+ node->data.box.x = node->box.x;
+ node->data.box.y = node->box.y;
+ tree_recalculate_node_positions(node->child);
+ } else {
+ y = node->box.y;
+ for (element = &node->data; element;
+ element = element->next) {
+ if (element->type == NODE_ELEMENT_TEXT_PLUS_SPRITE) {
+ element->box.x = node->box.x;
+ } else {
+ element->box.x = node->box.x + NODE_INSTEP;
+ }
+ element->box.y = y;
+ y += element->box.height;
+ }
+ }
+ } else {
+ node->data.box.x = node->box.x;
+ node->data.box.y = node->box.y;
+ }
+ }
+}
+
+
+/**
+ * Calculates the width of a node including any children
+ *
+ * \param node the node to calculate the height of
+ * \return the total width of the node and children
+ */
+int tree_get_node_width(struct node *node) {
+ int width = 0;
+ int child_width;
+
+ assert(node);
+
+ for (; node; node = node->next) {
+ if (width < (node->box.x + node->box.width))
+ width = node->box.x + node->box.width;
+ if ((node->child) && (node->expanded)) {
+ child_width = tree_get_node_width(node->child);
+ if (width < child_width)
+ width = child_width;
+ }
+ }
+ return width;
+}
+
+
+/**
+ * Calculates the height of a node including any children
+ *
+ * \param node the node to calculate the height of
+ * \return the total height of the node and children
+ */
+int tree_get_node_height(struct node *node) {
+ int y1;
+
+ assert(node);
+
+ if ((node->child) && (node->expanded)) {
+ y1 = node->box.y;
+ if (y1 < 0)
+ y1 = 0;
+ node = node->child;
+ while ((node->next) || ((node->child) && (node->expanded))) {
+ for (; node->next; node = node->next);
+ if ((node->child) && (node->expanded))
+ node = node->child;
+ }
+ return node->box.y + node->box.height - y1;
+ } else {
+ return node->box.height;
+ }
+}
+
+
+/**
+ * Updates all siblinds and descendants of a node to an expansion state.
+ * No update is performed for the tree changes.
+ *
+ * \param node the node to set all siblings and descendants of
+ * \param expanded the expansion state to set
+ */
+void tree_set_node_expanded(struct node *node, bool expanded) {
+ for (; node; node = node->next) {
+ if (node->expanded != expanded) {
+ node->expanded = expanded;
+ tree_recalculate_node(node, false);
+ }
+ if ((node->child) && (node->expanded))
+ tree_set_node_expanded(node->child, expanded);
+ }
+}
+
+
+/**
+ * Updates all siblinds and descendants of a node to an expansion state.
+ *
+ * \param tree the tree to update
+ * \param node the node to set all siblings and descendants of
+ * \param expanded the expansion state to set
+ * \param folder whether to update folders
+ * \param leaf whether to update leaves
+ * \return whether any changes were made
+ */
+bool tree_handle_expansion(struct tree *tree, struct node *node, bool expanded, bool folder,
+ bool leaf) {
+ struct node *entry = node;
+ bool redraw = false;
+
+ for (; node; node = node->next) {
+ if ((node->expanded != expanded) && (node != tree->root) &&
+ ((folder && (node->folder)) || (leaf && (!node->folder)))) {
+ node->expanded = expanded;
+ if (node->child)
+ tree_set_node_expanded(node->child, false);
+ tree_recalculate_node(node, false);
+ redraw = true;
+ }
+ if ((node->child) && (node->expanded))
+ redraw |= tree_handle_expansion(tree, node->child, expanded, folder, leaf);
+ }
+ if ((entry == tree->root) && (redraw)) {
+ tree_recalculate_node_positions(tree->root);
+ tree_redraw_area(tree, 0, 0, 16384, 16384);
+ tree_recalculate_size(tree);
+ }
+ return redraw;
+}
+
+
+/**
+ * Updates all siblinds and descendants of a node to an selected state.
+ * The required areas of the tree are redrawn.
+ *
+ * \param tree the tree to update nodes for
+ * \param node the node to set all siblings and descendants of
+ * \param selected the selection state to set
+ */
+void tree_set_node_selected(struct tree *tree, struct node *node, bool selected) {
+ for (; node; node = node->next) {
+ if ((node->selected != selected) && (node != tree->root)) {
+ node->selected = selected;
+ tree_redraw_area(tree, node->box.x, node->box.y, node->box.width,
+ node->data.box.height);
+ }
+ if ((node->child) && (node->expanded))
+ tree_set_node_selected(tree, node->child, selected);
+ }
+}
+
+
+/**
+ * Finds a node at a specific location.
+ *
+ * \param root the root node to check from
+ * \param x the x co-ordinate
+ * \param y the y co-ordinate
+ * \param furniture whether the returned area was in an elements furniture
+ * \return the node at the specified position, or NULL for none
+ */
+struct node *tree_get_node_at(struct node *root, int x, int y, bool *furniture) {
+ struct node_element *result;
+
+ if ((result = tree_get_node_element_at(root, x, y, furniture)))
+ return result->parent;
+ return NULL;
+}
+
+
+/**
+ * Finds a node element at a specific location.
+ *
+ * \param node the root node to check from
+ * \param x the x co-ordinate
+ * \param y the y co-ordinate
+ * \param furniture whether the returned area was in an elements furniture
+ * \return the node at the specified position, or NULL for none
+ */
+struct node_element *tree_get_node_element_at(struct node *node, int x, int y,
+ bool *furniture) {
+ struct node_element *element;
+
+ *furniture = false;
+ for (; node; node = node->next) {
+ if (node->box.y > y) return NULL;
+ if ((node->box.x - NODE_INSTEP < x) && (node->box.y < y) &&
+ (node->box.x + node->box.width >= x) &&
+ (node->box.y + node->box.height >= y)) {
+ if (node->expanded) {
+ for (element = &node->data; element;
+ element = element->next) {
+ if ((element->box.x < x) && (element->box.y < y) &&
+ (element->box.x + element->box.width >= x) &&
+ (element->box.y + element->box.height >= y))
+ return element;
+ }
+ } else if ((node->data.box.x < x) &&
+ (node->data.box.y < y) &&
+ (node->data.box.x + node->data.box.width >= x) &&
+ (node->data.box.y + node->data.box.height >= y))
+ return &node->data;
+ if (((node->child) || (node->data.next)) &&
+ (node->data.box.x - NODE_INSTEP + 8 < x) &&
+ (node->data.box.y + 8 < y) &&
+ (node->data.box.x > x) &&
+ (node->data.box.y + 32 > y)) {
+ *furniture = true;
+ return &node->data;
+ }
+ }
+
+ if ((node->child) && (node->expanded) &&
+ ((element = tree_get_node_element_at(node->child, x, y,
+ furniture))))
+ return element;
+ }
+ return NULL;
+}
+
+
+/**
+ * Finds a node element from a node with a specific user_type
+ *
+ * \param node the node to examine
+ * \param user_type the user_type to check for
+ * \return the corresponding element
+ */
+struct node_element *tree_find_element(struct node *node, int user_type) {
+ struct node_element *element;
+ for (element = &node->data; element; element = element->next)
+ if (element->user_type == user_type) return element;
+ return NULL;
+}
+
+
+/**
+ * Moves nodes within a tree.
+ *
+ * \param tree the tree to process
+ * \param link the node to link before/as a child (folders) or before/after (link)
+ * \param before whether to link siblings before or after the supplied node
+ */
+void tree_move_selected_nodes(struct tree *tree, struct node *destination, bool before) {
+ struct node *link;
+
+ tree_selected_to_processing(tree->root);
+ if (destination->processing)
+ return;
+ if ((destination->folder) && (!destination->expanded) && (!before)) {
+ destination->expanded = true;
+ tree_handle_node_changed(tree, destination, false, true);
+ }
+ link = tree_move_processing_node(tree->root, destination, before, true);
+ while (link)
+ link = tree_move_processing_node(tree->root, link, false, false);
+
+ tree_recalculate_node_positions(tree->root);
+ tree_redraw_area(tree, 0, 0, 16384, 16384);
+}
+
+
+/**
+ * Sets the processing flag to the selection state.
+ *
+ * \param node the node to process siblings and children of
+ */
+void tree_selected_to_processing(struct node *node) {
+ for (; node; node = node->next) {
+ node->processing = node->selected;
+ if (node->child)
+ tree_selected_to_processing(node->child);
+ }
+}
+
+
+/**
+ * Moves the first node in a tree with the processing flag set.
+ *
+ * \param tree the node to move siblings/children of
+ * \param link the node to link before/as a child (folders) or before/after (link)
+ * \param before whether to link siblings before or after the supplied node
+ * \param first whether to always link after the supplied node (ie not inside of folders)
+ * \return the node moved
+ */
+struct node *tree_move_processing_node(struct node *node, struct node *link, bool before,
+ bool first) {
+ struct node *result;
+
+ bool folder = link->folder;
+ for (; node; node = node->next) {
+ if (node->processing) {
+ node->processing = false;
+ tree_delink_node(node);
+ if (!first)
+ link->folder = false;
+ tree_link_node(link, node, before);
+ if (!first)
+ link->folder = folder;
+ return node;
+ }
+ if (node->child) {
+ result = tree_move_processing_node(node->child, link, before, first);
+ if (result)
+ return result;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Checks whether a node, its siblings or any children are selected.
+ *
+ * \param node the root node to check from
+ */
+bool tree_has_selection(struct node *node) {
+ for (; node; node = node->next) {
+ if (node->selected)
+ return true;
+ if ((node->child) && (node->expanded) &&
+ (tree_has_selection(node->child)))
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ * Updates the selected state for a region of nodes.
+ *
+ * \param tree the tree to update
+ * \param x the minimum x of the selection rectangle
+ * \param y the minimum y of the selection rectangle
+ * \param width the width of the selection rectangle
+ * \param height the height of the selection rectangle
+ * \param invert whether to invert the selected state
+ */
+void tree_handle_selection_area(struct tree *tree, int x, int y, int width, int height,
+ bool invert) {
+ assert(tree);
+ assert(tree->root);
+
+ if (!tree->root->child) return;
+
+ if (width < 0) {
+ x += width;
+ width =- width;
+ }
+ if (height < 0) {
+ y += height;
+ height =- height;
+ }
+
+ tree_handle_selection_area_node(tree, tree->root->child, x, y, width, height, invert);
+}
+
+
+/**
+ * Updates the selected state for a region of nodes.
+ *
+ * \param tree the tree to update
+ * \param node the node to update children and siblings of
+ * \param x the minimum x of the selection rectangle
+ * \param y the minimum y of the selection rectangle
+ * \param width the width of the selection rectangle
+ * \param height the height of the selection rectangle
+ * \param invert whether to invert the selected state
+ */
+void tree_handle_selection_area_node(struct tree *tree, struct node *node, int x, int y,
+ int width, int height, bool invert) {
+
+ struct node_element *element;
+ struct node *update;
+ int x_max, y_max;
+
+ assert(tree);
+ assert(node);
+
+ x_max = x + width;
+ y_max = y + height;
+
+ for (; node; node = node->next) {
+ if (node->box.y > y_max) return;
+ if ((node->box.x < x_max) && (node->box.y < y_max) &&
+ (node->box.x + node->box.width + NODE_INSTEP >= x) &&
+ (node->box.y + node->box.height >= y)) {
+ update = NULL;
+ if (node->expanded) {
+ for (element = &node->data; element;
+ element = element->next) {
+ if ((element->box.x < x_max) && (element->box.y < y_max) &&
+ (element->box.x + element->box.width >= x) &&
+ (element->box.y + element->box.height >= y)) {
+ update = element->parent;
+ break;
+ }
+ }
+ } else if ((node->data.box.x < x_max) &&
+ (node->data.box.y < y_max) &&
+ (node->data.box.x + node->data.box.width >= x) &&
+ (node->data.box.y + node->data.box.height >= y))
+ update = node->data.parent;
+ if ((update) && (node != tree->root)) {
+ if (invert) {
+ node->selected = !node->selected;
+ tree_handle_node_element_changed(tree, &node->data);
+ } else if (!node->selected) {
+ node->selected = true;
+ tree_handle_node_element_changed(tree, &node->data);
+ }
+ }
+ }
+ if ((node->child) && (node->expanded))
+ tree_handle_selection_area_node(tree, node->child, x, y, width, height,
+ invert);
+ }
+}
+
+
+/**
+ * Redraws a tree.
+ *
+ * \param tree the tree to draw
+ * \param clip_x the minimum x of the clipping rectangle
+ * \param clip_y the minimum y of the clipping rectangle
+ * \param clip_width the width of the clipping rectangle
+ * \param clip_height the height of the clipping rectangle
+ */
+void tree_draw(struct tree *tree, int clip_x, int clip_y, int clip_width,
+ int clip_height) {
+ assert(tree);
+ assert(tree->root);
+
+ if (!tree->root->child) return;
+
+ tree_initialise_redraw(tree);
+ tree_draw_node(tree, tree->root->child, clip_x,
+ clip_y, clip_width, clip_height);
+}
+
+
+/**
+ * Redraws a node.
+ *
+ * \param tree the tree to draw
+ * \param node the node to draw children and siblings of
+ * \param clip_x the minimum x of the clipping rectangle
+ * \param clip_y the minimum y of the clipping rectangle
+ * \param clip_width the width of the clipping rectangle
+ * \param clip_height the height of the clipping rectangle
+ */
+void tree_draw_node(struct tree *tree, struct node *node, int clip_x, int clip_y,
+ int clip_width, int clip_height) {
+
+ struct node_element *element;
+ int x_max, y_max;
+
+ assert(tree);
+ assert(node);
+
+ x_max = clip_x + clip_width + NODE_INSTEP;
+ y_max = clip_y + clip_height;
+
+ if ((node->parent->next) && (node->parent->next->box.y < clip_y))
+ return;
+
+ for (; node; node = node->next) {
+ if (node->box.y > y_max) return;
+ if (node->next)
+ tree_draw_line(tree, node->box.x - (NODE_INSTEP / 2),
+ node->box.y + (40 / 2), 0,
+ node->next->box.y - node->box.y);
+ if ((node->box.x < x_max) && (node->box.y < y_max) &&
+ (node->box.x + node->box.width + NODE_INSTEP >= clip_x) &&
+ (node->box.y + node->box.height >= clip_y)) {
+ if ((node->expanded) && (node->child))
+ tree_draw_line(tree, node->box.x + (NODE_INSTEP / 2),
+ node->data.box.y + node->data.box.height, 0,
+ (40 / 2));
+ tree_draw_line(tree, node->box.x - (NODE_INSTEP / 2),
+ node->data.box.y +
+ node->data.box.height - (40 / 2),
+ (NODE_INSTEP / 2) - 4, 0);
+ tree_draw_node_expansion(tree, node);
+ if (node->expanded)
+ for (element = &node->data; element;
+ element = element->next)
+ tree_draw_node_element(tree, element);
+ else
+ tree_draw_node_element(tree, &node->data);
+ }
+ if ((node->child) && (node->expanded))
+ tree_draw_node(tree, node->child, clip_x, clip_y, clip_width,
+ clip_height);
+ }
+}
+
+
+/**
+ * Gets link characteristics to insert a node at a specified position.
+ *
+ * \param tree the tree to find link information for
+ * \param x the x co-ordinate
+ * \param y the y co-ordinate
+ * \param before set to whether the node should be linked before on exit
+ * \return the node to link with
+ */
+struct node *tree_get_link_details(struct tree *tree, int x, int y, bool *before) {
+ struct node *node = NULL;
+ bool furniture;
+
+ assert(tree);
+ assert(tree->root);
+
+ *before = false;
+ if (tree->root->child)
+ node = tree_get_node_at(tree->root->child, x, y, &furniture);
+ if ((!node) || (furniture))
+ return tree->root;
+
+ if (y < (node->box.y + (node->box.height / 2))) {
+ *before = true;
+ } else if ((node->folder) && (node->expanded) && (node->child)) {
+ node = node->child;
+ *before = true;
+ }
+ return node;
+}
+
+
+/**
+ * Links a node into the tree.
+ *
+ * \param link the node to link before/as a child (folders) or before/after (link)
+ * \param node the node to link
+ * \param before whether to link siblings before or after the supplied node
+ */
+void tree_link_node(struct node *link, struct node *node, bool before) {
+ struct node *sibling;
+
+ assert(link);
+ assert(node);
+
+ if ((!link->folder) || (before)) {
+ node->parent = link->parent;
+ if (before) {
+ node->next = link;
+ node->previous = link->previous;
+ if (link->previous) link->previous->next = node;
+ link->previous = node;
+ if ((link->parent) && (link->parent->child == link))
+ link->parent->child = node;
+ } else {
+ node->previous = link;
+ node->next = link->next;
+ if (link->next) link->next->previous = node;
+ link->next = node;
+ }
+ } else {
+ sibling = link->child;
+ if (!sibling) {
+ link->child = node;
+ node->previous = NULL;
+ } else {
+ while (sibling->next)
+ sibling = sibling->next;
+ sibling->next = node;
+ node->previous = sibling;
+ }
+ node->parent = link;
+ node->next = NULL;
+ }
+}
+
+
+/**
+ * Delinks a node from the tree.
+ *
+ * \param node the node to delink
+ */
+void tree_delink_node(struct node *node) {
+ assert(node);
+
+ if (node->parent) {
+ if (node->parent->child == node)
+ node->parent->child = node->next;
+ if (node->parent->child == NULL)
+ node->parent->expanded = false;
+ node->parent = NULL;
+ }
+ if (node->previous)
+ node->previous->next = node->next;
+ if (node->next)
+ node->next->previous = node->previous;
+ node->previous = NULL;
+ node->next = NULL;
+}
+
+
+/**
+ * Deletes all selected node from the tree.
+ *
+ * \param tree the tree to delete from
+ * \param node the node to delete
+ */
+void tree_delete_selected_nodes(struct tree *tree, struct node *node) {
+ struct node *next;
+
+ while (node) {
+ next = node->next;
+ if ((node->selected) && (node != tree->root))
+ tree_delete_node(tree, node, false);
+ if (node->child)
+ tree_delete_selected_nodes(tree, node->child);
+ node = next;
+ }
+}
+
+
+/**
+ * Deletes a node from the tree.
+ *
+ * \param tree the tree to delete from
+ * \param node the node to delete
+ * \param siblings whether to delete all siblings
+ */
+void tree_delete_node(struct tree *tree, struct node *node, bool siblings) {
+ struct node *next;
+ struct node *parent;
+ struct node_element *element;
+
+ assert(node);
+
+ while (node) {
+ next = node->next;
+ if (node->child)
+ tree_delete_node(tree, node->child, true);
+ parent = node->parent;
+ tree_delink_node(node);
+ for (element = &node->data; element; element = element->next) {
+ if (element->text)
+ free(element->text);
+ if (element->sprite)
+ free(element->sprite); /* \todo platform specific bits */
+ }
+ while (node->data.next) {
+ element = node->data.next->next;
+ free(node->data.next);
+ node->data.next = element;
+ }
+ free(node);
+
+ if (!siblings)
+ node = NULL;
+ else
+ node = next;
+ }
+ tree_recalculate_node_positions(tree->root);
+ tree_redraw_area(tree, 0, 0, 16384, 16384); /* \todo correct area */
+ tree_recalculate_size(tree);
+}
+
+
+/**
+ * Creates a folder node with the specified title, and links it into the tree.
+ *
+ * \param parent the parent node, or NULL not to link
+ * \param title the node title (copied)
+ * \return the newly created node.
+ */
+struct node *tree_create_folder_node(struct node *parent, const char *title) {
+ struct node *node;
+
+ assert(title);
+
+ node = calloc(sizeof(struct node), 1);
+ if (!node) return NULL;
+ node->editable = true;
+ node->folder = true;
+ node->data.parent = node;
+ node->data.type = NODE_ELEMENT_TEXT;
+ node->data.text = squash_whitespace(title);
+ tree_set_node_sprite_folder(node);
+ if (parent)
+ tree_link_node(parent, node, false);
+ tree_recalculate_node(node, true);
+ return node;
+}
+
+
+/**
+ * Creates a leaf node with the specified title, and links it into the tree.
+ *
+ * \param parent the parent node, or NULL not to link
+ * \param title the node title (copied)
+ * \return the newly created node.
+ */
+struct node *tree_create_leaf_node(struct node *parent, const char *title) {
+ struct node *node;
+
+ assert(title);
+
+ node = calloc(sizeof(struct node), 1);
+ if (!node) return NULL;
+ node->folder = false;
+ node->data.parent = node;
+ node->data.type = NODE_ELEMENT_TEXT;
+ node->data.text = squash_whitespace(title);
+ if (parent)
+ tree_link_node(parent, node, false);
+ return node;
+}
+
+
+/**
+ * Creates a tree entry for a URL, and links it into the tree
+ *
+ * \param parent the node to link to
+ * \param title the node title
+ * \param url the node URL
+ * \param filetype the node filetype
+ * \param add_date the date added
+ * \param last_date the last visited date
+ * \param visits the number of visits
+ * \return the node created, or NULL for failure
+ */
+struct node *tree_create_URL_node(struct node *parent, const char *title,
+ const char *url, int filetype, int add_date, int last_date, int visits) {
+ struct node *node;
+ struct node_element *element;
+
+ assert(title);
+ assert(url);
+
+ node = tree_create_leaf_node(parent, title);
+ if (!node)
+ return NULL;
+ node->editable = true;
+
+ element = tree_create_node_element(node, TREE_ELEMENT_URL);
+ if (element) {
+ element->user_data = filetype;
+ element->type = NODE_ELEMENT_TEXT;
+ element->text = squash_whitespace(url);
+ }
+ element = tree_create_node_element(node, TREE_ELEMENT_ADDED);
+ if (element) {
+ element->type = NODE_ELEMENT_TEXT;
+ element->user_data = add_date;
+ }
+ element = tree_create_node_element(node, TREE_ELEMENT_LAST_VISIT);
+ if (element) {
+ element->type = NODE_ELEMENT_TEXT;
+ element->user_data = last_date;
+ }
+ element = tree_create_node_element(node, TREE_ELEMENT_VISITS);
+ if (element) {
+ element->type = NODE_ELEMENT_TEXT;
+ element->user_data = visits;
+ }
+
+ tree_update_URL_node(node);
+
+ node->expanded = true;
+ tree_recalculate_node(node, true);
+ node->expanded = false;
+
+ return node;
+}
+
+
+/**
+ * Resets all selected URL nodes from the tree.
+ *
+ * \param tree the tree to reset from
+ * \param node the node to reset
+ * \param selected whether to only reset selected nodes
+ */
+void tree_reset_URL_nodes(struct tree *tree, struct node *node, bool selected) {
+ for (; node; node = node->next) {
+ if (((node->selected) || (!selected)) && (!node->folder))
+ tree_reset_URL_node(tree, node);
+ if (node->child)
+ tree_reset_URL_nodes(tree, node->child,
+ !((node->selected) | selected));
+ }
+}
+
+
+/**
+ * Resets a tree entry for a URL
+ */
+void tree_reset_URL_node(struct tree *tree, struct node *node) {
+ struct node_element *element;
+
+ assert(tree);
+ assert(node);
+
+ element = tree_find_element(node, TREE_ELEMENT_LAST_VISIT);
+ if (element)
+ element->user_data = -1;
+ element = tree_find_element(node, TREE_ELEMENT_VISITS);
+ if (element)
+ element->user_data = 0;
+ tree_update_URL_node(node);
+ tree_recalculate_node(node, true);
+
+ if (node->expanded)
+ tree_redraw_area(tree, node->box.x, node->box.y + node->data.box.height,
+ node->box.width, node->box.height - node->data.box.height);
+
+}
+
+
+/**
+ * Creates an empty node element and links it to a node.
+ *
+ * \param parent the parent node
+ * \param user_type the required user_type
+ * \return the newly created element.
+ */
+struct node_element *tree_create_node_element(struct node *parent, int user_type) {
+ struct node_element *element;
+ struct node_element *link;
+
+ assert(parent);
+
+ element = calloc(sizeof(struct node_element), 1);
+ if (!element) return NULL;
+ element->parent = parent;
+ element->user_type = user_type;
+
+ for (link = parent->data.next; ((link) && (link->user_type < user_type));
+ link = link->next);
+ if (link) {
+ element->next = link->next;
+ link->next = element;
+ } else {
+ for (link = &parent->data; link->next; link = link->next);
+ link->next = element;
+ }
+ return element;
+}
+
+
+/**
+ * Recalculates the size of a tree.
+ *
+ * \param tree the tree to recalculate
+ */
+void tree_recalculate_size(struct tree *tree) {
+ int width, height;
+
+ assert(tree);
+
+ if (!tree->handle)
+ return;
+ width = tree->width;
+ height = tree->height;
+ tree->width = tree_get_node_width(tree->root);
+ tree->height = tree_get_node_height(tree->root);
+ if ((width != tree->width) || (height != tree->height))
+ tree_resized(tree);
+}
+
+
+/**
+ * Returns the selected node, or NULL if multiple nodes are selected.
+ *
+ * \param node the node to search sibling and children
+ * \return the selected node, or NULL if multiple nodes are selected
+ */
+struct node *tree_get_selected_node(struct node *node) {
+ struct node *result = NULL;
+ struct node *temp;
+
+ for (; node; node = node->next) {
+ if (node->selected) {
+ if (result)
+ return NULL;
+ result = node;
+ }
+ if ((node->child) && (node->expanded)) {
+ temp = tree_get_selected_node(node->child);
+ if (temp) {
+ if (result)
+ return NULL;
+ else
+ result = temp;
+ }
+ }
+ }
+ return result;
+}
diff --git a/desktop/tree.h b/desktop/tree.h
new file mode 100644
index 000000000..632667ad0
--- /dev/null
+++ b/desktop/tree.h
@@ -0,0 +1,137 @@
+/*
+ * This file is part of NetSurf, http://netsurf.sourceforge.net/
+ * Licensed under the GNU General Public License,
+ * http://www.opensource.org/licenses/gpl-license
+ * Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
+ */
+
+/** \file
+ * Generic tree handling (interface).
+ */
+
+#ifndef _NETSURF_DESKTOP_TREE_H_
+#define _NETSURF_DESKTOP_TREE_H_
+
+#include <stdbool.h>
+
+#define TREE_ELEMENT_URL 1
+#define TREE_ELEMENT_ADDED 2
+#define TREE_ELEMENT_LAST_VISIT 3
+#define TREE_ELEMENT_VISITS 4
+
+#define NODE_INSTEP 40
+
+struct node_sprite;
+
+typedef enum {
+ NODE_ELEMENT_TEXT, /* <-- Text only */
+ NODE_ELEMENT_TEXT_PLUS_SPRITE, /* <-- Text and sprite */
+ NODE_ELEMENT_SPRITE, /* <-- Sprite only */
+} node_element_type;
+
+
+struct node_element_box {
+ int x; /* <-- X offset from origin */
+ int y; /* <-- Y offset from origin */
+ int width; /* <-- Element width */
+ int height; /* <-- Element height */
+};
+
+
+struct node_element {
+ struct node *parent; /* <-- Parent node */
+ node_element_type type; /* <-- Element type */
+ struct node_element_box box; /* <-- Element bounding box */
+ char *text; /* <-- Text for the element */
+ struct node_sprite *sprite; /* <-- Sprite for the element */
+ struct node_element *next; /* <-- Next node element */
+ int user_data; /* <-- Private user data */
+ int user_type; /* <-- Private user data */
+};
+
+
+struct node {
+ bool selected; /* <-- Whether the node is selected */
+ bool expanded; /* <-- Whether the node is expanded */
+ bool folder; /* <-- Whether the node is a folder */
+ bool editable; /* <-- Whether the node is editable */
+ bool processing; /* <-- Internal flag used when moving */
+ struct node_element_box box; /* <-- Bounding box of all elements */
+ struct node_element data; /* <-- Data to display */
+ struct node *parent; /* <-- Parent entry (NULL for root) */
+ struct node *child; /* <-- First child */
+ struct node *previous; /* <-- Previous child of the parent */
+ struct node *next; /* <-- Next child of the parent */
+
+};
+
+struct tree {
+ unsigned int handle; /* <-- User assigned handle */
+ int offset_x; /* <-- User assigned tree x offset */
+ int offset_y; /* <-- User assigned tree y offset */
+ struct node *root; /* <-- Tree root element */
+ int width; /* <-- Tree width */
+ int height; /* <-- Tree height */
+ int window_width; /* <-- Tree window width */
+ int window_height; /* <-- Tree window height */
+ int edit_handle; /* <-- Handle for editing information */
+ bool movable; /* <-- Whether nodes can be moved */
+ struct node_element *editing; /* <-- Node element being edited */
+ char edit_buffer[256]; /* <-- Editing buffer */
+ struct node *temp_selection; /* <-- Temporarily selected node */
+};
+
+
+/* Non-platform specific code */
+void tree_initialise(struct tree *tree);
+void tree_initialise_nodes(struct node *root);
+void tree_handle_node_changed(struct tree *tree, struct node *node,
+ bool recalculate_sizes, bool expansion);
+void tree_handle_node_element_changed(struct tree *tree,
+ struct node_element *element);
+struct node *tree_get_node_at(struct node *root, int x, int y, bool *furniture);
+struct node_element *tree_get_node_element_at(struct node *node, int x, int y,
+ bool *furniture);
+struct node_element *tree_find_element(struct node *node, int user_type);
+void tree_move_selected_nodes(struct tree *tree, struct node *destination,
+ bool before);
+bool tree_has_selection(struct node *node);
+void tree_draw(struct tree *tree, int clip_x, int clip_y, int clip_width,
+ int clip_height);
+void tree_link_node(struct node *link, struct node *node, bool before);
+void tree_delink_node(struct node *node);
+struct node *tree_create_folder_node(struct node *parent, const char *title);
+struct node *tree_create_leaf_node(struct node *parent, const char *title);
+void tree_set_node_sprite(struct node *node, const char *sprite,
+ const char *expanded);
+void tree_set_node_sprite_folder(struct node *node);
+struct node *tree_create_URL_node(struct node *parent, const char *title,
+ const char *url, int filetype, int add_date, int last_date,
+ int visits);
+void tree_reset_URL_nodes(struct tree *tree, struct node *node, bool selected);
+void tree_set_node_expanded(struct node *node, bool expanded);
+void tree_set_node_selected(struct tree *tree, struct node *node,
+ bool selected);
+void tree_handle_selection_area(struct tree *tree, int x, int y, int width,
+ int height, bool invert);
+void tree_delete_selected_nodes(struct tree *tree, struct node *node);
+void tree_delete_node(struct tree *tree, struct node *node, bool siblings);
+void tree_recalculate_size(struct tree *tree);
+bool tree_handle_expansion(struct tree *tree, struct node *node, bool expanded,
+ bool folder, bool leaf);
+struct node *tree_get_selected_node(struct node *node);
+struct node *tree_get_link_details(struct tree *tree, int x, int y,
+ bool *before);
+
+
+/* Platform specific code */
+void tree_initialise_redraw(struct tree *tree);
+void tree_redraw_area(struct tree *tree, int x, int y, int width, int height);
+void tree_draw_line(struct tree *tree, int x, int y, int width, int height);
+void tree_draw_node_element(struct tree *tree, struct node_element *element);
+void tree_draw_node_expansion(struct tree *tree, struct node *node);
+void tree_recalculate_node_element(struct node_element *element);
+void tree_update_URL_node(struct node *node);
+void tree_resized(struct tree *tree);
+
+#endif
diff --git a/gtk/gtk_treeview.c b/gtk/gtk_treeview.c
new file mode 100644
index 000000000..ced83dd1c
--- /dev/null
+++ b/gtk/gtk_treeview.c
@@ -0,0 +1,96 @@
+/*
+ * This file is part of NetSurf, http://netsurf.sourceforge.net/
+ * Licensed under the GNU General Public License,
+ * http://www.opensource.org/licenses/gpl-license
+ * Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
+ */
+
+/** \file
+ * Generic tree handling (implementation).
+ */
+
+
+#include "netsurf/desktop/tree.h"
+
+
+/**
+ * Sets the origin variables to the correct values for a specified tree
+ *
+ * \param tree the tree to set the origin for
+ */
+void tree_initialise_redraw(struct tree *tree) {
+}
+
+
+/**
+ * Informs the current window manager that an area requires updating.
+ *
+ * \param tree the tree that is requesting a redraw
+ * \param x the x co-ordinate of the redraw area
+ * \param y the y co-ordinate of the redraw area
+ * \param width the width of the redraw area
+ * \param height the height of the redraw area
+ */
+void tree_redraw_area(struct tree *tree, int x, int y, int width, int height) {
+}
+
+
+/**
+ * Draws a line.
+ *
+ * \param tree the tree to draw a line for
+ * \param x the x co-ordinate
+ * \param x the y co-ordinate
+ * \param x the width of the line
+ * \param x the height of the line
+ */
+void tree_draw_line(struct tree *tree, int x, int y, int width, int height) {
+}
+
+
+/**
+ * Draws an element, including any expansion icons
+ *
+ * \param tree the tree to draw an element for
+ * \param element the element to draw
+ */
+void tree_draw_node_element(struct tree *tree, struct node_element *element) {
+}
+
+
+/**
+ * Draws an elements expansion icon
+ *
+ * \param tree the tree to draw the expansion for
+ * \param element the element to draw the expansion for
+ */
+void tree_draw_node_expansion(struct tree *tree, struct node *node) {
+}
+
+
+/**
+ * Recalculates the dimensions of a node element.
+ *
+ * \param element the element to recalculate
+ */
+void tree_recalculate_node_element(struct node_element *element) {
+}
+
+
+/**
+ * Updates the node details for a URL node.
+ * The internal node dimensions are not updated.
+ *
+ * \param node the node to update
+ */
+void tree_update_URL_node(struct node *node) {
+}
+
+
+/**
+ * Updates the tree owner following a tree resize
+ *
+ * \param tree the tree to update the owner of
+ */
+void tree_resized(struct tree *tree) {
+}
diff --git a/image/gif.c b/image/gif.c
index 8fabf5033..be59c478c 100644
--- a/image/gif.c
+++ b/image/gif.c
@@ -41,15 +41,15 @@ static void nsgif_get_frame(struct content *c);
bool nsgif_create(struct content *c, const char *params[]) {
union content_msg_data msg_data;
- /* Initialise our data structure
- */
- c->data.gif.gif = calloc(sizeof(gif_animation), 1);
- if (!c->data.gif.gif) {
+ /* Initialise our data structure
+ */
+ c->data.gif.gif = calloc(sizeof(gif_animation), 1);
+ if (!c->data.gif.gif) {
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
warn_user("NoMemory", 0);
- return false;
- }
+ return false;
+ }
c->data.gif.current_frame = 0;
return true;
}
@@ -109,9 +109,8 @@ bool nsgif_convert(struct content *c, int iwidth, int iheight) {
/* Schedule the animation if we have one
*/
- if (gif->frame_count > 1) {
+ if (gif->frame_count_partial > 1)
schedule(gif->frames[0].frame_delay, nsgif_animate, c);
- }
/* Exit as a success
*/
@@ -126,11 +125,10 @@ bool nsgif_redraw(struct content *c, int x, int y,
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
float scale, unsigned long background_colour) {
- nsgif_get_frame(c);
+ if (c->data.gif.current_frame != c->data.gif.gif->decoded_frame)
+ nsgif_get_frame(c);
c->bitmap = c->data.gif.gif->frame_image;
-
- return (c->data.gif.frame_drawn = plot.bitmap(x, y, width, height,
- c->bitmap, background_colour));
+ return plot.bitmap(x, y, width, height, c->bitmap, background_colour);
}
@@ -151,14 +149,16 @@ void nsgif_destroy(struct content *c)
* \param c the content to update
*/
void nsgif_get_frame(struct content *c) {
- int previous_frame, current_frame, frame;
+ int previous_frame, current_frame, frame;
current_frame = c->data.gif.current_frame;
- if (current_frame < c->data.gif.gif->decoded_frame) {
+ if (!option_animate_images)
+ current_frame = 0;
+ if (current_frame < c->data.gif.gif->decoded_frame)
previous_frame = 0;
- } else {
+ else
previous_frame = c->data.gif.gif->decoded_frame + 1;
- }
+
for (frame = previous_frame; frame <= current_frame; frame++)
gif_decode_frame(c->data.gif.gif, frame);
@@ -174,11 +174,11 @@ void nsgif_animate(void *p)
struct content *c = p;
union content_msg_data data;
int delay;
-
+
/* Advance by a frame, updating the loop count accordingly
*/
c->data.gif.current_frame++;
- if (c->data.gif.current_frame == (int)c->data.gif.gif->frame_count) {
+ if (c->data.gif.current_frame == (int)c->data.gif.gif->frame_count_partial) {
c->data.gif.current_frame = 0;
/* A loop count of 0 has a special meaning of infinite
@@ -186,29 +186,24 @@ void nsgif_animate(void *p)
if (c->data.gif.gif->loop_count != 0) {
c->data.gif.gif->loop_count--;
if (c->data.gif.gif->loop_count == 0) {
- c->data.gif.current_frame = c->data.gif.gif->frame_count - 1;
+ c->data.gif.current_frame = c->data.gif.gif->frame_count_partial - 1;
c->data.gif.gif->loop_count = -1;
}
}
}
- /* Animate onwards if the previous frame was used (ie it's onscreen), if not
- then we let the animation be performed by the redraw loop. By doing this
- it minimises the delay in the plot cycle, resulting in less flicker.
- */
- if (c->data.gif.frame_drawn) {
- nsgif_get_frame(c);
- c->data.gif.frame_drawn = false;
- }
-
/* Continue animating if we should
*/
if (c->data.gif.gif->loop_count >= 0) {
delay = c->data.gif.gif->frames[c->data.gif.current_frame].frame_delay;
- if (delay < option_minimum_gif_delay) delay = option_minimum_gif_delay;
+ if (delay < option_minimum_gif_delay)
+ delay = option_minimum_gif_delay;
schedule(delay, nsgif_animate, c);
}
+ if (!option_animate_images)
+ return;
+
/* area within gif to redraw */
data.redraw.x = c->data.gif.gif->frames[c->data.gif.current_frame].redraw_x;
data.redraw.y = c->data.gif.gif->frames[c->data.gif.current_frame].redraw_y;
diff --git a/image/gif.h b/image/gif.h
index db5b4b442..7c205ec3e 100644
--- a/image/gif.h
+++ b/image/gif.h
@@ -15,7 +15,6 @@ struct content;
struct content_gif_data {
struct gif_animation *gif; /**< GIF animation data */
int current_frame; /**< current frame to display [0...(max-1)] */
- bool frame_drawn; /**< set when current frame has been used */
};
bool nsgif_create(struct content *c, const char *params[]);
diff --git a/image/gifread.c b/image/gifread.c
index 77980ce25..8ca84d952 100644
--- a/image/gifread.c
+++ b/image/gifread.c
@@ -758,7 +758,7 @@ int gif_decode_frame(struct gif_animation *gif, unsigned int frame) {
*/
if ((background_action == 2) || (background_action == 3)) {
gif->dirty_frame = frame;
- LOG(("Dirty frame %i", gif->dirty_frame));
+// LOG(("Dirty frame %i", gif->dirty_frame));
}
/* Initialise the LZW decoding
diff --git a/image/mng.c b/image/mng.c
index 008e8363f..a223c7fff 100644
--- a/image/mng.c
+++ b/image/mng.c
@@ -19,6 +19,7 @@
#include "netsurf/utils/config.h"
#include "netsurf/content/content.h"
#include "netsurf/desktop/browser.h"
+#include "netsurf/desktop/options.h"
#include "netsurf/desktop/plotters.h"
#include "netsurf/image/bitmap.h"
#include "netsurf/image/mng.h"
@@ -387,7 +388,8 @@ bool nsmng_redraw(struct content *c, int x, int y,
/* Check if we need to restart the animation
*/
- if (c->data.mng.waiting) nsmng_animate(c);
+ if ((c->data.mng.waiting) && (option_animate_images))
+ nsmng_animate(c);
return ret;
}
diff --git a/makefile b/makefile
index de346e512..a3a79e5f3 100644
--- a/makefile
+++ b/makefile
@@ -22,7 +22,7 @@ OBJECTS_COMMON += css.o css_enum.o parser.o ruleset.o scanner.o # css/
OBJECTS_COMMON += box.o form.o html.o html_redraw.o layout.o \
textplain.o # render/
OBJECTS_COMMON += messages.o pool.o translit.o url.o utils.o # utils/
-OBJECTS_COMMON += imagemap.o loginlist.o options.o # desktop/
+OBJECTS_COMMON += imagemap.o loginlist.o options.o tree.o # desktop/
OBJECTS_IMAGE = jpeg.o mng.o gif.o gifread.o # image/
@@ -33,8 +33,9 @@ OBJECTS_RISCOS += 401login.o bitmap.o buffer.o debugwin.o \
gui.o help.o history.o hotlist.o image.o \
menus.o mouseactions.o plotters.o plugin.o print.o \
save.o save_complete.o save_draw.o save_text.o \
- schedule.o search.o sprite.o textselection.o theme.o thumbnail.o \
- ufont.o uri.o url_protocol.o wimp.o window.o # riscos/
+ schedule.o search.o sprite.o textselection.o theme.o \
+ thumbnail.o treeview.o ufont.o uri.o url_protocol.o \
+ wimp.o window.o # riscos/
# OBJECTS_RISCOS += memdebug.o
OBJECTS_NCOS = $(OBJECTS_RISCOS)
@@ -54,7 +55,7 @@ OBJECTS_GTK = $(OBJECTS_COMMON) $(OBJECTS_IMAGE)
OBJECTS_GTK += filetyped.o # debug/
OBJECTS_GTK += browser.o netsurf.o version.o # desktop/
OBJECTS_GTK += font_pango.o gtk_bitmap.o gtk_gui.o \
- gtk_plotters.o gtk_window.o # gtk/
+ gtk_plotters.o gtk_treeview.o gtk_window.o # gtk/
OBJDIR_RISCOS = arm-riscos-aof
@@ -162,7 +163,7 @@ utils/translit.c: transtab
# available), remove */*.[ch] from the line below.
# Under RISC OS, you may require *Set UnixFS$sfix "", if perl gives
# "No such file or directory" errors.
-depend: */*.[ch]
+depend:
@echo "--> modified files $?"
@echo "--> updating dependencies"
@-mkdir -p $(OBJDIR_RISCOS) $(OBJDIR_NCOS) $(OBJDIR_DEBUG) $(OBJDIR_GTK)
diff --git a/riscos/401login.c b/riscos/401login.c
index b2f3cf4f0..c9fe9a895 100644
--- a/riscos/401login.c
+++ b/riscos/401login.c
@@ -27,9 +27,9 @@ static void get_unamepwd(void);
static wimp_window *dialog_401_template;
extern wimp_w dialog_401li;
-static char *uname;
+static char uname[256];
static char *url;
-static char *pwd;
+static char pwd[256];
static struct browser_window *bwin;
@@ -66,8 +66,6 @@ void gui_401login_open(struct browser_window *bw, struct content *c, char *realm
void ro_gui_401login_open(wimp_w parent, char *host, char* realm, char *fetchurl)
{
url = xstrdup(fetchurl);
- uname = xcalloc(1, 256);
- pwd = xcalloc(1, 256);
uname[0] = pwd[0] = 0;
/* fill in download window icons */
@@ -128,9 +126,12 @@ void ro_gui_401login_click(wimp_pointer *pointer)
void get_unamepwd(void)
{
- char *lidets = xcalloc(strlen(uname)+strlen(pwd)+2, sizeof(char));
- if (lidets == NULL)
+ char *lidets = calloc(strlen(uname)+strlen(pwd)+2, sizeof(char));
+ if (!lidets) {
+ LOG(("Insufficient memory for calloc"));
+ warn_user("NoMemory", 0);
return;
+ }
sprintf(lidets, "%s:%s", uname, pwd);
diff --git a/riscos/gui.c b/riscos/gui.c
index b8134589f..4b5856efb 100644
--- a/riscos/gui.c
+++ b/riscos/gui.c
@@ -1,7 +1,7 @@
/*
* This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License,
- * http://www.opensource.org/licenses/gpl-license
+ * http://www.opensource.org/licenses/gpl-license
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
@@ -36,6 +36,7 @@
#include "netsurf/desktop/gui.h"
#include "netsurf/desktop/netsurf.h"
#include "netsurf/desktop/options.h"
+#include "netsurf/desktop/tree.h"
#include "netsurf/render/font.h"
#include "netsurf/render/html.h"
#include "netsurf/riscos/gui.h"
@@ -49,6 +50,7 @@
#endif
#include "netsurf/riscos/save_complete.h"
#include "netsurf/riscos/theme.h"
+#include "netsurf/riscos/treeview.h"
#ifdef WITH_URI
#include "netsurf/riscos/uri.h"
#endif
@@ -61,7 +63,7 @@
#include "netsurf/utils/utils.h"
const char *__dynamic_da_name = "NetSurf"; /**< For UnixLib. */
-int __feature_imagefs_is_file = 1; /**< For UnixLib. */
+int __feature_imagefs_is_file = 1; /**< For UnixLib. */
/* default filename handling */
int __riscosify_control = __RISCOSIFY_NO_SUFFIX |
__RISCOSIFY_NO_REVERSE_SUFFIX;
@@ -84,11 +86,11 @@ bool gui_reformat_pending = false;
gui_drag_type gui_current_drag_type;
wimp_t task_handle; /**< RISC OS wimp task handle. */
static clock_t gui_last_poll; /**< Time of last wimp_poll. */
-osspriteop_area *gui_sprites; /**< Sprite area containing pointer and hotlist sprites */
+osspriteop_area *gui_sprites; /**< Sprite area containing pointer and hotlist sprites */
/** Accepted wimp user messages. */
static wimp_MESSAGE_LIST(34) task_messages = { {
- message_HELP_REQUEST,
+ message_HELP_REQUEST,
message_DATA_SAVE,
message_DATA_SAVE_ACK,
message_DATA_LOAD,
@@ -184,7 +186,7 @@ void gui_init(int argc, char** argv)
save_complete_init();
#endif
- /* We don't have the universal boot sequence on NCOS */
+ /* We don't have the universal boot sequence on NCOS */
#ifndef ncos
options_read("Choices:WWW.NetSurf.Choices");
#else
@@ -203,8 +205,8 @@ void gui_init(int argc, char** argv)
default_stylesheet_url = strdup("file:/<NetSurf$Dir>/Resources/CSS");
adblock_stylesheet_url = strdup("file:/<NetSurf$Dir>/Resources/AdBlock");
- /* Totally pedantic, but base the taskname on the build options.
- */
+ /* Totally pedantic, but base the taskname on the build options.
+ */
#ifndef ncos
error = xwimp_initialise(wimp_VERSION_RO38, "NetSurf",
(const wimp_message_list *) &task_messages, 0,
@@ -220,7 +222,7 @@ void gui_init(int argc, char** argv)
die(error->errmess);
}
- /* We don't need to check the fonts on NCOS */
+ /* We don't need to check the fonts on NCOS */
#ifndef ncos
ro_gui_check_fonts();
#endif
@@ -231,11 +233,11 @@ void gui_init(int argc, char** argv)
xwimp_start_task("Desktop", 0);
/* Load our chosen theme
- */
- ro_gui_theme_initialise();
- descriptor = ro_gui_theme_find(option_theme);
- if (!descriptor) descriptor = ro_gui_theme_find("NetSurf");
- ro_gui_theme_apply(descriptor);
+ */
+ ro_gui_theme_initialise();
+ descriptor = ro_gui_theme_find(option_theme);
+ if (!descriptor) descriptor = ro_gui_theme_find("NetSurf");
+ ro_gui_theme_apply(descriptor);
/* Open the templates
*/
@@ -258,9 +260,10 @@ void gui_init(int argc, char** argv)
ro_gui_history_init();
wimp_close_template();
ro_gui_sprites_init();
- ro_gui_hotlist_init();
+ ro_gui_tree_initialise(); /* must be done after sprite loading */
+ ro_gui_hotlist_initialise();
- /* We don't create an Iconbar icon on NCOS */
+ /* We don't create an Iconbar icon on NCOS */
#ifndef ncos
ro_gui_icon_bar_create();
#endif
@@ -519,7 +522,7 @@ void gui_init2(int argc, char** argv)
void gui_quit(void)
{
ro_gui_window_quit();
- ro_gui_hotlist_save();
+ ro_gui_hotlist_save();
ro_gui_history_quit();
free(gui_sprites);
xwimp_close_down(task_handle);
@@ -686,10 +689,21 @@ void gui_multitask(void)
void ro_gui_poll_queue(wimp_event_no event, wimp_block *block)
{
struct ro_gui_poll_block *q =
- xcalloc(1, sizeof(struct ro_gui_poll_block));
+ calloc(1, sizeof(struct ro_gui_poll_block));
+ if (!q) {
+ LOG(("Insufficient memory for calloc"));
+ warn_user("NoMemory", 0);
+ return;
+ }
q->event = event;
- q->block = xcalloc(1, sizeof(*block));
+ q->block = calloc(1, sizeof(*block));
+ if (!q->block) {
+ free(q);
+ LOG(("Insufficient memory for calloc"));
+ warn_user("NoMemory", 0);
+ return;
+ }
memcpy(q->block, block, sizeof(*block));
q->next = NULL;
@@ -746,8 +760,8 @@ void ro_gui_redraw_window_request(wimp_draw *redraw)
if (redraw->w == history_window)
ro_gui_history_redraw(redraw);
- else if (redraw->w == hotlist_window)
- ro_gui_hotlist_redraw(redraw);
+ else if ((hotlist_tree) && (redraw->w == (wimp_w)hotlist_tree->handle))
+ ro_gui_tree_redraw(redraw, hotlist_tree);
else if ((hotlist_toolbar) && (hotlist_toolbar->toolbar_handle == redraw->w))
ro_gui_theme_redraw(hotlist_toolbar, redraw);
else if (redraw->w == dialog_debug)
@@ -757,7 +771,7 @@ void ro_gui_redraw_window_request(wimp_draw *redraw)
else if ((g = ro_gui_toolbar_lookup(redraw->w)) != NULL)
ro_gui_theme_redraw(g->toolbar, redraw);
else {
- ro_gui_dialog_redraw(redraw);
+ ro_gui_dialog_redraw(redraw);
}
}
@@ -774,6 +788,8 @@ void ro_gui_open_window_request(wimp_open *open)
g = ro_gui_window_lookup(open->w);
if (g) {
ro_gui_window_open(g, open);
+ } else if ((hotlist_tree) && (open->w == (wimp_w)hotlist_tree->handle)){
+ ro_gui_tree_open(open, hotlist_tree);
} else {
error = xwimp_open_window(open);
if (error) {
@@ -861,7 +877,7 @@ void ro_gui_mouse_click(wimp_pointer *pointer)
ro_gui_icon_bar_click(pointer);
else if (pointer->w == history_window)
ro_gui_history_click(pointer);
- else if (pointer->w == hotlist_window)
+ else if ((hotlist_tree) && (pointer->w == (wimp_w)hotlist_tree->handle))
ro_gui_hotlist_click(pointer);
else if (pointer->w == dialog_saveas)
ro_gui_save_click(pointer);
@@ -937,12 +953,12 @@ void ro_gui_drag_end(wimp_dragged *drag)
case GUI_DRAG_STATUS_RESIZE:
break;
- case GUI_DRAG_HOTLIST_SELECT:
- ro_gui_hotlist_selection_drag_end(drag);
+ case GUI_DRAG_TREE_SELECT:
+ ro_gui_tree_selection_drag_end(drag);
break;
- case GUI_DRAG_HOTLIST_MOVE:
- ro_gui_hotlist_move_drag_end(drag);
+ case GUI_DRAG_TREE_MOVE:
+ ro_gui_tree_move_drag_end(drag);
break;
}
}
@@ -958,13 +974,13 @@ void ro_gui_keypress(wimp_key *key)
struct gui_window *g;
os_error *error;
- if (key->w == hotlist_window)
+ if ((hotlist_tree) && (key->w == (wimp_w)hotlist_tree->handle)) {
handled = ro_gui_hotlist_keypress(key->c);
- else if ((g = ro_gui_window_lookup(key->w)) != NULL)
+ } else if ((g = ro_gui_window_lookup(key->w)) != NULL)
handled = ro_gui_window_keypress(g, key->c, false);
else if ((g = ro_gui_toolbar_lookup(key->w)) != NULL)
handled = ro_gui_window_keypress(g, key->c, true);
- else
+ else
handled = ro_gui_dialog_keypress(key);
if (!handled) {
@@ -1021,9 +1037,10 @@ void ro_gui_user_message(wimp_event_no event, wimp_message *message)
&message->data);
break;
case message_MENUS_DELETED:
- if (current_menu == hotlist_menu) {
+ if ((current_menu == hotlist_menu) && (hotlist_tree))
ro_gui_hotlist_menu_closed();
- }
+ current_menu = NULL;
+ current_gui = NULL;
break;
case message_MODE_CHANGE:
ro_gui_history_mode_change();
@@ -1127,10 +1144,13 @@ void ro_msg_dataload(wimp_message *message)
int file_type = message->data.data_xfer.file_type;
char *url = 0;
struct gui_window *g;
+ struct node *node;
+ struct node *link;
os_error *error;
+ int x, y;
+ bool before;
g = ro_gui_window_lookup(message->data.data_xfer.w);
-
if (g && ro_gui_window_dataload(g, message))
return;
@@ -1152,6 +1172,35 @@ void ro_msg_dataload(wimp_message *message)
else
return;
+
+ if (!url)
+ /* error has already been reported by one of the three
+ * functions called above */
+ return;
+
+ if (g) {
+ browser_window_go(g->bw, url, 0);
+ } else {
+ if ((hotlist_tree) && ((wimp_w)hotlist_tree->handle ==
+ message->data.data_xfer.w)) {
+ ro_gui_tree_get_tree_coordinates(hotlist_tree,
+ message->data.data_xfer.pos.x,
+ message->data.data_xfer.pos.y,
+ &x, &y);
+ link = tree_get_link_details(hotlist_tree, x, y, &before);
+ node = tree_create_URL_node(NULL,
+ messages_get("TreeImport"), url, file_type,
+ time(NULL), -1, 0);
+ tree_link_node(link, node, before);
+ tree_handle_node_changed(hotlist_tree, node, false, true);
+ tree_redraw_area(hotlist_tree, node->box.x - NODE_INSTEP, 0,
+ NODE_INSTEP, 16384);
+ ro_gui_tree_start_edit(hotlist_tree, &node->data, NULL);
+ } else {
+ browser_window_create(url, 0, 0);
+ }
+ }
+
/* send DataLoadAck */
message->action = message_DATA_LOAD_ACK;
message->your_ref = message->my_ref;
@@ -1163,16 +1212,6 @@ void ro_msg_dataload(wimp_message *message)
return;
}
- if (!url)
- /* error has already been reported by one of the three
- * functions called above */
- return;
-
- if (g)
- browser_window_go(g->bw, url, 0);
- else
- browser_window_create(url, 0, 0);
-
free(url);
}
diff --git a/riscos/gui.h b/riscos/gui.h
index c4d55f29a..bf5db9b85 100644
--- a/riscos/gui.h
+++ b/riscos/gui.h
@@ -19,6 +19,7 @@
#include "netsurf/desktop/netsurf.h"
#include "netsurf/desktop/gui.h"
#include "netsurf/desktop/options.h"
+#include "netsurf/desktop/tree.h"
#define THEMES_DIR "<NetSurf$Dir>.Themes"
@@ -31,7 +32,6 @@ extern wimp_w dialog_info, dialog_saveas, dialog_config, dialog_config_br,
dialog_config_th_pane, dialog_debug, dialog_folder, dialog_entry,
dialog_search, dialog_print, dialog_config_font;
extern wimp_w history_window;
-extern wimp_w hotlist_window;
extern wimp_menu *iconbar_menu, *browser_menu, *combo_menu, *hotlist_menu,
*proxyauth_menu, *languages_menu, *toolbar_menu,
*image_quality_menu;
@@ -44,6 +44,7 @@ extern osspriteop_area *gui_sprites;
extern struct toolbar *hotlist_toolbar;
extern bool dialog_folder_add, dialog_entry_add, hotlist_insert;
extern bool print_active, print_text_black;
+extern struct tree *hotlist_tree;
typedef enum {
GUI_SAVE_SOURCE,
@@ -60,7 +61,7 @@ typedef enum {
typedef enum { GUI_DRAG_SELECTION, GUI_DRAG_DOWNLOAD_SAVE,
GUI_DRAG_SAVE, GUI_DRAG_STATUS_RESIZE,
- GUI_DRAG_HOTLIST_SELECT, GUI_DRAG_HOTLIST_MOVE } gui_drag_type;
+ GUI_DRAG_TREE_SELECT, GUI_DRAG_TREE_MOVE } gui_drag_type;
extern gui_drag_type gui_current_drag_type;
@@ -86,7 +87,6 @@ struct gui_window {
/** Options. */
struct {
float scale; /**< Scale, 1.0 = 100%. */
- bool animate_images; /**< Animations should run. */
bool background_images; /**< Display background images. */
bool background_blending; /**< Perform background blending on text. */
bool buffer_animations; /**< Use screen buffering for animations. */
@@ -203,26 +203,16 @@ void ro_gui_history_click(wimp_pointer *pointer);
void ro_gui_history_mouse_at(wimp_pointer *pointer);
/* in hotlist.c */
-void ro_gui_hotlist_init(void);
+void ro_gui_hotlist_initialise(void);
void ro_gui_hotlist_save(void);
void ro_gui_hotlist_show(void);
-void ro_gui_hotlist_add(char *title, struct content *content);
-void ro_gui_hotlist_redraw(wimp_draw *redraw);
void ro_gui_hotlist_click(wimp_pointer *pointer);
-void ro_gui_hotlist_selection_drag_end(wimp_dragged *drag);
-void ro_gui_hotlist_move_drag_end(wimp_dragged *drag);
bool ro_gui_hotlist_keypress(int key);
-void ro_gui_hotlist_menu_closed(void);
void ro_gui_hotlist_toolbar_click(wimp_pointer* pointer);
-int ro_gui_hotlist_get_selected(bool folders);
-void ro_gui_hotlist_reset_statistics(void);
-void ro_gui_hotlist_set_selected(bool selected);
-void ro_gui_hotlist_set_expanded(bool expand, bool folders, bool links);
-void ro_gui_hotlist_delete_selected(void);
-void ro_gui_hotlist_save_as(const char *file);
-void ro_gui_hotlist_prepare_folder_dialog(bool selected);
-void ro_gui_hotlist_prepare_entry_dialog(bool selected);
+void ro_gui_hotlist_prepare_folder_dialog(struct node *node);
+void ro_gui_hotlist_prepare_entry_dialog(struct node *node);
void ro_gui_hotlist_dialog_click(wimp_pointer *pointer);
+void ro_gui_hotlist_menu_closed(void);
int ro_gui_hotlist_help(int x, int y);
/* in save.c */
diff --git a/riscos/help.c b/riscos/help.c
index 22fc5b09b..b6d7c0bb3 100644
--- a/riscos/help.c
+++ b/riscos/help.c
@@ -119,7 +119,7 @@ void ro_gui_interactive_help_request(wimp_message *message) {
sprintf(message_token, "HelpHotFolder%i", (int)icon);
} else if (window == dialog_entry) {
sprintf(message_token, "HelpHotEntry%i", (int)icon);
- } else if (window == hotlist_window) {
+ } else if ((hotlist_tree) && (window == (wimp_w)hotlist_tree->handle)) {
sprintf(message_token, "HelpHotlist%i",
ro_gui_hotlist_help(message_data->pos.x,
message_data->pos.y));
diff --git a/riscos/hotlist.c b/riscos/hotlist.c
index 021c5c365..055b71190 100644
--- a/riscos/hotlist.c
+++ b/riscos/hotlist.c
@@ -11,6 +11,7 @@
#include <string.h>
#include <stdbool.h>
+#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <swis.h>
@@ -22,102 +23,20 @@
#include "oslib/wimp.h"
#include "oslib/wimpspriteop.h"
#include "netsurf/content/content.h"
+#include "netsurf/desktop/tree.h"
#include "netsurf/riscos/gui.h"
#include "netsurf/riscos/theme.h"
#include "netsurf/riscos/tinct.h"
+#include "netsurf/riscos/treeview.h"
#include "netsurf/riscos/wimp.h"
#include "netsurf/utils/log.h"
#include "netsurf/utils/messages.h"
#include "netsurf/utils/utils.h"
#include "netsurf/utils/url.h"
-#define HOTLIST_EXPAND 0
-#define HOTLIST_COLLAPSE 1
-#define HOTLIST_ENTRY 2
-#define HOTLIST_LINE 3
-#define HOTLIST_TLINE 4
-#define HOTLIST_BLINE 5
-
-#define HOTLIST_TEXT_BUFFER 256
-
-#define HOTLIST_LEAF_INSET 32
-#define HOTLIST_ICON_WIDTH 36
-#define HOTLIST_LINE_HEIGHT 44
-#define HOTLIST_TEXT_PADDING 16
-
-struct hotlist_entry {
-
- /** The next hotlist entry at this level, or NULL for no more
- */
- struct hotlist_entry *next_entry;
-
- /** The child hotlist entry (NULL for no children).
- The children value must be set for this value to take effect.
- */
- struct hotlist_entry *child_entry;
-
- /** The hotlist entry that has this entry as its next entry
- */
- struct hotlist_entry *previous_entry;
-
- /** The hotlist entry that this is a child of
- */
- struct hotlist_entry *parent_entry;
-
- /** The number of children (-1 for non-folders, >=0 for folders)
- */
- int children;
-
- /** The title of the hotlist entry/folder, UTF-8.
- */
- char *title;
-
- /** The URL of the hotlist entry (NULL for folders)
- */
- char *url;
-
- /** Whether this entry is expanded
- */
- bool expanded;
-
- /** Whether this entry is selected
- */
- bool selected;
-
- /** The content filetype (not for folders)
- */
- int filetype;
-
- /** The number of visits
- */
- int visits;
-
- /** Add/last visit dates
- */
- time_t add_date;
- time_t last_date;
-
- /** Position on last reformat (relative to window origin)
- */
- int x0;
- int y0;
- int width;
- int height;
-
- /** Cached values
- */
- int collapsed_width;
- int expanded_width;
-
- /** The width of the various lines sub-text
- */
- int widths[4];
-
- /** Whether the item is awaiting processing
- */
- bool process;
-};
+static void ro_gui_hotlist_visited(struct content *content, struct tree *tree,
+ struct node *node);
/* A basic window for the toolbar and status
*/
@@ -129,7 +48,8 @@ static wimp_window hotlist_window_definition = {
wimp_WINDOW_NEW_FORMAT | wimp_WINDOW_MOVEABLE | wimp_WINDOW_BACK_ICON |
wimp_WINDOW_CLOSE_ICON | wimp_WINDOW_TITLE_ICON |
wimp_WINDOW_TOGGLE_ICON | wimp_WINDOW_SIZE_ICON |
- wimp_WINDOW_VSCROLL,
+ wimp_WINDOW_VSCROLL | wimp_WINDOW_IGNORE_XEXTENT |
+ wimp_WINDOW_IGNORE_YEXTENT,
wimp_COLOUR_BLACK,
wimp_COLOUR_LIGHT_GREY,
wimp_COLOUR_LIGHT_GREY,
@@ -138,158 +58,42 @@ static wimp_window hotlist_window_definition = {
wimp_COLOUR_MID_LIGHT_GREY,
wimp_COLOUR_CREAM,
0,
- {0, -800, 16384, 0},
+ {0, -16384, 16384, 0},
wimp_ICON_TEXT | wimp_ICON_INDIRECTED | wimp_ICON_HCENTRED |
wimp_ICON_VCENTRED,
wimp_BUTTON_DOUBLE_CLICK_DRAG << wimp_ICON_BUTTON_TYPE_SHIFT,
wimpspriteop_AREA,
1,
- 256,
+ 100,
{""},
- 0
+ 0,
+ {}
};
-/* An icon to plot text with
-*/
-static wimp_icon text_icon;
-static wimp_icon sprite_icon;
-
-/* Temporary workspace for plotting
-*/
-static char drag_name[12];
-static char icon_name[12];
-static char extended_text[HOTLIST_TEXT_BUFFER];
-
-/* Whether a reformat is pending
-*/
-static bool reformat_pending = false;
-static int max_width = 0;
-static int max_height = 0;
/* The hotlist window, toolbar and plot origins
*/
-wimp_w hotlist_window;
-struct toolbar *hotlist_toolbar = NULL;
-static int origin_x, origin_y;
-
-/* The current redraw rectangle
-*/
-static int clip_x0, clip_y0, clip_x1, clip_y1;
-
-/* The root entry
-*/
-static struct hotlist_entry root;
-
-/* The sprite header addresses for Tinct
-*/
-static char *sprite[6];
-
-/* The drag buttons
-*/
-bool dragging;
-wimp_mouse_state drag_buttons;
-
-/* Whether the current selection was from a menu click
-*/
-bool menu_selection = false;
-bool menu_open = false;
+static wimp_w hotlist_window;
+struct toolbar *hotlist_toolbar;
+struct tree *hotlist_tree;
/* Whether the editing facilities are for add so that we know how
to reset the dialog boxes on a adjust-cancel and the action to
perform on ok.
*/
-bool dialog_folder_add = false;
-bool dialog_entry_add = false;
-bool hotlist_insert = false;
-
+struct node *dialog_folder_node;
+struct node *dialog_entry_node;
-static bool ro_gui_hotlist_initialise_sprite(const char *name, int number);
-static bool ro_gui_hotlist_load(void);
-static void ro_gui_hotlist_load_file(const char *filename);
-static void ro_gui_hotlist_load_directory(xmlNode *ul,
- struct hotlist_entry *directory);
-static void ro_gui_hotlist_load_entry(xmlNode *li,
- struct hotlist_entry *directory);
-xmlNode *ro_gui_hotlist_find_element(xmlNode *node, const char *name);
-bool ro_gui_hotlist_save_directory(struct hotlist_entry *directory,
- xmlNode *node);
-bool ro_gui_hotlist_save_entry(struct hotlist_entry *entry,
- xmlNode *node);
-bool ro_gui_hotlist_save_entry_comment(xmlNode *node,
- const char *name, int value);
-static void ro_gui_hotlist_link_entry(struct hotlist_entry *link, struct hotlist_entry *entry, bool before);
-static void ro_gui_hotlist_delink_entry(struct hotlist_entry *entry);
-static void ro_gui_hotlist_delete_entry(struct hotlist_entry *entry, bool siblings);
-static void ro_gui_hotlist_visited_update(struct content *content, struct hotlist_entry *entry);
-static int ro_gui_hotlist_redraw_tree(struct hotlist_entry *entry, int level, int x0, int y0);
-static int ro_gui_hotlist_redraw_item(struct hotlist_entry *entry, int level, int x0, int y0);
-static struct hotlist_entry *ro_gui_hotlist_create_entry(const char *title, const char *url,
- int filetype, struct hotlist_entry *folder);
-static void ro_gui_hotlist_update_entry_size(struct hotlist_entry *entry);
-static struct hotlist_entry *ro_gui_hotlist_find_entry(int x, int y, struct hotlist_entry *entry);
-static int ro_gui_hotlist_selection_state(struct hotlist_entry *entry, bool selected, bool redraw);
-static void ro_gui_hotlist_selection_drag(struct hotlist_entry *entry,
- int x0, int y0, int x1, int y1,
- bool toggle, bool redraw);
-static int ro_gui_hotlist_selection_count(struct hotlist_entry *entry, bool folders);
-static void ro_gui_hotlist_update_expansion(struct hotlist_entry *entry, bool only_selected,
- bool folders, bool links, bool expand, bool contract);
-static void ro_gui_hotlist_launch_selection(struct hotlist_entry *entry);
-static void ro_gui_hotlist_invalidate_statistics(struct hotlist_entry *entry);
-static struct hotlist_entry *ro_gui_hotlist_first_selection(struct hotlist_entry *entry);
-static void ro_gui_hotlist_selection_to_process(struct hotlist_entry *entry);
-static bool ro_gui_hotlist_move_processing(struct hotlist_entry *entry, struct hotlist_entry *destination, bool before);
-
-#define hotlist_ensure_sprite(buffer, fallback) if (xwimpspriteop_read_sprite_info(buffer, 0, 0, 0, 0)) sprintf(buffer, fallback)
-#define hotlist_redraw_entry(entry, full) xwimp_force_redraw(hotlist_window, full ? 0 : entry->x0, \
- full ? -16384 : entry->y0, full ? 16384 : entry->x0 + entry->expanded_width, entry->y0 + entry->height);
-#define hotlist_redraw_entry_title(entry) xwimp_force_redraw(hotlist_window, entry->x0, \
- entry->y0 + entry->height - HOTLIST_LINE_HEIGHT, entry->x0 + entry->width, entry->y0 + entry->height);
-
-
-
-void ro_gui_hotlist_init(void) {
+void ro_gui_hotlist_initialise(void) {
+ FILE *fp;
const char *title;
- os_box extent = {0, 0, 0, 0};
os_error *error;
-
- /* Set the initial root options
- */
- root.next_entry = NULL;
- root.child_entry = NULL;
- root.children = 0;
- root.expanded = true;
-
- /* Load the hotlist
- */
- if (!ro_gui_hotlist_load()) return;
-
- /* Get our sprite ids for faster plotting.
- */
- if (ro_gui_hotlist_initialise_sprite("expand", HOTLIST_EXPAND) ||
- ro_gui_hotlist_initialise_sprite("collapse", HOTLIST_COLLAPSE) ||
- ro_gui_hotlist_initialise_sprite("entry", HOTLIST_ENTRY) ||
- ro_gui_hotlist_initialise_sprite("line", HOTLIST_LINE) ||
- ro_gui_hotlist_initialise_sprite("halflinet", HOTLIST_TLINE) ||
- ro_gui_hotlist_initialise_sprite("halflineb", HOTLIST_BLINE)) {
- return;
- }
-
- /* Update our text icon
- */
- text_icon.data.indirected_text.validation = (char *) -1;
- text_icon.data.indirected_text.size = 256;
- sprite_icon.flags = wimp_ICON_SPRITE | wimp_ICON_INDIRECTED |
- wimp_ICON_HCENTRED | wimp_ICON_VCENTRED |
- (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) |
- (wimp_COLOUR_VERY_LIGHT_GREY << wimp_ICON_BG_COLOUR_SHIFT);
- sprite_icon.data.indirected_sprite.area = wimpspriteop_AREA;
- sprite_icon.data.indirected_text.size = 12;
+ struct node *node;
/* Create our window
*/
title = messages_get("Hotlist");
- hotlist_window_definition.title_data.indirected_text.text = title;
+ hotlist_window_definition.title_data.indirected_text.text = strdup(title);
hotlist_window_definition.title_data.indirected_text.validation =
(char *) -1;
hotlist_window_definition.title_data.indirected_text.size = strlen(title);
@@ -299,47 +103,70 @@ void ro_gui_hotlist_init(void) {
error->errnum, error->errmess));
die(error->errmess);
}
+
+ /* Either load or create a hotlist
+ */
+ fp = fopen("Choices:WWW.NetSurf.Hotlist", "r");
+ if (!fp) {
+ hotlist_tree = calloc(sizeof(struct tree), 1);
+ if (!hotlist_tree) {
+ warn_user("NoMemory", 0);
+ return;
+ }
+ hotlist_tree->root = tree_create_folder_node(NULL, "Root");
+ if (!hotlist_tree->root) {
+ warn_user("NoMemory", 0);
+ free(hotlist_tree);
+ hotlist_tree = NULL;
+ }
+ hotlist_tree->root->expanded = true;
+ node = tree_create_folder_node(hotlist_tree->root, "NetSurf");
+ if (!node)
+ node = hotlist_tree->root;
+ tree_create_URL_node(node, messages_get("HotlistHomepage"),
+ "http://netsurf.sourceforge.net/", 0xfaf,
+ time(NULL), -1, 0);
+ tree_create_URL_node(node, messages_get("HotlistTestBuild"),
+ "http://netsurf.strcprstskrzkrk.co.uk/", 0xfaf,
+ time(NULL), -1, 0);
+ tree_initialise(hotlist_tree);
+ } else {
+ fclose(fp);
+ hotlist_tree = options_load_hotlist("Choices:WWW.NetSurf.Hotlist");
+ }
+ if (!hotlist_tree) return;
+ hotlist_tree->handle = (int)hotlist_window;
/* Create our toolbar
*/
hotlist_toolbar = ro_gui_theme_create_toolbar(NULL, THEME_HOTLIST_TOOLBAR);
- ro_gui_theme_attach_toolbar(hotlist_toolbar, hotlist_window);
-
- /* Update the extent
- */
if (hotlist_toolbar) {
- extent.x1 = 16384;
- extent.y1 = hotlist_toolbar->height;
- extent.y0 = -16384;
- error = xwimp_set_extent(hotlist_window, &extent);
- if (error) {
- LOG(("xwimp_set_extent: 0x%x: %s",
- error->errnum, error->errmess));
- die(error->errmess);
- }
- reformat_pending = true;
- }
+ ro_gui_theme_attach_toolbar(hotlist_toolbar, hotlist_window);
+ hotlist_tree->offset_y = hotlist_toolbar->height;
+ }
}
+
/**
- * Initialise a hotlist sprite for use with Tinct
- *
- * \param name the name of the sprite
- * \param number the sprite cache number
- * \return whether an error occurred
+ * Perform a save to the default file
*/
-bool ro_gui_hotlist_initialise_sprite(const char *name, int number) {
- os_error *error;
- sprintf(icon_name, "tr_%s", name);
- error = xosspriteop_select_sprite(osspriteop_USER_AREA, gui_sprites,
- (osspriteop_id)icon_name,
- (osspriteop_header **)&sprite[number]);
- if (error) {
- warn_user("MiscError", error->errmess);
- LOG(("Failed to load hotlist sprite 'tr_%s'", name));
- return true;
- }
- return false;
+void ro_gui_hotlist_save(void) {
+ os_error *error;
+
+ if (!hotlist_tree) return;
+
+ /* Ensure we have a directory to save to later.
+ */
+ xosfile_create_dir("<Choices$Write>.WWW", 0);
+ xosfile_create_dir("<Choices$Write>.WWW.NetSurf", 0);
+
+ /* Save to our file
+ */
+ options_save_hotlist(hotlist_tree, "<Choices$Write>.WWW.NetSurf.Hotlist");
+ error = xosfile_set_type("<Choices$Write>.WWW.NetSurf.Hotlist", 0xfaf);
+ if (error)
+ LOG(("xosfile_set_type: 0x%x: %s",
+ error->errnum, error->errmess));
}
@@ -355,7 +182,7 @@ void ro_gui_hotlist_show(void) {
/* We may have failed to initialise
*/
- if (!hotlist_window) return;
+ if (!hotlist_tree) return;
/* Get the window state
*/
@@ -370,10 +197,16 @@ void ro_gui_hotlist_show(void) {
open in the centre of the screen.
*/
if (!(state.flags & wimp_WINDOW_OPEN)) {
- /* Clear the selection/expansion states
- */
- ro_gui_hotlist_update_expansion(root.child_entry, false, true, true, false, true);
- ro_gui_hotlist_selection_state(root.child_entry, false, false);
+
+ /* Cancel any editing
+ */
+ ro_gui_tree_stop_edit(hotlist_tree);
+
+ /* Set the default state
+ */
+ if (hotlist_tree->root->child)
+ tree_handle_node_changed(hotlist_tree, hotlist_tree->root,
+ false, true);
/* Get the current screen size
*/
@@ -381,11 +214,11 @@ void ro_gui_hotlist_show(void) {
/* Move to the centre
*/
- dimension = state.visible.x1 - state.visible.x0;
+ dimension = 600; /*state.visible.x1 - state.visible.x0;*/
scroll_width = ro_get_vscroll_width(hotlist_window);
state.visible.x0 = (screen_width - (dimension + scroll_width)) / 2;
state.visible.x1 = state.visible.x0 + dimension;
- dimension = state.visible.y1 - state.visible.y0;
+ dimension = 800; /*state.visible.y1 - state.visible.y0;*/
state.visible.y0 = (screen_height - dimension) / 2;
state.visible.y1 = state.visible.y0 + dimension;
state.xscroll = 0;
@@ -397,2109 +230,228 @@ void ro_gui_hotlist_show(void) {
*/
ro_gui_menu_prepare_hotlist();
state.next = wimp_TOP;
- error = xwimp_open_window((wimp_open*)&state);
- if (error) {
- warn_user("WimpError", error->errmess);
- return;
- }
+ ro_gui_tree_open((wimp_open*)&state, hotlist_tree);
/* Set the caret position
*/
- xwimp_set_caret_position(state.w, -1, -100,
- -100, 32, -1);
-}
-
-
-bool ro_gui_hotlist_load(void) {
- fileswitch_object_type obj_type = 0;
- struct hotlist_entry *netsurf;
- struct hotlist_entry *entry;
-
- /* Check if we have an initial hotlist. OS_File does funny things relating to errors,
- so we use the object type to determine success
- */
- xosfile_read_stamped_no_path("Choices:WWW.NetSurf.Hotlist", &obj_type,
- (bits)0, (bits)0, (int *)0, (fileswitch_attr)0, (bits)0);
- if (obj_type == fileswitch_IS_FILE) {
- ro_gui_hotlist_load_file("Choices:WWW.NetSurf.Hotlist");
- return true;
-
- } else {
- /* Create a folder
- */
- netsurf = ro_gui_hotlist_create_entry("NetSurf", NULL, 0, &root);
- if (!netsurf)
- return false;
-
- /* Add some content
- */
- entry = ro_gui_hotlist_create_entry("NetSurf homepage",
- "http://netsurf.sourceforge.net/",
- 0xfaf, netsurf);
- if (!entry)
- return false;
- entry->add_date = (time_t) -1;
- entry = ro_gui_hotlist_create_entry("NetSurf test builds",
- "http://netsurf.strcprstskrzkrk.co.uk/",
- 0xfaf, netsurf);
- if (!entry)
- return false;
- entry->add_date = (time_t) -1;
-
- /* We succeeded
- */
- return true;
- }
-}
-
-
-/**
- * Load the hotlist from file.
- *
- * \param filename name of file to read
- */
-
-void ro_gui_hotlist_load_file(const char *filename)
-{
- xmlDoc *doc;
- xmlNode *html, *body, *ul;
-
- doc = htmlParseFile(filename, "iso-8859-1");
- if (!doc) {
- warn_user("HotlistLoadError", messages_get("ParsingFail"));
- return;
- }
-
- html = ro_gui_hotlist_find_element((xmlNode *) doc, "html");
- body = ro_gui_hotlist_find_element(html, "body");
- ul = ro_gui_hotlist_find_element(body, "ul");
- if (!ul) {
- xmlFreeDoc(doc);
- warn_user("HotlistLoadError",
- "(<html>...<body>...<ul> not found.)");
- return;
- }
-
- ro_gui_hotlist_load_directory(ul, &root);
-
- xmlFreeDoc(doc);
-}
-
-
-/**
- * Parse a directory represented as a ul.
- *
- * \param ul xmlNode for parsed ul
- * \param directory directory to add this directory to
- */
-
-void ro_gui_hotlist_load_directory(xmlNode *ul,
- struct hotlist_entry *directory)
-{
- char *title;
- struct hotlist_entry *dir;
- xmlNode *n;
-
- for (n = ul->children; n; n = n->next) {
- /* The ul may contain entries as a li, or directories as
- * an h4 followed by a ul. Non-element nodes may be present
- * (eg. text, comments), and are ignored. */
-
- if (n->type != XML_ELEMENT_NODE)
- continue;
-
- if (strcmp(n->name, "li") == 0) {
- /* entry */
- ro_gui_hotlist_load_entry(n, directory);
-
- } else if (strcmp(n->name, "h4") == 0) {
- /* directory */
- title = (char *) xmlNodeGetContent(n);
- if (!title) {
- warn_user("HotlistLoadError", "(Empty <h4> "
- "or memory exhausted.)");
- return;
- }
-
- for (n = n->next;
- n && n->type != XML_ELEMENT_NODE;
- n = n->next)
- ;
- if (!n || strcmp(n->name, "ul") != 0) {
- /* next element isn't expected ul */
- free(title);
- warn_user("HotlistLoadError", "(Expected "
- "<ul> not present.)");
- return;
- }
-
- dir = ro_gui_hotlist_create_entry(title, NULL, 0,
- directory);
- if (!dir)
- return;
- ro_gui_hotlist_load_directory(n, dir);
- }
- }
-}
-
-
-/**
- * Parse an entry represented as a li.
- *
- * \param li xmlNode for parsed li
- * \param directory directory to add this entry to
- */
-
-void ro_gui_hotlist_load_entry(xmlNode *li,
- struct hotlist_entry *directory)
-{
- char *url = 0;
- char *title = 0;
- int filetype = 0xfaf;
- int add_date = -1;
- int last_date = -1;
- int visits = 0;
- char *comment;
- struct hotlist_entry *entry;
- xmlNode *n;
-
- for (n = li->children; n; n = n->next) {
- /* The li must contain an "a" element, and may contain
- * some additional data as comments. */
-
- if (n->type == XML_ELEMENT_NODE &&
- strcmp(n->name, "a") == 0) {
- url = (char *) xmlGetProp(n, (const xmlChar *) "href");
- title = (char *) xmlNodeGetContent(n);
-
- } else if (n->type == XML_COMMENT_NODE) {
- comment = (char *) xmlNodeGetContent(n);
- if (!comment)
- continue;
- if (strncmp("Type:", comment, 5) == 0)
- filetype = atoi(comment + 5);
- else if (strncmp("Added:", comment, 6) == 0)
- add_date = atoi(comment + 6);
- else if (strncmp("LastVisit:", comment, 10) == 0)
- last_date = atoi(comment + 10);
- else if (strncmp("Visits:", comment, 7) == 0)
- visits = atoi(comment + 7);
- }
- }
-
- if (!url || !title) {
- warn_user("HotlistLoadError", "(Missing <a> in <li> or "
- "memory exhausted.)");
- return;
- }
-
- entry = ro_gui_hotlist_create_entry(title, url, filetype, directory);
- if (!entry)
- return;
- entry->add_date = add_date;
- entry->last_date = last_date;
- entry->visits = visits;
-}
-
-
-/**
- * Search the children of an xmlNode for an element.
- *
- * \param node xmlNode to search children of, or 0
- * \param name name of element to find
- * \return first child of node which is an element and matches name, or
- * 0 if not found or parameter node is 0
- */
-
-xmlNode *ro_gui_hotlist_find_element(xmlNode *node, const char *name)
-{
- xmlNode *n;
- if (!node)
- return 0;
- for (n = node->children;
- n && !(n->type == XML_ELEMENT_NODE &&
- strcmp(n->name, name) == 0);
- n = n->next)
- ;
- return n;
-}
-
-
-/**
- * Perform a save to the default file
- */
-
-void ro_gui_hotlist_save(void) {
- /* Don't save if we didn't load
- */
- if (!hotlist_window) return;
-
- /* Ensure we have a directory to save to later.
- */
- xosfile_create_dir("<Choices$Write>.WWW", 0);
- xosfile_create_dir("<Choices$Write>.WWW.NetSurf", 0);
-
- /* Save to our file
- */
- ro_gui_hotlist_save_as("<Choices$Write>.WWW.NetSurf.Hotlist");
-}
-
-
-/**
- * Perform a save to a specified file
- *
- * /param filename the file to save to
- */
-
-void ro_gui_hotlist_save_as(const char *filename)
-{
- int res;
- xmlDoc *doc;
- xmlNode *html, *head, *title, *body;
-
- /* Unfortunately the Browse Hotlist format is invalid HTML,
- * so this is a lie. */
- doc = htmlNewDoc("http://www.w3.org/TR/html4/strict.dtd",
- "-//W3C//DTD HTML 4.01//EN");
- if (!doc) {
- warn_user("NoMemory", 0);
- return;
- }
-
- html = xmlNewNode(NULL, "html");
- if (!html) {
- warn_user("NoMemory", 0);
- xmlFreeDoc(doc);
- return;
- }
- xmlDocSetRootElement(doc, html);
-
- head = xmlNewChild(html, NULL, "head", NULL);
- if (!head) {
- warn_user("NoMemory", 0);
- xmlFreeDoc(doc);
- return;
- }
-
- title = xmlNewTextChild(head, NULL, "title", "NetSurf Hotlist");
- if (!title) {
- warn_user("NoMemory", 0);
- xmlFreeDoc(doc);
- return;
- }
-
- body = xmlNewChild(html, NULL, "body", NULL);
- if (!body) {
- warn_user("NoMemory", 0);
- xmlFreeDoc(doc);
- return;
- }
-
- if (!ro_gui_hotlist_save_directory(&root, body)) {
- warn_user("NoMemory", 0);
- xmlFreeDoc(doc);
- return;
- }
-
- doc->charset = XML_CHAR_ENCODING_UTF8;
- res = htmlSaveFileEnc(filename, doc, "iso-8859-1");
- if (res == -1) {
- warn_user("HotlistSaveError", 0);
- xmlFreeDoc(doc);
- return;
- }
-
- xmlFreeDoc(doc);
-
- xosfile_set_type(filename, 0xfaf);
-}
-
-
-/**
- * Add a directory to the HTML tree for saving.
- *
- * \param directory hotlist directory to add
- * \param node node to add ul to
- * \return true on success, false on memory exhaustion
- */
-
-bool ro_gui_hotlist_save_directory(struct hotlist_entry *directory,
- xmlNode *node)
-{
- struct hotlist_entry *child;
- xmlNode *ul, *h4;
-
- ul = xmlNewChild(node, NULL, "ul", NULL);
- if (!ul)
- return false;
-
- for (child = directory->child_entry; child; child = child->next_entry) {
- if (child->url) {
- /* entry */
- if (!ro_gui_hotlist_save_entry(child, ul))
- return false;
-
- } else {
- /* directory */
- /* invalid HTML */
- h4 = xmlNewTextChild(ul, NULL, "h4", child->title);
- if (!h4)
- return false;
-
- if (!ro_gui_hotlist_save_directory(child, ul))
- return false;
- }
- }
-
- return true;
-}
-
-
-/**
- * Add an entry to the HTML tree for saving.
- *
- * \param entry hotlist entry to add
- * \param node node to add li to
- * \return true on success, false on memory exhaustion
- */
-
-bool ro_gui_hotlist_save_entry(struct hotlist_entry *entry,
- xmlNode *node)
-{
- xmlNode *li, *a;
- xmlAttr *href;
-
- li = xmlNewChild(node, NULL, "li", NULL);
- if (!li)
- return false;
-
- a = xmlNewTextChild(li, NULL, "a", entry->title);
- if (!a)
- return false;
-
- href = xmlNewProp(a, "href", entry->url);
- if (!href)
- return false;
-
- if (entry->filetype != 0xfaf)
- if (!ro_gui_hotlist_save_entry_comment(li,
- "Type", entry->filetype))
- return false;
-
- if (entry->add_date != -1)
- if (!ro_gui_hotlist_save_entry_comment(li,
- "Added", entry->add_date))
- return false;
-
- if (entry->last_date != -1)
- if (!ro_gui_hotlist_save_entry_comment(li,
- "LastVisit", entry->last_date))
- return false;
-
- if (entry->visits != 0)
- if (!ro_gui_hotlist_save_entry_comment(li,
- "Visits", entry->visits))
- return false;
-
- return true;
-}
-
-
-/**
- * Add a special comment node to the HTML tree for saving.
- *
- * \param node node to add comment to
- * \param name name of special comment
- * \param value value of special comment
- * \return true on success, false on memory exhaustion
- */
-
-bool ro_gui_hotlist_save_entry_comment(xmlNode *node,
- const char *name, int value)
-{
- char s[40];
- xmlNode *comment;
-
- snprintf(s, sizeof s, "%s:%i", name, value);
- s[sizeof s - 1] = 0;
-
- comment = xmlNewComment(s);
- if (!comment)
- return false;
- if (!xmlAddChild(node, comment)) {
- xmlFreeNode(comment);
- return false;
- }
-
- return true;
-}
-
-
-/**
- * Adds a hotlist entry to the root of the tree.
- *
- * \param title the entry title
- * \param content the content to add
- */
-void ro_gui_hotlist_add(char *title, struct content *content) {
- ro_gui_hotlist_create_entry(title, content->url, ro_content_filetype(content), &root);
-}
-
-
-/**
- * Informs the hotlist that some content has been visited
- *
- * \param content the content visited
- */
-void hotlist_visited(struct content *content) {
- if ((!content) || (!content->url)) return;
- ro_gui_hotlist_visited_update(content, root.child_entry);
-}
-
-
-/**
- * Informs the hotlist that some content has been visited (internal)
- *
- * \param content the content visited
- * \param entry the entry to check siblings and children of
- */
-void ro_gui_hotlist_visited_update(struct content *content, struct hotlist_entry *entry) {
- char *url;
- bool full = false;
-
- /* Update the hotlist
- */
- url = content->url;
- while (entry) {
- if ((entry->url) && (strcmp(url, entry->url) == 0)) {
- /* Check if we're going to need a full redraw downwards
- */
- full = ((entry->visits == 0) || (entry->last_date == -1));
-
- /* Update our values
- */
- if (entry->children == -1) entry->filetype = ro_content_filetype(content);
- entry->visits++;
- entry->last_date = time(NULL);
- ro_gui_hotlist_update_entry_size(entry);
-
- /* Redraw the least we can get away with
- */
- if (entry->expanded) hotlist_redraw_entry(entry, full);
- }
- if (entry->child_entry) ro_gui_hotlist_visited_update(content, entry->child_entry);
- entry = entry->next_entry;
- }
-}
-
-
-/**
- * Adds a hotlist entry to a folder of the tree.
- *
- * \param title the entry title (copied)
- * \param url the entry url (NULL to create a folder) (copied)
- * \param filetype filetype of entry
- * \param folder the folder to add the entry into
- * \return the new entry, or NULL on error and error reported
- */
-struct hotlist_entry *ro_gui_hotlist_create_entry(const char *title,
- const char *url, int filetype,
- struct hotlist_entry *folder) {
- struct hotlist_entry *entry;
- url_func_result res;
-
- /* Check we have a title or a URL
- */
- if (!title && !url) return NULL;
-
- /* Allocate some memory
- */
- entry = (struct hotlist_entry *)calloc(1, sizeof(struct hotlist_entry));
- if (!entry) {
- warn_user("NoMemory", 0);
- return NULL;
- }
-
- /* Normalise the URL and add the title if we have one, or
- use the URL instead
- */
- entry->url = 0;
- if ((url) && ((res = url_normalize(url, &entry->url)) != URL_FUNC_OK)) {
- /** \todo use correct error message */
- warn_user("NoMemory", 0);
- free(entry->url);
- free(entry);
- return NULL;
- }
- if (title) {
- entry->title = squash_whitespace(title);
- if (!entry->title) {
- warn_user("NoMemory", 0);
- free(entry->url);
- free(entry);
- return NULL;
- }
- entry->title = strip(entry->title);
- } else {
- entry->title = strdup(entry->url);
- if (!entry->title) {
- warn_user("NoMemory", 0);
- free(entry->url);
- free(entry);
- return NULL;
- }
- }
-
- /* Set the other values
- */
- entry->children = (url == NULL) ? 0 : -1;
- entry->filetype = filetype;
- entry->visits = 0;
- entry->add_date = time(NULL);
- entry->last_date = (time_t)-1;
- ro_gui_hotlist_update_entry_size(entry);
-
- /* Link into the tree
- */
- ro_gui_hotlist_link_entry(folder, entry, false);
- return entry;
-}
-
-
-/**
- * Links a hotlist entry into the tree.
- *
- * \param link the entry to link as a child (folders) or before/after (link)
- * \param entry the entry to link
- * \param before whether to link siblings before or after the supplied link
- */
-void ro_gui_hotlist_link_entry(struct hotlist_entry *link, struct hotlist_entry *entry, bool before) {
- struct hotlist_entry *link_entry;
-
- if ((!link || !entry) || (link == entry)) return;
-
- /* Check if the parent is a folder or an entry
- */
- if (link->children == -1) {
- entry->parent_entry = link->parent_entry;
- entry->parent_entry->children++;
- if (before) {
- entry->next_entry = link;
- entry->previous_entry = link->previous_entry;
- if (link->previous_entry) link->previous_entry->next_entry = entry;
- link->previous_entry = entry;
- if (link->parent_entry) {
- if (link->parent_entry->child_entry == link) {
- link->parent_entry->child_entry = entry;
- }
- }
- } else {
- entry->previous_entry = link;
- entry->next_entry = link->next_entry;
- if (link->next_entry) link->next_entry->previous_entry = entry;
- link->next_entry = entry;
- }
- } else {
- link_entry = link->child_entry;
-
- /* Link into the tree as a child at the end
- */
- if (!link_entry) {
- link->child_entry = entry;
- entry->previous_entry = NULL;
- } else {
- while (link_entry->next_entry) link_entry = link_entry->next_entry;
- link_entry->next_entry = entry;
- entry->previous_entry = link_entry;
- }
-
- /* Update the links
- */
- entry->parent_entry = link;
- entry->next_entry = NULL;
-
- /* Increment the number of children
- */
- link->children += 1;
- }
-
- /* Force a redraw
- */
- reformat_pending = true;
- xwimp_force_redraw(hotlist_window, 0, -16384, 16384, 0);
-}
-
-
-/**
- * De-links a hotlist entry from the tree.
- *
- * \param entry the entry to de-link
- */
-void ro_gui_hotlist_delink_entry(struct hotlist_entry *entry) {
- if (!entry) return;
-
- /* Sort out if the entry was the initial child reference
- */
- if (entry->parent_entry) {
- entry->parent_entry->children -= 1;
- if (entry->parent_entry->children == 0) entry->parent_entry->expanded = false;
- if (entry->parent_entry->child_entry == entry) {
- entry->parent_entry->child_entry = entry->next_entry;
- }
- entry->parent_entry = NULL;
- }
-
- /* Remove the entry from siblings
- */
- if (entry->previous_entry) {
- entry->previous_entry->next_entry = entry->next_entry;
- }
- if (entry->next_entry) {
- entry->next_entry->previous_entry = entry->previous_entry;
- }
- entry->previous_entry = NULL;
- entry->next_entry = NULL;
-
- /* Force a redraw
- */
- reformat_pending = true;
- xwimp_force_redraw(hotlist_window, 0, -16384, 16384, 0);
-}
-
-
-/**
- * Delete an entry and all children
- * This function also performs any necessary delinking
- *
- * \param entry the entry to delete
- * \param siblings delete all following siblings
- */
-void ro_gui_hotlist_delete_entry(struct hotlist_entry *entry, bool siblings) {
- struct hotlist_entry *next_entry = NULL;
- while (entry) {
-
- /* Recurse to children first
- */
- if (entry->child_entry) ro_gui_hotlist_delete_entry(entry->child_entry, true);
-
- /* Free our memory
- */
- free(entry->url);
- free(entry->title);
-
- /* Get the next entry before we de-link and delete
- */
- if (siblings) next_entry = entry->next_entry;
-
- /* Delink and delete our entry and move on
- */
- ro_gui_hotlist_delink_entry(entry);
- free(entry);
- entry = next_entry;
- }
-}
-
-
-/**
- * Updates and entrys size
- */
-void ro_gui_hotlist_update_entry_size(struct hotlist_entry *entry) {
- int width;
- int max_width;
- int line_number = 0;
-
- /* Get the width of the title
- */
- xwimptextop_string_width(entry->title,
- strlen(entry->title) > 256 ? 256 : strlen(entry->title),
- &width);
- entry->collapsed_width = width;
- max_width = width;
-
- /* Get the width of the URL
- */
- if (entry->url) {
- snprintf(extended_text, HOTLIST_TEXT_BUFFER,
- messages_get("HotlistURL"), entry->url);
- if (strlen(extended_text) >= 255) {
- extended_text[252] = '.';
- extended_text[253] = '.';
- extended_text[254] = '.';
- extended_text[255] = '\0';
- }
- xwimptextop_string_width(extended_text,
- strlen(extended_text) > 256 ? 256 : strlen(extended_text),
- &width);
- if (width > max_width) max_width = width;
- entry->widths[line_number++] = width;
- }
-
- /* Get the width of the add date
- */
- if (entry->add_date != -1) {
- snprintf(extended_text, HOTLIST_TEXT_BUFFER,
- messages_get("HotlistAdded"), ctime(&entry->add_date));
- xwimptextop_string_width(extended_text,
- strlen(extended_text) > 256 ? 256 : strlen(extended_text),
- &width);
- if (width > max_width) max_width = width;
- entry->widths[line_number++] = width;
- }
-
- /* Get the width of the last visit
- */
- if (entry->last_date != -1) {
- snprintf(extended_text, HOTLIST_TEXT_BUFFER,
- messages_get("HotlistLast"), ctime(&entry->last_date));
- xwimptextop_string_width(extended_text,
- strlen(extended_text) > 256 ? 256 : strlen(extended_text),
- &width);
- if (width > max_width) max_width = width;
- entry->widths[line_number++] = width;
- }
-
- /* Get the width of the visit count
- */
- if (entry->visits > 0) {
- snprintf(extended_text, HOTLIST_TEXT_BUFFER,
- messages_get("HotlistVisits"), entry->visits);
- xwimptextop_string_width(extended_text,
- strlen(extended_text) > 256 ? 256 : strlen(extended_text),
- &width);
- if (width > max_width) max_width = width;
- entry->widths[line_number++] = width;
- }
-
- /* Increase the text width by the borders
- */
- entry->expanded_width = max_width + HOTLIST_LEAF_INSET + HOTLIST_ICON_WIDTH + HOTLIST_TEXT_PADDING;
- entry->collapsed_width += HOTLIST_LEAF_INSET + HOTLIST_ICON_WIDTH + HOTLIST_TEXT_PADDING;
- reformat_pending = true;
-}
-
-
-/**
- * Redraws a section of the hotlist window
- *
- * \param redraw the area to redraw
- */
-void ro_gui_hotlist_redraw(wimp_draw *redraw) {
- wimp_window_state state;
- osbool more;
- os_box extent = {0, 0, 0, 0};;
-
- /* Reset our min/max sizes
- */
- max_width = 0;
- max_height = 0;
-
- /* Redraw each rectangle
- */
- more = wimp_redraw_window(redraw);
- while (more) {
- clip_x0 = redraw->clip.x0;
- clip_y0 = redraw->clip.y0;
- clip_x1 = redraw->clip.x1;
- clip_y1 = redraw->clip.y1;
- origin_x = redraw->box.x0 - redraw->xscroll;
- origin_y = redraw->box.y1 - redraw->yscroll;
- ro_gui_hotlist_redraw_tree(root.child_entry, 0,
- origin_x + 8, origin_y - 4);
- more = wimp_get_rectangle(redraw);
- }
-
- /* Check if we should reformat
- */
- if (reformat_pending) {
- max_width += 8;
- max_height -= 4;
- if (max_width < 600) max_width = 600;
- if (max_height > -800) max_height = -800;
- extent.x1 = max_width;
- extent.y0 = max_height;
- if (hotlist_toolbar) {
- extent.y1 += hotlist_toolbar->height;
- }
- xwimp_set_extent(hotlist_window, &extent);
- state.w = hotlist_window;
- wimp_get_window_state(&state);
- wimp_open_window((wimp_open *) &state);
- reformat_pending = false;
- }
-}
-
-
-/**
- * Redraws a section of the hotlist window (non-WIMP interface)
- *
- * \param entry the entry to draw descendants and siblings of
- * \param level the tree level of the entry
- * \param x0 the x co-ordinate to plot from
- * \param y0 the y co-ordinate to plot from
- * \returns the height of the tree
- */
-int ro_gui_hotlist_redraw_tree(struct hotlist_entry *entry, int level, int x0, int y0) {
- bool first = true;
- int cumulative = 0;
- int height = 0;
- int box_y0;
-
- if (!entry) return 0;
-
- /* Repeatedly draw our entries
- */
- while (entry) {
-
- /* Redraw the item
- */
- height = ro_gui_hotlist_redraw_item(entry, level, x0 + HOTLIST_LEAF_INSET, y0);
- box_y0 = y0;
- cumulative += height;
-
- /* Update the entry position
- */
- if (entry->children == -1) {
- entry->height = height;
- } else {
- entry->height = HOTLIST_LINE_HEIGHT;
- }
- entry->x0 = x0 - origin_x;
- entry->y0 = y0 - origin_y - entry->height;
- if (entry->expanded) {
- entry->width = entry->expanded_width;
- } else {
- entry->width = entry->collapsed_width;
- }
-
- /* Get the maximum extents
- */
- if ((x0 + entry->width) > (max_width + origin_x))
- max_width = x0 + entry->width - origin_x;
- if ((y0 - height) < (max_height + origin_y))
- max_height = y0 - height - origin_y;
-
- /* Draw the vertical links
- */
- if (entry->next_entry) {
- /* Draw a half-line for the first entry in the top tree
- */
- if (first && (level == 0)) {
- _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
- sprite[HOTLIST_BLINE], x0 + 8, y0 - HOTLIST_LINE_HEIGHT,
- tinct_BILINEAR_FILTER);
- y0 -= HOTLIST_LINE_HEIGHT;
- height -= HOTLIST_LINE_HEIGHT;
- }
-
- /* Draw the rest of the lines
- */
- while (height > 0) {
- _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
- sprite[HOTLIST_LINE], x0 + 8, y0 - HOTLIST_LINE_HEIGHT,
- tinct_BILINEAR_FILTER);
- y0 -= HOTLIST_LINE_HEIGHT;
- height -= HOTLIST_LINE_HEIGHT;
- }
-
- } else {
- /* Draw a half-line for the last entry
- */
- if (!first || (level != 0)) {
- _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
- sprite[HOTLIST_TLINE], x0 + 8, y0 - 22,
- tinct_BILINEAR_FILTER);
- height -= HOTLIST_LINE_HEIGHT;
- y0 -= HOTLIST_LINE_HEIGHT;
- }
- }
-
- /* Draw the expansion type
- */
- if (entry->children == 0) {
- _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
- sprite[HOTLIST_ENTRY], x0, box_y0 - 23,
- tinct_BILINEAR_FILTER);
- } else {
- if (entry->expanded) {
- _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
- sprite[HOTLIST_COLLAPSE], x0, box_y0 - 31,
- tinct_BILINEAR_FILTER);
- } else {
- _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
- sprite[HOTLIST_EXPAND], x0, box_y0 - 31,
- tinct_BILINEAR_FILTER);
- }
- }
-
- /* Move to the next entry
- */
- entry = entry->next_entry;
- first = false;
- }
-
- /* Return our height
- */
- return cumulative;
-}
-
-
-/**
- * Redraws an entry in the tree and any children
- *
- * \param entry the entry to redraw
- * \param level the level of the entry
- * \param x0 the x co-ordinate to plot at
- * \param y0 the y co-ordinate to plot at
- * \return the height of the entry
- */
-int ro_gui_hotlist_redraw_item(struct hotlist_entry *entry, int level, int x0, int y0) {
- int height = HOTLIST_LINE_HEIGHT;
- int line_y0;
- int line_height;
-
- /* Set the correct height
- */
- if ((entry->children == -1) && (entry->expanded)) {
- if (entry->url) height += HOTLIST_LINE_HEIGHT;
- if (entry->visits > 0) height += HOTLIST_LINE_HEIGHT;
- if (entry->add_date != -1) height += HOTLIST_LINE_HEIGHT;
- if (entry->last_date != -1) height += HOTLIST_LINE_HEIGHT;
- }
-
- /* Check whether we need to redraw
- */
- if ((x0 < clip_x1) && (y0 > clip_y0) && ((x0 + entry->width) > clip_x0) &&
- ((y0 - height) < clip_y1)) {
-
-
- /* Update the selection state
- */
- text_icon.flags = wimp_ICON_TEXT | (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) |
- (wimp_COLOUR_VERY_LIGHT_GREY << wimp_ICON_BG_COLOUR_SHIFT) |
- wimp_ICON_INDIRECTED | wimp_ICON_VCENTRED;
- if (entry->selected) {
- sprite_icon.flags |= wimp_ICON_SELECTED;
- text_icon.flags |= wimp_ICON_SELECTED;
- text_icon.flags |= wimp_ICON_FILLED;
- }
-
- /* Draw our icon type
- */
- sprite_icon.extent.x0 = x0 - origin_x;
- sprite_icon.extent.x1 = x0 - origin_x + HOTLIST_ICON_WIDTH;
- sprite_icon.extent.y0 = y0 - origin_y - HOTLIST_LINE_HEIGHT;
- sprite_icon.extent.y1 = y0 - origin_y;
- sprite_icon.data.indirected_sprite.id = (osspriteop_id)icon_name;
- if (entry->children != -1) {
- if ((entry->expanded) && (entry->children > 0)) {
- sprintf(icon_name, "small_diro");
- hotlist_ensure_sprite(icon_name, "small_dir");
- } else {
- sprintf(icon_name, "small_dir");
- }
- } else {
- /* Get the icon sprite
- */
- sprintf(icon_name, "small_%x", entry->filetype);
- hotlist_ensure_sprite(icon_name, "small_xxx");
- }
- xwimp_plot_icon(&sprite_icon);
-
- /* Draw our textual information
- */
- text_icon.data.indirected_text.text = entry->title;
- text_icon.extent.x0 = x0 - origin_x + HOTLIST_ICON_WIDTH;
- text_icon.extent.x1 = x0 - origin_x + entry->collapsed_width - HOTLIST_LEAF_INSET;
- text_icon.extent.y0 = y0 - origin_y - HOTLIST_LINE_HEIGHT + 2;
- text_icon.extent.y1 = y0 - origin_y - 2;
- xwimp_plot_icon(&text_icon);
-
- /* Clear the selection state
- */
- if (entry->selected) {
- sprite_icon.flags &= ~wimp_ICON_SELECTED;
- }
-
- /* Draw our further information if expanded
- */
- if ((entry->children == -1) && (entry->expanded) && (height > HOTLIST_LINE_HEIGHT)) {
- text_icon.flags = wimp_ICON_TEXT | (wimp_COLOUR_DARK_GREY << wimp_ICON_FG_COLOUR_SHIFT) |
- wimp_ICON_INDIRECTED | wimp_ICON_VCENTRED;
- text_icon.extent.y0 = y0 - origin_y - HOTLIST_LINE_HEIGHT;
- text_icon.extent.y1 = y0 - origin_y;
-
- /* Draw the lines
- */
- y0 -= HOTLIST_LINE_HEIGHT;
- line_y0 = y0;
- line_height = height - HOTLIST_LINE_HEIGHT;
- while (line_height > 0) {
- if (line_height == HOTLIST_LINE_HEIGHT) {
- _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
- sprite[HOTLIST_TLINE], x0 + 16, line_y0 - 22,
- tinct_BILINEAR_FILTER);
- } else {
- _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
- sprite[HOTLIST_LINE], x0 + 16, line_y0 - HOTLIST_LINE_HEIGHT,
- tinct_BILINEAR_FILTER);
- }
- _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
- sprite[HOTLIST_ENTRY], x0 + 8, line_y0 - 23,
- tinct_BILINEAR_FILTER);
- line_height -= HOTLIST_LINE_HEIGHT;
- line_y0 -= HOTLIST_LINE_HEIGHT;
- }
-
- /* Set the right extent of the icon to be big enough for anything
- */
- text_icon.extent.x1 = x0 - origin_x + 4096;
-
- /* Plot the URL text
- */
- text_icon.data.indirected_text.text = extended_text;
- if (entry->url) {
- snprintf(extended_text, HOTLIST_TEXT_BUFFER,
- messages_get("HotlistURL"), entry->url);
- if (strlen(extended_text) >= 255) {
- extended_text[252] = '.';
- extended_text[253] = '.';
- extended_text[254] = '.';
- extended_text[255] = '\0';
- }
- text_icon.extent.y0 -= HOTLIST_LINE_HEIGHT;
- text_icon.extent.y1 -= HOTLIST_LINE_HEIGHT;
- xwimp_plot_icon(&text_icon);
- }
-
- /* Plot the date added text
- */
- if (entry->add_date != -1) {
- snprintf(extended_text, HOTLIST_TEXT_BUFFER,
- messages_get("HotlistAdded"), ctime(&entry->add_date));
- text_icon.extent.y0 -= HOTLIST_LINE_HEIGHT;
- text_icon.extent.y1 -= HOTLIST_LINE_HEIGHT;
- xwimp_plot_icon(&text_icon);
- }
-
- /* Plot the last visited text
- */
- if (entry->last_date != -1) {
- snprintf(extended_text, HOTLIST_TEXT_BUFFER,
- messages_get("HotlistLast"), ctime(&entry->last_date));
- text_icon.extent.y0 -= HOTLIST_LINE_HEIGHT;
- text_icon.extent.y1 -= HOTLIST_LINE_HEIGHT;
- xwimp_plot_icon(&text_icon);
- }
-
- /* Plot the visit count text
- */
- if (entry->visits > 0) {
- snprintf(extended_text, HOTLIST_TEXT_BUFFER,
- messages_get("HotlistVisits"), entry->visits);
- text_icon.extent.y0 -= HOTLIST_LINE_HEIGHT;
- text_icon.extent.y1 -= HOTLIST_LINE_HEIGHT;
- xwimp_plot_icon(&text_icon);
- }
- }
- }
-
- /* Draw any children
- */
- if ((entry->child_entry) && (entry->expanded)) {
- height += ro_gui_hotlist_redraw_tree(entry->child_entry, level + 1,
- x0 + 8, y0 - HOTLIST_LINE_HEIGHT);
- }
- return height;
+ xwimp_set_caret_position(state.w, -1, -100, -100, 32, -1);
}
/**
* Respond to a mouse click
*
- * /param pointer the pointer state
+ * \param pointer the pointer state
*/
void ro_gui_hotlist_click(wimp_pointer *pointer) {
- wimp_caret caret;
- wimp_drag drag;
- struct hotlist_entry *entry;
- wimp_window_state state;
- wimp_mouse_state buttons;
- int x, y;
- int x_offset;
- int y_offset;
- bool no_entry = false;
- os_error *error;
- os_box box = { pointer->pos.x - 34, pointer->pos.y - 34,
- pointer->pos.x + 34, pointer->pos.y + 34 };
- int selection;
-
- /* Get the button state
- */
- buttons = pointer->buttons;
-
- /* Get the window state. Quite why the Wimp can't give relative
- positions is beyond me.
- */
- state.w = hotlist_window;
- wimp_get_window_state(&state);
-
- /* Translate by the origin/scroll values
- */
- x = (pointer->pos.x - (state.visible.x0 - state.xscroll));
- y = (pointer->pos.y - (state.visible.y1 - state.yscroll));
-
- /* We want the caret on a click
- */
- error = xwimp_get_caret_position(&caret);
- if (error) {
- LOG(("xwimp_get_caret_position: 0x%x: %s", error->errnum,
- error->errmess));
- }
- if (((pointer->buttons == (wimp_CLICK_SELECT << 8)) ||
- (pointer->buttons == (wimp_CLICK_ADJUST << 8))) &&
- (caret.w != state.w)) {
- error = xwimp_set_caret_position(state.w, -1, -100,
- -100, 32, -1);
- if (error) {
- LOG(("xwimp_set_caret_position: 0x%x: %s",
- error->errnum, error->errmess));
- }
- }
-
- /* Find our entry
- */
- entry = ro_gui_hotlist_find_entry(x, y, root.child_entry);
- if (entry) {
- /* Check if we clicked on the expanding bit
- */
- x_offset = x - entry->x0;
- y_offset = y - (entry->y0 + entry->height);
- if (((x_offset < HOTLIST_LEAF_INSET) && (y_offset > -HOTLIST_LINE_HEIGHT) &&
- ((buttons == wimp_CLICK_SELECT << 8) || (buttons == wimp_CLICK_ADJUST << 8) ||
- (buttons == wimp_DOUBLE_SELECT) || (buttons == wimp_DOUBLE_ADJUST))) ||
- ((entry->children != -1) &&
- ((buttons == wimp_DOUBLE_SELECT) || (buttons == wimp_DOUBLE_ADJUST)))) {
- if (entry->children != 0) {
- ro_gui_hotlist_update_expansion(entry->child_entry, false, true, true, false, true);
- ro_gui_hotlist_selection_state(entry->child_entry,
- false, false);
- entry->expanded = !entry->expanded;
- if (x_offset >= HOTLIST_LEAF_INSET) entry->selected = false;
- reformat_pending = true;
- hotlist_redraw_entry(entry, true);
- ro_gui_menu_prepare_hotlist();
- }
- } else if (x_offset >= HOTLIST_LEAF_INSET) {
-
- /* We treat a menu click as a Select click if we have no selections
- */
- if (buttons == wimp_CLICK_MENU) {
- if (ro_gui_hotlist_selection_count(root.child_entry, true) == 0) {
- menu_selection = true;
- buttons = (wimp_CLICK_SELECT << 8);
- }
- }
-
- /* Check for selection
- */
- if (buttons == (wimp_CLICK_SELECT << 8)) {
- if (!entry->selected) {
- ro_gui_hotlist_selection_state(root.child_entry,
- false, true);
- entry->selected = true;
- hotlist_redraw_entry_title(entry);
- ro_gui_menu_prepare_hotlist();
-
- }
- } else if (buttons == (wimp_CLICK_ADJUST << 8)) {
- entry->selected = !entry->selected;
- hotlist_redraw_entry_title(entry);
- ro_gui_menu_prepare_hotlist();
- }
-
- /* Check if we should open the URL
- */
- if (((buttons == wimp_DOUBLE_SELECT) || (buttons == wimp_DOUBLE_ADJUST)) &&
- (entry->children == -1)) {
- browser_window_create(entry->url, NULL, 0);
- if (buttons == wimp_DOUBLE_SELECT) {
- ro_gui_hotlist_selection_state(root.child_entry,
- false, true);
- ro_gui_menu_prepare_hotlist();
- } else {
- entry->selected = false;
- ro_gui_dialog_close_persistant(hotlist_window);
- xwimp_close_window(hotlist_window);
- }
- }
-
- /* Check if we should start a drag
- */
- if ((buttons == (wimp_CLICK_SELECT <<4)) || (buttons == (wimp_CLICK_ADJUST << 4))) {
- selection = ro_gui_hotlist_get_selected(true);
- if (selection > 0) {
- gui_current_drag_type = GUI_DRAG_HOTLIST_MOVE;
- if (selection > 1) {
- sprintf(drag_name, "package");
- } else {
- if (entry->children != -1) {
- if ((entry->expanded) && (entry->children > 0)) {
- sprintf(drag_name, "directoryo");
- hotlist_ensure_sprite(drag_name, "directory");
- } else {
- sprintf(drag_name, "directory");
- }
- } else {
- sprintf(drag_name, "file_%x", entry->filetype);
- hotlist_ensure_sprite(drag_name, "file_xxx");
- }
- }
- error = xdragasprite_start(dragasprite_HPOS_CENTRE |
- dragasprite_VPOS_CENTRE |
- dragasprite_BOUND_POINTER |
- dragasprite_DROP_SHADOW,
- (osspriteop_area *) 1, drag_name, &box, 0);
- dragging = true;
- }
- }
- } else {
- if (!((x_offset < HOTLIST_LEAF_INSET) && (y_offset > -HOTLIST_LINE_HEIGHT))) {
- no_entry = true;
- }
- }
- } else {
- no_entry = true;
- }
-
- /* Get the original button state back
- */
- buttons = pointer->buttons;
-
- /* Create a menu if we should
- */
- if (buttons == wimp_CLICK_MENU) {
+ ro_gui_tree_click(pointer, hotlist_tree);
+ if (pointer->buttons == wimp_CLICK_MENU)
ro_gui_create_menu(hotlist_menu, pointer->pos.x,
pointer->pos.y, NULL);
- menu_open = true;
- return;
- }
-
- /* Handle a click without an entry
- */
- if (no_entry) {
- /* Deselect everything if we click nowhere
- */
- if (buttons == (wimp_CLICK_SELECT << 8)) {
- ro_gui_hotlist_selection_state(root.child_entry,
- false, true);
- ro_gui_menu_prepare_hotlist();
- }
-
- /* Handle the start of a drag
- */
- if (buttons == (wimp_CLICK_SELECT << 4) ||
- buttons == (wimp_CLICK_ADJUST << 4)) {
-
- /* Clear the current selection
- */
- if (buttons == (wimp_CLICK_SELECT << 4)) {
- ro_gui_hotlist_selection_state(root.child_entry,
- false, true);
- ro_gui_menu_prepare_hotlist();
- }
-
- /* Start a drag box
- */
- drag_buttons = buttons;
- gui_current_drag_type = GUI_DRAG_HOTLIST_SELECT;
- drag.w = hotlist_window;
- drag.type = wimp_DRAG_USER_RUBBER;
- drag.initial.x0 = pointer->pos.x;
- drag.initial.x1 = pointer->pos.x;
- drag.initial.y0 = pointer->pos.y;
- drag.initial.y1 = pointer->pos.y;
- drag.bbox.x0 = state.visible.x0;
- drag.bbox.x1 = state.visible.x1;
- drag.bbox.y0 = state.visible.y0;
- drag.bbox.y1 = state.visible.y1;
- if (hotlist_toolbar) drag.bbox.y1 -= hotlist_toolbar->height;
- xwimp_drag_box(&drag);
- dragging = true;
- }
- }
-}
-
-
-/**
- * Find an entry at a particular position
- *
- * \param x the x co-ordinate
- * \param y the y co-ordinate
- * \param entry the entry to check down from (root->child_entry for the entire tree)
- * /return the entry occupying the positon
- */
-struct hotlist_entry *ro_gui_hotlist_find_entry(int x, int y, struct hotlist_entry *entry) {
- struct hotlist_entry *find_entry;
- int inset_x = 0;
- int inset_y = 0;
-
- /* Check we have an entry (only applies if we have an empty hotlist)
- */
- if (!entry) return NULL;
-
- /* Get the first child entry
- */
- while (entry) {
- /* Check if this entry could possibly match
- */
- if ((x > entry->x0) && (y > entry->y0) && (x < (entry->x0 + entry->width)) &&
- (y < (entry->y0 + entry->height))) {
-
- /* The top line extends all the way left
- */
- if (y - (entry->y0 + entry->height) > -HOTLIST_LINE_HEIGHT) {
- if (x < (entry->x0 + entry->collapsed_width)) return entry;
- return NULL;
- }
-
- /* No other entry can occupy the left edge
- */
- inset_x = x - entry->x0 - HOTLIST_LEAF_INSET - HOTLIST_ICON_WIDTH;
- if (inset_x < 0) return NULL;
-
- /* Check the right edge against our various widths
- */
- inset_y = -((y - entry->y0 - entry->height) / HOTLIST_LINE_HEIGHT);
- if (inset_x < (entry->widths[inset_y - 1] + HOTLIST_TEXT_PADDING)) return entry;
- return NULL;
- }
-
- /* Continue onwards
- */
- if ((entry->child_entry) && (entry->expanded)) {
- find_entry = ro_gui_hotlist_find_entry(x, y, entry->child_entry);
- if (find_entry) return find_entry;
- }
- entry = entry->next_entry;
- }
- return NULL;
-}
-
-
-/**
- * Updated the selection state of the tree
- *
- * \param entry the entry to update all siblings and descendants of
- * \param selected the selection state to set
- * \param redraw update the icons in the Wimp
- * \return the number of entries that have changed
- */
-int ro_gui_hotlist_selection_state(struct hotlist_entry *entry, bool selected, bool redraw) {
- int changes = 0;
-
- /* Check we have an entry (only applies if we have an empty hotlist)
- */
- if (!entry) return 0;
-
- /* Get the first child entry
- */
- while (entry) {
- /* Check this entry
- */
- if (entry->selected != selected) {
- /* Update the selection state
- */
- entry->selected = selected;
- changes++;
-
- /* Redraw the entrys first line
- */
- if (redraw) hotlist_redraw_entry_title(entry);
- }
-
- /* Continue onwards
- */
- if ((entry->child_entry) && ((!selected) || (entry->expanded))) {
- changes += ro_gui_hotlist_selection_state(entry->child_entry,
- selected, redraw & (entry->expanded));
- }
- entry = entry->next_entry;
- }
- return changes;
-}
-
-
-/**
- * Returns the first selected item
- *
- * \param entry the search siblings and children of
- * \return the first selected item
- */
-struct hotlist_entry *ro_gui_hotlist_first_selection(struct hotlist_entry *entry) {
- struct hotlist_entry *test_entry;
-
- /* Check we have an entry (only applies if we have an empty hotlist)
- */
- if (!entry) return NULL;
-
- /* Work through our entries
- */
- while (entry) {
- if (entry->selected) return entry;
- if (entry->child_entry) {
- test_entry = ro_gui_hotlist_first_selection(entry->child_entry);
- if (test_entry) return test_entry;
- }
- entry = entry->next_entry;
- }
- return NULL;
-}
-
-
-/**
- * Return the current number of selected items (internal interface)
- *
- * \param entry the entry to count siblings and children of
- */
-int ro_gui_hotlist_selection_count(struct hotlist_entry *entry, bool folders) {
- int count = 0;
- if (!entry) return 0;
- while (entry) {
- if ((entry->selected) && (folders || (entry->children == -1))) count++;
- if (entry->child_entry) count += ro_gui_hotlist_selection_count(entry->child_entry, folders);
- entry = entry->next_entry;
- }
- return count;
-}
-
-
-/**
- * Launch the current selection (internal interface)
- *
- * \param entry the entry to launch siblings and children of
- */
-void ro_gui_hotlist_launch_selection(struct hotlist_entry *entry) {
- if (!entry) return;
- while (entry) {
- if ((entry->selected) && (entry->url)) browser_window_create(entry->url, NULL, 0);
- if (entry->child_entry) ro_gui_hotlist_launch_selection(entry->child_entry);
- entry = entry->next_entry;
- }
-}
-
-
-/**
- * Invalidate the statistics for any selected items (internal interface)
- *
- * \param entry the entry to update siblings and children of
- */
-void ro_gui_hotlist_invalidate_statistics(struct hotlist_entry *entry) {
- if (!entry) return;
- while (entry) {
- if ((entry->selected) && (entry->children == -1)) {
- entry->visits = 0;
- entry->last_date = (time_t)-1;
- if (entry->expanded) hotlist_redraw_entry(entry, true);
- }
- if (entry->child_entry) ro_gui_hotlist_invalidate_statistics(entry->child_entry);
- entry = entry->next_entry;
- }
-}
-
-
-/**
- * Set the process flag for the current selection (internal interface)
- *
- * \param entry the entry to modify siblings and children of
- */
-void ro_gui_hotlist_selection_to_process(struct hotlist_entry *entry) {
- if (!entry) return;
- while (entry) {
- entry->process = entry->selected;
- if (entry->child_entry) ro_gui_hotlist_selection_to_process(entry->child_entry);
- entry = entry->next_entry;
- }
-}
-
-
-/**
- * Toggles the expanded state for selected icons
- * If neither expand not contract are set then the entries are toggled
- *
- * \param entry the entry to update all siblings and descendants of
- * \param only_selected whether to only update selected icons
- * \param folders whether to update folders
- * \param links whether to update links
- * \param expand force all entries to be expanded (dominant)
- * \param contract force all entries to be contracted (recessive)
- */
-void ro_gui_hotlist_update_expansion(struct hotlist_entry *entry, bool only_selected,
- bool folders, bool links, bool expand, bool contract) {
- bool current;
-
- /* Set a reformat to be pending
- */
- reformat_pending = true;
-
- /* Check we have an entry (only applies if we have an empty hotlist)
- */
- if (!entry) return;
-
- /* Get the first child entry
- */
- while (entry) {
- /* Check this entry
- */
- if ((entry->selected) || (!only_selected)) {
- current = entry->expanded;
-
- /* Only update what we should
- */
- if (((links) && (entry->children == -1)) || ((folders) && (entry->children > 0))) {
- /* Update the expansion state
- */
- if (expand) {
- entry->expanded = true;
- } else if (contract) {
- entry->expanded = false;
- } else {
- entry->expanded = !entry->expanded;
- }
- }
-
- /* If we have contracted then we de-select and collapse any children
- */
- if (entry->child_entry && !entry->expanded) {
- ro_gui_hotlist_update_expansion(entry->child_entry, false, true, true, false, true);
- ro_gui_hotlist_selection_state(entry->child_entry, false, false);
- }
-
- /* Redraw the entrys first line
- */
- if (current != entry->expanded) hotlist_redraw_entry(entry, true);
- }
-
- /* Continue onwards (child entries cannot be selected if the parent is
- not expanded)
- */
- if (entry->child_entry && entry->expanded) {
- ro_gui_hotlist_update_expansion(entry->child_entry,
- only_selected, folders, links, expand, contract);
- }
- entry = entry->next_entry;
- }
+ else
+ ro_gui_menu_prepare_hotlist();
}
/**
- * Updated the selection state of the tree
+ * Respond to a keypress
*
- * \param entry the entry to update all siblings and descendants of
- * \param x0 the left edge of the box
- * \param y0 the top edge of the box
- * \param x1 the right edge of the box
- * \param y1 the bottom edge of the box
- * \param toggle toggle the selection state, otherwise set
- * \param redraw update the icons in the Wimp
+ * \param key the key pressed
*/
-void ro_gui_hotlist_selection_drag(struct hotlist_entry *entry,
- int x0, int y0, int x1, int y1,
- bool toggle, bool redraw) {
- bool do_update;
- int line;
- int test_y;
-
- /* Check we have an entry (only applies if we have an empty hotlist)
- */
- if (!entry) return;
-
- /* Get the first child entry
- */
- while (entry) {
- /* Check if this entry could possibly match
- */
- if ((x1 > (entry->x0 + HOTLIST_LEAF_INSET)) && (y0 > entry->y0) &&
- (x0 < (entry->x0 + entry->width)) &&
- (y1 < (entry->y0 + entry->height))) {
- do_update = false;
-
- /* Check the exact area of the title line
- */
- if ((x1 > (entry->x0 + HOTLIST_LEAF_INSET)) &&
- (y0 > entry->y0 + entry->height - HOTLIST_LINE_HEIGHT) &&
- (x0 < (entry->x0 + entry->collapsed_width)) &&
- (y1 < (entry->y0 + entry->height))) {
- do_update = true;
- }
-
- /* Check the other lines
- */
- line = 1;
- test_y = entry->y0 + entry->height - HOTLIST_LINE_HEIGHT;
- while (((line * HOTLIST_LINE_HEIGHT) < entry->height) && (!do_update)) {
- /* Check this line
- */
- if ((x1 > (entry->x0 + HOTLIST_LEAF_INSET + HOTLIST_ICON_WIDTH)) &&
- (y1 < test_y) && (y0 > test_y - HOTLIST_LINE_HEIGHT) &&
- (x0 < (entry->x0 + entry->widths[line - 1] +
- HOTLIST_LEAF_INSET + HOTLIST_ICON_WIDTH +
- HOTLIST_TEXT_PADDING))) {
- do_update = true;
- }
-
- /* Move to the next line
- */
- line++;
- test_y -= HOTLIST_LINE_HEIGHT;
- }
-
- /* Redraw the entrys first line
- */
- if (do_update) {
- if (toggle) {
- entry->selected = !entry->selected;
- } else {
- entry->selected = true;
- }
- if (redraw) hotlist_redraw_entry_title(entry);
- }
- }
-
- /* Continue onwards
- */
- if ((entry->child_entry) && (entry->expanded)) {
- ro_gui_hotlist_selection_drag(entry->child_entry,
- x0, y0, x1, y1, toggle, redraw);
- }
- entry = entry->next_entry;
- do_update = false;
- }
-}
-
-
-/**
- * The end of a selection drag has been reached
- *
- * \param drag the final drag co-ordinates
- */
-void ro_gui_hotlist_selection_drag_end(wimp_dragged *drag) {
- wimp_window_state state;
- int x0, y0, x1, y1;
- int toolbar_height = 0;
-
- /* Reset our dragging state
- */
- dragging = false;
-
- /* Get the toolbar height
- */
- if (hotlist_toolbar) toolbar_height = hotlist_toolbar->height * 2;
-
- /* Get the window state to make everything relative
- */
- state.w = hotlist_window;
- wimp_get_window_state(&state);
-
- /* Create the relative positions
- */
- x0 = drag->final.x0 - state.visible.x0 - state.xscroll;
- x1 = drag->final.x1 - state.visible.x0 - state.xscroll;
- y0 = drag->final.y0 - state.visible.y1 - state.yscroll + toolbar_height;
- y1 = drag->final.y1 - state.visible.y1 - state.yscroll + toolbar_height;
-
- /* Make sure x0 < x1 and y0 > y1
- */
- if (x0 > x1) {
- x0 ^= x1;
- x1 ^= x0;
- x0 ^= x1;
- }
- if (y0 < y1) {
- y0 ^= y1;
- y1 ^= y0;
- y0 ^= y1;
- }
-
- /* Update the selection state
- */
- if (drag_buttons == (wimp_CLICK_SELECT << 4)) {
- ro_gui_hotlist_selection_drag(root.child_entry, x0, y0, x1, y1, false, true);
- } else {
- ro_gui_hotlist_selection_drag(root.child_entry, x0, y0, x1, y1, true, true);
- }
+bool ro_gui_hotlist_keypress(int key) {
+ // struct node_element *edit = hotlist_tree->editing;
+ bool result = ro_gui_tree_keypress(key, hotlist_tree);
ro_gui_menu_prepare_hotlist();
-}
-
-
-/**
- * The end of a item moving drag has been reached
- *
- * \param drag the final drag co-ordinates
- */
-void ro_gui_hotlist_move_drag_end(wimp_dragged *drag) {
- wimp_pointer pointer;
- int toolbar_height = 0;
- wimp_window_state state;
- struct hotlist_entry *test_entry;
- struct hotlist_entry *entry;
- int x, y, x0, y0, x1, y1;
- bool before = false;
-
- /* Reset our dragging state
- */
- dragging = false;
-
- /* Check we dropped to our window
- */
- xwimp_get_pointer_info(&pointer);
- if (pointer.w != hotlist_window) return;
-
- /* Get the toolbar height
- */
- if (hotlist_toolbar) toolbar_height = hotlist_toolbar->height * 2;
-
- /* Set the process flag for all selected items
- */
- ro_gui_hotlist_selection_to_process(root.child_entry);
-
- /* Get the window state to make everything relative
- */
- state.w = hotlist_window;
- wimp_get_window_state(&state);
-
- /* Create the relative positions
- */
- x0 = drag->final.x0 - state.visible.x0 - state.xscroll;
- x1 = drag->final.x1 - state.visible.x0 - state.xscroll;
- y0 = drag->final.y0 - state.visible.y1 - state.yscroll + toolbar_height;
- y1 = drag->final.y1 - state.visible.y1 - state.yscroll + toolbar_height;
- x = (x0 + x1) / 2;
- y = (y0 + y1) / 2;
-
- /* Find our entry
- */
- entry = ro_gui_hotlist_find_entry(x, y, root.child_entry);
- if (!entry) entry = &root;
-
- /* No parent of the destination can be processed
- */
- test_entry = entry;
- while (test_entry != NULL) {
- if (test_entry->process) return;
- test_entry = test_entry->parent_entry;
- }
- /* Check for before/after
- */
- before = ((y - (entry->y0 + entry->height)) > (-HOTLIST_LINE_HEIGHT / 2));
-
- /* Start our recursive moving
- */
- while (ro_gui_hotlist_move_processing(root.child_entry, entry, before));
-}
-
-
-
-bool ro_gui_hotlist_move_processing(struct hotlist_entry *entry, struct hotlist_entry *destination, bool before) {
- bool result = false;
- if (!entry) return false;
- while (entry) {
- if (entry->process) {
- entry->process = false;
- ro_gui_hotlist_delink_entry(entry);
- ro_gui_hotlist_link_entry(destination, entry, before);
- result = true;
- }
- if (entry->child_entry) {
- result |= ro_gui_hotlist_move_processing(entry->child_entry, destination, before);
- }
- entry = entry->next_entry;
- }
+/* if ((edit) && (!hotlist_tree->editing))
+ ro_gui_hotlist_save();
+*/
return result;
}
+
/**
- * Handle a menu being closed
+ * Handles a menu closed event
*/
void ro_gui_hotlist_menu_closed(void) {
- menu_open = false;
- if (menu_selection) {
- ro_gui_hotlist_selection_state(root.child_entry, false, true);
- menu_selection = false;
- }
+ ro_gui_tree_menu_closed(hotlist_tree);
+ current_menu = NULL;
+ ro_gui_menu_prepare_hotlist();
}
+
/**
- * Handle a keypress
+ * Respond to a mouse click
*
- * \param key the key pressed
- * \return whether the key was processed
+ * \param pointer the pointer state
*/
-bool ro_gui_hotlist_keypress(int key) {
- wimp_window_state state;
- int y;
-
- /* Handle basic keys
- */
- switch (key) {
- case 1: /* CTRL+A */
- ro_gui_hotlist_selection_state(root.child_entry, true, true);
- if (menu_open) ro_gui_create_menu(hotlist_menu, 0, 0, NULL);
- return true;
- case 26: /* CTRL+Z */
- ro_gui_hotlist_selection_state(root.child_entry, false, true);
- if (menu_open) ro_gui_create_menu(hotlist_menu, 0, 0, NULL);
- return true;
- case 32: /* SPACE */
- ro_gui_hotlist_update_expansion(root.child_entry, true, true, true, false, false);
- if (menu_open) ro_gui_create_menu(hotlist_menu, 0, 0, NULL);
- return true;
- case wimp_KEY_RETURN:
- ro_gui_hotlist_launch_selection(root.child_entry);
- return true;
- case wimp_KEY_F3:
- ro_gui_hotlist_save();
- return true;
- case wimp_KEY_UP:
- case wimp_KEY_DOWN:
- case wimp_KEY_PAGE_UP:
- case wimp_KEY_PAGE_DOWN:
- case wimp_KEY_CONTROL | wimp_KEY_UP:
- case wimp_KEY_CONTROL | wimp_KEY_DOWN:
- break;
-
- default:
- return false;
- }
-
- /* Handle keypress scrolling
- */
- state.w = hotlist_window;
- wimp_get_window_state(&state);
- y = state.visible.y1 - state.visible.y0 - 32;
- switch (key) {
- case wimp_KEY_UP:
- state.yscroll += 32;
- break;
- case wimp_KEY_DOWN:
- state.yscroll -= 32;
- break;
- case wimp_KEY_PAGE_UP:
- state.yscroll += y;
- break;
- case wimp_KEY_PAGE_DOWN:
- state.yscroll -= y;
- break;
- case wimp_KEY_CONTROL | wimp_KEY_UP:
- state.yscroll = 1000;
- break;
- case wimp_KEY_CONTROL | wimp_KEY_DOWN:
- state.yscroll = -0x10000000;
- break;
- }
- xwimp_open_window((wimp_open *) &state);
- return true;
-}
-
-
void ro_gui_hotlist_toolbar_click(wimp_pointer* pointer) {
- int selection;
+ struct node *node;
- /* Store the toolbar
- */
current_toolbar = hotlist_toolbar;
-
- /* Handle Menu clicks
- */
- if (pointer->buttons == wimp_CLICK_MENU) {
- ro_gui_create_menu(toolbar_menu, pointer->pos.x,
- pointer->pos.y, NULL);
- return;
- }
+ ro_gui_tree_stop_edit(hotlist_tree);
- /* Handle the buttons appropriately
- */
switch (pointer->i) {
case ICON_TOOLBAR_CREATE:
- hotlist_insert = false;
- if (pointer->buttons == wimp_CLICK_SELECT) {
- ro_gui_hotlist_prepare_folder_dialog(false);
- ro_gui_dialog_open_persistant(hotlist_window, dialog_folder, true);
- } else {
- ro_gui_hotlist_prepare_entry_dialog(false);
- ro_gui_dialog_open_persistant(hotlist_window, dialog_entry, true);
- }
+ node = tree_create_folder_node(hotlist_tree->root,
+ messages_get("TreeNewFolder"));
+ tree_redraw_area(hotlist_tree, node->box.x - NODE_INSTEP,
+ 0, NODE_INSTEP, 16384);
+ tree_handle_node_changed(hotlist_tree, node, false, true);
+ ro_gui_tree_start_edit(hotlist_tree, &node->data, NULL);
break;
case ICON_TOOLBAR_OPEN:
- selection = ro_gui_hotlist_get_selected(true);
- ro_gui_hotlist_update_expansion(root.child_entry, (selection != 0), true, false,
+ tree_handle_expansion(hotlist_tree, hotlist_tree->root,
(pointer->buttons == wimp_CLICK_SELECT),
- (pointer->buttons == wimp_CLICK_ADJUST));
+ true, false);
break;
case ICON_TOOLBAR_EXPAND:
- selection = ro_gui_hotlist_get_selected(true);
- ro_gui_hotlist_update_expansion(root.child_entry, (selection != 0), false, true,
+ tree_handle_expansion(hotlist_tree, hotlist_tree->root,
(pointer->buttons == wimp_CLICK_SELECT),
- (pointer->buttons == wimp_CLICK_ADJUST));
+ false, true);
break;
case ICON_TOOLBAR_DELETE:
- ro_gui_hotlist_delete_selected();
+ tree_delete_selected_nodes(hotlist_tree,
+ hotlist_tree->root);
break;
case ICON_TOOLBAR_LAUNCH:
- ro_gui_hotlist_keypress(wimp_KEY_RETURN);
+ ro_gui_tree_launch_selected(hotlist_tree);
break;
}
}
-void ro_gui_hotlist_prepare_folder_dialog(bool selected) {
- struct hotlist_entry *entry = NULL;
- if (selected) entry = ro_gui_hotlist_first_selection(root.child_entry);
-
- /* Update the title
- */
- dialog_folder_add = selected;
- if (selected) {
- ro_gui_set_window_title(dialog_folder, messages_get("EditFolder"));
- } else {
- ro_gui_set_window_title(dialog_folder, messages_get("NewFolder"));
- }
-
- /* Update the icons
- */
- if (entry == NULL) {
- ro_gui_set_icon_string(dialog_folder, 1, messages_get("Folder"));
- } else {
- ro_gui_set_icon_string(dialog_folder, 1, entry->title);
- }
-}
-
-void ro_gui_hotlist_prepare_entry_dialog(bool selected) {
- struct hotlist_entry *entry = NULL;
- if (selected) entry = ro_gui_hotlist_first_selection(root.child_entry);
-
- /* Update the title
- */
- dialog_entry_add = selected;
- if (selected) {
- ro_gui_set_window_title(dialog_entry, messages_get("EditLink"));
- } else {
- ro_gui_set_window_title(dialog_entry, messages_get("NewLink"));
- }
-
- /* Update the icons
- */
- if (entry == NULL) {
- ro_gui_set_icon_string(dialog_entry, 1, messages_get("Link"));
- ro_gui_set_icon_string(dialog_entry, 3, "");
- } else {
- ro_gui_set_icon_string(dialog_entry, 1, entry->title);
- ro_gui_set_icon_string(dialog_entry, 3, entry->url);
- }
-}
-
-
/**
- * Set all items to either selected or deselected
+ * Informs the hotlist that some content has been visited
*
- * \param selected the state to set all items to
+ * \param content the content visited
*/
-void ro_gui_hotlist_set_selected(bool selected) {
- ro_gui_hotlist_selection_state(root.child_entry, selected, true);
- menu_selection = false;
+void hotlist_visited(struct content *content) {
+ if ((!content) || (!content->url) || (!hotlist_tree))
+ return;
+ ro_gui_hotlist_visited(content, hotlist_tree, hotlist_tree->root);
}
/**
- * Reset the statistics for selected entries
+ * Informs the hotlist that some content has been visited
+ *
+ * \param content the content visited
+ * \param tree the tree to find the URL data from
+ * \param node the node to update siblings and children of
*/
-void ro_gui_hotlist_reset_statistics(void) {
- ro_gui_hotlist_invalidate_statistics(root.child_entry);
+void ro_gui_hotlist_visited(struct content *content, struct tree *tree,
+ struct node *node) {
+ struct node_element *element;
+
+ for (; node; node = node->next) {
+ if (!node->folder) {
+ element = tree_find_element(node, TREE_ELEMENT_URL);
+ if ((element) && (!strcmp(element->text, content->url))) {
+ element->user_data = ro_content_filetype(content);
+ element = tree_find_element(node,
+ TREE_ELEMENT_VISITS);
+ if (element)
+ element->user_data += 1;
+ element = tree_find_element(node,
+ TREE_ELEMENT_LAST_VISIT);
+ if (element)
+ element->user_data = time(NULL);
+ tree_update_URL_node(node);
+ tree_handle_node_changed(tree, node, true, false);
+ }
+ }
+ if (node->child)
+ ro_gui_hotlist_visited(content, tree, node->child);
+ }
}
/**
- * Return the current number of selected items
+ * Prepares the folder dialog contents for a node
*
- * \param folders include folders in the selection count
- * \return the number of selected items
+ * \param node the node to prepare the dialogue for, or NULL
*/
-int ro_gui_hotlist_get_selected(bool folders) {
- return ro_gui_hotlist_selection_count(root.child_entry, folders);
+void ro_gui_hotlist_prepare_folder_dialog(struct node *node) {
+ dialog_folder_node = node;
+ if (node) {
+ ro_gui_set_window_title(dialog_folder, messages_get("EditFolder"));
+ ro_gui_set_icon_string(dialog_folder, 1, node->data.text);
+ } else {
+ ro_gui_set_window_title(dialog_folder, messages_get("NewFolder"));
+ ro_gui_set_icon_string(dialog_folder, 1, messages_get("Folder"));
+ }
}
/**
- * Set all items to either selected or deselected
+ * Prepares the entry dialog contents for a node
*
- * \param expand whether to expand (collapse otherwise)
- * \param folders whether to update folders
- * \param links whether to update links
+ * \param node the node to prepare the dialogue for, or NULL
*/
-void ro_gui_hotlist_set_expanded(bool expand, bool folders, bool links) {
- ro_gui_hotlist_update_expansion(root.child_entry, false, folders, links, expand, !expand);
+void ro_gui_hotlist_prepare_entry_dialog(struct node *node) {
+ struct node_element *element;
+
+ dialog_entry_node = node;
+ if (node) {
+ ro_gui_set_window_title(dialog_entry, messages_get("EditLink"));
+ ro_gui_set_icon_string(dialog_entry, 1, node->data.text);
+ element = tree_find_element(node, TREE_ELEMENT_URL);
+ if (element)
+ ro_gui_set_icon_string(dialog_entry, 3, element->text);
+ else
+ ro_gui_set_icon_string(dialog_entry, 3, "");
+ } else {
+ ro_gui_set_window_title(dialog_entry, messages_get("NewLink"));
+ ro_gui_set_icon_string(dialog_entry, 1, messages_get("Link"));
+ ro_gui_set_icon_string(dialog_entry, 3, "");
+ }
}
/**
- * Deletes any selected items
+ * Respond to a mouse click
*
- * \param selected the state to set all items to
+ * \param pointer the pointer state
*/
-void ro_gui_hotlist_delete_selected(void) {
- struct hotlist_entry *entry;
- while ((entry = ro_gui_hotlist_first_selection(root.child_entry)) != NULL) {
- ro_gui_hotlist_delete_entry(entry, false);
- }
-}
-
void ro_gui_hotlist_dialog_click(wimp_pointer *pointer) {
- struct hotlist_entry *entry = NULL;
+ struct node_element *element;
+ struct node *node;
char *title = NULL;
char *url = NULL;
char *old_value;
int icon = pointer->i;
int close_icon, ok_icon;
- bool folder;
- bool add;
url_func_result res;
- /* Get our data
- */
if (pointer->w == dialog_entry) {
title = strip(ro_gui_get_icon_string(pointer->w, 1));
url = strip(ro_gui_get_icon_string(pointer->w, 3));
close_icon = 4;
ok_icon = 5;
- folder = false;
- add = !dialog_entry_add;
+ node = dialog_entry_node;
} else {
title = strip(ro_gui_get_icon_string(pointer->w, 1));
close_icon = 2;
ok_icon = 3;
- folder = true;
- add = !dialog_folder_add;
+ node = dialog_folder_node;
}
- /* Check for cancelling
- */
if (icon == close_icon) {
if (pointer->buttons == wimp_CLICK_SELECT) {
ro_gui_dialog_close(pointer->w);
xwimp_create_menu((wimp_menu *)-1, 0, 0);
- return;
- }
- if (folder) {
- ro_gui_hotlist_prepare_folder_dialog(dialog_folder_add);
} else {
- ro_gui_hotlist_prepare_entry_dialog(dialog_entry_add);
+ if (pointer->w == dialog_folder)
+ ro_gui_hotlist_prepare_folder_dialog(dialog_folder_node);
+ else
+ ro_gui_hotlist_prepare_entry_dialog(dialog_entry_node);
}
return;
}
- /* Check for ok
- */
- if (icon != ok_icon) return;
+ if (icon != ok_icon)
+ return;
/* Check we have valid values
*/
@@ -2514,95 +466,66 @@ void ro_gui_hotlist_dialog_click(wimp_pointer *pointer) {
/* Update/insert our data
*/
- if (add) {
- /* todo: insert at the selection place if hotlist_insert is set */
- ro_gui_hotlist_create_entry(title, url, folder ? 0 : 0xfaf, &root);
+ if (!node) {
+ if (pointer->w == dialog_folder) {
+ dialog_folder_node = tree_create_folder_node(hotlist_tree->root,
+ title);
+ node = dialog_folder_node;
+ } else {
+ dialog_entry_node = tree_create_URL_node(hotlist_tree->root,
+ title, url, 0xfaf, time(NULL), -1, 0);
+ node = dialog_entry_node;
+ }
+ tree_handle_node_changed(hotlist_tree, node, true, false);
+ ro_gui_tree_scroll_visible(hotlist_tree, &node->data);
+ tree_redraw_area(hotlist_tree, node->box.x - NODE_INSTEP,
+ 0, NODE_INSTEP, 16384);
} else {
- entry = ro_gui_hotlist_first_selection(root.child_entry);
- if (entry == NULL) return;
if (url) {
- old_value = entry->url;
- res = url_normalize(url, &entry->url);
- if (res != URL_FUNC_OK) {
- /** \todo use correct error message */
- warn_user("NoMemory", 0);
- entry->url = old_value;
- return;
+ element = tree_find_element(node, TREE_ELEMENT_URL);
+ if (element) {
+ old_value = element->text;
+ res = url_normalize(url, &element->text);
+ if (res != URL_FUNC_OK) {
+ warn_user("NoMemory", 0);
+ element->text = old_value;
+ return;
+ }
+ free(old_value);
}
- if (old_value) free(old_value);
}
if (title) {
- old_value = entry->title;
- entry->title = strdup(title);
- if (!entry->title) {
+ old_value = node->data.text;
+ node->data.text = strdup(title);
+ if (!node->data.text) {
warn_user("NoMemory", 0);
- entry->title = old_value;
+ node->data.text = old_value;
return;
}
free(old_value);
}
- hotlist_redraw_entry(entry, false); /* first for contracting size */
- ro_gui_hotlist_update_entry_size(entry);
- hotlist_redraw_entry(entry, false); /* then for expanding size */
+ tree_handle_node_changed(hotlist_tree, node, true, false);
}
- /* Close if we should
- */
if (pointer->buttons == wimp_CLICK_SELECT) {
xwimp_create_menu((wimp_menu *)-1, 0, 0);
ro_gui_dialog_close(pointer->w);
return;
}
-
- /* Update our display
- */
- if (folder) {
- ro_gui_hotlist_prepare_folder_dialog(dialog_folder_add);
- } else {
- ro_gui_hotlist_prepare_entry_dialog(dialog_entry_add);
- }
+ if (pointer->w == dialog_folder)
+ ro_gui_hotlist_prepare_folder_dialog(dialog_folder_node);
+ else
+ ro_gui_hotlist_prepare_entry_dialog(dialog_entry_node);
}
-int ro_gui_hotlist_help(int x, int y) {
- struct hotlist_entry *entry;
- wimp_window_state state;
- int toolbar_height = 0;
- int x_offset, y_offset;
-
- /* Return the dragging codes
- */
- if (dragging) {
- if (gui_current_drag_type == GUI_DRAG_HOTLIST_SELECT) return 6;
- if (gui_current_drag_type == GUI_DRAG_HOTLIST_MOVE) return 7;
- return -1;
- }
-
- /* Get the toolbar height
- */
- if (hotlist_toolbar) toolbar_height = hotlist_toolbar->height * 2;
-
- /* Get the window state to make everything relative
- */
- state.w = hotlist_window;
- wimp_get_window_state(&state);
-
- /* Create the relative positions
- */
- x = x - state.visible.x0 - state.xscroll;
- y = y - state.visible.y1 - state.yscroll + toolbar_height;
-
- /* Get the current entry
- */
- entry = ro_gui_hotlist_find_entry(x, y, root.child_entry);
- if (entry == NULL) return -1;
- /* Return the relevant code
- */
- x_offset = x - entry->x0;
- y_offset = y - (entry->y0 + entry->height);
- if ((x_offset < HOTLIST_LEAF_INSET) && (y_offset > -HOTLIST_LINE_HEIGHT)) {
- if (entry->children == 0) return -1;
- return (((entry->children == -1) ? 2 : 0) + ((entry->expanded) ? 1 : 0));
- }
- return ((entry->children == -1) ? 5 : 4);
+/**
+ * Attempts to process an interactive help message request
+ *
+ * \param x the x co-ordinate to give help for
+ * \param y the x co-ordinate to give help for
+ * \return the message code index
+ */
+int ro_gui_hotlist_help(int x, int y) {
+ return -1;
}
diff --git a/riscos/menus.c b/riscos/menus.c
index cc258eb79..9ae2b8d8a 100644
--- a/riscos/menus.c
+++ b/riscos/menus.c
@@ -27,6 +27,7 @@
#include "netsurf/riscos/options.h"
#include "netsurf/riscos/tinct.h"
#include "netsurf/riscos/theme.h"
+#include "netsurf/riscos/treeview.h"
#include "netsurf/riscos/wimp.h"
#include "netsurf/utils/log.h"
#include "netsurf/utils/messages.h"
@@ -120,14 +121,14 @@ static wimp_MENU(3) link_menu = {
static wimp_MENU(8) page_menu = {
{ "Page" }, 7,2,7,0, 200, 44, 0,
{
- { wimp_MENU_GIVE_WARNING, (wimp_menu *)1, DEFAULT_FLAGS, { "PageInfo" } },
- { wimp_MENU_GIVE_WARNING, (wimp_menu *)1, DEFAULT_FLAGS, { "Save" } },
- { wimp_MENU_GIVE_WARNING, (wimp_menu *)1, DEFAULT_FLAGS, { "SaveComp" } },
- { 0, (wimp_menu *)&export_menu, DEFAULT_FLAGS, { "Export" } },
- { 0, (wimp_menu *)&link_menu, DEFAULT_FLAGS, { "SaveURL" } },
- { wimp_MENU_GIVE_WARNING | wimp_MENU_SEPARATE, (wimp_menu *)1, DEFAULT_FLAGS, { "Print" } },
- { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "NewWindow" } },
- { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "ViewSrc" } }
+ { wimp_MENU_GIVE_WARNING, (wimp_menu *)1, DEFAULT_FLAGS, { "PageInfo" } },
+ { wimp_MENU_GIVE_WARNING, (wimp_menu *)1, DEFAULT_FLAGS, { "Save" } },
+ { wimp_MENU_GIVE_WARNING, (wimp_menu *)1, DEFAULT_FLAGS, { "SaveComp" } },
+ { 0, (wimp_menu *)&export_menu, DEFAULT_FLAGS, { "Export" } },
+ { 0, (wimp_menu *)&link_menu, DEFAULT_FLAGS, { "SaveURL" } },
+ { wimp_MENU_GIVE_WARNING | wimp_MENU_SEPARATE, (wimp_menu *)1, DEFAULT_FLAGS, { "Print" } },
+ { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "NewWindow" } },
+ { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "ViewSrc" } }
}
};
@@ -187,9 +188,8 @@ static wimp_MENU(5) navigate_menu = {
static wimp_MENU(3) image_menu = {
{ "Images" }, 7,2,7,0, 300, 44, 0,
{
- { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS | wimp_ICON_SHADED, { "ForeImg" } },
- { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "BackImg" } },
- { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "AnimImg" } }
+ { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS | wimp_ICON_SHADED, { "ForeImg" } },
+ { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "BackImg" } },
}
};
@@ -336,44 +336,30 @@ static wimp_MENU(3) hotlist_collapse = {
}
};
-
-static wimp_MENU(3) hotlist_save = {
- { "SaveSelect" }, 7,2,7,0, 200, 44, 0,
- {
- { wimp_MENU_GIVE_WARNING, (wimp_menu*)1, DEFAULT_FLAGS, { "URI" } },
- { wimp_MENU_GIVE_WARNING, (wimp_menu*)1, DEFAULT_FLAGS, { "URL" } },
- { wimp_MENU_LAST | wimp_MENU_GIVE_WARNING, (wimp_menu*)1, DEFAULT_FLAGS, { "HTML" } }
- }
-};
-
/* Hotlist file submenu
*/
-static wimp_MENU(5) hotlist_file = {
+static wimp_MENU(4) hotlist_file = {
{ "Hotlist" }, 7,2,7,0, 300, 44, 0,
{
{ 0, (wimp_menu *)&hotlist_new, DEFAULT_FLAGS, { "New" } },
- { wimp_MENU_GIVE_WARNING, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Save" } },
{ wimp_MENU_GIVE_WARNING | wimp_MENU_SEPARATE, (wimp_menu *)1, DEFAULT_FLAGS, { "Export" } },
{ 0, (wimp_menu *)&hotlist_expand, DEFAULT_FLAGS, { "Expand" } },
{ wimp_MENU_LAST, (wimp_menu *)&hotlist_collapse, DEFAULT_FLAGS, { "Collapse" } }
}
};
-
/* Hotlist file submenu
*/
-static wimp_MENU(5) hotlist_select = {
+static wimp_MENU(4) hotlist_select = {
{ "Selection" }, 7,2,7,0, 300, 44, 0,
{
- { wimp_MENU_GIVE_WARNING, (wimp_menu *)&hotlist_save, DEFAULT_FLAGS, { "SaveSelect" } },
- { wimp_MENU_GIVE_WARNING, (wimp_menu *)1, DEFAULT_FLAGS, { "Edit" } },
- { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Launch" } },
- { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Delete" } },
- { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "ResetUsage" } }
+ { wimp_MENU_GIVE_WARNING, (wimp_menu *)1, DEFAULT_FLAGS, { "Edit" } },
+ { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Launch" } },
+ { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Delete" } },
+ { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "ResetUsage" } }
}
};
-
/* Hotlist menu
*/
static wimp_MENU(4) hotlist_root = {
@@ -501,7 +487,6 @@ static wimp_menu *hotlist_new_menu = (wimp_menu *)&hotlist_new;
static wimp_menu *hotlist_expand_menu = (wimp_menu *)&hotlist_expand;
static wimp_menu *hotlist_collapse_menu = (wimp_menu *)&hotlist_collapse;
static wimp_menu *hotlist_file_menu = (wimp_menu *)&hotlist_file;
-static wimp_menu *hotlist_save_menu = (wimp_menu *)&hotlist_save;
static wimp_menu *hotlist_select_menu = (wimp_menu *)&hotlist_select;
@@ -535,7 +520,6 @@ void ro_gui_menus_init(void)
translate_menu(hotlist_expand_menu);
translate_menu(hotlist_collapse_menu);
translate_menu(hotlist_file_menu);
- translate_menu(hotlist_save_menu);
translate_menu(hotlist_select_menu);
translate_menu(toolbar_menu);
@@ -620,8 +604,8 @@ void build_languages_menu(void)
languages_menu->gap = 0;
while (context != -1) {
- e = xosgbpb_dir_entries_info("<NetSurf$Dir>.Resources", (osgbpb_info_list*)&info, 1, context, sizeof(info), 0, &read_count, &context);
-
+ e = xosgbpb_dir_entries_info("<NetSurf$Dir>.Resources", (osgbpb_info_list*)&info, 1,
+ context, sizeof(info), 0, &read_count, &context);
if (e)
die(e->errmess);
@@ -665,9 +649,6 @@ void ro_gui_create_menu(wimp_menu *menu, int x, int y, struct gui_window *g)
wimp_window_state state;
os_error *error;
- current_menu = menu;
- current_menu_x = x;
- current_menu_y = y;
current_gui = g;
if (menu == browser_menu) {
@@ -692,7 +673,7 @@ void ro_gui_create_menu(wimp_menu *menu, int x, int y, struct gui_window *g)
g->bw->current_content, doc_x, doc_y);
}
- if (!hotlist_window)
+ if (!hotlist_tree)
browser_utilities_menu->entries[0].icon_flags |=
wimp_ICON_SHADED;
if (gui_menu_object_box)
@@ -728,6 +709,10 @@ void ro_gui_create_menu(wimp_menu *menu, int x, int y, struct gui_window *g)
LOG(("xwimp_create_menu: 0x%x: %s",
error->errnum, error->errmess));
warn_user("MenuError", error->errmess);
+ } else {
+ current_menu = menu;
+ current_menu_x = x;
+ current_menu_y = y;
}
}
@@ -759,6 +744,7 @@ void ro_gui_menu_selection(wimp_selection *selection)
{
struct toolbar_icon *icon;
struct toolbar_icon *next;
+ struct node *node;
char url[80];
wimp_pointer pointer;
wimp_window_state state;
@@ -806,11 +792,11 @@ void ro_gui_menu_selection(wimp_selection *selection)
if ((height != current_toolbar->height) && (current_gui))
ro_gui_window_update_dimensions(current_gui,
height - current_toolbar->height);
- if ((height != current_toolbar->height) &&
+/* if ((height != current_toolbar->height) &&
(current_toolbar == hotlist_toolbar)) {
xwimp_force_redraw(hotlist_window, 0, -16384, 16384, 16384);
}
- ro_gui_menu_prepare_theme();
+*/ ro_gui_menu_prepare_theme();
break;
case 1: /* Toolbars-> */
@@ -855,46 +841,39 @@ void ro_gui_menu_selection(wimp_selection *selection)
switch (selection->items[1]) {
case 0: /* New */
break;
- case 1: /* Save */
- ro_gui_hotlist_save();
+ case 1: /* Export */
break;
- case 2: /* Export */
+ case 2: /* Expand */
+ tree_handle_expansion(hotlist_tree, hotlist_tree->root, true,
+ (selection->items[2] != 2), (selection->items[2] != 1));
break;
- case 3: /* Expand */
- ro_gui_hotlist_set_expanded(true,
- (selection->items[2] != 2),
- (selection->items[2] != 1));
- break;
- case 4: /* Collapse */
- ro_gui_hotlist_set_expanded(false,
- (selection->items[2] != 2),
- (selection->items[2] != 1));
+ case 3: /* Collapse */
+ tree_handle_expansion(hotlist_tree, hotlist_tree->root, false,
+ (selection->items[2] != 2), (selection->items[2] != 1));
break;
}
break;
case 1: /* Selection-> */
switch (selection->items[1]) {
- case 0: /* Save */
- break;
- case 1: /* Edit title-> */
+ case 0: /* Edit-> */
break;
- case 2: /* Launch */
- ro_gui_hotlist_keypress(wimp_KEY_RETURN);
+ case 1: /* Launch */
+ ro_gui_tree_launch_selected(hotlist_tree);
break;
- case 3: /* Delete */
- ro_gui_hotlist_delete_selected();
+ case 2: /* Delete */
+ tree_delete_selected_nodes(hotlist_tree, hotlist_tree->root);
break;
- case 4: /* Reset usage */
- ro_gui_hotlist_reset_statistics();
+ case 3: /* Reset usage */
+ tree_reset_URL_nodes(hotlist_tree, hotlist_tree->root, true);
break;
}
break;
case 2: /* Select all */
- ro_gui_hotlist_set_selected(true);
+ ro_gui_tree_keypress(1, hotlist_tree);
ro_gui_menu_prepare_hotlist();
break;
case 3: /* Clear */
- ro_gui_hotlist_set_selected(false);
+ ro_gui_tree_keypress(26, hotlist_tree);
ro_gui_menu_prepare_hotlist();
break;
}
@@ -924,7 +903,8 @@ void ro_gui_menu_selection(wimp_selection *selection)
case 5: /* Print */
break;
case 6: /* New window */
- browser_window_create(current_gui->bw->current_content->url, current_gui->bw, 0);
+ browser_window_create(current_gui->bw->current_content->url,
+ current_gui->bw, 0);
break;
case 7: /* Page source */
ro_gui_view_source(c);
@@ -971,7 +951,8 @@ void ro_gui_menu_selection(wimp_selection *selection)
switch (selection->items[1]) {
case 0: /* Home */
if (option_homepage_url && option_homepage_url[0]) {
- browser_window_go_post(current_gui->bw, option_homepage_url, 0, 0, true, 0);
+ browser_window_go_post(current_gui->bw, option_homepage_url,
+ 0, 0, true, 0);
} else {
snprintf(url, sizeof url,
"file:/<NetSurf$Dir>/Docs/intro_%s",
@@ -1009,10 +990,6 @@ void ro_gui_menu_selection(wimp_selection *selection)
current_gui->option.background_images =
!current_gui->option.background_images;
break;
- case 2:
- current_gui->option.animate_images =
- !current_gui->option.animate_images;
- break;
}
ro_gui_menu_prepare_images();
gui_window_redraw_window(current_gui);
@@ -1073,8 +1050,15 @@ void ro_gui_menu_selection(wimp_selection *selection)
case 0: /* Hotlist -> */
switch (selection->items[2]) {
case 0: /* Add to hotlist */
- ro_gui_hotlist_add(current_gui->title,
- current_gui->bw->current_content);
+ node = tree_create_URL_node(hotlist_tree->root,
+ messages_get(current_gui->title),
+ current_gui->bw->current_content->url,
+ ro_content_filetype(current_gui->bw->current_content),
+ time(NULL), -1, 0);
+ tree_redraw_area(hotlist_tree, node->box.x - NODE_INSTEP, 0,
+ NODE_INSTEP, 16384);
+ tree_handle_node_changed(hotlist_tree, node, false, true);
+ ro_gui_tree_scroll_visible(hotlist_tree, &node->data);
break;
case 1: /* Show hotlist */
ro_gui_hotlist_show();
@@ -1084,7 +1068,8 @@ void ro_gui_menu_selection(wimp_selection *selection)
case 1: /* Window -> */
switch (selection->items[2]) {
case 0:
- ro_gui_screen_size(&option_window_screen_width, &option_window_screen_height);
+ ro_gui_screen_size(&option_window_screen_width,
+ &option_window_screen_height);
state.w = current_gui->bw->window->window;
error = xwimp_get_window_state(&state);
if (error) {
@@ -1157,9 +1142,10 @@ void ro_gui_menu_selection(wimp_selection *selection)
current_menu_x, current_menu_y,
current_gui);
} else {
- if (current_menu == hotlist_menu) {
+ if (current_menu == hotlist_menu)
ro_gui_hotlist_menu_closed();
- }
+ current_menu = NULL;
+ current_gui = NULL;
}
}
@@ -1394,71 +1380,59 @@ void ro_gui_menu_browser_warning(wimp_message_menu_warning *warning)
void ro_gui_menu_hotlist_warning(wimp_message_menu_warning *warning)
{
- os_error *error = 0;
+ os_error *error = NULL;
+ struct node *node;
switch (warning->selection.items[0]) {
- case 0: /* Hotlist-> */
- switch (warning->selection.items[1]) {
- case 0: /* New-> */
- hotlist_insert = true;
- switch (warning->selection.items[2]) {
- case 0: /* Folder */
- ro_gui_hotlist_prepare_folder_dialog(false);
- error = xwimp_create_sub_menu(
- (wimp_menu *) dialog_folder,
- warning->pos.x, warning->pos.y);
- break;
- case 1: /* Entry */
- ro_gui_hotlist_prepare_entry_dialog(false);
- error = xwimp_create_sub_menu(
- (wimp_menu *) dialog_entry,
- warning->pos.x, warning->pos.y);
- }
- break;
- case 2: /* Export-> */
- ro_gui_save_open(GUI_SAVE_HOTLIST_EXPORT_HTML, 0, true,
- warning->pos.x, warning->pos.y, 0, false);
- break;
- }
- break;
- case 1: /* Selection-> */
- switch (warning->selection.items[1]) {
- case -1: /* Root */
- ro_gui_menu_prepare_hotlist();
- error = xwimp_create_sub_menu(hotlist_select_menu,
- warning->pos.x, warning->pos.y);
- break;
- case 0: /* Save-> */
- switch (warning->selection.items[2]) {
- case -1: /* No sub-menu */
- ro_gui_menu_prepare_hotlist();
- error = xwimp_create_sub_menu(hotlist_save_menu,
- warning->pos.x, warning->pos.y);
- break;
- case 1: /* URI */
- break;
- case 2: /* URL */
- break;
- case 3: /* HTML */
- break;
+ case 0: /* Hotlist-> */
+ switch (warning->selection.items[1]) {
+ case 0: /* New-> */
+ switch (warning->selection.items[2]) {
+ case 0: /* Folder */
+ ro_gui_hotlist_prepare_folder_dialog(NULL);
+ error = xwimp_create_sub_menu(
+ (wimp_menu *) dialog_folder,
+ warning->pos.x, warning->pos.y);
+ break;
+ case 1: /* Entry */
+ ro_gui_hotlist_prepare_entry_dialog(NULL);
+ error = xwimp_create_sub_menu(
+ (wimp_menu *) dialog_entry,
+ warning->pos.x, warning->pos.y);
+ break;
+ }
+ break;
+ case 1: /* Export-> */
+ ro_gui_save_open(GUI_SAVE_HOTLIST_EXPORT_HTML, 0, true,
+ warning->pos.x, warning->pos.y, 0, false);
+ break;
}
break;
- case 1: /* Edit-> */
- hotlist_insert = true;
- if (ro_gui_hotlist_get_selected(false) == 0) {
- ro_gui_hotlist_prepare_folder_dialog(true);
- error = xwimp_create_sub_menu(
- (wimp_menu *) dialog_folder,
- warning->pos.x, warning->pos.y);
- } else {
- ro_gui_hotlist_prepare_entry_dialog(true);
- error = xwimp_create_sub_menu(
- (wimp_menu *) dialog_entry,
- warning->pos.x, warning->pos.y);
+ case 1: /* Selection-> */
+ switch (warning->selection.items[1]) {
+ case -1: /* Root */
+ ro_gui_menu_prepare_hotlist();
+ error = xwimp_create_sub_menu(hotlist_select_menu,
+ warning->pos.x, warning->pos.y);
+ break;
+ case 0: /* Edit-> */
+ node = tree_get_selected_node(hotlist_tree->root);
+ if (!node)
+ break;
+ if (node->folder) {
+ ro_gui_hotlist_prepare_folder_dialog(node);
+ error = xwimp_create_sub_menu(
+ (wimp_menu *) dialog_folder,
+ warning->pos.x, warning->pos.y);
+ } else {
+ ro_gui_hotlist_prepare_entry_dialog(node);
+ error = xwimp_create_sub_menu(
+ (wimp_menu *) dialog_entry,
+ warning->pos.x, warning->pos.y);
+ }
+ break;
}
break;
- }
- break;
}
if (error) {
@@ -1535,6 +1509,7 @@ void ro_gui_prepare_navigate(struct gui_window *gui) {
ro_gui_set_icon_shaded_state(t->toolbar_handle, ICON_TOOLBAR_FORWARD, true);
ro_gui_set_icon_shaded_state(t->toolbar_handle, ICON_TOOLBAR_HISTORY, true);
}
+ ro_gui_set_icon_shaded_state(t->toolbar_handle, ICON_TOOLBAR_BOOKMARK, !hotlist_tree);
}
/* Update the stop/refresh icons/buttons
@@ -1611,7 +1586,6 @@ static void ro_gui_menu_prepare_images(void) {
browser_image_menu->entries[1].menu_flags &= ~wimp_MENU_TICKED;
if (current_gui->option.background_images) browser_image_menu->entries[1].menu_flags |= wimp_MENU_TICKED;
browser_image_menu->entries[2].menu_flags &= ~wimp_MENU_TICKED;
- if (current_gui->option.animate_images) browser_image_menu->entries[2].menu_flags |= wimp_MENU_TICKED;
}
@@ -1800,49 +1774,57 @@ void ro_gui_menu_prepare_scale(void) {
ro_gui_current_zoom_gui = current_gui;
}
+
/**
* Update hotlist menu (all of)
*/
void ro_gui_menu_prepare_hotlist(void) {
- int selection;
- int selection_full;
- selection = ro_gui_hotlist_get_selected(false);
- selection_full = ro_gui_hotlist_get_selected(true);
+ os_error *error;
+ bool reopen = false;
+ bool selection = false;
+ struct node *single = NULL;
+
+ if (hotlist_tree->root->child) {
+ single = tree_get_selected_node(hotlist_tree->root->child);
+ selection = tree_has_selection(hotlist_tree->root->child);
+ }
if (hotlist_toolbar) {
ro_gui_set_icon_shaded_state(hotlist_toolbar->toolbar_handle,
- ICON_TOOLBAR_DELETE, (selection_full == 0));
+ ICON_TOOLBAR_DELETE, !selection);
ro_gui_set_icon_shaded_state(hotlist_toolbar->toolbar_handle,
- ICON_TOOLBAR_LAUNCH, (selection == 0));
+ ICON_TOOLBAR_LAUNCH, !selection);
}
- if (selection_full == 0) {
- hotlist_menu->entries[1].icon_flags |= wimp_ICON_SHADED;
- hotlist_menu->entries[3].icon_flags |= wimp_ICON_SHADED;
- } else {
+
+ if (selection) {
+ reopen |= (hotlist_menu->entries[1].icon_flags & wimp_ICON_SHADED);
hotlist_menu->entries[1].icon_flags &= ~wimp_ICON_SHADED;
hotlist_menu->entries[3].icon_flags &= ~wimp_ICON_SHADED;
- }
- if (selection == 0) {
- hotlist_select_menu->entries[2].icon_flags |= wimp_ICON_SHADED;
- hotlist_select_menu->entries[4].icon_flags |= wimp_ICON_SHADED;
} else {
- hotlist_select_menu->entries[2].icon_flags &= ~wimp_ICON_SHADED;
- hotlist_select_menu->entries[4].icon_flags &= ~wimp_ICON_SHADED;
+ reopen |= !(hotlist_menu->entries[1].icon_flags & wimp_ICON_SHADED);
+ hotlist_menu->entries[1].icon_flags |= wimp_ICON_SHADED;
+ hotlist_menu->entries[3].icon_flags |= wimp_ICON_SHADED;
}
- if (selection_full != 1) {
- hotlist_select_menu->entries[1].icon_flags |= wimp_ICON_SHADED;
+
+ if (single) {
+ reopen |= (hotlist_select_menu->entries[0].icon_flags & wimp_ICON_SHADED);
+ hotlist_select_menu->entries[0].icon_flags &= ~wimp_ICON_SHADED;
} else {
- hotlist_select_menu->entries[1].icon_flags &= ~wimp_ICON_SHADED;
+ reopen |= !(hotlist_select_menu->entries[0].icon_flags & wimp_ICON_SHADED);
+ hotlist_select_menu->entries[0].icon_flags |= wimp_ICON_SHADED;
}
- if (selection != 1) {
- hotlist_save_menu->entries[0].icon_flags |= wimp_ICON_SHADED;
- hotlist_save_menu->entries[1].icon_flags |= wimp_ICON_SHADED;
- } else {
- hotlist_save_menu->entries[0].icon_flags &= ~wimp_ICON_SHADED;
- hotlist_save_menu->entries[1].icon_flags &= ~wimp_ICON_SHADED;
+
+ if ((reopen) && (current_menu == hotlist_menu)) {
+ error = xwimp_create_menu(hotlist_menu, 0, 0);
+ if (error) {
+ LOG(("xwimp_create_menu: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("MenuError", error->errmess);
+ }
}
}
+
/**
* Update the Interactive Help status
*
@@ -1926,8 +1908,11 @@ void ro_gui_menu_objectinfo(wimp_message_menu_warning *warning)
const char *mime = "-";
os_error *error;
- sprintf(icon_buf, "file_%x",
+ sprintf(icon_buf, "file_%.3x",
ro_content_filetype(gui_menu_object_box->object));
+ if (!ro_gui_wimp_sprite_exists(icon_buf))
+ sprintf(icon_buf, "file_xxx");
+
if (gui_menu_object_box->object->url)
url = gui_menu_object_box->object->url;
if (gui_menu_object_box->href)
diff --git a/riscos/options.h b/riscos/options.h
index 932486569..7ec661451 100644
--- a/riscos/options.h
+++ b/riscos/options.h
@@ -31,7 +31,6 @@ extern bool option_toolbar_show_status;
extern bool option_toolbar_show_buttons;
extern bool option_toolbar_show_address;
extern bool option_toolbar_show_throbber;
-extern bool option_animate_images;
extern int option_window_x;
extern int option_window_y;
extern int option_window_width;
@@ -88,7 +87,6 @@ bool option_toolbar_show_status = true; \
bool option_toolbar_show_buttons = true; \
bool option_toolbar_show_address = true; \
bool option_toolbar_show_throbber = true; \
-bool option_animate_images = true; \
int option_window_x = 0; \
int option_window_y = 0; \
int option_window_width = 0; \
@@ -145,7 +143,6 @@ bool option_font_ufont = false;
{ "toolbar_show_buttons", OPTION_BOOL, &option_toolbar_show_buttons }, \
{ "toolbar_show_address", OPTION_BOOL, &option_toolbar_show_address }, \
{ "toolbar_show_throbber", OPTION_BOOL, &option_toolbar_show_throbber }, \
-{ "animate_images", OPTION_BOOL, &option_animate_images }, \
{ "window_x", OPTION_INTEGER, &option_window_x }, \
{ "window_y", OPTION_INTEGER, &option_window_y }, \
{ "window_width", OPTION_INTEGER, &option_window_width }, \
diff --git a/riscos/save.c b/riscos/save.c
index 69d590e86..08d1f9fa7 100644
--- a/riscos/save.c
+++ b/riscos/save.c
@@ -309,7 +309,12 @@ void ro_gui_save_datasave_ack(wimp_message *message)
return;
break;
case GUI_SAVE_HOTLIST_EXPORT_HTML:
- ro_gui_hotlist_save_as(path);
+ if (!options_save_hotlist(hotlist_tree, path))
+ return;
+ error = xosfile_set_type(path, 0xfaf);
+ if (error)
+ LOG(("xosfile_set_type: 0x%x: %s",
+ error->errnum, error->errmess));
break;
}
diff --git a/riscos/treeview.c b/riscos/treeview.c
new file mode 100644
index 000000000..c8db5a21e
--- /dev/null
+++ b/riscos/treeview.c
@@ -0,0 +1,1183 @@
+/*
+ * This file is part of NetSurf, http://netsurf.sourceforge.net/
+ * Licensed under the GNU General Public License,
+ * http://www.opensource.org/licenses/gpl-license
+ * Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
+ */
+
+/** \file
+ * Generic tree handling (implementation).
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <swis.h>
+#include <time.h>
+#include "oslib/colourtrans.h"
+#include "oslib/dragasprite.h"
+#include "oslib/osbyte.h"
+#include "oslib/osspriteop.h"
+#include "oslib/wimp.h"
+#include "netsurf/desktop/tree.h"
+#include "netsurf/riscos/gui.h"
+#include "netsurf/riscos/tinct.h"
+#include "netsurf/riscos/treeview.h"
+#include "netsurf/riscos/wimp.h"
+#include "netsurf/utils/log.h"
+#include "netsurf/utils/messages.h"
+#include "netsurf/utils/utils.h"
+
+#define TREE_EXPAND 0
+#define TREE_COLLAPSE 1
+
+
+static bool ro_gui_tree_initialise_sprite(const char *name, int number);
+static void ro_gui_tree_launch_selected_node(struct node *node, bool all);
+static bool ro_gui_tree_launch_node(struct node *node);
+
+/* an array of sprite addresses for Tinct */
+static char *ro_gui_tree_sprites[2];
+
+/* origin adjustment */
+static int ro_gui_tree_origin_x;
+static int ro_gui_tree_origin_y;
+
+/* element drawing */
+static wimp_icon ro_gui_tree_icon;
+static char ro_gui_tree_icon_validation[24];
+static char ro_gui_tree_icon_null[] = "\0";
+
+/* dragging information */
+static struct tree *ro_gui_tree_current_drag_tree;
+static wimp_mouse_state ro_gui_tree_current_drag_buttons;
+
+/* editing information */
+static wimp_icon_create ro_gui_tree_edit_icon;
+
+/* dragging information */
+static char ro_gui_tree_drag_name[12];
+
+
+/**
+ * Performs any initialisation for tree rendering
+ */
+bool ro_gui_tree_initialise(void) {
+ if (ro_gui_tree_initialise_sprite("expand", TREE_EXPAND) ||
+ ro_gui_tree_initialise_sprite("collapse", TREE_COLLAPSE))
+ return false;
+
+ ro_gui_tree_edit_icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_INDIRECTED |
+ wimp_ICON_VCENTRED | wimp_ICON_FILLED | wimp_ICON_BORDER |
+ (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT) |
+ (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) |
+ (wimp_BUTTON_WRITABLE << wimp_ICON_BUTTON_TYPE_SHIFT);
+ ro_gui_tree_edit_icon.icon.data.indirected_text.validation =
+ ro_gui_tree_icon_null;
+ ro_gui_tree_edit_icon.icon.data.indirected_text.size = 256;
+
+ return true;
+}
+
+
+/**
+ * Initialise a sprite for use with Tinct
+ *
+ * \param name the name of the sprite
+ * \param number the sprite cache number
+ * \return whether an error occurred during initialisation
+ */
+bool ro_gui_tree_initialise_sprite(const char *name, int number) {
+ char icon_name[12];
+ os_error *error;
+
+ sprintf(icon_name, "tr_%s", name);
+ error = xosspriteop_select_sprite(osspriteop_USER_AREA, gui_sprites,
+ (osspriteop_id)icon_name,
+ (osspriteop_header **)&ro_gui_tree_sprites[number]);
+ if (error) {
+ warn_user("MiscError", error->errmess);
+ LOG(("Failed to find sprite 'tr_%s'", name));
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ * Informs the current window manager that an area requires updating.
+ *
+ * \param tree the tree that is requesting a redraw
+ * \param x the x co-ordinate of the redraw area
+ * \param y the y co-ordinate of the redraw area
+ * \param width the width of the redraw area
+ * \param height the height of the redraw area
+ */
+void tree_redraw_area(struct tree *tree, int x, int y, int width, int height) {
+ os_error *error;
+
+ assert(tree);
+ assert(tree->handle);
+
+ error = xwimp_force_redraw((wimp_w)tree->handle, tree->offset_x + x - 2,
+ -tree->offset_y - y - height, tree->offset_x + x + width + 4,
+ -tree->offset_y - y);
+ if (error) {
+ LOG(("xwimp_force_redraw: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
+}
+
+
+/**
+ * Draws a line.
+ *
+ * \param tree the tree to draw a line for
+ * \param x the x co-ordinate
+ * \param x the y co-ordinate
+ * \param x the width of the line
+ * \param x the height of the line
+ */
+void tree_draw_line(struct tree *tree, int x, int y, int width, int height) {
+ os_error *error;
+
+ assert(tree);
+
+ error = xcolourtrans_set_gcol((os_colour)0x88888800, 0, os_ACTION_OVERWRITE,
+ 0, 0);
+ if (error) {
+ LOG(("xcolourtrans_set_gcol: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("MiscError", error->errmess);
+ return;
+ }
+ error = xos_plot(os_MOVE_TO, ro_gui_tree_origin_x + x,
+ ro_gui_tree_origin_y - y);
+ if (!error)
+ xos_plot(os_PLOT_TO, ro_gui_tree_origin_x + x + width,
+ ro_gui_tree_origin_y - y - height);
+ if (error) {
+ LOG(("xos_plot: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("MiscError", error->errmess);
+ return;
+ }
+}
+
+
+/**
+ * Draws an element, including any expansion icons
+ *
+ * \param tree the tree to draw an element for
+ * \param element the element to draw
+ */
+void tree_draw_node_element(struct tree *tree, struct node_element *element) {
+ os_error *error;
+ int temp;
+
+ assert(tree);
+ assert(element);
+ assert(element->parent);
+
+ ro_gui_tree_icon.flags = wimp_ICON_INDIRECTED | wimp_ICON_VCENTRED |
+ (wimp_COLOUR_VERY_LIGHT_GREY << wimp_ICON_BG_COLOUR_SHIFT);
+ ro_gui_tree_icon.extent.x0 = tree->offset_x + element->box.x;
+ ro_gui_tree_icon.extent.y1 = -tree->offset_y - element->box.y;
+ ro_gui_tree_icon.extent.x1 = tree->offset_x + element->box.x +
+ element->box.width;
+ ro_gui_tree_icon.extent.y0 = -tree->offset_y - element->box.y -
+ element->box.height;
+ if (&element->parent->data == element) {
+ if (element->parent->selected)
+ ro_gui_tree_icon.flags |= wimp_ICON_SELECTED;
+ ro_gui_tree_icon.flags |= (wimp_COLOUR_BLACK <<
+ wimp_ICON_FG_COLOUR_SHIFT);
+ } else {
+ ro_gui_tree_icon.flags |= (wimp_COLOUR_DARK_GREY <<
+ wimp_ICON_FG_COLOUR_SHIFT);
+ }
+
+ switch (element->type) {
+ case NODE_ELEMENT_TEXT_PLUS_SPRITE:
+ assert(element->sprite);
+
+ ro_gui_tree_icon.flags |= wimp_ICON_TEXT | wimp_ICON_SPRITE;
+ ro_gui_tree_icon.data.indirected_text_and_sprite.text =
+ ro_gui_tree_icon_null;
+ ro_gui_tree_icon.data.indirected_text_and_sprite.validation =
+ ro_gui_tree_icon_validation;
+ ro_gui_tree_icon.data.indirected_text_and_sprite.size = 1;
+ if (element->parent->expanded) {
+ sprintf(ro_gui_tree_icon_validation, "S%s",
+ element->sprite->expanded_name);
+ } else {
+ sprintf(ro_gui_tree_icon_validation, "S%s",
+ element->sprite->name);
+ }
+ temp = ro_gui_tree_icon.extent.x1;
+ ro_gui_tree_icon.extent.x1 = ro_gui_tree_icon.extent.x0 +
+ NODE_INSTEP;
+ error = xwimp_plot_icon(&ro_gui_tree_icon);
+ if (error) {
+ LOG(("xwimp_plot_icon: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
+ ro_gui_tree_icon.extent.x0 = ro_gui_tree_icon.extent.x1;
+ ro_gui_tree_icon.extent.x1 = temp;
+ ro_gui_tree_icon.flags &= ~wimp_ICON_SPRITE;
+
+ case NODE_ELEMENT_TEXT:
+ assert(element->text);
+
+ if (element == tree->editing)
+ return;
+
+ if (ro_gui_tree_icon.flags & wimp_ICON_SELECTED)
+ ro_gui_tree_icon.flags |= wimp_ICON_FILLED;
+ ro_gui_tree_icon.flags |= wimp_ICON_TEXT;
+ ro_gui_tree_icon.data.indirected_text.text =
+ element->text;
+ ro_gui_tree_icon.data.indirected_text.validation =
+ ro_gui_tree_icon_null;
+ ro_gui_tree_icon.data.indirected_text.size =
+ strlen(element->text);
+ break;
+ case NODE_ELEMENT_SPRITE:
+ assert(element->sprite);
+
+ ro_gui_tree_icon.flags |= wimp_ICON_SPRITE;
+ ro_gui_tree_icon.data.indirected_sprite.id =
+ (osspriteop_id)element->sprite->name;
+ ro_gui_tree_icon.data.indirected_sprite.area =
+ element->sprite->area;
+ ro_gui_tree_icon.data.indirected_sprite.size =
+ strlen(element->sprite->name);
+ break;
+ }
+
+ error = xwimp_plot_icon(&ro_gui_tree_icon);
+ if (error) {
+ LOG(("xwimp_plot_icon: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
+}
+
+
+/**
+ * Draws an elements expansion icon
+ *
+ * \param tree the tree to draw the expansion for
+ * \param element the element to draw the expansion for
+ */
+void tree_draw_node_expansion(struct tree *tree, struct node *node) {
+ unsigned int type;
+
+ assert(tree);
+ assert(node);
+
+ if ((node->child) || (node->data.next)) {
+ if (node->expanded) {
+ type = TREE_COLLAPSE;
+ } else {
+ type = TREE_EXPAND;
+ }
+ _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
+ ro_gui_tree_sprites[type],
+ ro_gui_tree_origin_x + node->box.x -
+ (NODE_INSTEP / 2) - 8,
+ ro_gui_tree_origin_y - node->box.y -
+ (TREE_TEXT_HEIGHT / 2) - 8,
+ tinct_BILINEAR_FILTER);
+
+ }
+}
+
+
+/**
+ * Sets the origin variables to the correct values for a specified tree
+ *
+ * \param tree the tree to set the origin for
+ */
+void tree_initialise_redraw(struct tree *tree) {
+ os_error *error;
+ wimp_window_state state;
+
+ assert(tree->handle);
+
+ state.w = (wimp_w)tree->handle;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ LOG(("xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
+
+ ro_gui_tree_origin_x = state.visible.x0 - state.xscroll + tree->offset_x;
+ ro_gui_tree_origin_y = state.visible.y1 - state.yscroll - tree->offset_y;
+}
+
+
+/**
+ * Recalculates the dimensions of a node element.
+ *
+ * \param element the element to recalculate
+ */
+void tree_recalculate_node_element(struct node_element *element) {
+ os_error *error;
+ int sprite_width;
+ int sprite_height;
+ osspriteop_flags flags;
+
+ assert(element);
+
+ switch (element->type) {
+ case NODE_ELEMENT_TEXT_PLUS_SPRITE:
+ assert(element->sprite);
+ case NODE_ELEMENT_TEXT:
+ assert(element->text);
+
+ error = xwimptextop_string_width(element->text,
+ strlen(element->text),
+ &element->box.width);
+ if (error) {
+ LOG(("xwimptextop_string_width: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
+ element->box.width += 16;
+ element->box.height = TREE_TEXT_HEIGHT;
+ if (element->type == NODE_ELEMENT_TEXT_PLUS_SPRITE)
+ element->box.width += NODE_INSTEP;
+ break;
+ case NODE_ELEMENT_SPRITE:
+ assert(element->sprite);
+
+ flags = ((int)element->sprite->area == 1) ?
+ osspriteop_SYSTEM_AREA :
+ osspriteop_USER_AREA;
+ error = xosspriteop_read_sprite_info(flags,
+ element->sprite->area,
+ (osspriteop_id)element->sprite->name,
+ &sprite_width, &sprite_height, 0, 0);
+ if (error) {
+ LOG(("xosspriteop_read_sprite_info: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
+ element->box.width = sprite_width * 2;
+ element->box.height = sprite_height * 2;
+ if (element->box.height < TREE_TEXT_HEIGHT)
+ element->box.height = TREE_TEXT_HEIGHT;
+ break;
+ }
+}
+
+
+/**
+ * Sets a node element as having a specific sprite.
+ *
+ * \param node the node to update
+ * \param sprite the sprite to use
+ * \param selected the expanded sprite name to use
+ */
+void tree_set_node_sprite(struct node *node, const char *sprite,
+ const char *expanded) {
+ assert(node);
+ assert(sprite);
+ assert(expanded);
+ assert(node->data.type != NODE_ELEMENT_SPRITE);
+
+ node->data.sprite = calloc(sizeof(struct node_sprite), 1);
+ if (!node->data.sprite) return;
+ node->data.type = NODE_ELEMENT_TEXT_PLUS_SPRITE;
+ node->data.sprite->area = (osspriteop_area *)1;
+ sprintf(node->data.sprite->name, sprite);
+ sprintf(node->data.sprite->expanded_name, expanded);
+}
+
+
+/**
+ * Sets a node element as having a folder sprite
+ *
+ * \param node the node to update
+ */
+void tree_set_node_sprite_folder(struct node *node) {
+ assert(node->folder);
+
+ tree_set_node_sprite(node, "small_dir", "small_diro");
+}
+
+
+/**
+ * Updates the node details for a URL node.
+ * The internal node dimensions are not updated.
+ *
+ * \param node the node to update
+ */
+void tree_update_URL_node(struct node *node) {
+ struct node_element *element;
+ char buffer[256];
+
+ assert(node);
+
+ element = tree_find_element(node, TREE_ELEMENT_URL);
+ if (element) {
+ sprintf(buffer, "small_%.3x", element->user_data);
+ if (ro_gui_wimp_sprite_exists(buffer))
+ tree_set_node_sprite(node, buffer, buffer);
+ else
+ tree_set_node_sprite(node, "small_xxx", "small_xxx");
+ }
+
+ element = tree_find_element(node, TREE_ELEMENT_ADDED);
+ if (element) {
+ if (element->text) {
+ free(element->text);
+ element->text = NULL;
+ }
+ if (element->user_data > 0) {
+ snprintf(buffer, 256, messages_get("TreeAdded"),
+ ctime((time_t *)&element->user_data));
+ } else {
+ snprintf(buffer, 256, messages_get("TreeAdded"),
+ messages_get("TreeUnknown"));
+ }
+ element->text = strdup(buffer);
+ }
+
+ element = tree_find_element(node, TREE_ELEMENT_LAST_VISIT);
+ if (element) {
+ if (element->text) {
+ free(element->text);
+ element->text = NULL;
+ }
+ if (element->user_data > 0) {
+ snprintf(buffer, 256, messages_get("TreeLast"),
+ ctime((time_t *)&element->user_data));
+ } else {
+ snprintf(buffer, 256, messages_get("TreeLast"),
+ messages_get("TreeUnknown"));
+ }
+ element->text = strdup(buffer);
+ }
+
+ element = tree_find_element(node, TREE_ELEMENT_VISITS);
+ if (element) {
+ if (element->text) {
+ free(element->text);
+ element->text = NULL;
+ }
+ snprintf(buffer, 256, messages_get("TreeVisits"),
+ element->user_data);
+ element->text = strdup(buffer);
+ }
+
+}
+
+
+/**
+ * Updates the tree owner following a tree resize
+ *
+ * \param tree the tree to update the owner of
+ */
+void tree_resized(struct tree *tree) {
+ os_error *error;
+ wimp_window_state state;
+
+ assert(tree->handle);
+
+
+ state.w = (wimp_w)tree->handle;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ LOG(("xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return;
+ }
+ if (state.flags & wimp_WINDOW_OPEN)
+ ro_gui_tree_open((wimp_open *)&state, tree);
+}
+
+
+/**
+ * Redraws a tree window
+ *
+ * \param redraw the area to redraw
+ * \param tree the tree to redraw
+ */
+void ro_gui_tree_redraw(wimp_draw *redraw, struct tree *tree) {
+ osbool more;
+ int clip_x0, clip_x1, clip_y0, clip_y1, origin_x, origin_y;
+
+ more = wimp_redraw_window(redraw);
+ while (more) {
+ clip_x0 = redraw->clip.x0;
+ clip_y0 = redraw->clip.y0;
+ clip_x1 = redraw->clip.x1;
+ clip_y1 = redraw->clip.y1;
+ origin_x = redraw->box.x0 - redraw->xscroll;
+ origin_y = redraw->box.y1 - redraw->yscroll;
+ tree_draw(tree, clip_x0 - origin_x - tree->offset_x,
+ origin_y - clip_y1 - tree->offset_y,
+ clip_x1 - clip_x0, clip_y1 - clip_y0);
+ more = wimp_get_rectangle(redraw);
+ }
+}
+
+
+/**
+ * Handles a mouse click for a tree
+ *
+ * \param pointer the pointer state
+ * \param tree the tree to handle a click for
+ * \return whether the click was handled#
+ */
+bool ro_gui_tree_click(wimp_pointer *pointer, struct tree *tree) {
+ bool furniture;
+ struct node *node;
+ struct node_element *element;
+ int x, y;
+ int alt_pressed = 0;
+ wimp_window_state state;
+ wimp_caret caret;
+ wimp_drag drag;
+ wimp_auto_scroll_info scroll;
+ os_error *error;
+ os_box box = { pointer->pos.x - 34, pointer->pos.y - 34,
+ pointer->pos.x + 34, pointer->pos.y + 34 };
+
+ assert(tree);
+ assert(tree->root);
+
+ /* gain the input focus when required */
+ state.w = (wimp_w)tree->handle;
+ error = xwimp_get_window_state(&state);
+ if (error)
+ LOG(("xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ error = xwimp_get_caret_position(&caret);
+ if (error)
+ LOG(("xwimp_get_caret_position: 0x%x: %s",
+ error->errnum, error->errmess));
+ if (((pointer->buttons == (wimp_CLICK_SELECT << 8)) ||
+ (pointer->buttons == (wimp_CLICK_ADJUST << 8))) &&
+ (caret.w != state.w)) {
+ error = xwimp_set_caret_position((wimp_w)tree->handle, -1, -100,
+ -100, 32, -1);
+ if (error)
+ LOG(("xwimp_set_caret_position: 0x%x: %s",
+ error->errnum, error->errmess));
+ }
+
+ if (!tree->root->child)
+ return true;
+
+ tree_initialise_redraw(tree);
+ x = pointer->pos.x - ro_gui_tree_origin_x;
+ y = ro_gui_tree_origin_y - pointer->pos.y;
+ element = tree_get_node_element_at(tree->root->child, x, y, &furniture);
+ node = element->parent;
+
+
+ /* stop editing for anything but a drag */
+ if ((tree->editing) && (pointer->i != tree->edit_handle) &&
+ (pointer->buttons != (wimp_CLICK_SELECT << 4)))
+ ro_gui_tree_stop_edit(tree);
+
+ /* handle a menu click */
+ if (pointer->buttons == wimp_CLICK_MENU) {
+ if ((!element) || (!tree->root->child) ||
+ (tree_has_selection(tree->root->child)))
+ return true;
+ tree->temp_selection = node;
+ node->selected = true;
+ tree_handle_node_element_changed(tree, &node->data);
+ return true;
+
+ }
+
+ /* no item either means cancel selection on (select) click or a drag */
+ if (!element) {
+ if ((pointer->buttons == (wimp_CLICK_SELECT << 4)) ||
+ (pointer->buttons == (wimp_CLICK_SELECT << 8)))
+ tree_set_node_selected(tree, tree->root->child, false);
+ if ((pointer->buttons == (wimp_CLICK_SELECT << 4)) ||
+ (pointer->buttons == (wimp_CLICK_ADJUST << 4))) {
+
+ scroll.w = (wimp_w)tree->handle;
+ scroll.pause_zone_sizes.y0 = 80;
+ scroll.pause_zone_sizes.y1 = 80;
+ scroll.pause_duration = 0;
+ scroll.state_change = (void *)0;
+ error = xwimp_auto_scroll(wimp_AUTO_SCROLL_ENABLE_VERTICAL,
+ &scroll, 0);
+ if (error)
+ LOG(("xwimp_auto_scroll: 0x%x: %s",
+ error->errnum, error->errmess));
+
+ gui_current_drag_type = GUI_DRAG_TREE_SELECT;
+ ro_gui_tree_current_drag_tree = tree;
+ ro_gui_tree_current_drag_buttons = pointer->buttons;
+
+ drag.w = (wimp_w)tree->handle;
+ drag.type = wimp_DRAG_USER_RUBBER;
+ drag.initial.x0 = pointer->pos.x;
+ drag.initial.x1 = pointer->pos.x;
+ drag.initial.y0 = pointer->pos.y;
+ drag.initial.y1 = pointer->pos.y;
+ drag.bbox.x0 = state.visible.x0;
+ drag.bbox.x1 = state.visible.x1;
+ drag.bbox.y0 = -16384;//state.visible.y0;
+ drag.bbox.y1 = 16384;//state.visible.y1 - tree->offset_y;
+ error = xwimp_drag_box_with_flags(&drag,
+ wimp_DRAG_BOX_KEEP_IN_LINE |
+ wimp_DRAG_BOX_CLIP);
+ if (error)
+ LOG(("xwimp_drag_box_with_flags: 0x%x: %s",
+ error->errnum, error->errmess));
+
+ }
+ return true;
+ }
+
+ /* click on furniture or double click on folder toggles node expansion */
+ if (((furniture) && ((pointer->buttons == wimp_CLICK_SELECT << 8) ||
+ (pointer->buttons == wimp_CLICK_ADJUST << 8) ||
+ (pointer->buttons == wimp_CLICK_SELECT) ||
+ (pointer->buttons == wimp_CLICK_ADJUST))) ||
+ ((!furniture) && (node->child) &&
+ ((pointer->buttons == wimp_CLICK_SELECT) ||
+ (pointer->buttons == wimp_CLICK_ADJUST)))) {
+ node->expanded = !node->expanded;
+ if (!furniture)
+ node->selected = false;
+ tree_handle_node_changed(tree, node, false, true);
+ return true;
+ }
+
+ /* no use for any other furniture click */
+ if (furniture)
+ return true;
+
+ /* single/double alt+click starts editing */
+ if ((node->editable) && (!tree->editing) && ((element->user_type == 0) ||
+ (element->user_type == TREE_ELEMENT_URL)) &&
+ ((pointer->buttons == wimp_CLICK_SELECT) ||
+ (pointer->buttons == (wimp_CLICK_SELECT << 8)))) {
+ xosbyte1(osbyte_SCAN_KEYBOARD, 2 ^ 0x80, 0, &alt_pressed);
+ if ((alt_pressed == 0xff) &&
+ (element->type != NODE_ELEMENT_SPRITE)) {
+ ro_gui_tree_start_edit(tree, element, pointer);
+ return true;
+ }
+ }
+
+ /* double click starts launches the leaf */
+ if ((pointer->buttons == wimp_CLICK_SELECT) ||
+ (pointer->buttons == wimp_CLICK_ADJUST)) {
+ if (!ro_gui_tree_launch_node(node))
+ return false;
+ if (pointer->buttons == wimp_CLICK_ADJUST)
+ ro_gui_tree_keypress(wimp_KEY_CONTROL + wimp_KEY_F2, tree);
+ return true;
+ }
+
+ /* single click (select) cancels current selection and selects item */
+ if (pointer->buttons == (wimp_CLICK_SELECT << 8)) {
+ if (!node->selected) {
+ tree_set_node_selected(tree, tree->root->child, false);
+ node->selected = true;
+ tree_handle_node_element_changed(tree, &node->data);
+ }
+ return true;
+ }
+
+ /* single click (adjust) toggles item selection */
+ if (pointer->buttons == (wimp_CLICK_ADJUST << 8)) {
+ node->selected = !node->selected;
+ tree_handle_node_element_changed(tree, &node->data);
+ return true;
+ }
+
+ /* drag starts a drag operation */
+ if ((!tree->editing) && ((pointer->buttons == (wimp_CLICK_SELECT << 4)) ||
+ (pointer->buttons == (wimp_CLICK_ADJUST << 4)))) {
+
+ if (!node->selected) {
+ node->selected = true;
+ tree_handle_node_element_changed(tree, &node->data);
+ }
+
+ scroll.w = (wimp_w)tree->handle;
+ scroll.pause_zone_sizes.y0 = 80;
+ scroll.pause_zone_sizes.y1 = 80;
+ scroll.pause_duration = -1;
+ scroll.state_change = (void *)0;
+ error = xwimp_auto_scroll(wimp_AUTO_SCROLL_ENABLE_VERTICAL,
+ &scroll, 0);
+ if (error)
+ LOG(("xwimp_auto_scroll: 0x%x: %s",
+ error->errnum, error->errmess));
+
+ gui_current_drag_type = GUI_DRAG_TREE_MOVE;
+ ro_gui_tree_current_drag_tree = tree;
+ ro_gui_tree_current_drag_buttons = pointer->buttons;
+
+ node = tree_get_selected_node(tree->root);
+ if (node) {
+ if (node->folder) {
+ if ((node->expanded) &&
+ (ro_gui_wimp_sprite_exists("directoryo")))
+ sprintf(ro_gui_tree_drag_name, "directoryo");
+ else
+ sprintf(ro_gui_tree_drag_name, "directory");
+ } else {
+ element = tree_find_element(node, TREE_ELEMENT_URL);
+ if (element) {
+ sprintf(ro_gui_tree_drag_name, "file_%.3x",
+ element->user_data);
+ } else {
+ sprintf(ro_gui_tree_drag_name, "file_xxx");
+ }
+ if (!ro_gui_wimp_sprite_exists(ro_gui_tree_drag_name))
+ sprintf(ro_gui_tree_drag_name, "file_xxx");
+ }
+ } else {
+ sprintf(ro_gui_tree_drag_name, "package");
+ }
+
+ error = xdragasprite_start(dragasprite_HPOS_CENTRE |
+ dragasprite_VPOS_CENTRE |
+ dragasprite_BOUND_POINTER |
+ dragasprite_DROP_SHADOW,
+ (osspriteop_area *) 1,
+ ro_gui_tree_drag_name, &box, 0);
+ if (error)
+ LOG(("xdragasprite_start: 0x%x: %s",
+ error->errnum, error->errmess));
+ return true;
+ }
+
+
+ return false;
+}
+
+
+/**
+ * Handles a menu closed event
+ *
+ * \param tree the tree to handle the event for
+ */
+void ro_gui_tree_menu_closed(struct tree *tree) {
+ assert(tree);
+
+ if (tree->temp_selection) {
+ tree->temp_selection->selected = false;
+ tree_handle_node_element_changed(tree, &tree->temp_selection->data);
+ tree->temp_selection = NULL;
+ }
+}
+
+
+/**
+ * Starts an editing session
+ *
+ * \param tree the tree to start editing for
+ * \param element the element to edit
+ * \param pointer the pointer data to use for caret positioning (or NULL)
+ */
+void ro_gui_tree_start_edit(struct tree *tree, struct node_element *element,
+ wimp_pointer *pointer) {
+ os_error *error;
+ wimp_window_state state;
+ struct node *parent;
+
+ assert(tree);
+ assert(element);
+
+ if (tree->editing)
+ ro_gui_tree_stop_edit(tree);
+
+ parent = element->parent;
+ if (&parent->data == element)
+ parent = parent->parent;
+ for (; parent; parent = parent->parent) {
+ if (!parent->expanded) {
+ parent->expanded = true;
+ tree_handle_node_changed(tree, parent, false, true);
+ }
+ }
+
+ tree->editing = element;
+ snprintf(tree->edit_buffer, 256, element->text);
+ tree->edit_buffer[255] = '\0';
+ ro_gui_tree_edit_icon.w = (wimp_w)tree->handle;
+ ro_gui_tree_edit_icon.icon.extent.x0 = tree->offset_x + element->box.x - 2;
+ ro_gui_tree_edit_icon.icon.extent.x1 = tree->offset_x +
+ element->box.x + element->box.width + 2;
+ ro_gui_tree_edit_icon.icon.extent.y1 = -tree->offset_y - element->box.y;
+ ro_gui_tree_edit_icon.icon.extent.y0 = -tree->offset_y -
+ element->box.y - element->box.height;
+ if (element->type == NODE_ELEMENT_TEXT_PLUS_SPRITE)
+ ro_gui_tree_edit_icon.icon.extent.x0 += NODE_INSTEP;
+ ro_gui_tree_edit_icon.icon.data.indirected_text.text = tree->edit_buffer;
+ error = xwimp_create_icon(&ro_gui_tree_edit_icon,
+ &(wimp_i)tree->edit_handle);
+ if (error)
+ LOG(("xwimp_create_icon: 0x%x: %s",
+ error->errnum, error->errmess));
+ if (pointer) {
+ state.w = (wimp_w)tree->handle;
+ error = xwimp_get_window_state(&state);
+ if (error)
+ LOG(("xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ error = xwimp_set_caret_position((wimp_w)tree->handle,
+ (wimp_i)tree->edit_handle,
+ pointer->pos.x - state.visible.x0, 0,
+ element->box.height, -1);
+ } else {
+ error = xwimp_set_caret_position((wimp_w)tree->handle,
+ (wimp_i)tree->edit_handle,
+ 0, 0, -1, strlen(tree->edit_buffer));
+ }
+ if (error)
+ LOG(("xwimp_set_caret_position: 0x%x: %s",
+ error->errnum, error->errmess));
+ tree_handle_node_element_changed(tree, element);
+ ro_gui_tree_scroll_visible(tree, element);
+}
+
+
+/**
+ * Stops any current editing session
+ *
+ * \param tree the tree to stop editing for
+ */
+void ro_gui_tree_stop_edit(struct tree *tree) {
+ os_error *error;
+
+ assert(tree);
+
+ if (!tree->editing) return;
+
+ error = xwimp_delete_icon((wimp_w)tree->handle, (wimp_i)tree->edit_handle);
+ if (error)
+ LOG(("xwimp_delete_icon: 0x%x: %s",
+ error->errnum, error->errmess));
+ tree_handle_node_element_changed(tree, tree->editing);
+ tree->editing = NULL;
+
+ error = xwimp_set_caret_position((wimp_w)tree->handle, -1, -100,
+ -100, 32, -1);
+ if (error)
+ LOG(("xwimp_set_caret_position: 0x%x: %s",
+ error->errnum, error->errmess));
+ tree_recalculate_size(tree);
+}
+
+
+/**
+ * Scrolls the tree to make an element visible
+ *
+ * \param tree the tree to scroll
+ * \param element the element to display
+ */
+void ro_gui_tree_scroll_visible(struct tree *tree, struct node_element *element) {
+ wimp_window_state state;
+ int x0, x1, y0, y1;
+ os_error *error;
+
+ assert(element);
+
+ state.w = (wimp_w)tree->handle;
+ error = xwimp_get_window_state(&state);
+ if (error)
+ LOG(("xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ if (!(state.flags & wimp_WINDOW_OPEN))
+ return;
+ x0 = state.xscroll;
+ y0 = -state.yscroll;
+ x1 = x0 + state.visible.x1 - state.visible.x0 - tree->offset_x;
+ y1 = y0 - state.visible.y0 + state.visible.y1 - tree->offset_y;
+
+ state.yscroll = state.visible.y1 - state.visible.y0 - tree->offset_y - y1;
+ if ((element->box.y >= y0) && (element->box.y + element->box.height <= y1))
+ return;
+ if (element->box.y < y0)
+ state.yscroll = -element->box.y;
+ if (element->box.y + element->box.height > y1)
+ state.yscroll = state.visible.y1 - state.visible.y0 -
+ tree->offset_y -
+ (element->box.y + element->box.height);
+ ro_gui_tree_open((wimp_open *)&state, tree);
+}
+
+
+/**
+ * Handles a window open request
+ *
+ * \param open the window state
+ * \param tree the tree to handle a request for
+ */
+void ro_gui_tree_open(wimp_open *open, struct tree *tree) {
+ os_error *error;
+ int width;
+ int height;
+
+ width = open->visible.x1 - open->visible.x0;
+ if (width < (tree->offset_x + tree->width))
+ width = tree->offset_x + tree->width;
+ height = open->visible.y1 - open->visible.y0;
+ if (height < (tree->offset_y + tree->height))
+ height = tree->offset_y + tree->height;
+
+ if ((height != tree->window_height) || (width != tree->window_width)) {
+ os_box extent = { 0, -height, width, 0};
+ error = xwimp_set_extent((wimp_w)tree->handle, &extent);
+ if (error) {
+ LOG(("xwimp_set_extent: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
+ tree->window_width = width;
+ tree->window_height = height;
+ }
+
+ error = xwimp_open_window(open);
+ if (error) {
+ LOG(("xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
+}
+
+
+/**
+ * Handles a keypress for a tree
+ *
+ * \param key the key pressed
+ * \param tree the tree to handle a keypress for
+ * \return whether the key was processed
+ */
+bool ro_gui_tree_keypress(int key, struct tree *tree) {
+ os_error *error;
+ char *new_string;
+
+ /* Handle basic keys
+ */
+ switch (key) {
+ case 1: /* CTRL+A */
+ ro_gui_tree_stop_edit(tree);
+ if (tree->root->child) {
+ tree->temp_selection = NULL;
+ tree_set_node_selected(tree, tree->root, true);
+ }
+ return true;
+ case 24: /* CTRL+X */
+ ro_gui_tree_stop_edit(tree);
+ tree_delete_selected_nodes(hotlist_tree, hotlist_tree->root);
+ return true;
+ case 26: /* CTRL+Z */
+ tree->temp_selection = NULL;
+ ro_gui_tree_stop_edit(tree);
+ tree_set_node_selected(tree, tree->root, false);
+ return true;
+ case wimp_KEY_RETURN:
+ if (tree->editing) {
+ new_string = strdup(tree->edit_buffer);
+ if (new_string) {
+ if (tree->editing->text) {
+ free(tree->editing->text);
+ tree->editing->text = NULL;
+ }
+ tree->editing->text = new_string;
+ }
+ ro_gui_tree_stop_edit(tree);
+ tree_recalculate_size(tree);
+ } else {
+ ro_gui_tree_launch_selected(tree);
+ }
+ return true;
+ case wimp_KEY_CONTROL + wimp_KEY_F2:
+ error = xwimp_close_window((wimp_w)tree->handle);
+ if (error)
+ LOG(("xwimp_close_window: 0x%x: %s",
+ error->errnum, error->errmess));
+ return true;
+ case wimp_KEY_ESCAPE:
+ if (tree->editing) {
+ ro_gui_tree_stop_edit(tree);
+ } else {
+ /* \todo cancel drags etc. */
+ }
+ }
+ return false;
+}
+
+
+/**
+ * Handles the completion of a selection drag (GUI_DRAG_TREE_SELECT)
+ *
+ * \param drag the drag box information
+ */
+void ro_gui_tree_selection_drag_end(wimp_dragged *drag) {
+ wimp_window_state state;
+ wimp_auto_scroll_info scroll;
+ os_error *error;
+ int x0, y0, x1, y1;
+
+ scroll.w = (wimp_w)ro_gui_tree_current_drag_tree->handle;
+ error = xwimp_auto_scroll(0, &scroll, 0);
+ if (error)
+ LOG(("xwimp_auto_scroll: 0x%x: %s", error->errnum, error->errmess));
+
+ state.w = (wimp_w)ro_gui_tree_current_drag_tree->handle;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ LOG(("xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return;
+ }
+
+ x0 = drag->final.x0 - state.visible.x0 - state.xscroll +
+ ro_gui_tree_current_drag_tree->offset_x;
+ y0 = state.visible.y1 - state.yscroll - drag->final.y0 -
+ ro_gui_tree_current_drag_tree->offset_y;
+ x1 = drag->final.x1 - state.visible.x0 - state.xscroll +
+ ro_gui_tree_current_drag_tree->offset_x;
+ y1 = state.visible.y1 - state.yscroll - drag->final.y1 -
+ ro_gui_tree_current_drag_tree->offset_y;
+ tree_handle_selection_area(ro_gui_tree_current_drag_tree, x0, y0,
+ x1 - x0, y1 - y0,
+ (ro_gui_tree_current_drag_buttons == (wimp_CLICK_ADJUST << 4)));
+
+ /* send an empty keypress to stimulate the tree owner to update the GUI.
+ for this to work, we must always own the caret when this function is
+ called. */
+ error = xwimp_process_key(0);
+ if (error)
+ LOG(("xwimp_process_key: 0x%x: %s",
+ error->errnum, error->errmess));
+}
+
+
+/**
+ * Converts screen co-ordinates to tree ones
+ *
+ * \param tree the tree to calculate for
+ * \param x the screen x co-ordinate
+ * \param x the screen y co-ordinate
+ * \param tree_x updated to the tree x co-ordinate
+ * \param tree_y updated to the tree y co-ordinate
+ */
+void ro_gui_tree_get_tree_coordinates(struct tree *tree, int x, int y,
+ int *tree_x, int *tree_y) {
+ wimp_window_state state;
+ os_error *error;
+
+ state.w = (wimp_w)tree->handle;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ LOG(("xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return;
+ }
+ *tree_x = x - state.visible.x0 - state.xscroll + tree->offset_x;
+ *tree_y = state.visible.y1 - state.yscroll - y - tree->offset_y;
+}
+
+
+/**
+ * Handles the completion of a move drag (GUI_DRAG_TREE_MOVE)
+ *
+ * \param drag the drag box information
+ */
+void ro_gui_tree_move_drag_end(wimp_dragged *drag) {
+ wimp_pointer pointer;
+ wimp_auto_scroll_info scroll;
+ os_error *error;
+ struct node *node;
+ bool before;
+ int x, y;
+
+ scroll.w = (wimp_w)ro_gui_tree_current_drag_tree->handle;
+ error = xwimp_auto_scroll(0, &scroll, 0);
+ if (error)
+ LOG(("xwimp_auto_scroll: 0x%x: %s", error->errnum, error->errmess));
+
+ error = xwimp_get_pointer_info(&pointer);
+ if (error) {
+ LOG(("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return;
+ }
+
+ /* todo: handle export */
+ if (pointer.w != (wimp_w)ro_gui_tree_current_drag_tree->handle)
+ return;
+
+ /* internal drag */
+ ro_gui_tree_get_tree_coordinates(ro_gui_tree_current_drag_tree,
+ drag->final.x0 + 34, drag->final.y0 + 34, &x, &y);
+ node = tree_get_link_details(ro_gui_tree_current_drag_tree, x, y, &before);
+ tree_move_selected_nodes(ro_gui_tree_current_drag_tree, node, before);
+}
+
+
+/**
+ * Launches all selected nodes.
+ *
+ * \param tree the tree to launch all selected nodes for
+ */
+void ro_gui_tree_launch_selected(struct tree *tree) {
+ assert(tree);
+
+ if (tree->root->child)
+ ro_gui_tree_launch_selected_node(tree->root->child, false);
+}
+
+
+/**
+ * Launches all selected nodes.
+ *
+ * \param node the node to launch all selected nodes for
+ */
+void ro_gui_tree_launch_selected_node(struct node *node, bool all) {
+ for (; node; node = node->next) {
+ if (((node->selected) || (all)) && (!node->folder))
+ ro_gui_tree_launch_node(node);
+ if ((node->child) && ((node->expanded) || (node->selected) | (all)))
+ ro_gui_tree_launch_selected_node(node->child,
+ (node->selected) | (all));
+ }
+}
+
+
+/**
+ * Launches a node using all known methods.
+ *
+ * \param node the node to launch
+ * \return whether the node could be launched
+ */
+bool ro_gui_tree_launch_node(struct node *node) {
+ struct node_element *element;
+
+ assert(node);
+
+ element = tree_find_element(node, TREE_ELEMENT_URL);
+ if (element) {
+ browser_window_create(element->text, NULL, 0);
+ return true;
+ }
+
+ return false;
+}
diff --git a/riscos/treeview.h b/riscos/treeview.h
new file mode 100644
index 000000000..1757d2fd8
--- /dev/null
+++ b/riscos/treeview.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of NetSurf, http://netsurf.sourceforge.net/
+ * Licensed under the GNU General Public License,
+ * http://www.opensource.org/licenses/gpl-license
+ * Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
+ */
+
+/** \file
+ * Generic tree handling (interface).
+ */
+
+#ifndef _NETSURF_RISCOS_TREEVIEW_H_
+#define _NETSURF_RISCOS_TREEVIEW_H_
+
+#include <stdbool.h>
+#include "oslib/osspriteop.h"
+#include "oslib/wimp.h"
+#include "netsurf/desktop/tree.h"
+
+#define TREE_TEXT_HEIGHT 40
+#define TREE_SPRITE_WIDTH 40 /* text plus sprite entries only */
+
+struct node_sprite {
+ osspriteop_area *area;
+ char name[12];
+ char expanded_name[12];
+};
+
+bool ro_gui_tree_initialise(void);
+void ro_gui_tree_redraw(wimp_draw *redraw, struct tree *tree);
+bool ro_gui_tree_click(wimp_pointer *pointer, struct tree *tree);
+void ro_gui_tree_menu_closed(struct tree *tree);
+void ro_gui_tree_stop_edit(struct tree *tree);
+void ro_gui_tree_open(wimp_open *open, struct tree *tree);
+bool ro_gui_tree_keypress(int key, struct tree *tree);
+void ro_gui_tree_selection_drag_end(wimp_dragged *drag);
+void ro_gui_tree_move_drag_end(wimp_dragged *drag);
+void ro_gui_tree_launch_selected(struct tree *tree);
+void ro_gui_tree_start_edit(struct tree *tree, struct node_element *element,
+ wimp_pointer *pointer);
+void ro_gui_tree_scroll_visible(struct tree *tree, struct node_element *element);
+void ro_gui_tree_get_tree_coordinates(struct tree *tree, int x, int y,
+ int *tree_x, int *tree_y);
+
+#endif
diff --git a/riscos/wimp.c b/riscos/wimp.c
index 160b3da0d..012cdd6fb 100644
--- a/riscos/wimp.c
+++ b/riscos/wimp.c
@@ -311,6 +311,16 @@ void ro_gui_set_window_title(wimp_w w, const char *text) {
strncpy(window.title_data.indirected_text.text, text,
(unsigned int)window.title_data.indirected_text.size - 1);
window.title_data.indirected_text.text[window.title_data.indirected_text.size - 1] = '\0';
+
+ /* Redraw accordingly
+ */
+ error = xwimp_force_redraw_title(w);
+ if (error) {
+ LOG(("xwimp_force_redraw_title: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return;
+ }
}
@@ -430,7 +440,7 @@ void ro_gui_open_window_centre(wimp_w parent, wimp_w child) {
/* Move to the centre of the parent at the top of the stack
*/
dimension = state.visible.x1 - state.visible.x0;
- scroll_width = ro_get_vscroll_width(hotlist_window);
+ scroll_width = ro_get_vscroll_width(history_window);
state.visible.x0 = mid_x - (dimension + scroll_width) / 2;
state.visible.x1 = state.visible.x0 + dimension;
dimension = state.visible.y1 - state.visible.y0;
diff --git a/riscos/wimp.h b/riscos/wimp.h
index 26f44bd74..744917efb 100644
--- a/riscos/wimp.h
+++ b/riscos/wimp.h
@@ -53,4 +53,5 @@ void ro_gui_open_pane(wimp_w parent, wimp_w pane, int offset);
wimp_w ro_gui_set_window_background_colour(wimp_w window, wimp_colour background);
void ro_gui_set_icon_colours(wimp_w window, wimp_i icon,
wimp_colour foreground, wimp_colour background);
+
#endif
diff --git a/riscos/window.c b/riscos/window.c
index 42062718b..b9ba998c0 100644
--- a/riscos/window.c
+++ b/riscos/window.c
@@ -16,6 +16,7 @@
#include <assert.h>
#include <math.h>
#include <stdbool.h>
+#include <time.h>
#include <string.h>
#include "oslib/colourtrans.h"
#include "oslib/osspriteop.h"
@@ -32,10 +33,12 @@
#include "netsurf/riscos/options.h"
#include "netsurf/riscos/theme.h"
#include "netsurf/riscos/thumbnail.h"
+#include "netsurf/riscos/treeview.h"
#include "netsurf/riscos/wimp.h"
#include "netsurf/utils/log.h"
#include "netsurf/utils/url.h"
#include "netsurf/utils/utils.h"
+#include "netsurf/utils/messages.h"
/** List of all browser windows. */
@@ -537,7 +540,7 @@ void gui_window_update_box(struct gui_window *g,
/* Set the current redraw gui_window to get options from
*/
ro_gui_current_redraw_gui = g;
-/* if (data->redraw.full_redraw) */
+/* if (data->redraw.full_redraw) */
use_buffer = use_buffer || g->option.buffer_animations;
plot = ro_plotters;
@@ -807,10 +810,10 @@ char *gui_window_get_url(struct gui_window *g)
/**
* Forces all windows to be set to the current theme
*
- * /param g the gui window to update
+ * /param g the gui window to update
*/
void ro_gui_window_update_theme(void) {
- int height;
+ int height;
struct gui_window *g;
for (g = window_list; g; g = g->next) {
if (g->toolbar) {
@@ -821,7 +824,7 @@ void ro_gui_window_update_theme(void) {
if (height != 0)
ro_gui_window_update_dimensions(g, height);
} else {
- if (height != g->toolbar->height)
+ if (height != g->toolbar->height)
ro_gui_window_update_dimensions(g, height -
g->toolbar->height);
}
@@ -833,21 +836,25 @@ void ro_gui_window_update_theme(void) {
ro_gui_theme_destroy_toolbar(hotlist_toolbar);
hotlist_toolbar = NULL;
}
- ro_gui_theme_attach_toolbar(hotlist_toolbar, hotlist_window);
- xwimp_force_redraw(hotlist_window, 0, -16384, 16384, 16384);
+ if (hotlist_tree) {
+ ro_gui_theme_attach_toolbar(hotlist_toolbar,
+ (wimp_w)hotlist_tree->handle);
+ hotlist_tree->offset_y = hotlist_toolbar->height;
+ xwimp_force_redraw((wimp_w)hotlist_tree->handle,
+ 0, -16384, 16384, 16384);
+ }
}
-
}
/**
* Forces the windows extent to be updated
*
- * /param g the gui window to update
+ * /param g the gui window to update
* /param yscroll an amount to scroll the vertical scroll bar by
*/
void ro_gui_window_update_dimensions(struct gui_window *g, int yscroll) {
- os_error *error;
+ os_error *error;
wimp_window_state state;
if (!g) return;
state.w = g->window;
@@ -1089,6 +1096,7 @@ void ro_gui_window_mouse_at(struct gui_window *g, wimp_pointer *pointer)
void ro_gui_toolbar_click(struct gui_window *g, wimp_pointer *pointer)
{
+ struct node *node;
char url[80];
/* Store the toolbar
@@ -1160,11 +1168,17 @@ void ro_gui_toolbar_click(struct gui_window *g, wimp_pointer *pointer)
break;
case ICON_TOOLBAR_BOOKMARK:
- if (pointer->buttons == wimp_CLICK_ADJUST) {
- if (g->bw->current_content)
- ro_gui_hotlist_add(g->title,
- g->bw->current_content);
- } else {
+ if ((pointer->buttons == wimp_CLICK_ADJUST) && (hotlist_tree)) {
+ node = tree_create_URL_node(hotlist_tree->root,
+ messages_get(g->title),
+ g->bw->current_content->url,
+ ro_content_filetype(g->bw->current_content),
+ time(NULL), -1, 0);
+ tree_redraw_area(hotlist_tree, node->box.x - NODE_INSTEP, 0,
+ NODE_INSTEP, 16384);
+ tree_handle_node_changed(hotlist_tree, node, false, true);
+ ro_gui_tree_scroll_visible(hotlist_tree, &node->data);
+ } else if (hotlist_tree) {
ro_gui_hotlist_show();
}
break;
@@ -1790,7 +1804,6 @@ void ro_gui_window_clone_options(struct browser_window *new_bw,
*/
if (!old_gui) {
new_gui->option.scale = ((float)option_scale) / 100;
- new_gui->option.animate_images = option_animate_images;
new_gui->option.background_images = option_background_images;
new_gui->option.background_blending = option_background_blending;
new_gui->option.buffer_animations = option_buffer_animations;
@@ -1840,7 +1853,6 @@ void ro_gui_window_default_options(struct browser_window *bw) {
/* Save the basic options
*/
option_scale = gui->option.scale * 100;
- option_animate_images = gui->option.animate_images;
option_background_blending = gui->option.background_blending;
option_buffer_animations = gui->option.buffer_animations;
option_buffer_everything = gui->option.buffer_everything;