Iframe scrollbars.

svn path=/trunk/netsurf/; revision=12571
This commit is contained in:
Michael Drake 2011-07-05 20:13:28 +00:00
parent 1f9b970f57
commit 9f2ea3be4c
4 changed files with 401 additions and 24 deletions

View File

@ -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;

View File

@ -60,6 +60,8 @@ typedef enum {
DRAGGING_SELECTION,
DRAGGING_PAGE_SCROLL,
DRAGGING_FRAME,
DRAGGING_SCR_X,
DRAGGING_SCR_Y,
DRAGGING_OTHER
} browser_drag_type;
@ -135,6 +137,9 @@ struct browser_window {
int width;
int height;
struct scrollbar *scroll_x; /**< Horizontal scroll. */
struct scrollbar *scroll_y; /**< Vertical scroll. */
/** scale of window contents */
float scale;

View File

@ -34,6 +34,7 @@
#include "desktop/frames.h"
#include "desktop/history_core.h"
#include "desktop/gui.h"
#include "desktop/scrollbar.h"
#include "desktop/selection.h"
#include "utils/log.h"
#include "utils/messages.h"
@ -47,6 +48,121 @@ static bool browser_window_resolve_frame_dimension(struct browser_window *bw,
bool height);
/**
* Callback for (i)frame scrollbars.
*/
void browser_window_scroll_callback(void *client_data,
struct scrollbar_msg_data *scrollbar_data)
{
struct browser_window *bw = client_data;
switch(scrollbar_data->msg) {
case SCROLLBAR_MSG_REDRAW:
/* TODO: Is this needed? */
break;
case SCROLLBAR_MSG_MOVED:
html_redraw_a_box(bw->parent->current_content, bw->box);
break;
case SCROLLBAR_MSG_SCROLL_START:
if (scrollbar_is_horizontal(scrollbar_data->scrollbar))
browser_window_set_drag_type(bw, DRAGGING_SCR_X);
else
browser_window_set_drag_type(bw, DRAGGING_SCR_Y);
break;
case SCROLLBAR_MSG_SCROLL_FINISHED:
browser_window_set_drag_type(bw, DRAGGING_NONE);
browser_window_set_pointer(bw, GUI_POINTER_DEFAULT);
break;
}
}
/* exported interface, documented in browser.h */
void browser_window_handle_scrollbars(struct browser_window *bw)
{
hlcache_handle *h = bw->current_content;
bool scroll_x;
bool scroll_y;
int c_width = 0;
int c_height = 0;
assert(!bw->window); /* Core-handled windows only */
if (h != NULL) {
c_width = content_get_width(h);
c_height = content_get_height(h);
}
if (bw->scrolling == SCROLLING_YES) {
scroll_x = true;
scroll_y = true;
} else if (bw->scrolling == SCROLLING_AUTO &&
bw->current_content) {
int bw_width = bw->width;
int bw_height = bw->height;
/* subtract existing scrollbar width */
bw_width -= bw->scroll_y ? SCROLLBAR_WIDTH : 0;
bw_height -= bw->scroll_x ? SCROLLBAR_WIDTH : 0;
scroll_y = (c_height > bw_height) ? true : false;
scroll_x = (c_width > bw_width) ? true : false;
} else {
/* No scrollbars */
scroll_x = false;
scroll_y = false;
}
if (!scroll_x && bw->scroll_x != NULL) {
scrollbar_destroy(bw->scroll_x);
bw->scroll_x = NULL;
}
if (!scroll_y && bw->scroll_y != NULL) {
scrollbar_destroy(bw->scroll_y);
bw->scroll_y = NULL;
}
if (scroll_y) {
int length = bw->height;
int visible = bw->height - (scroll_x ? SCROLLBAR_WIDTH : 0);
if (bw->scroll_y == NULL) {
/* create vertical scrollbar */
if (!scrollbar_create(false, length, c_height, visible,
bw, browser_window_scroll_callback,
&(bw->scroll_y)))
return;
} else {
/* update vertical scrollbar */
scrollbar_set_extents(bw->scroll_y, length,
visible, c_height);
}
}
if (scroll_x) {
int length = bw->width - (scroll_y ? SCROLLBAR_WIDTH : 0);
int visible = length;
if (bw->scroll_x == NULL) {
/* create horizontal scrollbar */
if (!scrollbar_create(true, length, c_width, visible,
bw, browser_window_scroll_callback,
&(bw->scroll_x)))
return;
} else {
/* update horizontal scrollbar */
scrollbar_set_extents(bw->scroll_x, length,
visible, c_width);
}
}
if (scroll_x && scroll_y)
scrollbar_make_pair(bw->scroll_x, bw->scroll_y);
}
/**
* Create and open a iframes for a browser window.
*
@ -55,7 +171,8 @@ static bool browser_window_resolve_frame_dimension(struct browser_window *bw,
*/
void browser_window_create_iframes(struct browser_window *bw,
struct content_html_iframe *iframe) {
struct content_html_iframe *iframe)
{
struct browser_window *window;
struct content_html_iframe *cur;
struct rect rect;
@ -130,8 +247,16 @@ void browser_window_create_iframes(struct browser_window *bw,
void browser_window_recalculate_iframes(struct browser_window *bw)
{
/* TODO: decide if this is still needed after scrollbars are
* implemented */
struct browser_window *window;
int index;
for (index = 0; index < bw->iframe_count; index++) {
window = &(bw->iframes[index]);
if (window != NULL) {
browser_window_handle_scrollbars(window);
}
}
}

View File

@ -38,4 +38,15 @@ bool browser_window_resize_frames(struct browser_window *bw,
gui_pointer_shape *pointer, const char **status, bool *action);
void browser_window_resize_frame(struct browser_window *bw, int x, int y);
void browser_window_scroll_callback(void *client_data,
struct scrollbar_msg_data *scrollbar_data);
/**
* Create, remove, and update browser window scrollbars
*
* \param bw The browser window
*/
void browser_window_handle_scrollbars(struct browser_window *bw);
#endif