From 9f2ea3be4c50f0e30153fc648f3219b5bd7f3fa3 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Tue, 5 Jul 2011 20:13:28 +0000 Subject: Iframe scrollbars. svn path=/trunk/netsurf/; revision=12571 --- desktop/browser.c | 278 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 257 insertions(+), 21 deletions(-) (limited to 'desktop/browser.c') diff --git a/desktop/browser.c b/desktop/browser.c index fd2e28ebc..8b7741ca2 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -50,6 +50,7 @@ #include "desktop/gui.h" #include "desktop/knockout.h" #include "desktop/options.h" +#include "desktop/scrollbar.h" #include "desktop/selection.h" #include "desktop/textinput.h" #include "desktop/plotters.h" @@ -92,6 +93,46 @@ static void browser_window_find_target_internal(struct browser_window *bw, static void browser_window_mouse_drag_end(struct browser_window *bw, browser_mouse_state mouse, int x, int y); + +/** + * Get position of scrollbar widget within browser window. + * + * \param bw The browser window + * \param horizontal Whether to get position of horizontal scrollbar + * \param x Updated to x-coord of top left of scrollbar widget + * \param y Updated to y-coord of top left of scrollbar widget + */ + +static inline void browser_window_get_scrollbar_pos(struct browser_window *bw, + bool horizontal, int *x, int *y) +{ + if (horizontal) { + *x = 0; + *y = bw->height - SCROLLBAR_WIDTH; + } else { + *x = bw->width - SCROLLBAR_WIDTH; + *y = 0; + } +} + + +/** + * Get browser window scrollbar widget length + * + * \param bw The browser window + * \param horizontal Whether to get length of horizontal scrollbar + * \return the scrollbar's length + */ + +static inline int browser_window_get_scrollbar_len(struct browser_window *bw, + bool horizontal) +{ + if (horizontal) + return bw->width - (bw->scroll_y != NULL ? SCROLLBAR_WIDTH : 0); + else + return bw->height; +} + /* exported interface, documented in browser.h */ bool browser_window_redraw(struct browser_window *bw, int x, int y, const struct rect *clip, const struct redraw_context *ctx) @@ -102,6 +143,7 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y, bool plot_ok = true; content_type content_type; struct content_redraw_data data; + struct rect content_clip; if (bw == NULL) { LOG(("NULL browser window")); @@ -138,8 +180,8 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y, } /* Set up content redraw data */ - data.x = x; - data.y = y; + data.x = x - scrollbar_get_offset(bw->scroll_x); + data.y = y - scrollbar_get_offset(bw->scroll_y); data.width = width; data.height = height; @@ -147,9 +189,48 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y, data.scale = bw->scale; data.repeat_x = false; data.repeat_y = false; + + content_clip = *clip; + + if (!bw->window) { + int x0 = x * bw->scale; + int y0 = y * bw->scale; + int x1 = (x + bw->width - ((bw->scroll_y != NULL) ? + SCROLLBAR_WIDTH : 0)) * bw->scale; + int y1 = (y + bw->height - ((bw->scroll_x != NULL) ? + SCROLLBAR_WIDTH : 0)) * bw->scale; + + if (content_clip.x0 < x0) content_clip.x0 = x0; + if (content_clip.y0 < y0) content_clip.y0 = y0; + if (x1 < content_clip.x1) content_clip.x1 = x1; + if (y1 < content_clip.y1) content_clip.y1 = y1; + } /* Render the content */ - plot_ok &= content_redraw(bw->current_content, &data, clip, &new_ctx); + plot_ok &= content_redraw(bw->current_content, &data, + &content_clip, &new_ctx); + + /* Back to full clip rect */ + new_ctx.plot->clip(clip); + + if (!bw->window) { + /* Render scrollbars */ + int off_x, off_y; + if (bw->scroll_x != NULL) { + browser_window_get_scrollbar_pos(bw, true, + &off_x, &off_y); + plot_ok &= scrollbar_redraw(bw->scroll_x, + x + off_x, y + off_y, clip, + bw->scale, &new_ctx); + } + if (bw->scroll_y != NULL) { + browser_window_get_scrollbar_pos(bw, false, + &off_x, &off_y); + plot_ok &= scrollbar_redraw(bw->scroll_y, + x + off_x, y + off_y, clip, + bw->scale, &new_ctx); + } + } if (bw->browser_window_type != BROWSER_WINDOW_IFRAME && ctx->plot->option_knockout) { @@ -183,7 +264,7 @@ void browser_window_update_extent(struct browser_window *bw) gui_window_update_extent(bw->window); break; case BROWSER_WINDOW_IFRAME: - /* TODO */ + browser_window_handle_scrollbars(bw); break; } } @@ -207,8 +288,8 @@ void browser_window_get_position(struct browser_window *bw, bool root, break; case BROWSER_WINDOW_IFRAME: - *pos_x += bw->x * bw->scale; - *pos_y += bw->y * bw->scale; + *pos_x += (bw->x - scrollbar_get_offset(bw->scroll_x)) * bw->scale; + *pos_y += (bw->y - scrollbar_get_offset(bw->scroll_y)) * bw->scale; break; } @@ -257,6 +338,7 @@ struct browser_window * browser_window_get_root(struct browser_window *bw) } return bw; } + /* exported interface, documented in browser.h */ bool browser_window_has_selection(struct browser_window *bw) { @@ -272,6 +354,26 @@ bool browser_window_has_selection(struct browser_window *bw) } } +/** + * Set scroll offsets for a browser window. + * + * \param bw The browser window + * \param x The x scroll offset to set + * \param y The y scroll offset to set + */ + +static void browser_window_set_scroll(struct browser_window *bw, int x, int y) +{ + if (bw->window != NULL) { + gui_window_set_scroll(bw->window, x, y); + } else { + if (bw->scroll_x != NULL) + scrollbar_set(bw->scroll_x, x, false); + if (bw->scroll_y != NULL) + scrollbar_set(bw->scroll_y, y, false); + } +} + /** * Create and open a new root browser window with the given page. * @@ -351,6 +453,9 @@ void browser_window_initialise_common(struct browser_window *bw, bw->drag_type = DRAGGING_NONE; bw->scale = (float) option_scale / 100.0; + bw->scroll_x = NULL; + bw->scroll_y = NULL; + bw->focus = NULL; /* initialise status text cache */ @@ -716,6 +821,14 @@ nserror browser_window_callback(hlcache_handle *c, case CONTENT_MSG_DONE: assert(bw->current_content == c); + if (bw->window == NULL) { + /* Updated browser window's scrollbars. + * TODO: do this before CONTENT_MSG_DONE */ + browser_window_reformat(bw, true, + bw->width, bw->height); + browser_window_handle_scrollbars(bw); + } + browser_window_update(bw, false); browser_window_set_status(bw, content_get_status_message(c)); browser_window_stop_throbber(bw); @@ -1033,13 +1146,13 @@ void browser_window_update(struct browser_window *bw, bool scroll_to_top) browser_window_update_extent(bw); if (scroll_to_top) - gui_window_set_scroll(bw->window, 0, 0); + browser_window_set_scroll(bw, 0, 0); /* if frag_id exists, then try to scroll to it */ /** \TODO don't do this if the user has scrolled */ if (bw->frag_id && html_get_id_offset(bw->current_content, bw->frag_id, &x, &y)) { - gui_window_set_scroll(bw->window, x, y); + browser_window_set_scroll(bw, x, y); } gui_window_redraw_window(bw->window); @@ -1048,7 +1161,17 @@ void browser_window_update(struct browser_window *bw, bool scroll_to_top) case BROWSER_WINDOW_IFRAME: /* Internal iframe browser window */ - /** \TODO handle scrollbar extents, scroll offset */ + browser_window_update_extent(bw); + + if (scroll_to_top) + browser_window_set_scroll(bw, 0, 0); + + /* if frag_id exists, then try to scroll to it */ + /** \TODO don't do this if the user has scrolled */ + if (bw->frag_id && html_get_id_offset(bw->current_content, + bw->frag_id, &x, &y)) { + browser_window_set_scroll(bw, x, y); + } html_redraw_a_box(bw->parent->current_content, bw->box); break; @@ -1409,8 +1532,14 @@ void browser_window_reformat(struct browser_window *bw, bool background, if (bw->browser_window_type != BROWSER_WINDOW_IFRAME) { /* Iframe dimensions are already scaled in parent's layout */ - width /= bw->scale; + width /= bw->scale; height /= bw->scale; + } else { + width -= bw->scroll_y ? SCROLLBAR_WIDTH : 0; + height -= bw->scroll_x ? SCROLLBAR_WIDTH : 0; + + width = width > 0 ? width : 0; + height = height > 0 ? height : 0; } content_reformat(c, background, width, height); @@ -1688,6 +1817,8 @@ void browser_window_mouse_track(struct browser_window *bw, browser_mouse_state mouse, int x, int y) { hlcache_handle *c = bw->current_content; + const char *status = NULL; + gui_pointer_shape pointer = GUI_POINTER_DEFAULT; if (c == NULL && bw->drag_type != DRAGGING_FRAME) return; @@ -1696,6 +1827,51 @@ void browser_window_mouse_track(struct browser_window *bw, browser_window_mouse_drag_end(bw, mouse, x, y); } + if (bw->scroll_x != NULL) { + int scr_x, scr_y; + browser_window_get_scrollbar_pos(bw, true, &scr_x, &scr_y); + scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x); + scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y); + + if ((scr_x > 0 && scr_x < browser_window_get_scrollbar_len(bw, + true) && + scr_y > 0 && scr_y < SCROLLBAR_WIDTH) || + bw->drag_type == DRAGGING_SCR_X) { + status = scrollbar_mouse_action(bw->scroll_x, mouse, + scr_x, scr_y); + pointer = GUI_POINTER_DEFAULT; + + if (status != NULL) + browser_window_set_status(bw, status); + + browser_window_set_pointer(bw, pointer); + return; + } + } + + if (bw->scroll_y != NULL) { + int scr_x, scr_y; + browser_window_get_scrollbar_pos(bw, false, &scr_x, &scr_y); + scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x); + scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y); + + if ((scr_y > 0 && scr_y < browser_window_get_scrollbar_len(bw, + false) && + scr_x > 0 && scr_x < SCROLLBAR_WIDTH) || + bw->drag_type == DRAGGING_SCR_Y) { + + status = scrollbar_mouse_action(bw->scroll_y, mouse, + scr_x, scr_y); + pointer = GUI_POINTER_DEFAULT; + + if (status != NULL) + browser_window_set_status(bw, status); + + browser_window_set_pointer(bw, pointer); + return; + } + } + if (bw->drag_type == DRAGGING_FRAME) { browser_window_resize_frame(bw, bw->x0 + x, bw->y0 + y); } else if (bw->drag_type == DRAGGING_PAGE_SCROLL) { @@ -1710,17 +1886,7 @@ void browser_window_mouse_track(struct browser_window *bw, bw->drag_start_scroll_x = scrollx; bw->drag_start_scroll_y = scrolly; - switch (bw->browser_window_type) { - default: - /* Fall through to normal, until frame(set)s are - * handled in the core */ - case BROWSER_WINDOW_NORMAL: - gui_window_set_scroll(bw->window, scrollx, scrolly); - break; - case BROWSER_WINDOW_IFRAME: - /* TODO */ - break; - } + browser_window_set_scroll(bw, scrollx, scrolly); } else { assert(c != NULL); content_mouse_track(c, bw, mouse, x, y); @@ -1741,10 +1907,54 @@ void browser_window_mouse_click(struct browser_window *bw, browser_mouse_state mouse, int x, int y) { hlcache_handle *c = bw->current_content; + const char *status = NULL; + gui_pointer_shape pointer = GUI_POINTER_DEFAULT; if (!c) return; + if (bw->scroll_x != NULL) { + int scr_x, scr_y; + browser_window_get_scrollbar_pos(bw, true, &scr_x, &scr_y); + scr_x = x - scr_x; + scr_y = y - scr_y; + + if (scr_x > 0 && scr_x < browser_window_get_scrollbar_len(bw, + true) && + scr_y > 0 && scr_y < SCROLLBAR_WIDTH) { + status = scrollbar_mouse_action(bw->scroll_x, mouse, + scr_x, scr_y); + pointer = GUI_POINTER_DEFAULT; + + if (status != NULL) + browser_window_set_status(bw, status); + + browser_window_set_pointer(bw, pointer); + return; + } + } + + if (bw->scroll_y != NULL) { + int scr_x, scr_y; + browser_window_get_scrollbar_pos(bw, false, &scr_x, &scr_y); + scr_x = x - scr_x; + scr_y = y - scr_y; + + if (scr_y > 0 && scr_y < browser_window_get_scrollbar_len(bw, + false) && + scr_x > 0 && scr_x < SCROLLBAR_WIDTH) { + status = scrollbar_mouse_action(bw->scroll_y, mouse, + scr_x, scr_y); + pointer = GUI_POINTER_DEFAULT; + + if (status != NULL) + browser_window_set_status(bw, status); + + browser_window_set_pointer(bw, pointer); + return; + } + } + switch (content_get_type(c)) { case CONTENT_HTML: case CONTENT_TEXTPLAIN: @@ -1784,6 +1994,8 @@ void browser_window_mouse_click(struct browser_window *bw, void browser_window_mouse_drag_end(struct browser_window *bw, browser_mouse_state mouse, int x, int y) { + int scr_x, scr_y; + switch (bw->drag_type) { case DRAGGING_SELECTION: { @@ -1817,6 +2029,30 @@ void browser_window_mouse_drag_end(struct browser_window *bw, /* Drag handled by content handler */ break; + case DRAGGING_SCR_X: + + browser_window_get_scrollbar_pos(bw, true, &scr_x, &scr_y); + + scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x); + scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y); + + scrollbar_mouse_drag_end(bw->scroll_x, mouse, scr_x, scr_y); + + bw->drag_type = DRAGGING_NONE; + break; + + case DRAGGING_SCR_Y: + + browser_window_get_scrollbar_pos(bw, false, &scr_x, &scr_y); + + scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x); + scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y); + + scrollbar_mouse_drag_end(bw->scroll_y, mouse, scr_x, scr_y); + + bw->drag_type = DRAGGING_NONE; + break; + default: bw->drag_type = DRAGGING_NONE; break; -- cgit v1.2.3