diff options
Diffstat (limited to 'desktop/local_history.c')
-rw-r--r-- | desktop/local_history.c | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/desktop/local_history.c b/desktop/local_history.c new file mode 100644 index 000000000..75da4aff1 --- /dev/null +++ b/desktop/local_history.c @@ -0,0 +1,446 @@ +/* + * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * Local history viewer implementation + */ + +#include <stdlib.h> +#include <string.h> + +#include "utils/errors.h" +#include "utils/nsurl.h" +#include "netsurf/types.h" +#include "netsurf/layout.h" +#include "netsurf/core_window.h" +#include "netsurf/plotters.h" + +#include "desktop/gui_internal.h" +#include "desktop/system_colour.h" +#include "desktop/browser_private.h" +#include "desktop/browser_history.h" +#include "desktop/local_history.h" + +#define WIDTH 100 +#define HEIGHT 86 + +/** + * local history viewer context + */ +struct local_history_session { + struct browser_window *bw; + struct core_window_callback_table *cw_t; + void *core_window_handle; +}; + + +/** + * plot style for drawing lines between nodes + */ +static plot_style_t pstyle_line = { + .stroke_type = PLOT_OP_TYPE_SOLID, + .stroke_width = plot_style_int_to_fixed(2), +}; + + +/** + * plot style for drawing background + */ +static plot_style_t pstyle_bg = { + .fill_type = PLOT_OP_TYPE_SOLID, +}; + + +/** + * plot style for drawing rectangle round unselected nodes + */ +static plot_style_t pstyle_rect = { + .stroke_type = PLOT_OP_TYPE_SOLID, + .stroke_width = plot_style_int_to_fixed(1), +}; + + +/** + * plot style for drawing rectangle round selected nodes + */ +static plot_style_t pstyle_rect_sel = { + .stroke_type = PLOT_OP_TYPE_SOLID, + .stroke_width = plot_style_int_to_fixed(3), +}; + + +/** + * plot style for font on unselected nodes + */ +static plot_font_style_t pfstyle_node = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 8 * PLOT_STYLE_SCALE, + .weight = 400, + .flags = FONTF_NONE, +}; + + +/** + * plot style for font on unselected nodes + */ +static plot_font_style_t pfstyle_node_sel = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 8 * PLOT_STYLE_SCALE, + .weight = 900, + .flags = FONTF_NONE, +}; + + +/** + * Recursively redraw a history entry. + * + * \param history history containing the entry + * \param entry entry to render + * \param clip redraw area + * \param x window x offset + * \param y window y offset + * \param ctx current redraw context + */ +static nserror +redraw_entry(struct history *history, + struct history_entry *entry, + struct rect *clip, + int x, int y, + const struct redraw_context *ctx) +{ + size_t char_offset; + int actual_x; + struct history_entry *child; + int tailsize = 5; + + plot_style_t *pstyle; + plot_font_style_t *pfstyle; + struct rect rect; + nserror res; + + /* setup plot styles */ + if (entry == history->current) { + pstyle = &pstyle_rect_sel; + pfstyle = &pfstyle_node_sel; + } else { + pstyle = &pstyle_rect; + pfstyle = &pfstyle_node; + } + + /* Only attempt to plot bitmap if it is present */ + if (entry->page.bitmap != NULL) { + res = ctx->plot->bitmap(ctx, + entry->page.bitmap, + entry->x + x, + entry->y + y, + WIDTH, HEIGHT, + 0xffffff, + 0); + if (res != NSERROR_OK) { + return res; + } + } + + rect.x0 = entry->x - 1 + x; + rect.y0 = entry->y - 1 + y; + rect.x1 = entry->x + x + WIDTH; + rect.y1 = entry->y + y + HEIGHT; + res = ctx->plot->rectangle(ctx, pstyle, &rect); + if (res != NSERROR_OK) { + return res; + } + + res = guit->layout->position(plot_style_font, entry->page.title, + strlen(entry->page.title), WIDTH, + &char_offset, &actual_x); + if (res != NSERROR_OK) { + return res; + } + + res = ctx->plot->text(ctx, + pfstyle, + entry->x + x, + entry->y + HEIGHT + 12 + y, + entry->page.title, + char_offset); + if (res != NSERROR_OK) { + return res; + } + + /* for each child node draw a line and recurse redraw into it */ + for (child = entry->forward; child; child = child->next) { + rect.x0 = entry->x + WIDTH + x; + rect.y0 = entry->y + HEIGHT / 2 + y; + rect.x1 = entry->x + WIDTH + tailsize + x; + rect.y1 = entry->y + HEIGHT / 2 + y; + res = ctx->plot->line(ctx, &pstyle_line, &rect); + if (res != NSERROR_OK) { + return res; + } + + rect.x0 = entry->x + WIDTH + tailsize + x; + rect.y0 = entry->y + HEIGHT / 2 + y; + rect.x1 = child->x - tailsize + x; + rect.y1 = child->y + HEIGHT / 2 + y; + res = ctx->plot->line(ctx, &pstyle_line, &rect); + if (res != NSERROR_OK) { + return res; + } + + rect.x0 = child->x - tailsize + x; + rect.y0 = child->y + HEIGHT / 2 + y; + rect.x1 = child->x + x; + rect.y1 = child->y + HEIGHT / 2 + y; + res = ctx->plot->line(ctx, &pstyle_line, &rect); + if (res != NSERROR_OK) { + return res; + } + + res = redraw_entry(history, child, clip, x, y, ctx); + if (res != NSERROR_OK) { + return res; + } + } + + return NSERROR_OK; +} + + +/** + * Find the history entry at a position. + * + * \param entry entry to search from + * \param x coordinate + * \param y coordinate + * \return an entry if found, 0 if none + */ +static struct history_entry * +find_entry_position(struct history_entry *entry, int x, int y) +{ + struct history_entry *child; + struct history_entry *found; + + if (!entry) { + return NULL; + } + + if ((entry->x <= x) && + (x <= entry->x + WIDTH) && + (entry->y <= y) && + (y <= entry->y + HEIGHT)) { + return entry; + } + + for (child = entry->forward; child; child = child->next) { + found = find_entry_position(child, x, y); + if (found) { + return found; + } + } + + return NULL; +} + + +/* exported interface documented in desktop/local_history.h */ +nserror +local_history_init(struct core_window_callback_table *cw_t, + void *core_window_handle, + struct browser_window *bw, + struct local_history_session **session) +{ + nserror res; + struct local_history_session *nses; + + res = ns_system_colour_char("Window", &pstyle_bg.fill_colour); + if (res != NSERROR_OK) { + return res; + } + pfstyle_node.background = pstyle_bg.fill_colour; + pfstyle_node_sel.background = pstyle_bg.fill_colour; + + res = ns_system_colour_char("GrayText", &pstyle_line.stroke_colour); + if (res != NSERROR_OK) { + return res; + } + pstyle_rect.stroke_colour = pstyle_line.stroke_colour; + pfstyle_node.foreground = pstyle_line.stroke_colour; + + res = ns_system_colour_char("Highlight", &pstyle_rect_sel.stroke_colour); + if (res != NSERROR_OK) { + return res; + } + pfstyle_node_sel.foreground = pstyle_rect_sel.stroke_colour; + + nses = calloc(1, sizeof(struct local_history_session)); + if (nses == NULL) { + return NSERROR_NOMEM; + } + + nses->cw_t = cw_t; + nses->core_window_handle = core_window_handle; + + local_history_set(nses, bw); + + *session = nses; + + return NSERROR_OK; +} + +/* exported interface documented in desktop/local_history.h */ +nserror local_history_fini(struct local_history_session *session) +{ + free(session); + + return NSERROR_OK; +} + + +/* exported interface documented in desktop/local_history.h */ +nserror +local_history_redraw(struct local_history_session *session, + int x, + int y, + struct rect *clip, + const struct redraw_context *ctx) +{ + struct rect r = { + .x0 = clip->x0 + x, + .y0 = clip->y0 + y, + .x1 = clip->x1 + x, + .y1 = clip->y1 + y, + }; + + if (session->bw == NULL) { + return NSERROR_OK; + } + + if (session->bw->history->start == NULL) { + return NSERROR_OK; + } + + ctx->plot->clip(ctx, &r); + ctx->plot->rectangle(ctx, &pstyle_bg, &r); + + return redraw_entry(session->bw->history, + session->bw->history->start, + clip, + x, y, + ctx); +} + +/* exported interface documented in desktop/local_history.h */ +nserror +local_history_mouse_action(struct local_history_session *session, + enum browser_mouse_state mouse, + int x, + int y) +{ + struct history_entry *entry; + bool new_window; + + if (session->bw == NULL) { + return NSERROR_BAD_PARAMETER; + } + + if ((mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2)) == 0) { + return NSERROR_NOT_IMPLEMENTED; + } + + entry = find_entry_position(session->bw->history->start, x, y); + if (entry == NULL) { + return NSERROR_NOT_FOUND; + } + + if (entry == session->bw->history->current) { + return NSERROR_PERMISSION; + } + + if (mouse & BROWSER_MOUSE_PRESS_1) { + new_window = false; + } else if (mouse & BROWSER_MOUSE_PRESS_2) { + new_window = true; + } else { + new_window = false; + } + + browser_window_history_go(session->bw, entry, new_window); + + return NSERROR_OK; +} + +/* exported interface documented in desktop/local_history.h */ +bool +local_history_keypress(struct local_history_session *session, uint32_t key) +{ + return false; +} + +/* exported interface documented in desktop/local_history.h */ +nserror +local_history_set(struct local_history_session *session, + struct browser_window *bw) +{ + session->bw = bw; + if (bw != NULL) { + assert(session->bw->history != NULL); + + session->cw_t->update_size(session->core_window_handle, + session->bw->history->width, + session->bw->history->height); + } + + return NSERROR_OK; +} + + +/* exported interface documented in desktop/local_history.h */ +nserror +local_history_get_size(struct local_history_session *session, + int *width, + int *height) +{ + *width = session->bw->history->width + 20; + *height = session->bw->history->height + 20; + + return NSERROR_OK; +} + + +/* exported interface documented in desktop/local_history.h */ +nserror +local_history_get_url(struct local_history_session *session, + int x, int y, + nsurl **url_out) +{ + struct history_entry *entry; + + if (session->bw == NULL) { + return NSERROR_BAD_PARAMETER; + } + + entry = find_entry_position(session->bw->history->start, x, y); + if (entry == NULL) { + return NSERROR_NOT_FOUND; + } + + *url_out = nsurl_ref(entry->page.url); + + return NSERROR_OK; +} |