From fece5a0287e470be950f0e929b5a7546d2c543db Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Wed, 30 Jun 2004 17:44:11 +0000 Subject: [project @ 2004-06-30 17:44:11 by rjw] Missing file from last commit. svn path=/import/netsurf/; revision=1031 --- riscos/hotlist.c | 753 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 753 insertions(+) create mode 100644 riscos/hotlist.c (limited to 'riscos/hotlist.c') diff --git a/riscos/hotlist.c b/riscos/hotlist.c new file mode 100644 index 000000000..441fcba39 --- /dev/null +++ b/riscos/hotlist.c @@ -0,0 +1,753 @@ +/* + * 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 + */ + +/** \file + * Hotlist (implementation). + */ + +#include +#include +#include +#include "oslib/colourtrans.h" +#include "oslib/wimp.h" +#include "oslib/wimpspriteop.h" +#include "netsurf/riscos/gui.h" +#include "netsurf/riscos/wimp.h" +#include "netsurf/utils/log.h" +#include "netsurf/utils/utils.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 + +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 number of children (-1 for non-folders, >=0 for folders) + */ + int children; + + /** The title of the hotlist entry/folder + */ + 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; + + /** Position on last reformat (relative to window origin) + */ + int x0; + int y0; + int width; + int height; + + /** Cached values + */ + int collapsed_width; + int expanded_width; +}; + + +/* A basic window for the toolbar and status +*/ +static wimp_window hotlist_window_definition = { + {0, 0, 600, 800}, + 0, + 0, + wimp_TOP, + 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_COLOUR_BLACK, + wimp_COLOUR_LIGHT_GREY, + wimp_COLOUR_LIGHT_GREY, + wimp_COLOUR_VERY_LIGHT_GREY, + wimp_COLOUR_DARK_GREY, + wimp_COLOUR_MID_LIGHT_GREY, + wimp_COLOUR_CREAM, + 0, + {0, -800, 16384, 0}, + wimp_ICON_TEXT | wimp_ICON_HCENTRED | wimp_ICON_VCENTRED, + (wimp_BUTTON_DOUBLE_CLICK_DRAG << wimp_ICON_BUTTON_TYPE_SHIFT), + wimpspriteop_AREA, + 1, + 1, + {"Hotlist"}, + 0, + { } +}; + +/* An icon to plot text with +*/ +static wimp_icon text_icon; +static wimp_icon sprite_icon; +static char null_text_string[] = "\0"; + +/* Whether a reformat is pending +*/ +bool reformat_pending = false; +int max_width = 0; +int max_height = 0; + +/* The hotlist window and plot origins +*/ +wimp_w hotlist_window; +int origin_x, origin_y; + +/* The root entry +*/ +struct hotlist_entry root; + +/* The sprite ids for far faster plotting +*/ +static osspriteop_id sprite[6]; + +/* Pixel translation tables +*/ +osspriteop_trans_tab *pixel_table; + + +static void ro_gui_hotlist_load(void); +static void ro_gui_hotlist_save(void); +static void ro_gui_hotlist_link_entry(struct hotlist_entry *parent, 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(char *title, char *url, + 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); + + +void ro_gui_hotlist_init(void) { + os_error *error; + + /* Get our sprite ids for faster plotting. This could be done in a + far more elegant manner, but it's late and my girlfriend will + kill me if I don't go to bed soon. Sorry. + */ + error = xosspriteop_select_sprite(osspriteop_USER_AREA, gui_sprites, + (osspriteop_id)"tr_expand", + (osspriteop_header **)&sprite[HOTLIST_EXPAND]); + if (!error) + error = xosspriteop_select_sprite(osspriteop_USER_AREA, gui_sprites, + (osspriteop_id)"tr_collapse", + (osspriteop_header **)&sprite[HOTLIST_COLLAPSE]); + if (!error) + error = xosspriteop_select_sprite(osspriteop_USER_AREA, gui_sprites, + (osspriteop_id)"tr_entry", + (osspriteop_header **)&sprite[HOTLIST_ENTRY]); + if (!error) + error = xosspriteop_select_sprite(osspriteop_USER_AREA, gui_sprites, + (osspriteop_id)"tr_line", + (osspriteop_header **)&sprite[HOTLIST_LINE]); + if (!error) + error = xosspriteop_select_sprite(osspriteop_USER_AREA, gui_sprites, + (osspriteop_id)"tr_halflinet", + (osspriteop_header **)&sprite[HOTLIST_TLINE]); + if (!error) + error = xosspriteop_select_sprite(osspriteop_USER_AREA, gui_sprites, + (osspriteop_id)"tr_halflineb", + (osspriteop_header **)&sprite[HOTLIST_BLINE]); + if (error) { + warn_user("MiscError", error->errmess); + return; + } + + /* Update our text icon + */ + text_icon.flags = wimp_ICON_TEXT | (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | + wimp_ICON_INDIRECTED | wimp_ICON_VCENTRED; + text_icon.data.indirected_text.validation = null_text_string; + text_icon.data.indirected_text.size = 256; + sprite_icon.flags = wimp_ICON_SPRITE | wimp_ICON_INDIRECTED | + wimp_ICON_HCENTRED | wimp_ICON_VCENTRED; + sprite_icon.data.indirected_sprite.area = wimpspriteop_AREA; + sprite_icon.data.indirected_text.size = 12; + + /* Create our window + */ + error = xwimp_create_window(&hotlist_window_definition, &hotlist_window); + if (error) { + warn_user("WimpError", error->errmess); + return; + } + + /* Set the root options + */ + root.next_entry = NULL; + root.child_entry = NULL; + root.children = 0; + root.expanded = true; + + /* Load the hotlist + */ + ro_gui_hotlist_load(); +} + + +/** + * Shows the hotlist window. + */ +void ro_gui_hotlist_show(void) { + os_error *error; + int screen_width, screen_height; + wimp_window_state state; + int dimension; + int scroll_width; + + /* We may have failed to initialise + */ + if (!hotlist_window) return; + + /* Get the window state + */ + state.w = hotlist_window; + error = xwimp_get_window_state(&state); + if (error) { + warn_user("WimpError", error->errmess); + return; + } + + /* If we're open we jump to the top of the stack, if not then we + open in the centre of the screen. + */ + if (!(state.flags & wimp_WINDOW_OPEN)) { + /* Get the current screen size + */ + ro_gui_screen_size(&screen_width, &screen_height); + + /* Move to the centre + */ + dimension = 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; + state.visible.y0 = (screen_height - dimension) / 2; + state.visible.y1 = state.visible.y0 + dimension; + } + + /* Open the window at the top of the stack + */ + state.next = wimp_TOP; + error = xwimp_open_window((wimp_open*)&state); + if (error) { + warn_user("WimpError", error->errmess); + return; + } +} + +void ro_gui_hotlist_load(void) { + struct hotlist_entry *netsurf; + + /* Create a folder + */ + netsurf = ro_gui_hotlist_create("NetSurf", NULL, &root); + netsurf->expanded = true; + + /* Add some content + */ + ro_gui_hotlist_create("NetSurf homepage", "http://netsurf.sf.net", netsurf); + ro_gui_hotlist_create("NetSurf test builds", "http://netsurf.strcpstskrzkrk.net", netsurf); + +} + +void ro_gui_hotlist_save(void) { +} + + +/** + * Adds a hotlist entry to the root of the tree. + * + * \param title the entry title + * \param url the entry url (NULL to create a folder) + */ +void ro_gui_hotlist_add(char *title, char *url) { + ro_gui_hotlist_create(title, url, &root); +} + + +/** + * Adds a hotlist entry to the root of the tree (internal). + * + * \param title the entry title + * \param url the entry url (NULL to create a folder) + * \param folder the folder to add the entry into + */ +struct hotlist_entry *ro_gui_hotlist_create(char *title, char *url, + struct hotlist_entry *folder) { + struct hotlist_entry *entry; + + /* 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; + } + + /* And enough for the url/title + */ + if (url) { + entry->url = malloc(strlen(url) + 1); + if (!entry->url) { + warn_user("NoMemory", 0); + free(entry); + return NULL; + } + strcpy(entry->url, url); + } + + /* Add the title if we have one, or use the URL instead + */ + if (title) { + entry->title = malloc(strlen(title) + 1); + if (!entry->title) { + warn_user("NoMemory", 0); + free(entry->url); + free(entry); + return NULL; + } + strcpy(entry->title, title); + } else { + entry->title = entry->url; + } + + /* Set the children count + */ + if (url) { + entry->children = -1; + } else { + entry->children = 0; + } + + /* Set the expanded/selected state + */ + entry->expanded = false; + entry->selected = false; + + /* Set the width + */ + ro_gui_hotlist_update_entry_size(entry); + + /* Link in as the last entry in root + */ + ro_gui_hotlist_link_entry(folder, entry); + return entry; +} + + +/** + * Links a hotlist entry into the tree. + * + * \param parent the parent entry to link under + * \param entry the entry to link + */ +void ro_gui_hotlist_link_entry(struct hotlist_entry *parent, struct hotlist_entry *entry) { + struct hotlist_entry *link_entry; + + if (!parent || !entry) return; + + /* Ensure the parent is a folder + */ + if (parent->children == -1) return; + + /* Get the first child entry + */ + link_entry = parent->child_entry; + if (!link_entry) { + parent->child_entry = entry; + } else { + while (link_entry->next_entry) link_entry = link_entry->next_entry; + link_entry->next_entry = entry; + } + + /* Increment the number of children + */ + parent->children += 1; + + /* Force a redraw + */ + reformat_pending = true; + xwimp_force_redraw(hotlist_window, 0, -16384, 16384, 0); +} + + +/** + * Updates and entrys size + */ +void ro_gui_hotlist_update_entry_size(struct hotlist_entry *entry) { + int width; + + /* Get the width of the title + */ + xwimptextop_string_width(entry->title, + strlen(entry->title) > 256 ? 256 : strlen(entry->title), + &width); + entry->collapsed_width = width + 32 + 36 + 8; + + /* Get the width of the URL + */ + if (entry->url) { + xwimptextop_string_width(entry->url, + strlen(entry->url) > 256 ? 256 : strlen(entry->url), + &width); + if (width < entry->collapsed_width) width = entry->collapsed_width; + } + entry->expanded_width = width + 32 + 36 + 8; + + /* All entries are 44 units high + */ + entry->height = 44; +} + + +/** + * Redraws a section of the hotlist window + */ +void ro_gui_hotlist_redraw(wimp_draw *redraw) { + osbool more; + unsigned int size; + os_box extent = {0, 0, 0, 0};; + + /* Reset our min/max sizes + */ + max_width = 0; + max_height = 0; + + /* Get a pixel translation table for the sprites. We only + get one for all the sprites, so they must all have the + same characteristics. + */ + xcolourtrans_generate_table_for_sprite(gui_sprites, sprite[HOTLIST_EXPAND], + colourtrans_CURRENT_MODE, colourtrans_CURRENT_PALETTE, + 0, colourtrans_GIVEN_SPRITE, 0, 0, &size); + pixel_table = malloc(size); + if (pixel_table) { + xcolourtrans_generate_table_for_sprite(gui_sprites, sprite[HOTLIST_EXPAND], + colourtrans_CURRENT_MODE, colourtrans_CURRENT_PALETTE, + pixel_table, colourtrans_GIVEN_SPRITE, 0, 0, 0); + } else { + pixel_table = 0; + } + + /* Redraw each rectangle + */ + more = wimp_redraw_window(redraw); + while (more) { + 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); + } + + /* Free our memory + */ + if (pixel_table) free(pixel_table); + pixel_table = NULL; + + /* 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; + xwimp_set_extent(hotlist_window, &extent); + reformat_pending = false; + } +} + + +/** + * Redraws a section of the hotlist window (non-WIMP interface) + */ +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) { + /* Update the entry position + */ + entry->x0 = x0 - origin_x; + entry->y0 = y0 - 44 - origin_y; + if (entry->expanded) { + entry->width = entry->expanded_width; + } else { + entry->width = entry->collapsed_width; + } + if ((x0 + entry->width) > (max_width + origin_x)) + max_width = x0 + entry->width - origin_x; + if ((y0 - 44) < (max_height + origin_y)) + max_height = y0 - 44 - origin_y; + + /* Redraw the item + */ + height = ro_gui_hotlist_redraw_item(entry, level, x0 + 32, y0); + box_y0 = y0; + cumulative += height; + + /* Draw the vertical links + */ + if (entry->next_entry) { + /* Draw a half-line for the first entry in the top tree + */ + if (first && (level == 0)) { + xosspriteop_put_sprite_scaled(osspriteop_PTR, + gui_sprites, sprite[HOTLIST_BLINE], + x0 + 8, y0 - 44, + osspriteop_USE_MASK | osspriteop_USE_PALETTE, + 0, pixel_table); + y0 -= 44; + height -= 44; + } + + /* Draw the rest of the lines + */ + while (height > 0) { + xosspriteop_put_sprite_scaled(osspriteop_PTR, + gui_sprites, sprite[HOTLIST_LINE], + x0 + 8, y0 - 44, + osspriteop_USE_MASK | osspriteop_USE_PALETTE, + 0, pixel_table); + y0 -= 44; + height -= 44; + } + + } else { + /* Draw a half-line for the last entry + */ + if (!first || (level != 0)) { + xosspriteop_put_sprite_scaled(osspriteop_PTR, + gui_sprites, sprite[HOTLIST_TLINE], + x0 + 8, y0 - 22, + osspriteop_USE_MASK | osspriteop_USE_PALETTE, + 0, pixel_table); + height -= 44; + y0 -= 44; + } + } + + /* Draw the expansion type + */ + if (entry->children == 0) { + xosspriteop_put_sprite_scaled(osspriteop_PTR, + gui_sprites, sprite[HOTLIST_ENTRY], + x0, box_y0 - 31, + osspriteop_USE_MASK | osspriteop_USE_PALETTE, + 0, pixel_table); + } else { + if (entry->expanded) { + xosspriteop_put_sprite_scaled(osspriteop_PTR, + gui_sprites, sprite[HOTLIST_COLLAPSE], + x0, box_y0 - 31, + osspriteop_USE_MASK | osspriteop_USE_PALETTE, + 0, pixel_table); + } else { + xosspriteop_put_sprite_scaled(osspriteop_PTR, + gui_sprites, sprite[HOTLIST_EXPAND], + x0, box_y0 - 31, + osspriteop_USE_MASK | osspriteop_USE_PALETTE, + 0, pixel_table); + + + } + + } + + /* Move to the next entry + */ + entry = entry->next_entry; + first = false; + } + + /* Return our height + */ + return cumulative; +} + + +int ro_gui_hotlist_redraw_item(struct hotlist_entry *entry, int level, int x0, int y0) { + int height = 44; + + /* Update the selection state + */ + if (entry->selected) { + sprite_icon.flags |= wimp_ICON_SELECTED; + text_icon.flags |= wimp_ICON_SELECTED; + } + + /* Draw our icon type + */ + sprite_icon.extent.x0 = x0 - origin_x; + sprite_icon.extent.x1 = x0 - origin_x + 36; + sprite_icon.extent.y0 = y0 - origin_y - 44; + sprite_icon.extent.y1 = y0 - origin_y; + if (entry->children != -1) { + if (entry->selected) { + sprite_icon.data.indirected_sprite.id = (osspriteop_id)"small_diro"; + } else { + sprite_icon.data.indirected_sprite.id = (osspriteop_id)"small_dir"; + } + } else { + sprite_icon.data.indirected_sprite.id = (osspriteop_id)"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 + 36; + text_icon.extent.x1 = x0 - origin_x + 1024; + text_icon.extent.y0 = y0 - origin_y - 44; + text_icon.extent.y1 = y0 - origin_y; + xwimp_plot_icon(&text_icon); + + /* Clear the selection state + */ + if (entry->selected) { + sprite_icon.flags &= ~wimp_ICON_SELECTED; + text_icon.flags &= ~wimp_ICON_SELECTED; + } + + /* Draw our further information if expanded + */ + if ((entry->children == -1) && (entry->expanded) && (entry->url)) { + /* Draw the line + */ + y0 -= 44; + xosspriteop_put_sprite_scaled(osspriteop_PTR, + gui_sprites, sprite[HOTLIST_TLINE], + x0 + 16, y0 - 24, + osspriteop_USE_MASK | osspriteop_USE_PALETTE, + 0, pixel_table); + xosspriteop_put_sprite_scaled(osspriteop_PTR, + gui_sprites, sprite[HOTLIST_ENTRY], + x0 + 8, y0 - 31, + osspriteop_USE_MASK | osspriteop_USE_PALETTE, + 0, pixel_table); + + /* Plot the text + */ + text_icon.data.indirected_text.text = entry->url; + text_icon.extent.y0 -= 44; + text_icon.extent.y1 -= 44; + xwimp_plot_icon(&text_icon); + height += 44; + } + + /* Draw any children + */ + if ((entry->child_entry) && (entry->expanded)) { + height += ro_gui_hotlist_redraw_tree(entry->child_entry, level + 1, + x0 + 8, y0 - 44); + } + return height; +} + + +void ro_gui_hotlist_click(wimp_pointer *pointer) { + struct hotlist_entry *entry; + wimp_window_state state; + wimp_mouse_state buttons; + int x, y; + int x_offset; + + /* 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)); + + + /* 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; + if ((x_offset < 32) || (buttons == wimp_DOUBLE_SELECT)) { + entry->expanded = !entry->expanded; + xwimp_force_redraw(hotlist_window, 0, -16384, 16384, 0); + } else { + + } + } + +} + + +struct hotlist_entry *ro_gui_hotlist_find_entry(int x, int y, struct hotlist_entry *entry) { + struct hotlist_entry *find_entry; + + /* 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 this entry + */ + if ((x > entry->x0) && (y > entry->y0) && (x < (entry->x0 + entry->width)) && + (y < (entry->y0 + entry->height))) { + return entry; + } + + /* 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; +} -- cgit v1.2.3