Commit 2c969f45 authored by Andrew Hodgkinson's avatar Andrew Hodgkinson
Browse files

Tidied up Hotlist source a bit

parent f2a7d4b0
/* Copyright 1997 Acorn Computers Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/***************************************************/
/* File : Hotlist.c */
/* */
/* Purpose: Managing a hotlist in the browser. */
/* */
/* Author : D.T.A.Brown */
/* */
/* History: 06-Aug-97: Created. */
/* 22-Aug-97: (ADH/DTAB) Integrated into */
/* main browser code. */
/***************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "swis.h"
#include "toolbox.h"
#include "wimp.h"
#include "wimplib.h"
#include "menu.h"
#include "event.h"
#include "gadgets.h"
#include "svcprint.h"
#include "Global.h"
#include "FromROSLib.h"
#include "Utils.h"
#include "FetchPage.h"
#include "Save.h"
#include "Toolbars.h"
#include "Windows.h"
#include "Hotlist.h"
/* Local definitions */
#define HotlistWrite(fn) {written = (fn); if (written < 0) return _kernel_last_oserror();}
/* Local statics */
static hotlist_item * hotlist_root = NULL; /* Pointer to the hotlist root directory item */
static int hotlist_windowid; /* Object ID of the hotlist window */
static hotlist_item * hotlist_newitem; /* When ever a new item is created this points to it */
static int menu_itemno = 0; /* Item over which menu was pressed */
static hotlist_item * selected_parent = NULL; /* The parent directory of all selected items */
static int number_selected = 0; /* The number of items selected */
static unsigned int last_selected_item = 0xffffffff; /* The last item which was selected */
static int hotlist_dragging = 0; /* Holds a set of values for different dragging cases (see Hotlist.h) */
static unsigned int highlighted_itemno; /* During dragging, the number of a directory item using the '...+' sprite */
static hotlist_item * hotlist_current_highlighted = NULL; /* To save scanning lists, pointer to the highlighted item */
static unsigned int hotlist_bbar_size = 0; /* Height in OS units of the button bar */
static unsigned int alter_new; /* Remembers if the edit dialogue is Alter or New; see */
/* HOTLIST_MENUSECTION_NEW and HOTLIST_MENUSECTION_ALTER */
static unsigned int item_number; /* Current item being considered for drawing */
/* Event handler prototypes */
static _kernel_oserror * hotlist_selection_box_start(void);
static WimpEventHandler hotlist_redraw_handler;
static WimpEventHandler hotlist_mouse_click_handler;
static WimpEventHandler hotlist_drag_completed_handler;
static WimpEventHandler hotlist_null_handler;
static WimpEventHandler hotlist_null_drag_select_handler;
static ToolboxEventHandler hotlist_menuopen_handler;
static ToolboxEventHandler hotlist_menuclose_handler;
static ToolboxEventHandler hotlist_menu_selectall_handler;
static ToolboxEventHandler hotlist_menu_clearselect_handler;
static ToolboxEventHandler hotlist_menu_openall_handler;
static ToolboxEventHandler hotlist_menu_closeall_handler;
static ToolboxEventHandler hotlist_menu_delete_handler;
static ToolboxEventHandler hotlist_show_editurl_handler;
static ToolboxEventHandler hotlist_show_rendirectory_handler;
static ToolboxEventHandler hotlist_show_newurl_handler;
static ToolboxEventHandler hotlist_show_newdirectory_handler;
static ToolboxEventHandler hotlist_newedit_url_handler;
static ToolboxEventHandler hotlist_newren_directory_handler;
static ToolboxEventHandler hotlist_reset_url_handler;
static ToolboxEventHandler hotlist_reset_directory_handler;
/* Debug functions */
#ifdef TRACE
static void hotlist_display_item(hotlist_item * item);
static void hotlist_display_tree(hotlist_item * list, int indent);
#endif
/* Miscellaneous function prototypes */
static _kernel_oserror * hotlist_get_entry_sizes (unsigned int * item_height, unsigned int * item_dir_width, unsigned int * item_url_width);
static void hotlist_scan_for_subdirectories (hotlist_item * item);
static hotlist_item * _hotlist_find_item (hotlist_item * list, unsigned int item_no);
static hotlist_item * hotlist_find_item (hotlist_item * list, unsigned int item_no);
static int _hotlist_find_no_from_item (hotlist_item * list, hotlist_item * item);
static int hotlist_find_no_from_item (hotlist_item * item);
static hotlist_item * _hotlist_find_selected_item (hotlist_item * list);
static hotlist_item * hotlist_find_selected_item (void);
static void _hotlist_count_displayed_items (hotlist_item * list);
static unsigned int hotlist_count_displayed_items (hotlist_item * list);
static void _hotlist_draw (hotlist_item * list, unsigned int first_item, unsigned int last_item, unsigned int indent);
static void hotlist_draw (hotlist_item * list, unsigned int first_item, unsigned int last_item);
static void _hotlist_get_max_width (hotlist_item * list, unsigned int indent);
static void _hotlist_redraw_now (hotlist_item * list);
static void hotlist_redraw_now (void);
static unsigned int hotlist_get_max_width (hotlist_item * list);
static void hotlist_get_shape (unsigned int * xmin, unsigned int * xmax, hotlist_item * item);
static void hotlist_directory_open_close (hotlist_item * item, unsigned int itemno);
static void hotlist_redraw_items (unsigned int firstitem, unsigned int lastitem);
static void hotlist_clear_selection (void);
static void hotlist_launch_url (hotlist_item * item);
static _kernel_oserror * hotlist_process_click_on_item (unsigned int itemno, hotlist_item * item, int buttons, int x, int y);
static _kernel_oserror * hotlist_process_click (int x, int y, int buttons);
static void hotlist_window_preopen (hl_opentype type);
static void hotlist_setmenu_details (ObjectId menuid);
static _kernel_oserror * hotlist_save_entries (FILE * fileptr, hotlist_item * list);
static void hotlist_lower_tags (char * string);
static _kernel_oserror * hotlist_load_directory (FILE * fileptr, hotlist_item * target);
static void hotlist_drag_renderer (hotlist_item * item, unsigned int item_height, unsigned int item_dir_width, unsigned int item_url_width);
static void hotlist_start_drag (void);
/* List manupulation */
static void hotlist_unlink (hotlist_item * item);
static _kernel_oserror * hotlist_link (hotlist_item * item, hotlist_item * target, unsigned int position);
static _kernel_oserror * hotlist_new_directory (hotlist_item * parent, char * directory_name, unsigned int position, hotlist_item ** new);
static _kernel_oserror * hotlist_new_url (hotlist_item * parent, unsigned int position, char * url_description, char * url);
static void hotlist_delete_item (hotlist_item * item);
static _kernel_oserror * hotlist_move_item (hotlist_item * source, hotlist_item * target, unsigned int position);
static _kernel_oserror * hotlist_copy_item (hotlist_item * source, hotlist_item * target, unsigned int position, hotlist_item ** new_item);
static int hotlist_set_flags (hotlist_item * list, hotlist_type type, unsigned int flags);
static int hotlist_clear_flags (hotlist_item * list, hotlist_type type, unsigned int flags);
#ifdef TRACE
/*************************************************/
/* hotlist_display_item() */
/* */
/* This function display the data held by a */
/* single hotlist_item */
/* */
/* Parameters: Pointer to a hotlist_item */
/*************************************************/
static void hotlist_display_item(hotlist_item * item)
{
Printf("\nhotlist_display_item for %p\n",item);
Printf("--------------------\n");
Printf("type = %d\n", item->type);
Printf("name = %s\n", item->name);
Printf("flags = %d\n", item->flags);
Printf("parent = %p\n", item->parent);
Printf("previous = %p\n", item->previous);
Printf("next = %p\n", item->next);
Printf("data.generic_data = %p ", item->data.generic_data);
switch(item->type)
{
case hl_url:
{
Printf("URL(%s)\n", item->data.url);
}
break;
case hl_directory:
{
Printf("sub directory pointer\n");
}
break;
default:
{
Printf("\n");
}
break;
}
}
/*************************************************/
/* hotlist_display_tree() */
/* */
/* Recursivly display the hotlist tree starting */
/* from the passed item */
/* */
/* Parameters: Pointer to a hotlist_item */
/* value to start indent at */
/* recommended 0 */
/*************************************************/
static void hotlist_display_tree(hotlist_item * list, int indent)
{
int count;
Printf("\nhotlist_display_tree for %p, indent %d\n", list, indent);
Printf("--------------------\n\n");
while (list)
{
for (count = 0; count < indent; count++) Printf("| ");
switch (list->type)
{
case hl_url:
{
Printf("%s:URL(%s)\n", list->name, list->data.url);
}
break;
case hl_directory:
{
Printf("%s:DIRECTORY", list->name);
}
if (list->flags & HOTLIST_D_HAS_SUBDIRECTORY) Printf(" (Has sub directory)");
if (list->flags & HOTLIST_D_IS_OPEN)
{
Printf(" (Open)\n");
hotlist_display_tree(list->data.directory_content, indent + 1);
}
else
{
Printf(" (Closed)\n");
hotlist_display_tree(list->data.directory_content, indent + 1);
}
break;
default:
{
Printf("%s:UNRECOGNISED TYPE\n", list->name);
}
break;
}
list = list->next;
}
}
#endif
/*************************************************/
/* hotlist_get_entry_sizes() */
/* */
/* This function reads the size of the sprites */
/* to be used by the hotlist and from them */
/* determines the size of the hotlist entries. */
/* */
/* Parameters: Pointer to an int, in which the */
/* height of an item is placed in */
/* OS units; */
/* */
/* Pointer to an int, in which the */
/* minimum width of a directory item */
/* is returned, in OS units; */
/* */
/* Pointer to an int, in which the */
/* minimum width of a URL item is */
/* returned, in OS units. */
/* */
/* Assumes: Any of the pointers may be NULL. */
/*************************************************/
static _kernel_oserror * hotlist_get_entry_sizes(unsigned int * item_height, unsigned int * item_dir_width, unsigned int * item_url_width)
{
_kernel_oserror * e;
int width, height;
/* Get the open directory sprite size */
RetError(read_sprite_size(OPEN_DIRECTORY_SPRITE, &width, &height));
/* Use this for the minimum width of a directory entry */
/* and the height of an item. */
if (item_dir_width) *item_dir_width = width;
if (item_height) *item_height = height;
/* Now read the closed sprite; if the size is greater */
/* than the width or height found above, use the new */
/* sizes instead. */
RetError(read_sprite_size(CLOSED_DIRECTORY_SPRITE, &width, &height));
if (item_height && height > *item_height) *item_height = height;
if (item_dir_width && width > *item_dir_width) *item_dir_width = width;
/* Similarly for the insert item sprite. */
RetError(read_sprite_size(INSERT_DIRECTORY_SPRITE, &width, &height));
if (item_height && height > *item_height) *item_height = height;
if (item_dir_width && width > *item_dir_width) *item_dir_width = width;
/* Find the URL sprite size, and if required increase the */
/* minimum entry height again based on this. */
RetError(read_sprite_size(URL_SPRITE, &width, &height));
if (item_height && height > *item_height) *item_height= height;
/* Set the URL width to the value found above and add 8 to */
/* all of them for aesthetics. */
if (item_url_width) *item_url_width = width + 8; /* +8 for aesthetics */
if (item_dir_width) *item_dir_width += 8;
if (item_height) *item_height += 8;
return NULL;
}
/*************************************************/
/* hotlist_unlink() */
/* */
/* This function unlinks the passed item from */
/* the items linked in before and after it. */
/* */
/* Parameters: Pointer to the hotlist_item */
/* struct to remove. */
/*************************************************/
static void hotlist_unlink(hotlist_item *item)
{
if (item->parent && item->parent->data.directory_content == item) item->parent->data.directory_content = item->next;
if (item->previous) item->previous->next = item->next;
if (item->next) item->next->previous = item->previous;
/* Not strictly needed, but added to ensure robustness */
item->next = NULL;
item->previous = NULL;
item->parent = NULL;
}
/*************************************************/
/* hotlist_link() */
/* */
/* This function links the passed item to the */
/* passed target. */
/* */
/* It can link the item in four different ways; */
/* before or after the target, or if the target */
/* is a directory, at the beginning or end of */
/* that directory's contents. */
/* */
/* Parameters: Pointer to the hotlist_item */
/* struct to link in; */
/* */
/* Pointer to the hotlist_item */
/* struct to link to; */
/* */
/* Position to link to - */
/* HOTLIST_POSITION_BEGINNING */
/* HOTLIST_POSITION_END */
/* HOTLIST_POSITION_BEFORE or */
/* HOTLIST_POSITION_AFTER. */
/* */
/* Assumes: The item and target pointers are */
/* not NULL and are valid; */
/* */
/* That if adding to the beginning */
/* or end, the target is a directory */
/* (in both cases, an error will be */
/* raised in TRACE builds if the */
/* assumptions are violated). */
/*************************************************/
static _kernel_oserror * hotlist_link(hotlist_item * item, hotlist_item * target, unsigned int position)
{
#ifdef TRACE
/* Test certain basic assumptions are not violated */
if (!item || !target)
{
erb.errnum = Utils_Error_Custom_Normal;
strcpy(erb.errmess, "NULL hotlist item or target pointer in hotlist_link");
show_error_ret(&erb);
return NULL;
}
if (
(
position == HOTLIST_POSITION_BEGINNING ||
position == HOTLIST_POSITION_END
)
&& target->type != hl_directory
)
{
erb.errnum = Utils_Error_Custom_Normal;
strcpy(erb.errmess, "Cannot insert at item at the beginning or end when the target is not a directory, in hotlist_link");
show_error_ret(&erb);
return NULL;
}
#endif
switch (position)
{
case HOTLIST_POSITION_BEFORE:
{
/* Simple insertion above the target item */
item->next = target;
item->previous = target->previous;
item->parent = target->parent;
target->previous = item;
if (item->previous) item->previous->next = item;
if (item->parent && item->parent->data.directory_content == target) item->parent->data.directory_content = item;
}
break;
default: /* We'll allow a default to adding after the target item */
case HOTLIST_POSITION_AFTER:
{
/* Again, a simple insertion after the target item */
item->previous = target;
item->next = target->next;
item->parent = target->parent;
target->next = item;
if (item->next) item->next->previous = item;
}
break;
case HOTLIST_POSITION_BEGINNING:
{
/* A bit harder - insert at the top of a directory. */
/* First a quick sanity check - TRACE builds will */
/* already have faulted this, but For non-TRACE */
/* builds, at least this will stop things dying. */
if (target->type != hl_directory) return NULL;
/* This item is going to be at the beginning of a */
/* directory, so there is never a previous item. */
item->previous = NULL;
/* The next item is the one that used to be at the top */
/* of the directory, and the parent for this item will */
/* obviously be the target. */
item->next = target->data.directory_content;
item->parent = target;
/* If we have a next item, make sure its previous field */
/* now points to the new item at the top. */
if (item->next) item->next->previous = item;
/* The target should point to the new top item, too. */
target->data.directory_content = item;
}
break;
case HOTLIST_POSITION_END:
{
hotlist_item * last;
/* Similarly, add to the end of the directory */
if (target->type != hl_directory) return NULL;
/* As before the parent must be the target item */
item->parent = target;
/* Now look from the start of the directory downwards for */
/* the last item currently present. */
last = target->data.directory_content;
while(last && last->next) last = last->next;
/* The new item must point to that one as in its previous field, */
/* and has no next item to point to. */
item->previous = last;
item->next = NULL;
if (last)
{
/* If there were any items in the directory, make sure that the */
/* last one points to the new bottom entry. */
last->next = item;
}
else
{
/* Otherwise, the parent directory should point to this item */
target->data.directory_content = item;
}
}
break;
}
/* Finished... */
return NULL;
}
/*************************************************/
/* hotlist_new_directory() */
/* */
/* This function creates a new directory */
/* at the beginning of the given parent. */
/* */
/* */
/* Parameters: Pointer to a hotlist_item of type */
/* directory that represents the */
/* parent item for this new entry; */
/* */
/* Name of new directory to create; */
/* */
/* Position to create the new item */
/* relative to the parent (as for */
/* hotlist_link); */
/* */
/* Pointer to a pointer to a */
/* hotlist_item struct, which will */
/* be filled in with the address of */
/* the new item (unless there is an */
/* error returned). */
/* */
/* Assumes: That the pointer to a pointer to */
/* a hotlist_item struct is not NULL */
/* (it would make little sense to */
/* allow this...). */
/*************************************************/
static _kernel_oserror * hotlist_new_directory(hotlist_item * parent, char * directory_name, unsigned int position, hotlist_item ** new)
{
char * perm_dirname;
hotlist_item * item;
_kernel_oserror * e;
if (!directory_name) return NULL;
/* Allocate space for the item and its name */
item = malloc(sizeof(hotlist_item));
if (!item)
{
make_no_memory_error(4);
return &erb;
}
perm_dirname = malloc(strlen(directory_name) + 1);
if (!perm_dirname)
{
free(item);
make_no_memory_error(5);
return NULL;
}
/* Copy the name into the new buffer */
strcpy(perm_dirname, directory_name);
/* Initialise the new hotlist item */
item->type = hl_directory;
item->flags = DIRECTORY_FLAGS;
item->name = perm_dirname;
item->data.directory_content = NULL;
if (parent)
{
/* If we have been given a parent item, link this new */
/* directory to it. */
e = hotlist_link(item, parent, position);
/* If there's an error, free the item structure and name, */
/* and return that error. */
if (e)
{
free(item);
free(perm_dirname);
return e;
}
}
else
{
/* If there's no parent item, fill the various pointers */
/* to other things in the list with NULL. */
item->next = NULL;
item->previous = NULL;
item->parent = NULL;
}
/* Record the new item in the hotlist_newitem static */
hotlist_newitem = item;
/* Return the address of the new item and exit */
*new = item;
return NULL;
}
/*************************************************/
/* hotlist_new_url() */
/* */
/* This function creates a new url */
/* at the end of the passed directory */
/* */
/* Parameters: Pointer to a hotlist_item struct */
/* representing a directory to add */
/* the URL to; */
/* */
/* Position within that directory */
/* to link to (number of items from */
/* the start); */
/* */
/* Description of the URL (e.g. from */
/* the page title); */
/* */
/* Pointer to the URL itself. */
/*************************************************/
static _kernel_oserror * hotlist_new_url(hotlist_item * parent, unsigned int position, char * url_description, char * url)
{
char * perm_url_desc;
char * perm_url;
hotlist_item * item;
_kernel_oserror * e;
/* Allocate a new hotlist_item structure */
if ((item = malloc(sizeof(hotlist_item))) == NULL)
{
#ifdef TRACE
if (tl & (1<<25)) Printf("Error: Could not allocate room for new URL item\n");
#endif
goto hotlist_new_url_no_memory; /* See bottom of function */
}
/* Allocate space for the description string */
perm_url_desc = malloc(strlen(url_description) + 1);
if (perm_url_desc == NULL) goto hotlist_new_url_no_memory; /* See bottom of function */
/* Allocate space for the URL */
perm_url = malloc(strlen(url) + 1);
if (perm_url == NULL)
{
free(perm_url_desc);
goto hotlist_new_url_no_memory; /* See bottom of function */
}
/* Copy the given description and URL to the allocated space */
strcpy(perm_url_desc, url_description);
strcpy(perm_url, url);
/* Fill in miscellaneous parts of the hotlist_item structure */
item->type = hl_url;
item->flags = URL_FLAGS;
item->name = perm_url_desc;
item->data.url = perm_url;
/* Link the item to the rest of the hotlist */
e = hotlist_link(item, parent, position);
if (e)
{
free(item);
free(perm_url_desc);
free(perm_url);
return e;
}
/* Remember which item was added in the hotlist_newitem static */
/* and exit with no error. */
hotlist_newitem = item;
return NULL;
/* Code for a common error case */
hotlist_new_url_no_memory:
erb.errnum = Utils_Error_Custom_Normal;
StrNCpy0(erb.errmess,
lookup_token("NoMemURL:There is not enough free memory to add another URL to the hotlist.",
0,
0));
return &erb;
}
/*************************************************/
/* hotlist_delete_item() */
/* */
/* This function deletes an item from the */
/* hotlist structure; it will recursively delete */
/* directories. */
/* */
/* Parameters: Pointer to the hotlist_item */
/* struct to delete. */
/*************************************************/
static void hotlist_delete_item(hotlist_item * item)
{
if (item)
{
switch (item->type)
{
/* For a URL item, unlink it from the list */
/* and free associated memory. */
case hl_url:
{
hotlist_unlink(item);
free(item->name);
free(item->data.url);
free(item);
}
break;
case hl_directory:
{
/* Recursively delete all items in the directory */
while (item->data.directory_content)
{
hotlist_delete_item(item->data.directory_content);
}
/* Now unlink the item */
hotlist_unlink(item);
/* Free associated memory */
free(item);
free(item->name);
/* The deletions will affect whether or not other */
/* items have subdirectories, so update the */
/* relevant parts of all items in the list. */
hotlist_scan_for_subdirectories(item->parent);
}
break;
default:
{
#ifdef TRACE
/* A 'should never happen' case! */
erb.errnum = Utils_Error_Custom_Message;
strcpy(erb.errmess, "Unrecognised item type in hotlist_delete_item - possibly memory corruption?");
show_error_ret(&erb);
#endif
}
break;
}
}
}
/*************************************************/
/* hotlist_move_item() */
/* */
/* This function takes an item and moves its */
/* position within the directory tree. */
/* */
/* Parameters: Pointer to the hotlist_item */
/* struct to move; */
/* */
/* Pointer to the hotlist_item */
/* structure to move to; */
/* */
/* Position relative to that struct */
/* for the item to go to, as for */
/* hotlist_link. */
/* */
/* Assumes: It is assumed that if the object */
/* is a directory it is not being */
/* moved into it self or one of its */
/* children. If this is not the case */
/* then both it and its children */
/* will become unlinked from the */
/* hotlist structure (nasty...). */
/*************************************************/
static _kernel_oserror * hotlist_move_item(hotlist_item * source, hotlist_item * target, unsigned int position)
{
/* Unlink item from directory structure */
hotlist_unlink(source);
/* Link into new position in directory structure */
return hotlist_link(source, target, position);
}
/*************************************************/
/* hotlist_copy_item() */
/* */
/* This function copies an item, and in the case */
/* of it being a directory, its children, to the */
/* specified place. */
/* */
/* Parameters: Pointer to the hotlist_item */
/* struct to copy; */
/* */
/* Pointer to the hotlist_item */
/* struct to copy to; */
/* */
/* Position relative to that item to */
/* copy to, as for hotlist_link; */
/* */
/* Pointer to a pointer to a */
/* hotlist_item struct, in which the */
/* address of the new item is */
/* returned. */
/* */
/* Assumes: It is assumed that if the object */
/* is a directory it is not being */
/* copied into it self or one of its */
/* children - if it is the function */
/* will keep recursing and */
/* eventually run out of stack; */
/* */
/* The pointer to the pointer to the */
/* hotlist_item struct may be NULL. */
/*************************************************/
static _kernel_oserror * hotlist_copy_item(hotlist_item * source, hotlist_item * target,
unsigned int position, hotlist_item ** new_item)
{
_kernel_oserror * e;
hotlist_item * newdir;
newdir = NULL;
switch(source->type)
{
/* For a URL, create a new item based on the source one */
case hl_url:
{
return hotlist_new_url(target, position, source->name, source->data.url);
}
break;
/* For a directory, first create a new item based on the source one */
case hl_directory:
{
hotlist_item * content;
RetError(hotlist_new_directory(target, source->name, position, &newdir));
/* Now copy the contents recursively */
content = source->data.directory_content;
while (content)
{
RetError(hotlist_copy_item(content, newdir, HOTLIST_POSITION_END, NULL));
content = content->next;
}
}
break;
}
/* Fill in the new_item return value */
if (new_item)
{
if (newdir) *new_item = newdir;
else *new_item = hotlist_newitem;
}
return NULL;
}
/*************************************************/
/* hotlist_scan_for_subdirectories() */
/* */
/* This function will scan a directory contents */
/* for any subdirectories. If it finds one it */
/* will set the directory's */
/* HOTLIST_HAS_SUBDIRECTORY bit, else it unsets */
/* the bit. */
/* */
/* Parameters: Pointer to the hotlist_item */
/* struct representing the directory */
/* to scan. */
/*************************************************/
static void hotlist_scan_for_subdirectories(hotlist_item * item)
{
hotlist_item * list;
/* Only proceed if we've been given an item and it */
/* is a directory */
if (item && item->type == hl_directory)
{
list = item->data.directory_content;
/* Go through the contents looking for a directory */
/* within - as soon as one is found we can set the */
/* bit and exit */
while(list)
{
if (list->type == hl_directory)
{
item->flags |= HOTLIST_D_HAS_SUBDIRECTORY;
return;
}
list = list->next;
}
/* If the loop exits there were no directories inside */
/* the given one, so unset the bit. */
item->flags &= ~HOTLIST_D_HAS_SUBDIRECTORY;
}
}
/*************************************************/
/* _hotlist_find_item() */
/* */
/* This function does all the work for */
/* hotlist_find_item() */
/* */
/* Parameters: Pointer to a hotlist_item */
/* the n'th item to return */
/* */
/* Returns: Pointer to the requested item or */
/* NULL if it does not exist */
/*************************************************/
static hotlist_item * _hotlist_find_item(hotlist_item * list, unsigned int item_no)
{
hotlist_item * temp;
while(list)
{
if (item_no == item_number) return list; /* Found the list item */
item_number++;
if (list->type == hl_directory && list->flags & HOTLIST_D_IS_OPEN)
{
temp = _hotlist_find_item(list->data.directory_content, item_no);
if (temp) return temp;
}
list = list->next;
}
return NULL; /* List does not extend far enough */
}
/*************************************************/
/* hotlist_find_item() */
/* */
/* This function will recursivly scan through */
/* a hotlist structure and return a pointer to */
/* the n'th item. It will only recurse through */
/* open directories. */
/* */
/* Parameters: Pointer to a hotlist_item */
/* the n'th item to return */
/* */
/* Returns: Pointer to the requested item or */
/* NULL if it does not exist */
/* */
/* Note: This function doesn't actually */
/* do any of the real work but */
/* merely sets up a global variable */
/* and calls _hotlist_find_item() */
/*************************************************/
static hotlist_item * hotlist_find_item(hotlist_item *list, unsigned int item_no)
{
item_number = 0;
return _hotlist_find_item(list, item_no);
}
/*************************************************/
/* _hotlist_find_no_from_item() */
/* */
/* This function does all the work for */
/* hotlist_find_no_from_item() */
/* */
/* Parameters: Pointer to a hotlist_item */
/* the item whose position should be */
/* returned. */
/* */
/* Returns: The item position or */
/* -1 if it does not exist */
/*************************************************/
static int _hotlist_find_no_from_item(hotlist_item *list, hotlist_item *item)
{
int temp;
while(list)
{
if (item == list) return item_number; /* Found the list item */
item_number++;
if (list->type == hl_directory && list->flags & HOTLIST_D_IS_OPEN)
{
temp = _hotlist_find_no_from_item(list->data.directory_content, item);
if (temp >= 0) return temp;
}
list = list->next;
}
return -1;
}
/*************************************************/
/* hotlist_find_no_from_item() */
/* */
/* This function will recursivly scan through */
/* a hotlist structure and return the position */
/* of the specified item. It will only recurse */
/* through open directories. */
/* */
/* Parameters: Pointer to a hotlist_item */
/* Pointer to the item to find */
/* */
/* Returns: Position of the requested item or */
/* -1 if it does not exist */
/* */
/* Note: This function doesn't actually */
/* do any of the real work but */
/* merely sets up a global variable */
/* and calls */
/* _hotlist_find_no_from_item() */
/*************************************************/
static int hotlist_find_no_from_item(hotlist_item *item)
{
item_number = 0;
return _hotlist_find_no_from_item(hotlist_root->data.directory_content, item);
}
/************************************************/
/* _hotlist_find_selected_item() */
/* */
/* This function does the work for */
/* hotlist_find_selected_item() */
/************************************************/
hotlist_item * _hotlist_find_selected_item(hotlist_item *list)
{
hotlist_item *temp;
while(list)
{
if (list->flags & HOTLIST_G_IS_SELECTED) return list;
if (list->type == hl_directory)
{
temp = _hotlist_find_selected_item(list->data.directory_content);
if (temp) return temp;
}
list = list->next;
}
return NULL;
}
/*************************************************/
/* hotlist_find_selected_item() */
/* */
/* This function returns a pointer to the first */
/* selected item found */
/*************************************************/
static hotlist_item * hotlist_find_selected_item(void)
{
return _hotlist_find_selected_item(hotlist_root);
}
/*************************************************/
/* _hotlist_count_displayed_items() */
/* */
/* This routine does all the work for */
/* hotlist_count_displayed_items() */
/*************************************************/
static void _hotlist_count_displayed_items(hotlist_item *list)
{
while(list)
{
if (list->type == hl_directory && list->flags & HOTLIST_D_IS_OPEN)
{
_hotlist_count_displayed_items(list->data.directory_content);
}
list = list->next;
item_number++;
}
}
/*************************************************/
/* hotlist_count_displayed_items() */
/* */
/* This routine counts the number of items to be */
/* displayed in the hotlist window */
/* */
/* Parameters: Pointer to a hotlist_item */
/* */
/* Returns: the number of items visible in */
/* the list */
/*************************************************/
static unsigned int hotlist_count_displayed_items(hotlist_item *list)
{
item_number = 0;
_hotlist_count_displayed_items(list);
return item_number;
}
/*************************************************/
/* hotlist_set_flags() */
/* */
/* This function will recursivly set flags for */
/* either a specified type of hotlist_item or */
/* all hotlist_items if hl_ALL is specified */
/* all items which are changed will also have */
/* their HOTLIST_G_REDRAW_NOW bit set */
/* */
/* Parameters: Pointer to a hotlist_item */
/* type of hotlist_item to set flags */
/* for */
/* flags to set */
/* */
/* Returns: 1 if any flags were set */
/* 0 if no flags were set */
/*************************************************/
static int hotlist_set_flags(hotlist_item *list, hotlist_type type, unsigned int flags)
{
int changed;
changed = 0;
while(list)
{
if (type == hl_ALL || type == list->type)
{
if (list->flags | flags != list->flags)
{
list->flags |= HOTLIST_G_REDRAW_NOW;
changed = 1;
}
list->flags |= flags;
}
if (list->type == hl_directory)
{
if (hotlist_set_flags(list->data.directory_content, type, flags)) changed = 1;
}
list = list->next;
}
return changed;
}
/*************************************************/
/* hotlist_clear_flags() */
/* */
/* This function will recursivly clear flags for */
/* either a specified type of hotlist_item or */
/* all hotlist_items if hl_ALL is specified */
/* all items which are changed will also have */
/* their HOTLIST_G_REDRAW_NOW bit set except if */
/* the routine is set to clear the */
/* HOTLIST_G_REDRAW_NOW bit */
/* */
/* Parameters: Pointer to a hotlist_item */
/* type of hotlist_item to clear */
/* flags for */
/* flags to clear */
/* */
/* Returns: 1 if any flags were cleared */
/* 0 if no flags were cleared */
/*************************************************/
static int hotlist_clear_flags(hotlist_item *list, hotlist_type type, unsigned int flags)
{
int changed;
changed = 0;
while(list)
{
if (type == hl_ALL || type == list->type)
{
if (list->flags & ~flags != list->flags)
{
list->flags |= HOTLIST_G_REDRAW_NOW;
changed = 1;
}
list->flags &= ~flags;
}
if (list->type == hl_directory)
{
if (hotlist_clear_flags(list->data.directory_content, type, flags)) changed = 1;
}
list = list->next;
}
return changed;
}
/*************************************************/
/* _hotlist_draw() */
/* */
/* This function does all the hard work for */
/* hotlist_draw() */
/* */
/* Parameters: Pointer to a hotlist_item */
/* First item number to draw */
/* Last item number to draw */
/* Level of indentation */
/*************************************************/
static void _hotlist_draw(hotlist_item *list,
unsigned int first_item,
unsigned int last_item,
unsigned int indent)
{
WimpIconBlock hotlist_iconblock;
unsigned int item_height, item_dir_width, item_url_width;
unsigned int temp_width;
_kernel_swi_regs regs;
hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width);
while(list)
{
if (item_number > last_item) return; /* Break out if done all items to be displayed */
if (item_number >= first_item)
{
/* draw it */
hotlist_iconblock.flags = HOTLIST_SPRITE_ICON_FLAGS;
if (list->flags & HOTLIST_G_IS_SELECTED) hotlist_iconblock.flags |= WimpIcon_Selected;
hotlist_iconblock.data.is.sprite_area = (void*)sprite_block;
switch(list->type) /* Set appropriate sprite and width of sprite */
{
case hl_url:
hotlist_iconblock.data.is.sprite = URL_SPRITE;
hotlist_iconblock.data.is.sprite_name_length = strlen(URL_SPRITE);
temp_width = item_url_width;
break;
case hl_directory:
temp_width = item_dir_width;
if (list->flags & HOTLIST_D_IS_HIGHLIGHTED)
{
hotlist_iconblock.data.is.sprite = INSERT_DIRECTORY_SPRITE;
hotlist_iconblock.data.is.sprite_name_length = strlen(INSERT_DIRECTORY_SPRITE);
}
else
{
if (list->flags & HOTLIST_D_IS_OPEN)
{
hotlist_iconblock.data.is.sprite = OPEN_DIRECTORY_SPRITE;
hotlist_iconblock.data.is.sprite_name_length = strlen(OPEN_DIRECTORY_SPRITE);
}
else
{
hotlist_iconblock.data.is.sprite = CLOSED_DIRECTORY_SPRITE;
hotlist_iconblock.data.is.sprite_name_length = strlen(CLOSED_DIRECTORY_SPRITE);
}
}
break;
default:
temp_width = 0; /* Only here to stop warnings */
}
hotlist_iconblock.bbox.xmin = indent;
hotlist_iconblock.bbox.xmax = indent + temp_width;
hotlist_iconblock.bbox.ymax = (-item_height*item_number);
hotlist_iconblock.bbox.ymin = ((-item_height*item_number) - item_height);
wimp_plot_icon(&hotlist_iconblock); /* Plot sprite icon */
regs.r[0] = 1;
regs.r[1] = (int)list->name;
regs.r[2] = 0;
wimp_text_op(&regs); /* Get width of text for text icon */
if (list->flags & HOTLIST_G_IS_SELECTED)
hotlist_iconblock.flags = HOTLIST_TEXT_ICON_FLAGS_SELECTED;
else
hotlist_iconblock.flags = HOTLIST_TEXT_ICON_FLAGS_UNSELECTED;
hotlist_iconblock.bbox.xmin = indent+temp_width+2;
hotlist_iconblock.bbox.xmax = indent+temp_width+2+regs.r[0] + 12;
hotlist_iconblock.bbox.ymax = (-item_height*item_number) - 2;
hotlist_iconblock.bbox.ymin = (-item_height*item_number) - item_height + 2;
hotlist_iconblock.data.it.buffer = list->name;
hotlist_iconblock.data.it.buffer_size = strlen(list->name);
wimp_plot_icon(&hotlist_iconblock);
/*! drawit */
}
item_number++;
if (list->type == hl_directory && list->flags & HOTLIST_D_IS_OPEN)
{
_hotlist_draw(list->data.directory_content, first_item, last_item, indent + item_dir_width);
}
list = list->next;
}
}
/*************************************************/
/* hotlist_draw() */
/* */
/* This function will recursivly draw the */
/* hotlist */
/* */
/* Parameters: Pointer to a hotlist_item */
/* First item number to draw */
/* Last item number to draw */
/* */
/* Note: This function doesn't actually */
/* do any of the real work but */
/* merely sets up global variables */
/* and calls _hotlist_draw() */
/*************************************************/
static void hotlist_draw(hotlist_item *list,
unsigned int first_item,
unsigned int last_item)
{
item_number = 0;
_hotlist_draw(list, first_item, last_item, 0);
}
/*************************************************/
/* _hotlist_get_max_width */
/* */
/* This function does all the work for */
/* hotlist_get_max_width */
/*************************************************/
static void _hotlist_get_max_width(hotlist_item *list, unsigned int indent)
{
unsigned int item_height, item_dir_width, item_url_width;
unsigned int temp_width;
_kernel_swi_regs regs;
hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width);
while(list)
{
switch(list->type)
{
case hl_directory:
temp_width = item_dir_width;
break;
case hl_url:
temp_width = item_url_width;
break;
default:
temp_width = 0;
break;
}
regs.r[0] = 1;
regs.r[1] = (int)list->name;
regs.r[2] = 0;
wimp_text_op(&regs);
temp_width += indent+2+regs.r[0] + 12;
if (temp_width > item_number) item_number = temp_width;
if (list->type == hl_directory && list->flags & HOTLIST_D_IS_OPEN)
{
_hotlist_get_max_width(list->data.directory_content, indent + item_dir_width);
}
list = list->next;
item_number++;
}
}
/*************************************************/
/* hotlist_get_max_width() */
/* */
/* This function returns the maximum width of */
/* of the displayed hotlist entries */
/* */
/* */
/*************************************************/
static unsigned int hotlist_get_max_width(hotlist_item *list)
{
item_number = 0;
_hotlist_get_max_width(list, 0);
return item_number;
}
/*************************************************/
/* _hotlist_redraw_now() */
/* */
/* This function does the work for */
/* hotlist_redraw_now() */
/*************************************************/
static void _hotlist_redraw_now(hotlist_item *list)
{
while(list)
{
if (list->flags & HOTLIST_G_REDRAW_NOW)
{
hotlist_redraw_items(item_number, item_number);
list->flags &= ~HOTLIST_G_REDRAW_NOW;
}
item_number++;
if (list->type == hl_directory && list->flags & HOTLIST_D_IS_OPEN)
{
_hotlist_redraw_now(list->data.directory_content);
}
list = list->next;
}
}
/*************************************************/
/* hotlist_redraw_now() */
/* */
/* This function redraws all visible items with */
/* the HOTLIST_G_REDRAW_NOW bit set */
/*************************************************/
static void hotlist_redraw_now(void)
{
item_number = 0;
_hotlist_redraw_now(hotlist_root->data.directory_content);
}
/*************************************************/
/* hotlist_add() */
/* */
/* Add a new URL to the hotlist. */
/* */
/* Parameters: Description of the URL (e.g. from */
/* the page title); */
/* */
/* Pointer to the URL itself; */
/* */
/* 0 to add to the top, 1 to add to */
/* the bottom. */
/*************************************************/
_kernel_oserror * hotlist_add(char * description, char * url, int at_bottom)
{
_kernel_oserror * e = NULL;
int position;
position = at_bottom ? HOTLIST_POSITION_END : HOTLIST_POSITION_BEGINNING;
/* Add the item and ensure the window extent etc. is correct */
e = hotlist_new_url(hotlist_root,
position,
description,
url);
if (!e) hotlist_window_preopen(already_open);
/* Optimise the redraw to do as little as possible depending */
/* upon where in the list the item was added. */
switch (position)
{
default:
case HOTLIST_POSITION_END:
{
hotlist_redraw_now();
}
break;
case HOTLIST_POSITION_BEGINNING:
{
hotlist_redraw_items(0,
hotlist_count_displayed_items(hotlist_root->data.directory_content));
}
break;
}
return e;
}
/*************************************************/
/* hotlist_get_shape() */
/* */
/* This function calculates the xmin and xmax */
/* of the passed hotlist_item */
/* */
/* Parameters: *xmin */
/* *xmax */
/* item */
/*************************************************/
static void hotlist_get_shape(unsigned int *xmin,
unsigned int *xmax,
hotlist_item *item)
{
unsigned int item_height, item_dir_width, item_url_width;
int count = 0, temp_width;
_kernel_swi_regs regs;
hotlist_item *tempitem;
hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width);
tempitem = item;
while(tempitem)
{
tempitem = tempitem->parent;
count++;
}
count -= 2;
regs.r[0] = 1;
regs.r[1] = (int)item->name;
regs.r[2] = 0;
wimp_text_op(&regs);
switch(item->type)
{
case hl_directory:
temp_width = item_dir_width;
break;
case hl_url:
temp_width = item_url_width;
break;
default:
temp_width = 0;
break;
}
*xmin = count * item_dir_width;
*xmax = count * item_dir_width + temp_width + regs.r[0] + 2 + 12;
}
/*************************************************/
/* hotlist_directory_open_close() */
/* */
/* This function opens or closes a directory */
/* along with all required redrawing */
/* */
/* Parameters: hotlist_item */
/* item number on screen */
/*************************************************/
static void hotlist_directory_open_close(hotlist_item *item, unsigned int itemno)
{
unsigned int item_height, item_dir_width, item_url_width;
int top, window_handle;
BBox bbox;
hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width);
item->flags ^= HOTLIST_D_IS_OPEN;
hotlist_window_preopen(already_open);
show_error(window_get_wimp_handle(0, hotlist_windowid, &window_handle));
window_get_extent(0, hotlist_windowid, &bbox);
top = -itemno * item_height; /* Window relative coordinate */
if (item->data.directory_content)
{
show_error(wimp_force_redraw(window_handle,
bbox.xmin,
bbox.ymin,
bbox.xmax,
top));
}
else
{
show_error(wimp_force_redraw(window_handle,
bbox.xmin,
top-item_height,
bbox.xmax,
top));
}
}
/*************************************************/
/* hotlist_redraw_items() */
/* */
/* This function forces the redraw of a set of */
/* items */
/* */
/* Parameters: itemno */
/*************************************************/
static void hotlist_redraw_items(unsigned int firstitem, unsigned int lastitem)
{
unsigned int item_height, item_dir_width, item_url_width;
BBox bbox;
int window_handle;
hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width);
show_error(window_get_wimp_handle(0, hotlist_windowid, &window_handle));
window_get_extent(0, hotlist_windowid, &bbox);
wimp_force_redraw(window_handle,
bbox.xmin,
- (lastitem + 1) * item_height,
bbox.xmax,
- firstitem * item_height);
}
/*************************************************/
/* hotlist_clear_selection() */
/* */
/* This function unselects all items and redraws */
/* appropriate items */
/*************************************************/
static void hotlist_clear_selection(void)
{
hotlist_clear_flags(hotlist_root->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED);
hotlist_redraw_now();
number_selected = 0;
}
/*************************************************/
/* hotlist_launch_url() */
/* */
/* This function launches the url in the passed */
/* item */
/* */
/* Parameters: hotlist_item */
/*************************************************/
static void hotlist_launch_url(hotlist_item * item)
{
#ifdef TRACE
if (tl & (1u<<25)) hotlist_display_item(item);
#endif
windows_create_browser(item->data.url, NULL, NULL, NULL, 0);
}
/*************************************************/
/* hotlist_process_click_on_item() */
/* */
/* This function handles mouse clicks on hotlist */
/* items */
/*************************************************/
static _kernel_oserror * hotlist_process_click_on_item(unsigned int itemno,
hotlist_item *item,
int buttons,
int x,
int y)
{
switch(buttons)
{
case Wimp_MouseButtonSelect:
if (last_selected_item == itemno)
{
switch(item->type)
{
case hl_directory:
hotlist_directory_open_close(item, itemno);
break;
case hl_url:
hotlist_launch_url(item);
break;
}
item->flags &= ~HOTLIST_G_IS_SELECTED;
number_selected--;
hotlist_redraw_items(itemno, itemno);
}
break; /* Double click select */
case Wimp_MouseButtonAdjust:
if (last_selected_item == itemno)
{
switch(item->type)
{
case hl_directory:
hotlist_directory_open_close(item, itemno);
break;
case hl_url:
hotlist_launch_url(item);
toolbox_hide_object(0, hotlist_windowid);
break;
}
item->flags &= ~HOTLIST_G_IS_SELECTED;
number_selected--;
hotlist_redraw_items(itemno, itemno);
}
break; /* Double click adjust */
case 64: /* Drag select */
hotlist_start_drag();
break;
case 16: /* Drag adjust */
if (!(item->flags & HOTLIST_G_IS_SELECTED))
{
item->flags |= HOTLIST_G_IS_SELECTED;
number_selected++;
selected_parent = item->parent;
last_selected_item = itemno;
}
hotlist_start_drag();
hotlist_redraw_items(itemno, itemno);
break;
case 1024: /* Click select */
if (item->flags & HOTLIST_G_IS_SELECTED)
{
/* Do nothing when selected */
}
else
{
hotlist_clear_selection();
item->flags |= HOTLIST_G_IS_SELECTED;
selected_parent = item->parent;
number_selected++;
hotlist_redraw_items(itemno, itemno);
}
last_selected_item = itemno;
break;
case 256: /* Click adjust */
if (selected_parent != item->parent && item->type != hl_url) hotlist_clear_selection();
item->flags ^= HOTLIST_G_IS_SELECTED;
if (item->flags & HOTLIST_G_IS_SELECTED)
{
number_selected++;
}
else
{
number_selected--;
}
hotlist_redraw_items(itemno, itemno);
selected_parent = item->parent;
last_selected_item = itemno;
break;
}
return NULL;
}
/*************************************************/
/* hotlist_process_click() */
/* */
/* This function handles mouse clicks on the */
/* hotlist window */
/* */
/* Parameters: x position */
/* y position */
/* button state */
/*************************************************/
static _kernel_oserror * hotlist_process_click(int x, int y, int buttons)
{
unsigned int item_height, item_dir_width, item_url_width;
hotlist_item *item;
unsigned int xmin, xmax, itemno;
hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width);
itemno = -y / item_height;
item = hotlist_find_item(hotlist_root->data.directory_content, itemno);
if (item) hotlist_get_shape(&xmin, &xmax, item);
if (item && x >= xmin && x <= xmax)
{
return hotlist_process_click_on_item(itemno, item, buttons, x, y);
}
else
{
switch(buttons)
{
case Wimp_MouseButtonSelect:
break; /* Double click select */
case Wimp_MouseButtonAdjust:
break; /* Double click adjust */
case 64: /* Drag select */
hotlist_clear_selection();
hotlist_selection_box_start();
break;
case 16: /* Drag adjust */
hotlist_clear_selection();
hotlist_selection_box_start();
break;
case 1024:
hotlist_clear_selection();
last_selected_item = 0xffffffff;
break; /* Click select */
case 256:
last_selected_item = 0xffffffff;
break; /* Click adjust */
}
}
return NULL;
}
/*************************************************/
/* hotlist_window_preopen() */
/* */
/* This function should be called before opening */
/* the hotlist window. When opentype is */
/* not_open the window is opened as large as is */
/* required to show all items. When opentype is */
/* already_open the window size will grow enough */
/* to allow all items to fit but its screen size */
/* will not change, if the window needs to */
/* it will do so but its work area will not get */
/* any smaller than the current visible area */
/* */
/* Parameters: opentype */
/* */
/*************************************************/
static void hotlist_window_preopen(hl_opentype type)
{
unsigned int item_height, item_dir_width, item_url_width;
unsigned int number, maxlen;
BBox bbox;
WimpGetWindowStateBlock state;
int height, width;
hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width);
number = hotlist_count_displayed_items(hotlist_root->data.directory_content);
maxlen = hotlist_get_max_width(hotlist_root->data.directory_content) + 4;
show_error(window_get_wimp_handle(0, hotlist_windowid, &state.window_handle));
wimp_get_window_state(&state);
if (number < HOTLIST_WINDOW_MIN_HEIGHT) number = HOTLIST_WINDOW_MIN_HEIGHT;
if (maxlen < HOTLIST_WINDOW_MIN_WIDTH) maxlen = HOTLIST_WINDOW_MIN_WIDTH;
if (type == already_open)
window_get_extent(0, hotlist_windowid, &bbox);
bbox.ymin = -number * item_height;
bbox.xmax = maxlen;
if (type == already_open)
{
width = state.visible_area.xmax - state.visible_area.xmin;
height = state.visible_area.ymax - state.visible_area.ymin + hotlist_bbar_size;
if (bbox.ymin > -height) bbox.ymin = -height;
if (bbox.xmax < width) bbox.xmax = width;
}
bbox.ymax = hotlist_bbar_size;
bbox.xmin = 0;
window_set_extent(0, hotlist_windowid, &bbox);
if (type == already_open)
{
show_error(window_get_wimp_handle(0, hotlist_windowid, &state.window_handle));
wimp_get_window_state(&state);
wimp_open_window((WimpOpenWindowBlock*)&state);
}
}
/*************************************************/
/* hotlist_redraw_handler() */
/* */
/* This function redraws the hotlist window */
/*************************************************/
static int hotlist_redraw_handler(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle)
{
unsigned int item_height, item_dir_width, item_url_width;
unsigned int first_item, last_item;
int more;
WimpRedrawWindowBlock block;
hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width);
block.window_handle = event->redraw_window_request.window_handle;
wimp_redraw_window(&block, &more);
while(more)
{
first_item = -(block.redraw_area.ymax - (block.visible_area.ymax - block.yscroll)) / item_height;
last_item = (-(block.redraw_area.ymin - (block.visible_area.ymax - block.yscroll)) / item_height) + 1;
hotlist_draw(hotlist_root->data.directory_content,
first_item,
last_item);
wimp_get_rectangle(&block, &more);
}
return 0;
}
/*************************************************/
/* hotlist_mouse_click_handler() */
/* */
/* This function handles mouse clicks in the */
/* hotlist window */
/*************************************************/
static int hotlist_mouse_click_handler(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle)
{
WimpGetWindowStateBlock state;
state.window_handle = event->mouse_click.window_handle;
wimp_get_window_state(&state);
wimp_set_caret_position(state.window_handle, -1, 0, 0, -1, -1);
hotlist_process_click(event->mouse_click.mouse_x + (state.xscroll - state.visible_area.xmin),
event->mouse_click.mouse_y + (state.yscroll - state.visible_area.ymax),
event->mouse_click.buttons);
return 0;
}
/*************************************************/
/* hotlist_menuclose_handler() */
/* */
/* This function handles closed menu events */
/*************************************************/
static int hotlist_menuclose_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
{
ObjectId submenu_id;
if (number_selected == -1)
{
hotlist_clear_selection();
number_selected = 0;
}
show_error(menu_get_sub_menu_show(0, id_block->self_id, HOTLIST_URL_MENUITEM, &submenu_id));
if (submenu_id) show_error(toolbox_delete_object(0, submenu_id));
menu_set_sub_menu_show(0, id_block->self_id, HOTLIST_URL_MENUITEM, 0);
return 0;
}
void hotlist_setmenu_details(ObjectId menuid)
{
hotlist_item * item;
char entrytext[32];
ObjectId submenu_id;
switch(number_selected)
{
case 0:
menu_set_entry_text(0, menuid, HOTLIST_URL_MENUITEM, "URL ''");
menu_set_fade(0, menuid, HOTLIST_URL_MENUITEM, 1);
menu_set_fade(0, menuid, HOTLIST_CLEARSELECTION_MENUITEM, 1); /* Fade clear selection */
break;
case -1:
case 1:
item = hotlist_find_selected_item(); /* One item selected */
switch(item->type)
{
case hl_directory:
strcpy(entrytext, "Dir. '");
toolbox_create_object(0, "HLDirmenu", &submenu_id);
menu_set_sub_menu_show(0, menuid, HOTLIST_URL_MENUITEM, submenu_id);
break;
case hl_url:
strcpy(entrytext, "URL '");
toolbox_create_object(0, "HLURLmenu", &submenu_id);
menu_set_sub_menu_show(0, menuid, HOTLIST_URL_MENUITEM, submenu_id);
break;
}
strncat(entrytext, item->name, 10);
if (strlen(item->name) > 10) strcat(entrytext, "...");
strcat(entrytext, "'");
menu_set_entry_text(0, menuid, HOTLIST_URL_MENUITEM, entrytext);
menu_set_fade(0, menuid, HOTLIST_URL_MENUITEM, 0); /* unfade URL '' */
menu_set_fade(0, menuid, HOTLIST_CLEARSELECTION_MENUITEM, 0); /* unfade clear selection */
break;
default:
menu_set_entry_text(0, menuid, HOTLIST_URL_MENUITEM, "Selection"); /* Multiple items selected */
menu_set_fade(0, menuid, HOTLIST_URL_MENUITEM, 0); /* unfade URL '' */
menu_set_fade(0, menuid, HOTLIST_CLEARSELECTION_MENUITEM, 0); /* unfade clear selection */
toolbox_create_object(0, "HLSlctmenu", &submenu_id);
menu_set_sub_menu_show(0, menuid, HOTLIST_URL_MENUITEM, submenu_id);
break;
}
}
/*************************************************/
/* hotlist_menuopen_handler() */
/* */
/* This function handles opened menu events */
/*************************************************/
static int hotlist_menuopen_handler(int event_code, ToolboxEvent * event, IdBlock * id_block, void * handle)
{
WimpGetWindowStateBlock state;
WimpGetPointerInfoBlock pointerblock;
hotlist_item * item;
unsigned int item_height, item_dir_width, item_url_width;
unsigned int xmin, xmax;
int window_handle;
hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width);
if (event_code == HotlistMenuOpened)
{
window_get_wimp_handle(0, hotlist_windowid, &window_handle);
state.window_handle = window_handle;
wimp_get_window_state(&state);
wimp_get_pointer_info(&pointerblock);
pointerblock.x = pointerblock.x + (state.xscroll - state.visible_area.xmin);
pointerblock.y = pointerblock.y + (state.yscroll - state.visible_area.ymax);
menu_itemno = -pointerblock.y / item_height;
}
if (number_selected == 0)
{
item = hotlist_find_item(hotlist_root->data.directory_content, menu_itemno);
if (item)
{
hotlist_get_shape(&xmin, &xmax, item);
}
if (item && pointerblock.x >= xmin && pointerblock.x <= xmax)
{
item->flags |= HOTLIST_G_IS_SELECTED;
selected_parent = item->parent;
number_selected = -1;
hotlist_redraw_items(menu_itemno, menu_itemno);
}
}
hotlist_setmenu_details(id_block->self_id);
return 0;
}
/*************************************************/
/* hotlist_save_entries() */
/* */
/* This function recurses through the hotlist */
/* directory structure saving all directories */
/* and entries as it goes. */
/* */
/* Parameters: Pointer to a FILE struct for the */
/* file to write to; */
/* */
/* Pointer to a hotlist_item struct */
/* representing the first item in */
/* the directory to save (which may */
/* itself be a directory). */
/* */
/* Assumes: The FILE pointer must not be NULL */
/* however the hotlist_item pointer */
/* can be (e.g. an empty directory). */
/*************************************************/
static _kernel_oserror * hotlist_save_entries(FILE * fileptr, hotlist_item * list)
{
int written;
_kernel_oserror * e;
/* Write the entry header */
HotlistWrite(fprintf(fileptr, "<ul>\n"));
/* Follow the directory list */
while (list)
{
switch (list->type)
{
/* Write a link for URLs */
case hl_url:
{
HotlistWrite(fprintf(fileptr, "<li><a href=\"%s\">%s</a>\n", list->data.url, list->name));
}
break;
/* Write a heading for directories */
case hl_directory:
{
HotlistWrite(fprintf(fileptr, "<h4>%s</h4>\n", list->name));
/* Recursive call for the directory contents */
RetError(hotlist_save_entries(fileptr, list->data.directory_content));
}
break;
}
/* Continue down the list */
list = list->next;
}
/* Write the entry footer */
HotlistWrite(fprintf(fileptr, "</ul>\n"));
return NULL;
}
/*************************************************/
/* hotlist_save() */
/* */
/* This function saves the hotlist as an HTML */
/* file. */
/* */
/* Parameters: Pointer to the filename to load */
/* (null terminated). */
/*************************************************/
_kernel_oserror * hotlist_save(char * filename)
{
FILE * fileptr;
_kernel_oserror * e;
int written;
/* Open the file for writng */
fileptr = fopen(filename, "wb");
/* Complain if it fails */
if (fileptr == NULL) return _kernel_last_oserror();
/* Write the file header */
HotlistWrite(fprintf(fileptr, "<html>\n"));
HotlistWrite(fprintf(fileptr, "<head><title>Hotlist</title></head>\n"));
HotlistWrite(fprintf(fileptr, "<body>\n"));
/* Fill in the body */
e = hotlist_save_entries(fileptr, hotlist_root->data.directory_content);
if (e)
{
fclose(fileptr);
return e;
}
/* Write the footer and close the file */
HotlistWrite(fprintf(fileptr, "</body>\n"));
HotlistWrite(fprintf(fileptr, "</html>\n"));
fclose(fileptr);
/* Set the filetype to HTML (0xfaf) */
return _swix(OS_File,
_INR(0,2),
18,
filename,
FileType_HTML);
}
/*************************************************/
/* hotlist_lower_tags() */
/* */
/* This function processes the passed string */
/* turning all characters within a tag to lower */
/* case. It will detect characters within quotes */
/* and leave their case the same; this will */
/* preserve the case of URLs. */
/* */
/* Obviously, this assumes that the HTML file */
/* being fed in is not broken; tags and quoted */
/* text must always be correctly closed, and */
/* in both cases must not span multiple lines. */
/* */
/* Parameters: Pointer to the string to process. */
/*************************************************/
static void hotlist_lower_tags(char *string)
{
int intag = 0, inquotes = 0;
while (*string)
{
if (intag)
{
if (inquotes)
{
if (*string == '"') inquotes = 0;
}
else
{
if (*string == '"') inquotes = 1;
if (*string == '>') intag --;
*string = tolower(*string);
}
}
else
{
if (*string == '<') intag++;
}
string++;
}
}
/*************************************************/
/* hotlist_load_directory() */
/* */
/* This function loads the directory contents of */
/* a hotlist HTML file previously saved by */
/* hotlist_save or a compatible source. For */
/* example, at the time of creation this can */
/* correctly load and understand hotlist files */
/* from at least one other popular browser. */
/* */
/* Parameters: Pointer to a FILE struct through */
/* which data will be read; */
/* */
/* Pointer to a hotlist_item; new */
/* data structures generated from */
/* the file contents are added to */
/* the linked list that this struct */
/* lies in. */
/*************************************************/
static _kernel_oserror * hotlist_load_directory(FILE * fileptr, hotlist_item * target)
{
_kernel_oserror * e = NULL;
static char * next_directory_name = NULL;
static char * string_buffer = NULL;
static char * str_ptr;
char * url;
hotlist_item * new_dir;
unsigned int unfollowed_uls = 0;
long int file_position;
int character, count;
/* Go through the file in chunks */
while (!feof(fileptr)) /* In theory the code below means you'll never get this; but just to be safe... */
{
file_position = ftell(fileptr);
/* Scan ahead to find the end of line - marked by any */
/* control character, in this case; need to include */
/* as many consecutive control chars as are present */
/* in the file, in the count. */
do
{
/* First, get to either a control char or EOF */
character = fgetc(fileptr);
}
while (character > 31 && character != EOF);
while (character < 32 && character != EOF)
{
/* If we're not on EOF, continue until we're no longer */
/* on a control char or hit EOF. */
character = fgetc(fileptr);
}
/* Work out how many bytes we've read */
count = (int) (ftell(fileptr) - file_position);
/* If count is zero, we're at the end of the file */
if (!count) break;
/* If we're not on EOF and don't have a control char, then */
/* we overshot by one; so we would want to subtract one */
/* from count. However, to ensure string manipulation */
/* works OK, we'll need one char to null terminate the */
/* string. So in that case, we need to *add* one to count */
/* if the above condition isn't true. */
if (!(character > 31 && character != EOF)) count ++;
/* Right, after all that messing around rewind to the stored */
/* file position and allocate a buffer for this string. */
if (fseek(fileptr, file_position, SEEK_SET))
{
e = _kernel_last_oserror();
goto hotlist_load_directory_exit; /* (See near end of function) */
}
/* Note that string_buffer is a static, as this way only one */
/* of these buffers ever exists, even for recursive calls. */
if (string_buffer) free(string_buffer);
string_buffer = malloc(count);
/* Complain if the allocation fails */
if (!string_buffer)
{
make_no_memory_error(2);
e = &erb;
goto hotlist_load_directory_exit; /* (See near end of function) */
}
/* Read the data and force a terminator at the end of the buffer, */
/* just to be safe. */
if (fread(string_buffer, sizeof(char), count - 1, fileptr) != count - 1)
{
e = _kernel_last_oserror();
goto hotlist_load_directory_exit; /* (See near end of function) */
}
string_buffer[count - 1] = 0;
/* Convert tags to lower case */
hotlist_lower_tags(string_buffer);
/* Treat any opening '<h...>' tag (header) as the title to a directory */
str_ptr = strstr(string_buffer, "<h");
if (
str_ptr &&
str_ptr[2] >= '1' &&
str_ptr[2] <= '6' &&
str_ptr[3] == '>'
)
{
/* Read the directory name (up to the closing '</h...>') */
str_ptr = strtok(str_ptr + 4, "<");
/* Allocate space for it */
if (next_directory_name) free(next_directory_name);
next_directory_name = malloc(strlen(str_ptr) + 1);
/* Complain if the allocation fails */
if (!next_directory_name)
{
make_no_memory_error(3);
e = &erb;
goto hotlist_load_directory_exit; /* (See near end of function) */
}
/* Otherwise, copy the name in */
strcpy(next_directory_name, str_ptr);
}
/* Treat any '<a href=...>' attribute contents (link) as a URL for the hotlist */
else if ((str_ptr = strstr(string_buffer, "<a href=\"")) != NULL) /* Using '!= NULL' stops a compiler warning... */
{
/* First extract the URL */
str_ptr += 9; /* Derived from strlen("<a href=\"") */
str_ptr = strtok(str_ptr, "\"");
/* Because we're about to use strtok() to extract the title, it'll */
/* put a convenient terminator into the string_buffer block at the */
/* end of the URL. So all we need to do is record the current */
/* pointer in the block, str_ptr, for use when we finally add the */
/* item to the hotlist. */
url = str_ptr;
/* Extract the title - between the closing '>' of the '<a href=...' */
/* and the opening '<' of the '</a>'. */
str_ptr = strtok(NULL, "><");
/* Add this item */
e = hotlist_new_url(target, HOTLIST_POSITION_END, str_ptr, url);
if (e) goto hotlist_load_directory_exit; /* (See near end of function) */
}
/* Treat any '<ul>' tags as the start of a new directory. The name comes */
/* from a preceeding '<h...>' tag (see above). */
else if ((str_ptr = strstr(string_buffer, "<ul>")) != NULL) /* New directory */
{
if (!next_directory_name)
{
/* If we don't have a directory name for this one, apparently, flag it */
/* by incrementing the unmatched '<ul>' counter. */
unfollowed_uls ++;
}
else
{
/* Otherwise, add the directory */
e = hotlist_new_directory(target, next_directory_name, HOTLIST_POSITION_END, &new_dir);
if (e) goto hotlist_load_directory_exit;
free(next_directory_name);
next_directory_name = NULL;
/* If the directory was added, recursively load the contents */
if (new_dir)
{
/* Note this will invalidate string_buffer. The contents must */
/* not be used after the call! */
e = hotlist_load_directory(fileptr, new_dir);
if (e) goto hotlist_load_directory_exit; /* (See near end of function) */
}
else
{
/* If the directory was not added, flag it */
unfollowed_uls ++;
}
}
}
/* Treat any '</ul>' tags as the end of a directory. */
else if ((str_ptr = strstr(string_buffer, "</ul>")) != NULL) /* Close directory */
{
/* If we have unfollowed '<ul>' tags, decrement the counter; */
/* otherwise, exit quietly. */
if (unfollowed_uls) unfollowed_uls--;
else goto hotlist_load_directory_exit; /* (See near end of function) */
}
}
/* This section is not necessarily an error exit condition, so */
/* the code falls through to it in normal running. If 'e' is */
/* NULL there's still no error returned in the end. Note */
/* though how the various buffers are freed, and thus */
/* invalidated, at this point; so during recursive routines, */
/* they must not be accessed after the recursive call has */
/* been made (unless, of course, they are reallocated). */
hotlist_load_directory_exit:
/* Free up the temporary buffers */
if (string_buffer)
{
free(string_buffer);
string_buffer = NULL;
}
if (next_directory_name)
{
free(next_directory_name);
next_directory_name = NULL;
}
// We could at this point give a warning if unfollowed_uls is non-zero.
return e;
}
/*************************************************/
/* hotlist_load() */
/* */
/* This function loads an HTML file previously */
/* saved by hotlist_save as the new hotlist. */
/* */
/* Parameters: Pointer to the filename to load */
/* (null terminated). */
/*************************************************/
_kernel_oserror * hotlist_load(char * filename)
{
_kernel_oserror * e;
FILE * fileptr;
/* First delete all the existing hotlist items */
while (hotlist_root->data.directory_content)
{
hotlist_delete_item(hotlist_root->data.directory_content);
}
/* Open the file */
fileptr = fopen(filename, "r");
if (fileptr == NULL)
{
erb.errnum = Utils_Error_Custom_Normal;
StrNCpy0(erb.errmess,
lookup_token("HlCantLoad:Hotlist file could not be loaded",
0,
0));
return &erb;
}
/* Load it (any errors are returned right at the end) */
e = hotlist_load_directory(fileptr, hotlist_root);
fclose(fileptr);
/* Clear all of the various flags for redraw, */
/* selection etc. now that we have a new */
/* hotlist. */
hotlist_clear_flags(hotlist_root, hl_ALL, HOTLIST_G_REDRAW_NOW);
#ifdef TRACE
/* Show the tree now the file is loaded */
if (tl & (1u<<25)) hotlist_display_tree(hotlist_root, 0);
#endif
/* Finished; redraw issues are left to the caller */
return e;
}
/*************************************************/
/* hotlist_initialise() */
/* */
/* This function initialises the hotlist library */
/* routines, and must be called before any other */
/* hotlist functions. */
/*************************************************/
_kernel_oserror * hotlist_initialise(void)
{
_kernel_oserror * e;
ObjectId toolbar;
ObjectId menu_id;
BBox bbox;
/* Create root directory item */
RetError(hotlist_new_directory(NULL, "Root", 0, &hotlist_root));
/* Create the hotlist window */
RetError(toolbox_create_object(0, "HotlistWind", &hotlist_windowid));
/* Is there a toolbar? */
RetError(window_get_tool_bars(InternalTopLeft,
hotlist_windowid,
NULL,
&toolbar,
NULL,
NULL));
/* If so, read the size */
if (toolbar != 0)
{
RetError(window_get_extent(0, toolbar, &bbox));
hotlist_bbar_size = bbox.ymax - bbox.ymin;
}
else hotlist_bbar_size = 0;
/* Register event handlers for redraw, clicks and drags in the */
/* main hotlist window. */
RetError(event_register_wimp_handler(hotlist_windowid,
Wimp_ERedrawWindow,
hotlist_redraw_handler,
NULL));
RetError(event_register_wimp_handler(hotlist_windowid,
Wimp_EMouseClick,
hotlist_mouse_click_handler,
NULL));
RetError(event_register_wimp_handler(-1,
Wimp_EUserDrag,
hotlist_drag_completed_handler,
NULL));
/* Menu handlers */
RetError(window_get_menu(0, hotlist_windowid, &menu_id));
RetError(event_register_toolbox_handler(menu_id,
HotlistMenuOpened,
hotlist_menuopen_handler,
NULL));
RetError(event_register_toolbox_handler(menu_id,
HotlistMenuClosed,
hotlist_menuclose_handler,
NULL));
/* Main menu items */
RetError(event_register_toolbox_handler(-1,
HotlistSelectAll,
hotlist_menu_selectall_handler,
NULL));
RetError(event_register_toolbox_handler(-1,
HotlistClearSelect,
hotlist_menu_clearselect_handler,
NULL));
RetError(event_register_toolbox_handler(-1,
HotlistOpenAll,
hotlist_menu_openall_handler,
NULL));
RetError(event_register_toolbox_handler(-1,
HotlistCloseAll,
hotlist_menu_closeall_handler,
NULL));
RetError(event_register_toolbox_handler(-1,
HotlistDelete,
hotlist_menu_delete_handler,
NULL));
/* Submenu warning events */
RetError(event_register_toolbox_handler(-1,
HotlistShowEditURL,
hotlist_show_editurl_handler,
NULL));
RetError(event_register_toolbox_handler(-1,
HotlistShowRenameDirectory,
hotlist_show_rendirectory_handler,
NULL));
RetError(event_register_toolbox_handler(-1,
HotlistShowNewURL,
hotlist_show_newurl_handler,
NULL));
RetError(event_register_toolbox_handler(-1,
HotlistShowNewDirectory,
hotlist_show_newdirectory_handler,
NULL));
/* Hotlist related dialogue events */
RetError(event_register_toolbox_handler(-1,
HotlistNewEditURLOk,
hotlist_newedit_url_handler,
NULL));
RetError(event_register_toolbox_handler(-1,
HotlistNewRenameDirectoryOk,
hotlist_newren_directory_handler,
NULL));
RetError(event_register_toolbox_handler(-1,
HotlistNewEditURLCancel,
hotlist_reset_url_handler,
NULL));
RetError(event_register_toolbox_handler(-1,
HotlistNewRenameDirectoryCancel,
hotlist_reset_directory_handler,
NULL));
return NULL;
}
/*************************************************/
/* hotlist_open() */
/* */
/* Opens the hotlist window. */
/* */
/* Parameters: Show type (as for a call to */
/* Toolbox_ShowObject); */
/* */
/* Show block (as for a call to */
/* Toolbox_ShowObject); */
/* */
/* 0 to open showing descriptions, */
/* or 1 to open showing URLs. */
/*************************************************/
_kernel_oserror * hotlist_open(int show_type, void * type, int show_urls)
{
// Not implemented yet...
show_urls = show_urls;
/* Set the size of the window etc. */
hotlist_window_preopen(not_open);
/* Show the hotlist */
return toolbox_show_object(0,
hotlist_windowid,
show_type,
type,
0,
0);
}
/*************************************************/
/* hotlist_close() */
/* */
/* Closes the hotlist window. */
/*************************************************/
_kernel_oserror * hotlist_close(void)
{
return toolbox_hide_object(0, hotlist_windowid);
}
/*************************************************/
/* hotlist_menu_selectall_handler() */
/* */
/* This function handles the select all menu */
/* item */
/*************************************************/
static int hotlist_menu_selectall_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
{
hotlist_item *item;
ObjectId sub_menu;
if (!hotlist_root->data.directory_content) return 0;
item = hotlist_find_item(hotlist_root->data.directory_content, menu_itemno);
if (item && item->parent)
{
item = item->parent->data.directory_content;
number_selected = 0;
while(item)
{
item->flags |= HOTLIST_G_IS_SELECTED | HOTLIST_G_REDRAW_NOW;
number_selected++;
item = item->next;
}
hotlist_redraw_now();
menu_get_sub_menu_show(0, id_block->self_id, HOTLIST_URL_MENUITEM, &sub_menu);
menu_set_sub_menu_show(0, id_block->self_id, HOTLIST_URL_MENUITEM, 0);
if (sub_menu) toolbox_delete_object(0, sub_menu);
hotlist_setmenu_details(id_block->self_id);
}
return 0;
}
/*************************************************/
/* hotlist_menu_clearselection_handler() */
/* */
/* This function handles the clear selection */
/* menu item */
/*************************************************/
static int hotlist_menu_clearselect_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
{
hotlist_clear_selection();
menu_set_entry_text(0, id_block->self_id, 0x05, "URL ''");
menu_set_fade(0, id_block->self_id, 0x05, 1); /* Fade URL'' selection */
menu_set_fade(0, id_block->self_id, 0x01, 1); /* Fade clear selection */
return 0;
}
/*************************************************/
/* hotlist_menu_openall_handler() */
/* */
/* This function handles the open all menu item */
/*************************************************/
static int hotlist_menu_openall_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
{
if (hotlist_root->data.directory_content)
{
menu_itemno = 0;
hotlist_set_flags(hotlist_root->data.directory_content, hl_directory, HOTLIST_D_IS_OPEN);
hotlist_clear_flags(hotlist_root->data.directory_content, hl_directory, HOTLIST_G_REDRAW_NOW);
hotlist_redraw_items(0, hotlist_count_displayed_items(hotlist_root->data.directory_content));
hotlist_window_preopen(already_open);
}
return 0;
}
/*************************************************/
/* hotlist_menu_closeall_handler() */
/* */
/* This function handles the close all menu */
/* item */
/*************************************************/
static int hotlist_menu_closeall_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
{
unsigned int noitems;
if (hotlist_root->data.directory_content)
{
menu_itemno = 0;
noitems = hotlist_count_displayed_items(hotlist_root->data.directory_content);
hotlist_clear_flags(hotlist_root->data.directory_content,
hl_directory,
HOTLIST_D_IS_OPEN | HOTLIST_G_REDRAW_NOW);
hotlist_clear_selection();
hotlist_redraw_items(0, noitems);
menu_set_entry_text(0, id_block->self_id, HOTLIST_URL_MENUITEM, "URL ''");
menu_set_fade(0, id_block->self_id, HOTLIST_URL_MENUITEM, 1); /* Fade URL'' selection */
menu_set_fade(0, id_block->self_id, HOTLIST_CLEARSELECTION_MENUITEM, 1); /* Fade clear selection */
hotlist_window_preopen(already_open);
}
return 0;
}
/*************************************************/
/* hotlist_menu_delete_handler() */
/* */
/* This function handles the delete menu item */
/*************************************************/
static int hotlist_menu_delete_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
{
hotlist_item *item;
unsigned int noitems;
noitems = hotlist_count_displayed_items(hotlist_root->data.directory_content);
if (!number_selected) return 0;
while((item = hotlist_find_selected_item())!=NULL)
{
hotlist_delete_item(item);
}
number_selected = 0;
hotlist_redraw_items(0, noitems);
hotlist_window_preopen(already_open);
toolbox_hide_object(0, id_block->ancestor_id);
return 0;
}
/*************************************************/
/* hotlist_show_editurl_handler() */
/* */
/* This function fills in the description and */
/* url fields of the edit url dialogue box */
/*************************************************/
static int hotlist_show_editurl_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
{
hotlist_item *item;
ObjectId dboxid;
#ifdef TRACE
Printf("hotlist_show_editurl_handler\n");
#endif
item = hotlist_find_selected_item();
if (!item) return 0;
menu_get_sub_menu_show(0, id_block->self_id, id_block->self_component, &dboxid);
alter_new = HOTLIST_MENUSECTION_ALTER;
window_set_title(0, dboxid, "Edit URL");
writablefield_set_value(0, dboxid, 0x01, item->name);
writablefield_set_value(0, dboxid, 0x05, item->data.url);
actionbutton_set_text(0, dboxid, 0x02, "Alter");
return 0;
}
/*************************************************/
/* hotlist_show_rendirectory_handler() */
/* */
/* This function fills in the name field of the */
/* rename directory dialogue box */
/*************************************************/
static int hotlist_show_rendirectory_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
{
hotlist_item *item;
ObjectId dboxid;
#ifdef TRACE
Printf("hotlist_show_rendirectory_handler\n");
#endif
item = hotlist_find_selected_item();
if (!item) return 0;
menu_get_sub_menu_show(0, id_block->self_id, id_block->self_component, &dboxid);
alter_new = HOTLIST_MENUSECTION_ALTER;
window_set_title(0, dboxid, "Rename Directory");
writablefield_set_value(0, dboxid, 0x01, item->name);
actionbutton_set_text(0, dboxid, 0x02, "Rename");
return 0;
}
/*************************************************/
/* hotlist_show_newurl_handler() */
/* */
/* This function emptys the description and url */
/* fields of the new url dialogue box */
/*************************************************/
static int hotlist_show_newurl_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
{
ObjectId dboxid;
#ifdef TRACE
Printf("hotlist_show_newurl_handler\n");
#endif
menu_get_sub_menu_show(0, id_block->self_id, id_block->self_component, &dboxid);
alter_new = HOTLIST_MENUSECTION_NEW;
writablefield_set_value(0, dboxid, 0x01, "");
writablefield_set_value(0, dboxid, 0x05, "");
window_set_title(0, dboxid, "Create new URL");
actionbutton_set_text(0, dboxid, 0x02, "Create");
return 0;
}
/*************************************************/
/* hotlist_show_newdirectory_handler() */
/* */
/* This function emptys the name field of the */
/* new directory dialogue box */
/*************************************************/
static int hotlist_show_newdirectory_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
{
ObjectId dboxid;
#ifdef TRACE
Printf("hotlist_show_newdirectory_handler\n");
#endif
menu_get_sub_menu_show(0, id_block->self_id, id_block->self_component, &dboxid);
alter_new = HOTLIST_MENUSECTION_NEW;
writablefield_set_value(0, dboxid, 0x01, "");
window_set_title(0, dboxid, "Create new Directory");
actionbutton_set_text(0, dboxid, 0x02, "Create");
return 0;
}
/*************************************************/
/* hotlist_newedit_url_handler() */
/* */
/* This function either alters the selected urls */
/* name and url fields or creates a new url in */
/* the directory the pointer was in when menu */
/* was clicked in the hotlist window. */
/*************************************************/
static int hotlist_newedit_url_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
{
hotlist_item *item, *tempitem;
char *tempdesc, *tempurl;
int size;
item = hotlist_find_selected_item();
writablefield_get_value(0,
id_block->self_id,
HOTLIST_NEWURL_NAME,
NULL,
0,
&size);
tempdesc = malloc(size);
if (!tempdesc) return 0; /* ERROR can't rename */
writablefield_get_value(0,
id_block->self_id,
HOTLIST_NEWURL_NAME,
tempdesc,
size,
&size);
writablefield_get_value(0,
id_block->self_id,
HOTLIST_NEWURL_URL,
NULL,
0,
&size);
tempurl = malloc(size);
if (!tempurl)
{
free(tempdesc);
return 0; /* ERROR can't rename */
}
writablefield_get_value(0,
id_block->self_id,
HOTLIST_NEWURL_URL,
tempurl,
size,
&size);
switch(alter_new)
{
case HOTLIST_MENUSECTION_NEW:
tempitem = hotlist_find_item(hotlist_root->data.directory_content, menu_itemno);
if (!tempitem) tempitem = hotlist_root;
else
{
tempitem = tempitem->parent;
}
show_error(hotlist_new_url(tempitem,
HOTLIST_POSITION_END,
tempdesc,
tempurl));
hotlist_window_preopen(already_open);
hotlist_redraw_now();
free(tempdesc);
free(tempurl);
break;
case HOTLIST_MENUSECTION_ALTER:
free(item->name);
free(item->data.url);
item->name = tempdesc;
item->data.url = tempurl;
item->flags |= HOTLIST_G_REDRAW_NOW;
hotlist_window_preopen(already_open);
hotlist_redraw_now();
//toolbox_hide_object(0, id_block->ancestor_id);
break;
}
return 0;
}
/*************************************************/
/* hotlist_newren_directory_handler() */
/* */
/* This function either alters the selected */
/* directorys name or creates a new directory in */
/* the directory the pointer was in when menu */
/* was clicked in the hotlist window. */
/*************************************************/
static int hotlist_newren_directory_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
{
int size;
hotlist_item *item, *tempitem;
char *tempname;
item = hotlist_find_selected_item();
writablefield_get_value(0,
id_block->self_id,
HOTLIST_NEWDIRECTORY_NAME,
NULL,
0,
&size);
tempname = malloc(size);
if (!tempname) return 0; /* ERROR can't rename */
writablefield_get_value(0,
id_block->self_id,
HOTLIST_NEWDIRECTORY_NAME,
tempname,
size,
&size);
switch(alter_new)
{
case HOTLIST_MENUSECTION_NEW:
tempitem = hotlist_find_item(hotlist_root->data.directory_content, menu_itemno);
if (!tempitem) tempitem = hotlist_root;
else
tempitem = tempitem->parent;
hotlist_new_directory(tempitem,
tempname,
HOTLIST_POSITION_END,
&tempitem);
hotlist_window_preopen(already_open);
hotlist_redraw_now();
free(tempname);
break;
case HOTLIST_MENUSECTION_ALTER:
free(item->name);
item->name = tempname;
item->flags |= HOTLIST_G_REDRAW_NOW;
hotlist_window_preopen(already_open);
hotlist_redraw_now();
//toolbox_hide_object(0, id_block->ancestor_id);
break;
}
return 0;
}
/*************************************************/
/* hotlist_newren_directory_handler() */
/* */
/* This function is called when Cancel is */
/* clicked on in the new or edit urldialogue */
/* box. It resets the contents to their */
/* previous state. */
/*************************************************/
static int hotlist_reset_url_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
{
hotlist_item *item;
switch(alter_new)
{
case HOTLIST_MENUSECTION_NEW:
writablefield_set_value(0, id_block->self_id, 0x01, "");
writablefield_set_value(0, id_block->self_id, 0x05, "");
break;
case HOTLIST_MENUSECTION_ALTER:
item = hotlist_find_selected_item();
writablefield_set_value(0, id_block->self_id, 0x01, item->name);
writablefield_set_value(0, id_block->self_id, 0x05, item->data.url);
break;
}
return 0;
}
/*************************************************/
/* hotlist_reset_directory_handler() */
/* */
/* This function is called when Cancel is */
/* clicked on in the new or rename directory */
/* dialogue box. It resets the contents to */
/* their previous state. */
/*************************************************/
static int hotlist_reset_directory_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
{
hotlist_item *item;
switch(alter_new)
{
case HOTLIST_MENUSECTION_NEW:
writablefield_set_value(0, id_block->self_id, 0x01, "");
break;
case HOTLIST_MENUSECTION_ALTER:
item = hotlist_find_selected_item();
writablefield_set_value(0, id_block->self_id, 0x01, item->name);
break;
}
return 0;
}
/*************************************************/
/* hotlist_drag_renderer() */
/* */
/* renders a single hotlist item at 0,0 for use */
/* with draganobject */
/* */
/* Parameters: pointer to the item to render */
/*************************************************/
static void hotlist_drag_renderer(hotlist_item *item, unsigned int item_height, unsigned int item_dir_width, unsigned int item_url_width)
{
/* DONT PUT Printf's in here, doesn't work (on pipefs anyway) */
WimpIconBlock hotlist_iconblock;
int temp_width;
_kernel_swi_regs regs;
hotlist_iconblock.flags = HOTLIST_SPRITE_ICON_FLAGS;
hotlist_iconblock.data.is.sprite_area = (void*)sprite_block;
switch(item->type) /* Set appropriate sprite and width of sprite */
{
case hl_url:
hotlist_iconblock.data.is.sprite = URL_SPRITE;
hotlist_iconblock.data.is.sprite_name_length = strlen(URL_SPRITE);
temp_width = item_url_width;
break;
case hl_directory:
temp_width = item_dir_width;
hotlist_iconblock.data.is.sprite = CLOSED_DIRECTORY_SPRITE;
hotlist_iconblock.data.is.sprite_name_length = strlen(CLOSED_DIRECTORY_SPRITE);
break;
default:
temp_width = 0; /* Prevent warnings */
break;
}
hotlist_iconblock.bbox.xmin = 2;
hotlist_iconblock.bbox.xmax = 2 + temp_width;
hotlist_iconblock.bbox.ymax = 2 + item_height;
hotlist_iconblock.bbox.ymin = 2;
if (wimp_plot_icon(&hotlist_iconblock)) /* Plot sprite icon */
{
/* Error has happened, don't know what to do about it */
}
regs.r[0] = 1;
regs.r[1] = (int)item->name;
regs.r[2] = 0;
if (wimp_text_op(&regs)) /* Get width of text for text icon */
{
/* Error has happened, don't know what to do about it */
}
hotlist_iconblock.flags = HOTLIST_TEXT_ICON_FLAGS_DRAG;
hotlist_iconblock.bbox.xmin = temp_width + 4;
hotlist_iconblock.bbox.xmax = temp_width + regs.r[0] + 16;
hotlist_iconblock.bbox.ymax = item_height;
hotlist_iconblock.bbox.ymin = 4;
hotlist_iconblock.data.it.buffer = item->name;
hotlist_iconblock.data.it.buffer_size = strlen(item->name);
if (wimp_plot_icon(&hotlist_iconblock))
{
/* Error has happened, don't know what to do about it */
}
}
/*************************************************/
/* hotlist_start_drag() */
/* */
/* This function is called to start a drag */
/* operation from the hotlist window. A drag */
/* box will be initiated bounding all selected */
/* items. */
/*************************************************/
static _kernel_oserror *_hotlist_start_drag(void)
{
_kernel_swi_regs regs;
_kernel_oserror *err;
unsigned int item_height, item_dir_width, item_url_width;
hotlist_item *item;
WimpDragBox box;
WimpGetPointerInfoBlock pointerblock;
unsigned int xmin, xmax, xlow, xhigh;
int top, bottom, item_no, xorigin, yorigin, screenwidth, screenheight, tempint;
WimpGetWindowStateBlock state;
int redraw_params[4];
int width, height;
wimp_get_pointer_info(&pointerblock); /* Read pointer position */
hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width);
item = hotlist_find_selected_item();
item_no = hotlist_find_no_from_item(item);
top = -item_no * item_height;
bottom = -(item_no + 1) * item_height;
if (item_no < 0) return NULL; /* Selected item not found, this should never happen */
hotlist_get_shape(&xmin, &xmax, item);
item = item->next;
if (number_selected > 1)
{
while(item)
{
item_no++;
hotlist_get_shape(&xlow, &xhigh, item);
if (item->flags & HOTLIST_G_IS_SELECTED)
{
if (xlow < xmin) xmin = xlow; /* Should never happen, left hand side should not be ragged */
if (xhigh > xmax) xmax = xhigh;
bottom = -(item_no + 1) * item_height;
}
item = item->next;
}
}
show_error(window_get_wimp_handle(0, hotlist_windowid, &state.window_handle));
wimp_get_window_state(&state);
xorigin = state.xscroll - state.visible_area.xmin;
yorigin = state.yscroll - state.visible_area.ymax;
_swix(OS_ReadModeVariable, _INR(0,1) | _OUT(2), -1, 11, &screenwidth);
_swix(OS_ReadModeVariable, _INR(0,1) | _OUT(2), -1, 12, &screenheight);
_swix(OS_ReadModeVariable, _INR(0,1) | _OUT(2), -1, 4, &tempint);
screenwidth <<= tempint;
_swix(OS_ReadModeVariable, _INR(0,1) | _OUT(2), -1, 5, &tempint);
screenheight <<= tempint;
if (_kernel_osbyte(161, 28, 0) & (1<<(8+1))) /* solid drag */
{
if (number_selected == 1)
{
box.dragging_box.xmin = xmin-xorigin; /* box shape */
box.dragging_box.ymin = bottom-yorigin;
box.dragging_box.xmax = xmax-xorigin;
box.dragging_box.ymax = top-yorigin;
redraw_params[0] = (int)hotlist_find_selected_item();
redraw_params[1] = (int)item_height;
redraw_params[2] = (int)item_dir_width;
redraw_params[3] = (int)item_url_width;
regs.r[0] = (2<<0) | (2<<2) | (1<<6) | (1<<7) | (1<<16);
regs.r[1] = (int)hotlist_drag_renderer;
regs.r[2] = (int)redraw_params;
regs.r[3] = (int)&(box.dragging_box);
if (!_kernel_swi(DragAnObject_Start, &regs, &regs))
{
hotlist_dragging = HOTLIST_SOLID_DRAG_OBJECT; /* Set global variable saying we are currently dragging */
/* so we know whether to process a user_drag_box event */
return NULL;
}
}
else
{
if (!read_sprite_size(SELECTION_SPRITE, &width, &height))
{
box.dragging_box.xmin = pointerblock.x - (width/2 + 10); /* box shape */
box.dragging_box.ymin = pointerblock.y - (height/2 + 10);
box.dragging_box.xmax = pointerblock.x + (width/2 + 10);
box.dragging_box.ymax = pointerblock.y + (height/2 + 10);
regs.r[0] = (1<<0) | (1<<2) | (1<<6) | (1<<7);
regs.r[1] = (int)sprite_block; /* browser sprite area */
regs.r[2] = (int)"package";
regs.r[3] = (int)&(box.dragging_box);
if (!_kernel_swi(DragASprite_Start, &regs, &regs))
{
hotlist_dragging = HOTLIST_SOLID_DRAG_SPRITE;
return NULL;
}
}
}
}
box.drag_type = Wimp_DragBox_DragFixedDash;
box.dragging_box.xmin = xmin-xorigin; /* box shape */
box.dragging_box.xmax = xmax-xorigin;
box.dragging_box.ymin = bottom-yorigin;
box.dragging_box.ymax = top-yorigin;
box.parent_box.xmin = -(pointerblock.x - box.dragging_box.xmin); /* Bounding box for dragged box */
box.parent_box.xmax = screenwidth+(box.dragging_box.xmax - pointerblock.x);
box.parent_box.ymin = -(pointerblock.y - box.dragging_box.ymin);
box.parent_box.ymax = screenheight+(box.dragging_box.ymax - pointerblock.y);
err = wimp_drag_box(&box); /* start drag box */
if (err) return err;
hotlist_dragging = HOTLIST_BOX_DRAG; /* Set global variable saying we are currently dragging */
/* so we know whether to process a user_drag_box event */
return NULL;
}
void hotlist_start_drag(void)
{
_kernel_oserror *err;
err = _hotlist_start_drag();
if (err)
{
show_error_ret(err);
return;
}
/* Register NULL handler */
register_null_claimant(Wimp_ENull, hotlist_null_handler, NULL);
}
/*************************************************/
/* hotlist_is_inside() */
/* */
/* Checks if one hotlist_item is held inside */
/* the directory structure of another */
/* hotlist_item */
/* */
/* Parameters: pointer to possibly inside item */
/* pointer to outside item */
/* */
/* Returns: 1 if item is inside, 0 otherwise */
/*************************************************/
static int hotlist_is_inside(hotlist_item *inside, hotlist_item *outside)
{
while(inside)
{
if (inside == outside) return 1;
inside = inside->parent;
}
return 0;
}
/*************************************************/
/* hotlist_drag_completed_handler() */
/* */
/* This function is called when a user_drag */
/* completes. If the drag is one started by the */
/* hotlist section it is processed. Dropping */
/* the drag in the hotlist window will move or */
/* copy the items being dragged. */
/* Dropping the drag in any other window is */
/* currently ignored */
/*************************************************/
static int hotlist_drag_completed_handler(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle)
{
unsigned int item_height, item_dir_width, item_url_width;
ObjectId window_handle;
ComponentId comp;
WimpGetPointerInfoBlock pointerblock;
WimpGetWindowStateBlock state;
int winx, winy, shift;
unsigned int top, bottom, bottom2, tempint, position, xmin, xmax;
hotlist_item *targetitem, *sourceitem, *tempitem;
_swix(OS_Byte, _INR(0,1) | _OUT(1), 121, 128, &shift); /* Check if SHIFT is pressed */
if (!hotlist_dragging) return 0;
switch(hotlist_dragging)
{
case HOTLIST_SOLID_DRAG_OBJECT:
_swix(DragAnObject_Stop, 0);
break;
case HOTLIST_SOLID_DRAG_SPRITE:
_swix(DragASprite_Stop, 0);
break;
case HOTLIST_BOX_DRAG_SELECTION:
deregister_null_claimant(Wimp_ENull, hotlist_null_drag_select_handler, NULL);
return 0; /* No action taken at end of drag, selection is done by null handler during drag */
break;
default:
break;
}
if (hotlist_current_highlighted)
{
hotlist_current_highlighted->flags &= ~HOTLIST_D_IS_HIGHLIGHTED;
hotlist_redraw_items(highlighted_itemno, highlighted_itemno);
hotlist_current_highlighted = NULL;
}
deregister_null_claimant(Wimp_ENull, hotlist_null_handler, NULL);
hotlist_dragging = 0;
wimp_get_pointer_info(&pointerblock);
show_error(window_wimp_to_toolbox(0,
pointerblock.window_handle,
pointerblock.icon_handle,
&window_handle,
&comp));
if (window_handle == hotlist_windowid)
{
/* Drag was dropped in hotlist window */
if (pointerblock.icon_handle != -1) return 0; /* Only understand drops on workspace */
hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width);
state.window_handle = pointerblock.window_handle;
wimp_get_window_state(&state);
winx = pointerblock.x + (state.xscroll - state.visible_area.xmin);
winy = pointerblock.y + (state.yscroll - state.visible_area.ymax);
targetitem = hotlist_find_item(hotlist_root->data.directory_content, -winy/item_height);
top = -winy/item_height;
/* Decide where to put the items */
if (targetitem)
{
hotlist_get_shape(&xmin, &xmax, targetitem);
if (targetitem->type == hl_directory && winx >= xmin && winx <= xmin+item_dir_width)
{
position = HOTLIST_POSITION_BEGINNING; /* Put in directory */
}
else
{
if ((-winy % item_height) > item_height / 2)
position = HOTLIST_POSITION_AFTER; /* Put items after target item */
else
position = HOTLIST_POSITION_BEFORE; /* Put items before target item */
}
}
else
{
targetitem = hotlist_root;
position = HOTLIST_POSITION_END;
}
tempint = hotlist_find_no_from_item(hotlist_find_selected_item());
if (tempint < top) top = tempint;
bottom = hotlist_count_displayed_items(hotlist_root->data.directory_content);
if (targetitem->flags & HOTLIST_G_IS_SELECTED) return 0; /* do nothing if dropped on selected items */
sourceitem = hotlist_find_selected_item();
/* Check to see if moving the selection to this position is acceptable -----------------------*/
tempitem = sourceitem;
while(tempitem)
{
if (tempitem->flags & HOTLIST_G_IS_SELECTED && tempitem->type == hl_directory)
{
if (hotlist_is_inside(targetitem, tempitem))
{
StrNCpy0(erb.errmess,
lookup_token("NotIntoself:A directory cannot be copied or moved into itself.",
0,
0));
erb.errnum = Utils_Error_Custom_Message;
show_error_ret(&erb);
return 0;
}
}
tempitem = tempitem->next;
}
/* Only get this far if it is ----------------------------------------------------------------*/
sourceitem->flags &= ~HOTLIST_G_IS_SELECTED;
if (!shift)
{
/* Move selected items */
hotlist_move_item(sourceitem, targetitem, position); /* Move first item to specified position */
/* before/after/in target */
targetitem = sourceitem;
while((sourceitem = hotlist_find_selected_item()) != NULL)
{
sourceitem->flags &= ~HOTLIST_G_IS_SELECTED;
hotlist_move_item(sourceitem, targetitem, HOTLIST_POSITION_AFTER); /* Move all subsequent items to follow */
/* first moved item */
targetitem = sourceitem;
}
}
else
{
/* Copy selected items */
hotlist_copy_item(sourceitem, targetitem, position, &targetitem); /* Copy first item to specified position */
/* before/after/in target */
while((sourceitem = hotlist_find_selected_item()) != NULL)
{
sourceitem->flags &= ~HOTLIST_G_IS_SELECTED;
hotlist_copy_item(sourceitem, /* Copy all subsequent items to follow */
targetitem, /* first copied item */
HOTLIST_POSITION_AFTER,
&targetitem);
}
}
number_selected = 0;
selected_parent = NULL;
bottom2 = hotlist_count_displayed_items(hotlist_root->data.directory_content);
if (bottom2 > bottom) bottom = bottom2;
hotlist_redraw_items(top, bottom);
hotlist_window_preopen(already_open);
}
else
{
/* Drag was dropped in non-hotlist window */
}
return 0;
}
void hotlist_autoscroll(int x, int y, int window_handle)
{
int scroll_changed;
WimpGetWindowStateBlock state;
static unsigned int hscroll_speed, vscroll_speed; /* Separate h/v velocities */
static int last_window_handle = 0;
state.window_handle = window_handle;
if (last_window_handle != window_handle)
{
last_window_handle = window_handle;
hscroll_speed = 0;
vscroll_speed = 0;
}
wimp_get_window_state(&state);
/* Auto scrolling of hotlist window when dragging */
scroll_changed = 0;
if ((y > state.visible_area.ymax - HOTLIST_SCROLL_BOUNDARY_SIZE) && y < state.visible_area.ymax)
{
state.yscroll += vscroll_speed;
scroll_changed |= 1;
}
else
if ((y < state.visible_area.ymin + HOTLIST_SCROLL_BOUNDARY_SIZE) && y > state.visible_area.ymin)
{
state.yscroll -= vscroll_speed;
scroll_changed |= 1;
}
if ((x > state.visible_area.xmax - HOTLIST_SCROLL_BOUNDARY_SIZE) && x < state.visible_area.xmax)
{
state.xscroll += hscroll_speed;
scroll_changed |= 2;
}
else
if ((x < state.visible_area.xmin + HOTLIST_SCROLL_BOUNDARY_SIZE) && x > state.visible_area.xmin)
{
state.xscroll -= hscroll_speed;
scroll_changed |= 2;
}
if (scroll_changed)
{
wimp_open_window((WimpOpenWindowBlock*)&state);
}
if (scroll_changed & 1)
{
vscroll_speed += HOTLIST_SCROLL_SPEED_INC;
if (vscroll_speed > HOTLIST_SCROLL_SPEED_MAX) vscroll_speed = HOTLIST_SCROLL_SPEED_MAX;
}
else
{
vscroll_speed = HOTLIST_SCROLL_SPEED_MIN;
}
if (scroll_changed & 2)
{
hscroll_speed += HOTLIST_SCROLL_SPEED_INC;
if (hscroll_speed > HOTLIST_SCROLL_SPEED_MAX) hscroll_speed = HOTLIST_SCROLL_SPEED_MAX;
}
else
{
hscroll_speed = HOTLIST_SCROLL_SPEED_MIN;
}
}
/*************************************************/
/* hotlist_null_handler() */
/* */
/* Called every null event while drag is in */
/* operation */
/*************************************************/
static int hotlist_null_handler(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle)
{
int x, y, buttons;
unsigned int itemno, xmin, xmax;
unsigned int item_height, item_dir_width, item_url_width;
hotlist_item *item;
ObjectId window;
ComponentId component;
WimpGetWindowStateBlock state;
window_get_pointer_info(0, &x, &y, &buttons, &window, &component);
if (window == hotlist_windowid)
{
window_get_wimp_handle(0, window, &state.window_handle);
hotlist_autoscroll(x, y, state.window_handle);
/* Display arrow pointing into directory to say that dropping */
/* here will put in directory rather than next to it */
wimp_get_window_state(&state);
hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width);
x += (state.xscroll - state.visible_area.xmin);
y += (state.yscroll - state.visible_area.ymax);
itemno = -y / item_height;
item = hotlist_find_item(hotlist_root->data.directory_content, itemno);
if (item && item->type == hl_directory && !(item->flags & HOTLIST_G_IS_SELECTED))
{
hotlist_get_shape(&xmin, &xmax, item);
if (x >= xmin && x <= xmin + item_dir_width)
{
if (hotlist_current_highlighted != item)
{
if (hotlist_current_highlighted)
{
hotlist_current_highlighted->flags &= ~HOTLIST_D_IS_HIGHLIGHTED;
hotlist_redraw_items(highlighted_itemno, highlighted_itemno);
}
item->flags |= HOTLIST_D_IS_HIGHLIGHTED;
hotlist_current_highlighted = item;
highlighted_itemno = itemno;
hotlist_redraw_items(highlighted_itemno, highlighted_itemno);
}
}
else
{
if (hotlist_current_highlighted)
{
hotlist_current_highlighted->flags &= ~HOTLIST_D_IS_HIGHLIGHTED;
hotlist_redraw_items(highlighted_itemno, highlighted_itemno);
hotlist_current_highlighted = NULL;
}
}
}
else
{
if (hotlist_current_highlighted)
{
hotlist_current_highlighted->flags &= ~HOTLIST_D_IS_HIGHLIGHTED;
hotlist_redraw_items(highlighted_itemno, highlighted_itemno);
hotlist_current_highlighted = NULL;
}
}
}
else
{
/* non hotlist window */
if (hotlist_current_highlighted)
{
hotlist_current_highlighted->flags &= ~HOTLIST_D_IS_HIGHLIGHTED;
hotlist_redraw_items(highlighted_itemno, highlighted_itemno);
hotlist_current_highlighted = NULL;
}
}
return 0;
}
/* Simple non-scrolling selection box, to be improved later */
int selection_x, selection_y; /* Workarea relative corner of selection box */
_kernel_oserror *hotlist_selection_box_start(void)
{
_kernel_oserror *err;
WimpDragBox box;
WimpGetPointerInfoBlock pointerblock;
WimpGetWindowStateBlock state;
wimp_get_pointer_info(&pointerblock); /* Read pointer position */
show_error(window_get_wimp_handle(0, hotlist_windowid, &state.window_handle));
wimp_get_window_state(&state);
selection_x = pointerblock.x + (state.xscroll - state.visible_area.xmin);
selection_y = pointerblock.y + (state.yscroll - state.visible_area.ymax);
box.drag_type = Wimp_DragBox_DragRubberDash;
box.dragging_box.xmin = pointerblock.x; /* box shape */
box.dragging_box.xmax = pointerblock.x;
box.dragging_box.ymin = pointerblock.y;
box.dragging_box.ymax = pointerblock.y;
box.parent_box.xmin = state.visible_area.xmin; /* Bounding box for dragged box */
box.parent_box.xmax = state.visible_area.xmax;
box.parent_box.ymin = state.visible_area.ymin;
box.parent_box.ymax = state.visible_area.ymax;
err = wimp_drag_box(&box); /* start drag box */
if (err) return err;
hotlist_dragging = HOTLIST_BOX_DRAG_SELECTION; /* Set global variable saying we are currently dragging */
/* so we know whether to process a user_drag_box event */
register_null_claimant(Wimp_ENull, hotlist_null_drag_select_handler, NULL);
return NULL;
}
int hotlist_null_drag_select_handler(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle)
{
WimpGetPointerInfoBlock pointerblock;
unsigned int item_height, item_dir_width, item_url_width;
int workx, worky;
hotlist_item *item;
WimpGetWindowStateBlock state;
unsigned int item_min, item_max, itemno, itemxmin, itemxmax;
int minx, maxx;
int last_item;
wimp_get_pointer_info(&pointerblock); /* Read pointer position */
show_error(window_get_wimp_handle(0, hotlist_windowid, &state.window_handle));
wimp_get_window_state(&state);
hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width);
workx = pointerblock.x + (state.xscroll - state.visible_area.xmin);
worky = pointerblock.y + (state.yscroll - state.visible_area.ymax);
item_min = -worky / item_height;
if (-selection_y / item_height < item_min) item_min = -selection_y / item_height;
item_max = (-worky / item_height);
if ((-selection_y / item_height) > item_max) item_max = (-selection_y / item_height);
if (selection_x < workx)
{
minx = selection_x;
maxx = workx;
}
else
{
minx = workx;
maxx = selection_x;
}
/* Change from here onwards */
last_item = hotlist_count_displayed_items(hotlist_root->data.directory_content);
for(itemno = 0; itemno <= last_item; itemno++)
{
item = hotlist_find_item(hotlist_root->data.directory_content, itemno);
if (item)
{
if (itemno >= item_min && itemno <= item_max)
{
hotlist_get_shape(&itemxmin, &itemxmax, item);
if (number_selected == 0)
{
if (!(maxx < itemxmin || minx > itemxmax) && (!(item->flags & HOTLIST_G_IS_SELECTED)))
{
item->flags |= HOTLIST_G_IS_SELECTED;
hotlist_redraw_items(itemno, itemno);
selected_parent = item->parent;
number_selected++;
}
}
else
{
if (!(maxx < itemxmin || minx > itemxmax))
{
if ((selected_parent == item->parent || item->type == hl_url) && (!(item->flags & HOTLIST_G_IS_SELECTED)))
{
item->flags |= HOTLIST_G_IS_SELECTED;
hotlist_redraw_items(itemno, itemno);
number_selected++;
}
}
else
{
if (item->flags & HOTLIST_G_IS_SELECTED)
{
item->flags &= ~HOTLIST_G_IS_SELECTED;
hotlist_redraw_items(itemno, itemno);
number_selected--;
}
}
}
}
else
{
if (item->flags & HOTLIST_G_IS_SELECTED)
{
item->flags &= ~HOTLIST_G_IS_SELECTED;
hotlist_redraw_items(itemno, itemno);
number_selected--;
}
}
}
}
return 0;
}
/* Copyright 1997 Acorn Computers Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/***************************************************/
/* File : Hotlist.h */
/* */
/* Purpose: Managing a hotlist in the browser. */
/* */
/* Author : D.T.A.Brown */
/* */
/* History: 06-Aug-97: Created. */
/* 22-Aug-97: (ADH/DTAB) Integrated into */
/* main browser code. */
/* 25-Aug-97: (ADH) Definitions imported */
/* from TBEvents.h. */
/***************************************************/
#ifndef REMOTE_HOTLIST
/* Dialogue definitions (event codes) */
#define HotlistShowEditURL 0x300b
#define HotlistShowRenameDirectory 0x300c
#define HotlistShowNewURL 0x300d
#define HotlistShowNewDirectory 0x300e
#define HotlistNewEditURLOk 0x300f
#define HotlistNewRenameDirectoryOk 0x3010
#define HotlistNewEditURLCancel 0x3011
#define HotlistNewRenameDirectoryCancel 0x3012
/* Menu definitions (event codes) */
#define ShowHotlist 0x3000
#define AddThisPage 0x3001
#define RemoveThisPage 0x3002
#define SaveHotlist 0x3003
#define HotlistMenuOpened 0x3004
#define HotlistMenuClosed 0x3005
#define HotlistSelectAll 0x3006
#define HotlistClearSelect 0x3007
#define HotlistOpenAll 0x3008
#define HotlistCloseAll 0x3009
#define HotlistDelete 0x300a
/* Enumerations */
typedef enum hotlist_type
{
hl_directory,
hl_url,
/* Special case to allow range checking - must be the last item */
hl_ALL
} hotlist_type;
typedef enum hl_opentype
{
not_open,
already_open
} hl_opentype;
/* Structures */
typedef struct hotlist_item
{
hotlist_type type; /* Item type */
unsigned int flags;
char * name; /* Leaf name (NULL terminated string) */
union
{
char * url; /* Pointer to url (NULL terminated string) */
struct hotlist_item * directory_content; /* Pointer to directory contents */
void * generic_data; /* generic type */
} data;
struct hotlist_item * parent; /* Points to parent directory or NULL if none */
struct hotlist_item * previous; /* Points to previous hotlist_item or NULL if none */
struct hotlist_item * next; /* Points to next hotlist_item or NULL if no more */
} hotlist_item;
/* Miscellaneous definitions */
#define HOTLIST_MAX_TYPE hl_url
#define HOTLIST_G_IS_SELECTED (1<<0)
#define HOTLIST_G_REDRAW_NOW (1<<1)
#define HOTLIST_D_HAS_SUBDIRECTORY (1<<16)
#define HOTLIST_D_IS_OPEN (1<<17)
#define HOTLIST_D_IS_HIGHLIGHTED (1<<18)
#define DIRECTORY_FLAGS HOTLIST_G_REDRAW_NOW
#define URL_FLAGS HOTLIST_G_REDRAW_NOW
#define HOTLIST_SPRITE_ICON_FLAGS (WimpIcon_Sprite | \
WimpIcon_HCentred | \
WimpIcon_VCentred | \
WimpIcon_Indirected | \
WimpIcon_FGColour * 7 | \
WimpIcon_BGColour * 0)
#define HOTLIST_TEXT_ICON_FLAGS_SELECTED (WimpIcon_Text | \
WimpIcon_Filled | \
WimpIcon_VCentred | \
WimpIcon_Indirected | \
WimpIcon_FGColour * 1 | \
WimpIcon_BGColour * 7)
#define HOTLIST_TEXT_ICON_FLAGS_UNSELECTED (WimpIcon_Text | \
WimpIcon_VCentred | \
WimpIcon_Indirected | \
WimpIcon_FGColour * 7 | \
WimpIcon_BGColour * 0)
#define HOTLIST_TEXT_ICON_FLAGS_DRAG (WimpIcon_Text | \
WimpIcon_Filled | \
WimpIcon_VCentred | \
WimpIcon_Indirected | \
WimpIcon_FGColour * 7 | \
WimpIcon_BGColour * 1)
#define HOTLIST_POSITION_BEFORE 0 /* before item */
#define HOTLIST_POSITION_AFTER 1 /* after item */
#define HOTLIST_POSITION_BEGINNING 2 /* beginning of directory */
#define HOTLIST_POSITION_END 3 /* end of directory */
#define HOTLIST_BOX_DRAG 1
#define HOTLIST_SOLID_DRAG_OBJECT 2
#define HOTLIST_SOLID_DRAG_SPRITE 3
#define HOTLIST_BOX_DRAG_SELECTION 4
#define HOTLIST_WINDOW_MIN_WIDTH 480
#define HOTLIST_WINDOW_MIN_HEIGHT 3 /* In items */
#define HOTLIST_MENUSECTION_NEW 1
#define HOTLIST_MENUSECTION_ALTER 2
#define OPEN_DIRECTORY_SPRITE "small_diro"
#define CLOSED_DIRECTORY_SPRITE "small_dir"
#define INSERT_DIRECTORY_SPRITE "small_dir+"
#define URL_SPRITE "small_b28"
#define SELECTION_SPRITE "package"
#define HOTLIST_SCROLL_BOUNDARY_SIZE 32
#define HOTLIST_SCROLL_SPEED_MIN 8
#define HOTLIST_SCROLL_SPEED_INC 8
#define HOTLIST_SCROLL_SPEED_MAX 128
/* Various component IDs */
#define HOTLIST_URL_MENUITEM 0x05
#define HOTLIST_SELECTALL_MENUITEM 0x00
#define HOTLIST_CLEARSELECTION_MENUITEM 0x01
#define HOTLIST_NEWDIRECTORY_MENUITEM 0x02
#define HOTLIST_NEWURL_MENUITEM 0x06
#define HOTLIST_OPENALL_MENUITEM 0x03
#define HOTLIST_CLOSEALL_MENUITEM 0x04
#define HOTLIST_SAVE_SUBMENUITEM 0x00
#define HOTLIST_RENAME_SUBMENUITEM 0x01
#define HOTLIST_DELETE_SUBMENUITEM 0x02
#define HOTLIST_NEWDIRECTORY_NAME 0x01
#define HOTLIST_NEWDIRECTORY_CANCEL 0x03
#define HOTLIST_NEWDIRECTORY_NEW 0x02
#define HOTLIST_NEWURL_NAME 0x01
#define HOTLIST_NEWURL_URL 0x05
#define HOTLIST_NEWURL_CANCEL 0x03
#define HOTLIST_NEWURL_NEW 0x02
/* Function prototypes */
_kernel_oserror * hotlist_initialise (void);
_kernel_oserror * hotlist_open (int show_type, void * type, int show_urls);
_kernel_oserror * hotlist_close (void);
_kernel_oserror * hotlist_load (char * filename);
_kernel_oserror * hotlist_save (char * filename);
_kernel_oserror * hotlist_add (char * description, char * url, int at_bottom);
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment