mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-26 05:57:00 +03:00
0e72b17299
Norcroft compatibility fix. svn path=/import/netsurf/; revision=1406
1184 lines
32 KiB
C
1184 lines
32 KiB
C
/*
|
|
* This file is part of NetSurf, http://netsurf.sourceforge.net/
|
|
* Licensed under the GNU General Public License,
|
|
* http://www.opensource.org/licenses/gpl-license
|
|
* Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
|
|
*/
|
|
|
|
/** \file
|
|
* Generic tree handling (implementation).
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <swis.h>
|
|
#include <time.h>
|
|
#include "oslib/colourtrans.h"
|
|
#include "oslib/dragasprite.h"
|
|
#include "oslib/osbyte.h"
|
|
#include "oslib/osspriteop.h"
|
|
#include "oslib/wimp.h"
|
|
#include "netsurf/desktop/tree.h"
|
|
#include "netsurf/riscos/gui.h"
|
|
#include "netsurf/riscos/tinct.h"
|
|
#include "netsurf/riscos/treeview.h"
|
|
#include "netsurf/riscos/wimp.h"
|
|
#include "netsurf/utils/log.h"
|
|
#include "netsurf/utils/messages.h"
|
|
#include "netsurf/utils/utils.h"
|
|
|
|
#define TREE_EXPAND 0
|
|
#define TREE_COLLAPSE 1
|
|
|
|
|
|
static bool ro_gui_tree_initialise_sprite(const char *name, int number);
|
|
static void ro_gui_tree_launch_selected_node(struct node *node, bool all);
|
|
static bool ro_gui_tree_launch_node(struct node *node);
|
|
|
|
/* an array of sprite addresses for Tinct */
|
|
static char *ro_gui_tree_sprites[2];
|
|
|
|
/* origin adjustment */
|
|
static int ro_gui_tree_origin_x;
|
|
static int ro_gui_tree_origin_y;
|
|
|
|
/* element drawing */
|
|
static wimp_icon ro_gui_tree_icon;
|
|
static char ro_gui_tree_icon_validation[24];
|
|
static char ro_gui_tree_icon_null[] = "\0";
|
|
|
|
/* dragging information */
|
|
static struct tree *ro_gui_tree_current_drag_tree;
|
|
static wimp_mouse_state ro_gui_tree_current_drag_buttons;
|
|
|
|
/* editing information */
|
|
static wimp_icon_create ro_gui_tree_edit_icon;
|
|
|
|
/* dragging information */
|
|
static char ro_gui_tree_drag_name[12];
|
|
|
|
|
|
/**
|
|
* Performs any initialisation for tree rendering
|
|
*/
|
|
bool ro_gui_tree_initialise(void) {
|
|
if (ro_gui_tree_initialise_sprite("expand", TREE_EXPAND) ||
|
|
ro_gui_tree_initialise_sprite("collapse", TREE_COLLAPSE))
|
|
return false;
|
|
|
|
ro_gui_tree_edit_icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_INDIRECTED |
|
|
wimp_ICON_VCENTRED | wimp_ICON_FILLED | wimp_ICON_BORDER |
|
|
(wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT) |
|
|
(wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) |
|
|
(wimp_BUTTON_WRITABLE << wimp_ICON_BUTTON_TYPE_SHIFT);
|
|
ro_gui_tree_edit_icon.icon.data.indirected_text.validation =
|
|
ro_gui_tree_icon_null;
|
|
ro_gui_tree_edit_icon.icon.data.indirected_text.size = 256;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Initialise a sprite for use with Tinct
|
|
*
|
|
* \param name the name of the sprite
|
|
* \param number the sprite cache number
|
|
* \return whether an error occurred during initialisation
|
|
*/
|
|
bool ro_gui_tree_initialise_sprite(const char *name, int number) {
|
|
char icon_name[12];
|
|
os_error *error;
|
|
|
|
sprintf(icon_name, "tr_%s", name);
|
|
error = xosspriteop_select_sprite(osspriteop_USER_AREA, gui_sprites,
|
|
(osspriteop_id)icon_name,
|
|
(osspriteop_header **)&ro_gui_tree_sprites[number]);
|
|
if (error) {
|
|
warn_user("MiscError", error->errmess);
|
|
LOG(("Failed to find sprite 'tr_%s'", name));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Informs the current window manager that an area requires updating.
|
|
*
|
|
* \param tree the tree that is requesting a redraw
|
|
* \param x the x co-ordinate of the redraw area
|
|
* \param y the y co-ordinate of the redraw area
|
|
* \param width the width of the redraw area
|
|
* \param height the height of the redraw area
|
|
*/
|
|
void tree_redraw_area(struct tree *tree, int x, int y, int width, int height) {
|
|
os_error *error;
|
|
|
|
assert(tree);
|
|
assert(tree->handle);
|
|
|
|
error = xwimp_force_redraw((wimp_w)tree->handle, tree->offset_x + x - 2,
|
|
-tree->offset_y - y - height, tree->offset_x + x + width + 4,
|
|
-tree->offset_y - y);
|
|
if (error) {
|
|
LOG(("xwimp_force_redraw: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
warn_user("WimpError", error->errmess);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Draws a line.
|
|
*
|
|
* \param tree the tree to draw a line for
|
|
* \param x the x co-ordinate
|
|
* \param x the y co-ordinate
|
|
* \param x the width of the line
|
|
* \param x the height of the line
|
|
*/
|
|
void tree_draw_line(struct tree *tree, int x, int y, int width, int height) {
|
|
os_error *error;
|
|
|
|
assert(tree);
|
|
|
|
error = xcolourtrans_set_gcol((os_colour)0x88888800, 0, os_ACTION_OVERWRITE,
|
|
0, 0);
|
|
if (error) {
|
|
LOG(("xcolourtrans_set_gcol: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
warn_user("MiscError", error->errmess);
|
|
return;
|
|
}
|
|
error = xos_plot(os_MOVE_TO, ro_gui_tree_origin_x + x,
|
|
ro_gui_tree_origin_y - y);
|
|
if (!error)
|
|
xos_plot(os_PLOT_TO, ro_gui_tree_origin_x + x + width,
|
|
ro_gui_tree_origin_y - y - height);
|
|
if (error) {
|
|
LOG(("xos_plot: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
warn_user("MiscError", error->errmess);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Draws an element, including any expansion icons
|
|
*
|
|
* \param tree the tree to draw an element for
|
|
* \param element the element to draw
|
|
*/
|
|
void tree_draw_node_element(struct tree *tree, struct node_element *element) {
|
|
os_error *error;
|
|
int temp;
|
|
|
|
assert(tree);
|
|
assert(element);
|
|
assert(element->parent);
|
|
|
|
ro_gui_tree_icon.flags = wimp_ICON_INDIRECTED | wimp_ICON_VCENTRED |
|
|
(wimp_COLOUR_VERY_LIGHT_GREY << wimp_ICON_BG_COLOUR_SHIFT);
|
|
ro_gui_tree_icon.extent.x0 = tree->offset_x + element->box.x;
|
|
ro_gui_tree_icon.extent.y1 = -tree->offset_y - element->box.y;
|
|
ro_gui_tree_icon.extent.x1 = tree->offset_x + element->box.x +
|
|
element->box.width;
|
|
ro_gui_tree_icon.extent.y0 = -tree->offset_y - element->box.y -
|
|
element->box.height;
|
|
if (&element->parent->data == element) {
|
|
if (element->parent->selected)
|
|
ro_gui_tree_icon.flags |= wimp_ICON_SELECTED;
|
|
ro_gui_tree_icon.flags |= (wimp_COLOUR_BLACK <<
|
|
wimp_ICON_FG_COLOUR_SHIFT);
|
|
} else {
|
|
ro_gui_tree_icon.flags |= (wimp_COLOUR_DARK_GREY <<
|
|
wimp_ICON_FG_COLOUR_SHIFT);
|
|
}
|
|
|
|
switch (element->type) {
|
|
case NODE_ELEMENT_TEXT_PLUS_SPRITE:
|
|
assert(element->sprite);
|
|
|
|
ro_gui_tree_icon.flags |= wimp_ICON_TEXT | wimp_ICON_SPRITE;
|
|
ro_gui_tree_icon.data.indirected_text_and_sprite.text =
|
|
ro_gui_tree_icon_null;
|
|
ro_gui_tree_icon.data.indirected_text_and_sprite.validation =
|
|
ro_gui_tree_icon_validation;
|
|
ro_gui_tree_icon.data.indirected_text_and_sprite.size = 1;
|
|
if (element->parent->expanded) {
|
|
sprintf(ro_gui_tree_icon_validation, "S%s",
|
|
element->sprite->expanded_name);
|
|
} else {
|
|
sprintf(ro_gui_tree_icon_validation, "S%s",
|
|
element->sprite->name);
|
|
}
|
|
temp = ro_gui_tree_icon.extent.x1;
|
|
ro_gui_tree_icon.extent.x1 = ro_gui_tree_icon.extent.x0 +
|
|
NODE_INSTEP;
|
|
error = xwimp_plot_icon(&ro_gui_tree_icon);
|
|
if (error) {
|
|
LOG(("xwimp_plot_icon: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
warn_user("WimpError", error->errmess);
|
|
}
|
|
ro_gui_tree_icon.extent.x0 = ro_gui_tree_icon.extent.x1;
|
|
ro_gui_tree_icon.extent.x1 = temp;
|
|
ro_gui_tree_icon.flags &= ~wimp_ICON_SPRITE;
|
|
|
|
case NODE_ELEMENT_TEXT:
|
|
assert(element->text);
|
|
|
|
if (element == tree->editing)
|
|
return;
|
|
|
|
if (ro_gui_tree_icon.flags & wimp_ICON_SELECTED)
|
|
ro_gui_tree_icon.flags |= wimp_ICON_FILLED;
|
|
ro_gui_tree_icon.flags |= wimp_ICON_TEXT;
|
|
ro_gui_tree_icon.data.indirected_text.text =
|
|
element->text;
|
|
ro_gui_tree_icon.data.indirected_text.validation =
|
|
ro_gui_tree_icon_null;
|
|
ro_gui_tree_icon.data.indirected_text.size =
|
|
strlen(element->text);
|
|
break;
|
|
case NODE_ELEMENT_SPRITE:
|
|
assert(element->sprite);
|
|
|
|
ro_gui_tree_icon.flags |= wimp_ICON_SPRITE;
|
|
ro_gui_tree_icon.data.indirected_sprite.id =
|
|
(osspriteop_id)element->sprite->name;
|
|
ro_gui_tree_icon.data.indirected_sprite.area =
|
|
element->sprite->area;
|
|
ro_gui_tree_icon.data.indirected_sprite.size =
|
|
strlen(element->sprite->name);
|
|
break;
|
|
}
|
|
|
|
error = xwimp_plot_icon(&ro_gui_tree_icon);
|
|
if (error) {
|
|
LOG(("xwimp_plot_icon: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
warn_user("WimpError", error->errmess);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Draws an elements expansion icon
|
|
*
|
|
* \param tree the tree to draw the expansion for
|
|
* \param element the element to draw the expansion for
|
|
*/
|
|
void tree_draw_node_expansion(struct tree *tree, struct node *node) {
|
|
unsigned int type;
|
|
|
|
assert(tree);
|
|
assert(node);
|
|
|
|
if ((node->child) || (node->data.next)) {
|
|
if (node->expanded) {
|
|
type = TREE_COLLAPSE;
|
|
} else {
|
|
type = TREE_EXPAND;
|
|
}
|
|
_swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
|
|
ro_gui_tree_sprites[type],
|
|
ro_gui_tree_origin_x + node->box.x -
|
|
(NODE_INSTEP / 2) - 8,
|
|
ro_gui_tree_origin_y - node->box.y -
|
|
(TREE_TEXT_HEIGHT / 2) - 8,
|
|
tinct_BILINEAR_FILTER);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets the origin variables to the correct values for a specified tree
|
|
*
|
|
* \param tree the tree to set the origin for
|
|
*/
|
|
void tree_initialise_redraw(struct tree *tree) {
|
|
os_error *error;
|
|
wimp_window_state state;
|
|
|
|
assert(tree->handle);
|
|
|
|
state.w = (wimp_w)tree->handle;
|
|
error = xwimp_get_window_state(&state);
|
|
if (error) {
|
|
LOG(("xwimp_get_window_state: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
warn_user("WimpError", error->errmess);
|
|
}
|
|
|
|
ro_gui_tree_origin_x = state.visible.x0 - state.xscroll + tree->offset_x;
|
|
ro_gui_tree_origin_y = state.visible.y1 - state.yscroll - tree->offset_y;
|
|
}
|
|
|
|
|
|
/**
|
|
* Recalculates the dimensions of a node element.
|
|
*
|
|
* \param element the element to recalculate
|
|
*/
|
|
void tree_recalculate_node_element(struct node_element *element) {
|
|
os_error *error;
|
|
int sprite_width;
|
|
int sprite_height;
|
|
osspriteop_flags flags;
|
|
|
|
assert(element);
|
|
|
|
switch (element->type) {
|
|
case NODE_ELEMENT_TEXT_PLUS_SPRITE:
|
|
assert(element->sprite);
|
|
case NODE_ELEMENT_TEXT:
|
|
assert(element->text);
|
|
|
|
error = xwimptextop_string_width(element->text,
|
|
strlen(element->text),
|
|
&element->box.width);
|
|
if (error) {
|
|
LOG(("xwimptextop_string_width: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
warn_user("WimpError", error->errmess);
|
|
}
|
|
element->box.width += 16;
|
|
element->box.height = TREE_TEXT_HEIGHT;
|
|
if (element->type == NODE_ELEMENT_TEXT_PLUS_SPRITE)
|
|
element->box.width += NODE_INSTEP;
|
|
break;
|
|
case NODE_ELEMENT_SPRITE:
|
|
assert(element->sprite);
|
|
|
|
flags = ((int)element->sprite->area == 1) ?
|
|
osspriteop_SYSTEM_AREA :
|
|
osspriteop_USER_AREA;
|
|
error = xosspriteop_read_sprite_info(flags,
|
|
element->sprite->area,
|
|
(osspriteop_id)element->sprite->name,
|
|
&sprite_width, &sprite_height, 0, 0);
|
|
if (error) {
|
|
LOG(("xosspriteop_read_sprite_info: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
warn_user("WimpError", error->errmess);
|
|
}
|
|
element->box.width = sprite_width * 2;
|
|
element->box.height = sprite_height * 2;
|
|
if (element->box.height < TREE_TEXT_HEIGHT)
|
|
element->box.height = TREE_TEXT_HEIGHT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets a node element as having a specific sprite.
|
|
*
|
|
* \param node the node to update
|
|
* \param sprite the sprite to use
|
|
* \param selected the expanded sprite name to use
|
|
*/
|
|
void tree_set_node_sprite(struct node *node, const char *sprite,
|
|
const char *expanded) {
|
|
assert(node);
|
|
assert(sprite);
|
|
assert(expanded);
|
|
assert(node->data.type != NODE_ELEMENT_SPRITE);
|
|
|
|
node->data.sprite = calloc(sizeof(struct node_sprite), 1);
|
|
if (!node->data.sprite) return;
|
|
node->data.type = NODE_ELEMENT_TEXT_PLUS_SPRITE;
|
|
node->data.sprite->area = (osspriteop_area *)1;
|
|
sprintf(node->data.sprite->name, sprite);
|
|
sprintf(node->data.sprite->expanded_name, expanded);
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets a node element as having a folder sprite
|
|
*
|
|
* \param node the node to update
|
|
*/
|
|
void tree_set_node_sprite_folder(struct node *node) {
|
|
assert(node->folder);
|
|
|
|
tree_set_node_sprite(node, "small_dir", "small_diro");
|
|
}
|
|
|
|
|
|
/**
|
|
* Updates the node details for a URL node.
|
|
* The internal node dimensions are not updated.
|
|
*
|
|
* \param node the node to update
|
|
*/
|
|
void tree_update_URL_node(struct node *node) {
|
|
struct node_element *element;
|
|
char buffer[256];
|
|
|
|
assert(node);
|
|
|
|
element = tree_find_element(node, TREE_ELEMENT_URL);
|
|
if (element) {
|
|
sprintf(buffer, "small_%.3x", element->user_data);
|
|
if (ro_gui_wimp_sprite_exists(buffer))
|
|
tree_set_node_sprite(node, buffer, buffer);
|
|
else
|
|
tree_set_node_sprite(node, "small_xxx", "small_xxx");
|
|
}
|
|
|
|
element = tree_find_element(node, TREE_ELEMENT_ADDED);
|
|
if (element) {
|
|
if (element->text) {
|
|
free(element->text);
|
|
element->text = NULL;
|
|
}
|
|
if (element->user_data > 0) {
|
|
snprintf(buffer, 256, messages_get("TreeAdded"),
|
|
ctime((time_t *)&element->user_data));
|
|
} else {
|
|
snprintf(buffer, 256, messages_get("TreeAdded"),
|
|
messages_get("TreeUnknown"));
|
|
}
|
|
element->text = strdup(buffer);
|
|
}
|
|
|
|
element = tree_find_element(node, TREE_ELEMENT_LAST_VISIT);
|
|
if (element) {
|
|
if (element->text) {
|
|
free(element->text);
|
|
element->text = NULL;
|
|
}
|
|
if (element->user_data > 0) {
|
|
snprintf(buffer, 256, messages_get("TreeLast"),
|
|
ctime((time_t *)&element->user_data));
|
|
} else {
|
|
snprintf(buffer, 256, messages_get("TreeLast"),
|
|
messages_get("TreeUnknown"));
|
|
}
|
|
element->text = strdup(buffer);
|
|
}
|
|
|
|
element = tree_find_element(node, TREE_ELEMENT_VISITS);
|
|
if (element) {
|
|
if (element->text) {
|
|
free(element->text);
|
|
element->text = NULL;
|
|
}
|
|
snprintf(buffer, 256, messages_get("TreeVisits"),
|
|
element->user_data);
|
|
element->text = strdup(buffer);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Updates the tree owner following a tree resize
|
|
*
|
|
* \param tree the tree to update the owner of
|
|
*/
|
|
void tree_resized(struct tree *tree) {
|
|
os_error *error;
|
|
wimp_window_state state;
|
|
|
|
assert(tree->handle);
|
|
|
|
|
|
state.w = (wimp_w)tree->handle;
|
|
error = xwimp_get_window_state(&state);
|
|
if (error) {
|
|
LOG(("xwimp_get_window_state: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
warn_user("WimpError", error->errmess);
|
|
return;
|
|
}
|
|
if (state.flags & wimp_WINDOW_OPEN)
|
|
ro_gui_tree_open((wimp_open *)&state, tree);
|
|
}
|
|
|
|
|
|
/**
|
|
* Redraws a tree window
|
|
*
|
|
* \param redraw the area to redraw
|
|
* \param tree the tree to redraw
|
|
*/
|
|
void ro_gui_tree_redraw(wimp_draw *redraw, struct tree *tree) {
|
|
osbool more;
|
|
int clip_x0, clip_x1, clip_y0, clip_y1, origin_x, origin_y;
|
|
|
|
more = wimp_redraw_window(redraw);
|
|
while (more) {
|
|
clip_x0 = redraw->clip.x0;
|
|
clip_y0 = redraw->clip.y0;
|
|
clip_x1 = redraw->clip.x1;
|
|
clip_y1 = redraw->clip.y1;
|
|
origin_x = redraw->box.x0 - redraw->xscroll;
|
|
origin_y = redraw->box.y1 - redraw->yscroll;
|
|
tree_draw(tree, clip_x0 - origin_x - tree->offset_x,
|
|
origin_y - clip_y1 - tree->offset_y,
|
|
clip_x1 - clip_x0, clip_y1 - clip_y0);
|
|
more = wimp_get_rectangle(redraw);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Handles a mouse click for a tree
|
|
*
|
|
* \param pointer the pointer state
|
|
* \param tree the tree to handle a click for
|
|
* \return whether the click was handled#
|
|
*/
|
|
bool ro_gui_tree_click(wimp_pointer *pointer, struct tree *tree) {
|
|
bool furniture;
|
|
struct node *node;
|
|
struct node_element *element;
|
|
int x, y;
|
|
int alt_pressed = 0;
|
|
wimp_window_state state;
|
|
wimp_caret caret;
|
|
wimp_drag drag;
|
|
wimp_auto_scroll_info scroll;
|
|
os_error *error;
|
|
os_box box = { pointer->pos.x - 34, pointer->pos.y - 34,
|
|
pointer->pos.x + 34, pointer->pos.y + 34 };
|
|
|
|
assert(tree);
|
|
assert(tree->root);
|
|
|
|
/* gain the input focus when required */
|
|
state.w = (wimp_w)tree->handle;
|
|
error = xwimp_get_window_state(&state);
|
|
if (error)
|
|
LOG(("xwimp_get_window_state: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
error = xwimp_get_caret_position(&caret);
|
|
if (error)
|
|
LOG(("xwimp_get_caret_position: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
if (((pointer->buttons == (wimp_CLICK_SELECT << 8)) ||
|
|
(pointer->buttons == (wimp_CLICK_ADJUST << 8))) &&
|
|
(caret.w != state.w)) {
|
|
error = xwimp_set_caret_position((wimp_w)tree->handle, -1, -100,
|
|
-100, 32, -1);
|
|
if (error)
|
|
LOG(("xwimp_set_caret_position: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
}
|
|
|
|
if (!tree->root->child)
|
|
return true;
|
|
|
|
tree_initialise_redraw(tree);
|
|
x = pointer->pos.x - ro_gui_tree_origin_x;
|
|
y = ro_gui_tree_origin_y - pointer->pos.y;
|
|
element = tree_get_node_element_at(tree->root->child, x, y, &furniture);
|
|
node = element->parent;
|
|
|
|
|
|
/* stop editing for anything but a drag */
|
|
if ((tree->editing) && (pointer->i != tree->edit_handle) &&
|
|
(pointer->buttons != (wimp_CLICK_SELECT << 4)))
|
|
ro_gui_tree_stop_edit(tree);
|
|
|
|
/* handle a menu click */
|
|
if (pointer->buttons == wimp_CLICK_MENU) {
|
|
if ((!element) || (!tree->root->child) ||
|
|
(tree_has_selection(tree->root->child)))
|
|
return true;
|
|
tree->temp_selection = node;
|
|
node->selected = true;
|
|
tree_handle_node_element_changed(tree, &node->data);
|
|
return true;
|
|
|
|
}
|
|
|
|
/* no item either means cancel selection on (select) click or a drag */
|
|
if (!element) {
|
|
if ((pointer->buttons == (wimp_CLICK_SELECT << 4)) ||
|
|
(pointer->buttons == (wimp_CLICK_SELECT << 8)))
|
|
tree_set_node_selected(tree, tree->root->child, false);
|
|
if ((pointer->buttons == (wimp_CLICK_SELECT << 4)) ||
|
|
(pointer->buttons == (wimp_CLICK_ADJUST << 4))) {
|
|
|
|
scroll.w = (wimp_w)tree->handle;
|
|
scroll.pause_zone_sizes.y0 = 80;
|
|
scroll.pause_zone_sizes.y1 = 80;
|
|
scroll.pause_duration = 0;
|
|
scroll.state_change = (void *)0;
|
|
error = xwimp_auto_scroll(wimp_AUTO_SCROLL_ENABLE_VERTICAL,
|
|
&scroll, 0);
|
|
if (error)
|
|
LOG(("xwimp_auto_scroll: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
|
|
gui_current_drag_type = GUI_DRAG_TREE_SELECT;
|
|
ro_gui_tree_current_drag_tree = tree;
|
|
ro_gui_tree_current_drag_buttons = pointer->buttons;
|
|
|
|
drag.w = (wimp_w)tree->handle;
|
|
drag.type = wimp_DRAG_USER_RUBBER;
|
|
drag.initial.x0 = pointer->pos.x;
|
|
drag.initial.x1 = pointer->pos.x;
|
|
drag.initial.y0 = pointer->pos.y;
|
|
drag.initial.y1 = pointer->pos.y;
|
|
drag.bbox.x0 = state.visible.x0;
|
|
drag.bbox.x1 = state.visible.x1;
|
|
drag.bbox.y0 = -16384;//state.visible.y0;
|
|
drag.bbox.y1 = 16384;//state.visible.y1 - tree->offset_y;
|
|
error = xwimp_drag_box_with_flags(&drag,
|
|
wimp_DRAG_BOX_KEEP_IN_LINE |
|
|
wimp_DRAG_BOX_CLIP);
|
|
if (error)
|
|
LOG(("xwimp_drag_box_with_flags: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/* click on furniture or double click on folder toggles node expansion */
|
|
if (((furniture) && ((pointer->buttons == wimp_CLICK_SELECT << 8) ||
|
|
(pointer->buttons == wimp_CLICK_ADJUST << 8) ||
|
|
(pointer->buttons == wimp_CLICK_SELECT) ||
|
|
(pointer->buttons == wimp_CLICK_ADJUST))) ||
|
|
((!furniture) && (node->child) &&
|
|
((pointer->buttons == wimp_CLICK_SELECT) ||
|
|
(pointer->buttons == wimp_CLICK_ADJUST)))) {
|
|
node->expanded = !node->expanded;
|
|
if (!furniture)
|
|
node->selected = false;
|
|
tree_handle_node_changed(tree, node, false, true);
|
|
return true;
|
|
}
|
|
|
|
/* no use for any other furniture click */
|
|
if (furniture)
|
|
return true;
|
|
|
|
/* single/double alt+click starts editing */
|
|
if ((node->editable) && (!tree->editing) && ((element->user_type == 0) ||
|
|
(element->user_type == TREE_ELEMENT_URL)) &&
|
|
((pointer->buttons == wimp_CLICK_SELECT) ||
|
|
(pointer->buttons == (wimp_CLICK_SELECT << 8)))) {
|
|
xosbyte1(osbyte_SCAN_KEYBOARD, 2 ^ 0x80, 0, &alt_pressed);
|
|
if ((alt_pressed == 0xff) &&
|
|
(element->type != NODE_ELEMENT_SPRITE)) {
|
|
ro_gui_tree_start_edit(tree, element, pointer);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/* double click starts launches the leaf */
|
|
if ((pointer->buttons == wimp_CLICK_SELECT) ||
|
|
(pointer->buttons == wimp_CLICK_ADJUST)) {
|
|
if (!ro_gui_tree_launch_node(node))
|
|
return false;
|
|
if (pointer->buttons == wimp_CLICK_ADJUST)
|
|
ro_gui_tree_keypress(wimp_KEY_CONTROL + wimp_KEY_F2, tree);
|
|
return true;
|
|
}
|
|
|
|
/* single click (select) cancels current selection and selects item */
|
|
if (pointer->buttons == (wimp_CLICK_SELECT << 8)) {
|
|
if (!node->selected) {
|
|
tree_set_node_selected(tree, tree->root->child, false);
|
|
node->selected = true;
|
|
tree_handle_node_element_changed(tree, &node->data);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/* single click (adjust) toggles item selection */
|
|
if (pointer->buttons == (wimp_CLICK_ADJUST << 8)) {
|
|
node->selected = !node->selected;
|
|
tree_handle_node_element_changed(tree, &node->data);
|
|
return true;
|
|
}
|
|
|
|
/* drag starts a drag operation */
|
|
if ((!tree->editing) && ((pointer->buttons == (wimp_CLICK_SELECT << 4)) ||
|
|
(pointer->buttons == (wimp_CLICK_ADJUST << 4)))) {
|
|
|
|
if (!node->selected) {
|
|
node->selected = true;
|
|
tree_handle_node_element_changed(tree, &node->data);
|
|
}
|
|
|
|
scroll.w = (wimp_w)tree->handle;
|
|
scroll.pause_zone_sizes.y0 = 80;
|
|
scroll.pause_zone_sizes.y1 = 80;
|
|
scroll.pause_duration = -1;
|
|
scroll.state_change = (void *)0;
|
|
error = xwimp_auto_scroll(wimp_AUTO_SCROLL_ENABLE_VERTICAL,
|
|
&scroll, 0);
|
|
if (error)
|
|
LOG(("xwimp_auto_scroll: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
|
|
gui_current_drag_type = GUI_DRAG_TREE_MOVE;
|
|
ro_gui_tree_current_drag_tree = tree;
|
|
ro_gui_tree_current_drag_buttons = pointer->buttons;
|
|
|
|
node = tree_get_selected_node(tree->root);
|
|
if (node) {
|
|
if (node->folder) {
|
|
if ((node->expanded) &&
|
|
(ro_gui_wimp_sprite_exists("directoryo")))
|
|
sprintf(ro_gui_tree_drag_name, "directoryo");
|
|
else
|
|
sprintf(ro_gui_tree_drag_name, "directory");
|
|
} else {
|
|
element = tree_find_element(node, TREE_ELEMENT_URL);
|
|
if (element) {
|
|
sprintf(ro_gui_tree_drag_name, "file_%.3x",
|
|
element->user_data);
|
|
} else {
|
|
sprintf(ro_gui_tree_drag_name, "file_xxx");
|
|
}
|
|
if (!ro_gui_wimp_sprite_exists(ro_gui_tree_drag_name))
|
|
sprintf(ro_gui_tree_drag_name, "file_xxx");
|
|
}
|
|
} else {
|
|
sprintf(ro_gui_tree_drag_name, "package");
|
|
}
|
|
|
|
error = xdragasprite_start(dragasprite_HPOS_CENTRE |
|
|
dragasprite_VPOS_CENTRE |
|
|
dragasprite_BOUND_POINTER |
|
|
dragasprite_DROP_SHADOW,
|
|
(osspriteop_area *) 1,
|
|
ro_gui_tree_drag_name, &box, 0);
|
|
if (error)
|
|
LOG(("xdragasprite_start: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
return true;
|
|
}
|
|
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Handles a menu closed event
|
|
*
|
|
* \param tree the tree to handle the event for
|
|
*/
|
|
void ro_gui_tree_menu_closed(struct tree *tree) {
|
|
assert(tree);
|
|
|
|
if (tree->temp_selection) {
|
|
tree->temp_selection->selected = false;
|
|
tree_handle_node_element_changed(tree, &tree->temp_selection->data);
|
|
tree->temp_selection = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Starts an editing session
|
|
*
|
|
* \param tree the tree to start editing for
|
|
* \param element the element to edit
|
|
* \param pointer the pointer data to use for caret positioning (or NULL)
|
|
*/
|
|
void ro_gui_tree_start_edit(struct tree *tree, struct node_element *element,
|
|
wimp_pointer *pointer) {
|
|
os_error *error;
|
|
wimp_window_state state;
|
|
struct node *parent;
|
|
|
|
assert(tree);
|
|
assert(element);
|
|
|
|
if (tree->editing)
|
|
ro_gui_tree_stop_edit(tree);
|
|
|
|
parent = element->parent;
|
|
if (&parent->data == element)
|
|
parent = parent->parent;
|
|
for (; parent; parent = parent->parent) {
|
|
if (!parent->expanded) {
|
|
parent->expanded = true;
|
|
tree_handle_node_changed(tree, parent, false, true);
|
|
}
|
|
}
|
|
|
|
tree->editing = element;
|
|
snprintf(tree->edit_buffer, 256, element->text);
|
|
tree->edit_buffer[255] = '\0';
|
|
ro_gui_tree_edit_icon.w = (wimp_w)tree->handle;
|
|
ro_gui_tree_edit_icon.icon.extent.x0 = tree->offset_x + element->box.x - 2;
|
|
ro_gui_tree_edit_icon.icon.extent.x1 = tree->offset_x +
|
|
element->box.x + element->box.width + 2;
|
|
ro_gui_tree_edit_icon.icon.extent.y1 = -tree->offset_y - element->box.y;
|
|
ro_gui_tree_edit_icon.icon.extent.y0 = -tree->offset_y -
|
|
element->box.y - element->box.height;
|
|
if (element->type == NODE_ELEMENT_TEXT_PLUS_SPRITE)
|
|
ro_gui_tree_edit_icon.icon.extent.x0 += NODE_INSTEP;
|
|
ro_gui_tree_edit_icon.icon.data.indirected_text.text = tree->edit_buffer;
|
|
error = xwimp_create_icon(&ro_gui_tree_edit_icon,
|
|
(wimp_i *)&tree->edit_handle);
|
|
if (error)
|
|
LOG(("xwimp_create_icon: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
if (pointer) {
|
|
state.w = (wimp_w)tree->handle;
|
|
error = xwimp_get_window_state(&state);
|
|
if (error)
|
|
LOG(("xwimp_get_window_state: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
error = xwimp_set_caret_position((wimp_w)tree->handle,
|
|
(wimp_i)tree->edit_handle,
|
|
pointer->pos.x - state.visible.x0, 0,
|
|
element->box.height, -1);
|
|
} else {
|
|
error = xwimp_set_caret_position((wimp_w)tree->handle,
|
|
(wimp_i)tree->edit_handle,
|
|
0, 0, -1, strlen(tree->edit_buffer));
|
|
}
|
|
if (error)
|
|
LOG(("xwimp_set_caret_position: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
tree_handle_node_element_changed(tree, element);
|
|
ro_gui_tree_scroll_visible(tree, element);
|
|
}
|
|
|
|
|
|
/**
|
|
* Stops any current editing session
|
|
*
|
|
* \param tree the tree to stop editing for
|
|
*/
|
|
void ro_gui_tree_stop_edit(struct tree *tree) {
|
|
os_error *error;
|
|
|
|
assert(tree);
|
|
|
|
if (!tree->editing) return;
|
|
|
|
error = xwimp_delete_icon((wimp_w)tree->handle, (wimp_i)tree->edit_handle);
|
|
if (error)
|
|
LOG(("xwimp_delete_icon: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
tree_handle_node_element_changed(tree, tree->editing);
|
|
tree->editing = NULL;
|
|
|
|
error = xwimp_set_caret_position((wimp_w)tree->handle, -1, -100,
|
|
-100, 32, -1);
|
|
if (error)
|
|
LOG(("xwimp_set_caret_position: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
tree_recalculate_size(tree);
|
|
}
|
|
|
|
|
|
/**
|
|
* Scrolls the tree to make an element visible
|
|
*
|
|
* \param tree the tree to scroll
|
|
* \param element the element to display
|
|
*/
|
|
void ro_gui_tree_scroll_visible(struct tree *tree, struct node_element *element) {
|
|
wimp_window_state state;
|
|
int x0, x1, y0, y1;
|
|
os_error *error;
|
|
|
|
assert(element);
|
|
|
|
state.w = (wimp_w)tree->handle;
|
|
error = xwimp_get_window_state(&state);
|
|
if (error)
|
|
LOG(("xwimp_get_window_state: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
if (!(state.flags & wimp_WINDOW_OPEN))
|
|
return;
|
|
x0 = state.xscroll;
|
|
y0 = -state.yscroll;
|
|
x1 = x0 + state.visible.x1 - state.visible.x0 - tree->offset_x;
|
|
y1 = y0 - state.visible.y0 + state.visible.y1 - tree->offset_y;
|
|
|
|
state.yscroll = state.visible.y1 - state.visible.y0 - tree->offset_y - y1;
|
|
if ((element->box.y >= y0) && (element->box.y + element->box.height <= y1))
|
|
return;
|
|
if (element->box.y < y0)
|
|
state.yscroll = -element->box.y;
|
|
if (element->box.y + element->box.height > y1)
|
|
state.yscroll = state.visible.y1 - state.visible.y0 -
|
|
tree->offset_y -
|
|
(element->box.y + element->box.height);
|
|
ro_gui_tree_open((wimp_open *)&state, tree);
|
|
}
|
|
|
|
|
|
/**
|
|
* Handles a window open request
|
|
*
|
|
* \param open the window state
|
|
* \param tree the tree to handle a request for
|
|
*/
|
|
void ro_gui_tree_open(wimp_open *open, struct tree *tree) {
|
|
os_error *error;
|
|
int width;
|
|
int height;
|
|
|
|
width = open->visible.x1 - open->visible.x0;
|
|
if (width < (tree->offset_x + tree->width))
|
|
width = tree->offset_x + tree->width;
|
|
height = open->visible.y1 - open->visible.y0;
|
|
if (height < (tree->offset_y + tree->height))
|
|
height = tree->offset_y + tree->height;
|
|
|
|
if ((height != tree->window_height) || (width != tree->window_width)) {
|
|
os_box extent = { 0, -height, width, 0};
|
|
error = xwimp_set_extent((wimp_w)tree->handle, &extent);
|
|
if (error) {
|
|
LOG(("xwimp_set_extent: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
warn_user("WimpError", error->errmess);
|
|
}
|
|
tree->window_width = width;
|
|
tree->window_height = height;
|
|
}
|
|
|
|
error = xwimp_open_window(open);
|
|
if (error) {
|
|
LOG(("xwimp_open_window: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
warn_user("WimpError", error->errmess);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Handles a keypress for a tree
|
|
*
|
|
* \param key the key pressed
|
|
* \param tree the tree to handle a keypress for
|
|
* \return whether the key was processed
|
|
*/
|
|
bool ro_gui_tree_keypress(int key, struct tree *tree) {
|
|
os_error *error;
|
|
char *new_string;
|
|
|
|
/* Handle basic keys
|
|
*/
|
|
switch (key) {
|
|
case 1: /* CTRL+A */
|
|
ro_gui_tree_stop_edit(tree);
|
|
if (tree->root->child) {
|
|
tree->temp_selection = NULL;
|
|
tree_set_node_selected(tree, tree->root, true);
|
|
}
|
|
return true;
|
|
case 24: /* CTRL+X */
|
|
ro_gui_tree_stop_edit(tree);
|
|
tree_delete_selected_nodes(hotlist_tree, hotlist_tree->root);
|
|
return true;
|
|
case 26: /* CTRL+Z */
|
|
tree->temp_selection = NULL;
|
|
ro_gui_tree_stop_edit(tree);
|
|
tree_set_node_selected(tree, tree->root, false);
|
|
return true;
|
|
case wimp_KEY_RETURN:
|
|
if (tree->editing) {
|
|
new_string = strdup(tree->edit_buffer);
|
|
if (new_string) {
|
|
if (tree->editing->text) {
|
|
free(tree->editing->text);
|
|
tree->editing->text = NULL;
|
|
}
|
|
tree->editing->text = new_string;
|
|
}
|
|
ro_gui_tree_stop_edit(tree);
|
|
tree_recalculate_size(tree);
|
|
} else {
|
|
ro_gui_tree_launch_selected(tree);
|
|
}
|
|
return true;
|
|
case wimp_KEY_CONTROL + wimp_KEY_F2:
|
|
error = xwimp_close_window((wimp_w)tree->handle);
|
|
if (error)
|
|
LOG(("xwimp_close_window: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
return true;
|
|
case wimp_KEY_ESCAPE:
|
|
if (tree->editing) {
|
|
ro_gui_tree_stop_edit(tree);
|
|
} else {
|
|
/* \todo cancel drags etc. */
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Handles the completion of a selection drag (GUI_DRAG_TREE_SELECT)
|
|
*
|
|
* \param drag the drag box information
|
|
*/
|
|
void ro_gui_tree_selection_drag_end(wimp_dragged *drag) {
|
|
wimp_window_state state;
|
|
wimp_auto_scroll_info scroll;
|
|
os_error *error;
|
|
int x0, y0, x1, y1;
|
|
|
|
scroll.w = (wimp_w)ro_gui_tree_current_drag_tree->handle;
|
|
error = xwimp_auto_scroll(0, &scroll, 0);
|
|
if (error)
|
|
LOG(("xwimp_auto_scroll: 0x%x: %s", error->errnum, error->errmess));
|
|
|
|
state.w = (wimp_w)ro_gui_tree_current_drag_tree->handle;
|
|
error = xwimp_get_window_state(&state);
|
|
if (error) {
|
|
LOG(("xwimp_get_window_state: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
warn_user("WimpError", error->errmess);
|
|
return;
|
|
}
|
|
|
|
x0 = drag->final.x0 - state.visible.x0 - state.xscroll +
|
|
ro_gui_tree_current_drag_tree->offset_x;
|
|
y0 = state.visible.y1 - state.yscroll - drag->final.y0 -
|
|
ro_gui_tree_current_drag_tree->offset_y;
|
|
x1 = drag->final.x1 - state.visible.x0 - state.xscroll +
|
|
ro_gui_tree_current_drag_tree->offset_x;
|
|
y1 = state.visible.y1 - state.yscroll - drag->final.y1 -
|
|
ro_gui_tree_current_drag_tree->offset_y;
|
|
tree_handle_selection_area(ro_gui_tree_current_drag_tree, x0, y0,
|
|
x1 - x0, y1 - y0,
|
|
(ro_gui_tree_current_drag_buttons == (wimp_CLICK_ADJUST << 4)));
|
|
|
|
/* send an empty keypress to stimulate the tree owner to update the GUI.
|
|
for this to work, we must always own the caret when this function is
|
|
called. */
|
|
error = xwimp_process_key(0);
|
|
if (error)
|
|
LOG(("xwimp_process_key: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
}
|
|
|
|
|
|
/**
|
|
* Converts screen co-ordinates to tree ones
|
|
*
|
|
* \param tree the tree to calculate for
|
|
* \param x the screen x co-ordinate
|
|
* \param x the screen y co-ordinate
|
|
* \param tree_x updated to the tree x co-ordinate
|
|
* \param tree_y updated to the tree y co-ordinate
|
|
*/
|
|
void ro_gui_tree_get_tree_coordinates(struct tree *tree, int x, int y,
|
|
int *tree_x, int *tree_y) {
|
|
wimp_window_state state;
|
|
os_error *error;
|
|
|
|
state.w = (wimp_w)tree->handle;
|
|
error = xwimp_get_window_state(&state);
|
|
if (error) {
|
|
LOG(("xwimp_get_window_state: 0x%x: %s",
|
|
error->errnum, error->errmess));
|
|
warn_user("WimpError", error->errmess);
|
|
return;
|
|
}
|
|
*tree_x = x - state.visible.x0 - state.xscroll + tree->offset_x;
|
|
*tree_y = state.visible.y1 - state.yscroll - y - tree->offset_y;
|
|
}
|
|
|
|
|
|
/**
|
|
* Handles the completion of a move drag (GUI_DRAG_TREE_MOVE)
|
|
*
|
|
* \param drag the drag box information
|
|
*/
|
|
void ro_gui_tree_move_drag_end(wimp_dragged *drag) {
|
|
wimp_pointer pointer;
|
|
wimp_auto_scroll_info scroll;
|
|
os_error *error;
|
|
struct node *node;
|
|
bool before;
|
|
int x, y;
|
|
|
|
scroll.w = (wimp_w)ro_gui_tree_current_drag_tree->handle;
|
|
error = xwimp_auto_scroll(0, &scroll, 0);
|
|
if (error)
|
|
LOG(("xwimp_auto_scroll: 0x%x: %s", error->errnum, error->errmess));
|
|
|
|
error = xwimp_get_pointer_info(&pointer);
|
|
if (error) {
|
|
LOG(("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess));
|
|
warn_user("WimpError", error->errmess);
|
|
return;
|
|
}
|
|
|
|
/* todo: handle export */
|
|
if (pointer.w != (wimp_w)ro_gui_tree_current_drag_tree->handle)
|
|
return;
|
|
|
|
/* internal drag */
|
|
ro_gui_tree_get_tree_coordinates(ro_gui_tree_current_drag_tree,
|
|
drag->final.x0 + 34, drag->final.y0 + 34, &x, &y);
|
|
node = tree_get_link_details(ro_gui_tree_current_drag_tree, x, y, &before);
|
|
tree_move_selected_nodes(ro_gui_tree_current_drag_tree, node, before);
|
|
}
|
|
|
|
|
|
/**
|
|
* Launches all selected nodes.
|
|
*
|
|
* \param tree the tree to launch all selected nodes for
|
|
*/
|
|
void ro_gui_tree_launch_selected(struct tree *tree) {
|
|
assert(tree);
|
|
|
|
if (tree->root->child)
|
|
ro_gui_tree_launch_selected_node(tree->root->child, false);
|
|
}
|
|
|
|
|
|
/**
|
|
* Launches all selected nodes.
|
|
*
|
|
* \param node the node to launch all selected nodes for
|
|
*/
|
|
void ro_gui_tree_launch_selected_node(struct node *node, bool all) {
|
|
for (; node; node = node->next) {
|
|
if (((node->selected) || (all)) && (!node->folder))
|
|
ro_gui_tree_launch_node(node);
|
|
if ((node->child) && ((node->expanded) || (node->selected) | (all)))
|
|
ro_gui_tree_launch_selected_node(node->child,
|
|
(node->selected) | (all));
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Launches a node using all known methods.
|
|
*
|
|
* \param node the node to launch
|
|
* \return whether the node could be launched
|
|
*/
|
|
bool ro_gui_tree_launch_node(struct node *node) {
|
|
struct node_element *element;
|
|
|
|
assert(node);
|
|
|
|
element = tree_find_element(node, TREE_ELEMENT_URL);
|
|
if (element) {
|
|
browser_window_create(element->text, NULL, 0);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|