From bc546388ce428be5cfa37cecb174d549c7b30320 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Tue, 23 Mar 2021 22:07:34 +0000 Subject: greatly improve fltk browser user interface --- frontends/fltk/window.cpp | 618 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 482 insertions(+), 136 deletions(-) diff --git a/frontends/fltk/window.cpp b/frontends/fltk/window.cpp index 19aa26556..fffc38064 100644 --- a/frontends/fltk/window.cpp +++ b/frontends/fltk/window.cpp @@ -24,11 +24,17 @@ #include #include #include +#include #include +#include +#include +#include extern "C" { #include "utils/errors.h" +#include "utils/nsoption.h" +#include "utils/nsurl.h" #include "netsurf/types.h" #include "netsurf/mouse.h" #include "netsurf/window.h" @@ -36,6 +42,7 @@ extern "C" { #include "netsurf/content.h" #include "netsurf/browser_window.h" #include "netsurf/mouse.h" +#include "desktop/browser_history.h" } @@ -44,10 +51,16 @@ extern "C" { extern bool nsfltk_done; +struct gui_window { + class NS_Window *window; +}; + class NS_Widget : public Fl_Widget { private: - struct browser_window *mbw; + struct browser_window *m_bw; + int m_xoffset; + int m_yoffset; protected: void draw(); @@ -55,38 +68,19 @@ protected: public: NS_Widget(int X,int Y,int W,int H, struct browser_window *bw) - : Fl_Widget(X,Y,W,H), mbw(bw) {} -}; - - -class NS_Window : public Fl_Double_Window -{ -private: - struct browser_window *mbw; - NS_Widget *mnswidget; - - void close_callback(Fl_Widget *w); - static void static_close_callback(Fl_Widget *w, void *f) { ((NS_Window *)f)->close_callback(w); } + : Fl_Widget(X,Y,W,H), m_bw(bw), m_xoffset(0), m_yoffset(0) {} -public: - NS_Window(int W, int H, struct browser_window *bw) - : Fl_Double_Window(W,H), mbw(bw) { - this->callback(static_close_callback, (void *)this); - mnswidget = new NS_Widget(0, 0, W, H, bw); - this->end(); - } - ~NS_Window() { nsfltk_done=true; } + bool get_scroll(int *sx, int *sy); + nserror get_dimensions(int *width, int *height); - NS_Widget *get_nswidget() { return mnswidget; } + nserror invalidate(const struct rect *rect); + void vscroll_callback(Fl_Scrollbar *w); + void hscroll_callback(Fl_Scrollbar *w); }; -struct gui_window { - struct browser_window *bw; - NS_Window *window; -}; /** - * method to handle events on the netsurf browsing widget + * handle events on the netsurf browsing widget */ int NS_Widget::handle(int event) { @@ -99,10 +93,10 @@ int NS_Widget::handle(int event) if (button == FL_LEFT_MOUSE) { state |= BROWSER_MOUSE_PRESS_1; } - browser_window_mouse_click(mbw, + browser_window_mouse_click(m_bw, (browser_mouse_state)state, - Fl::event_x() - x(), - Fl::event_y() - y()); + Fl::event_x() - x() + m_xoffset, + Fl::event_y() - y() + m_yoffset); return 1; case FL_RELEASE: @@ -111,10 +105,10 @@ int NS_Widget::handle(int event) state |= BROWSER_MOUSE_CLICK_1; } - browser_window_mouse_click(mbw, + browser_window_mouse_click(m_bw, (browser_mouse_state)state, - Fl::event_x() - x(), - Fl::event_y() - y()); + Fl::event_x() - x() + m_xoffset, + Fl::event_y() - y() + m_yoffset); return 1; default: @@ -124,7 +118,7 @@ int NS_Widget::handle(int event) /** - * method to redraw the netsurf browsing widget + * redraw the netsurf browsing widget */ void NS_Widget::draw() { @@ -140,103 +134,352 @@ void NS_Widget::draw() .priv = NULL, }; - browser_window_redraw(mbw, x(), y(), &clip, &ctx); + browser_window_redraw(m_bw, + x() - m_xoffset, + y() - m_yoffset, + &clip, + &ctx); } + /** - * callback when fltk window is closed + * vertical scrollbar position has been changed */ -void NS_Window::close_callback(Fl_Widget *w) +void NS_Widget::vscroll_callback(Fl_Scrollbar *sb) { - browser_window_destroy(mbw); + m_yoffset = sb->value(); + damage(FL_DAMAGE_SCROLL); } + /** - * Create and open a gui window for a browsing context. - * - * The implementing front end must create a context suitable - * for it to display a window referred to as the "gui window". - * - * The frontend will be expected to request the core redraw - * areas of the gui window which have become invalidated - * either from toolkit expose events or as a result of a - * invalidate() call. - * - * Most core operations used by the frontend concerning browser - * windows require passing the browser window context therefor - * the gui window must include a reference to the browser - * window passed here. - * - * If GW_CREATE_CLONE flag is set existing is non-NULL. - * - * \param bw The core browsing context associated with the gui window - * \param existing An existing gui_window, may be NULL. - * \param flags flags to control the gui window creation. - * \return gui window, or NULL on error. + * horizontal scrollbar position has been changed */ -static struct gui_window * -nsfltk_window_create(struct browser_window *bw, - struct gui_window *existing, - gui_window_create_flags flags) +void NS_Widget::hscroll_callback(Fl_Scrollbar *sb) { - struct gui_window *gw; - gw = (struct gui_window *)calloc(1, sizeof(struct gui_window)); - - gw->window = new NS_Window(800,600, bw); + m_xoffset = sb->value(); + damage(FL_DAMAGE_SCROLL); +} - gw->window->show(); +/** + * get the current scroll offsets + */ +bool NS_Widget::get_scroll(int *sx, int *sy) +{ + *sx = m_xoffset; + *sy = m_yoffset; - return gw; + return true; } + /** - * Destroy previously created gui window - * - * \param gw The gui window to destroy. + * get the viewable dimensions of browsing context */ -static void nsfltk_window_destroy(struct gui_window *gw) +nserror NS_Widget::get_dimensions(int *width, int *height) { - Fl::delete_widget(gw->window); - free(gw); + *width = w(); + *height = h(); + + return NSERROR_OK; } /** - * Invalidate an area of a window. - * - * The specified area of the window should now be considered - * out of date. If the area is NULL the entire window must be - * invalidated. It is expected that the windowing system will - * then subsequently cause redraw/expose operations as - * necessary. - * - * \note the frontend should not attempt to actually start the - * redraw operations as a result of this callback because the - * core redraw functions may already be threaded. - * - * \param gw The gui window to invalidate. - * \param rect area to redraw or NULL for the entire window area - * \return NSERROR_OK on success or appropriate error code + * mark an area of the browsing context as invalid */ -static nserror -nsfltk_window_invalidate(struct gui_window *gw, const struct rect *rect) +nserror NS_Widget::invalidate(const struct rect *rect) { - NS_Widget *nswidget; - nswidget = gw->window->get_nswidget(); - if (rect == NULL) { - nswidget->damage(FL_DAMAGE_ALL); + damage(FL_DAMAGE_ALL); + } else { + damage(FL_DAMAGE_ALL, + rect->x0, + rect->y0, + rect->x1 - rect->x0, + rect->y1 - rect->y0); + } + return NSERROR_OK; + +} + +/** + * widget representing url bar + */ +class NS_URLBar : public Fl_Pack +{ +private: + struct browser_window *m_bw; + Fl_Button *m_back_button; + Fl_Button *m_forward_button; + Fl_Input *m_input; + + void back_callback(Fl_Button *button); + void forward_callback(Fl_Button *button); +public: + NS_URLBar(int X,int Y,int W,int H, struct browser_window *bw); + nserror set_url(struct nsurl *url); + + /* static wrapper for fltk callbacks */ + static void static_back_callback(Fl_Widget *w, void *f); + static void static_forward_callback(Fl_Widget *w, void *f); + +}; + +NS_URLBar::NS_URLBar(int X,int Y,int W,int H, struct browser_window *bw) + : Fl_Pack(X,Y,W,H), m_bw(bw) +{ + type(Fl_Pack::HORIZONTAL); + spacing(4); + + m_back_button = new Fl_Button(0,0,H,H, "B"); + m_back_button->callback(static_back_callback, (void *)this); + + m_forward_button = new Fl_Button(0,0,H,H, "F"); + m_forward_button->callback(static_forward_callback, (void *)this); + + m_input = new Fl_Input(0,0,W,H); + + end(); + + resizable(m_input); +} + +nserror NS_URLBar::set_url(struct nsurl *url) +{ + size_t idn_url_l; + char *idn_url_s = NULL; + if (nsurl_get_utf8(url, &idn_url_s, &idn_url_l) == NSERROR_OK) { + m_input->value(idn_url_s, idn_url_l-1); + free(idn_url_s); } else { - nswidget->damage(FL_DAMAGE_ALL, - rect->x0, - rect->y0, - rect->x1 - rect->x0, - rect->y1 - rect->y0); + m_input->value(nsurl_access(url)); } return NSERROR_OK; } +void NS_URLBar::back_callback(Fl_Button *button) +{ + browser_window_history_back(m_bw, false); +} + +void NS_URLBar::forward_callback(Fl_Button *button) +{ + browser_window_history_forward(m_bw, false); +} + + +void NS_URLBar::static_back_callback(Fl_Widget *w, void *f) +{ + ((NS_URLBar *)f)->back_callback((Fl_Button *)w); +} + +void NS_URLBar::static_forward_callback(Fl_Widget *w, void *f) +{ + ((NS_URLBar *)f)->forward_callback((Fl_Button *)w); +} + + +/** + * Class for netsurf window + */ +class NS_Window : public Fl_Double_Window +{ +private: + struct browser_window *m_bw; + + NS_URLBar *m_nsurlbar; + NS_Widget *m_nswidget; + Fl_Scrollbar *m_vscrollbar; + Fl_Scrollbar *m_hscrollbar; + Fl_Output *m_status; + + nserror set_scroll(const struct rect *rect); + void set_status(const char *text); + void set_title(const char *title); + nserror set_extent(int w, int h); + + void close_callback(Fl_Widget *w); + + /* static wrapper for fltk callbacks */ + static void static_close_callback(Fl_Widget *w, void *f); + static void static_hscroll_callback(Fl_Widget *w, void *f); + static void static_vscroll_callback(Fl_Widget *w, void *f); + +public: + NS_Window(int W, int H, struct browser_window *bw); + ~NS_Window() { nsfltk_done=true; } + + /* static wrappers to be able to call instance methods */ + static nserror static_set_scroll(struct gui_window *gw, const struct rect *rect); + static void static_set_status(struct gui_window *gw, const char *text); + static void static_set_title(struct gui_window *gw, const char *title); + + static bool static_get_scroll(struct gui_window *gw, int *sx, int *sy); + static nserror static_set_url(struct gui_window *gw, struct nsurl *url); + + static nserror static_event(struct gui_window *gw, enum gui_window_event event); + static nserror static_invalidate(struct gui_window *gw, const struct rect *rect); + static nserror static_get_dimensions(struct gui_window *gw, int *width, int *height); + static struct gui_window *static_create(struct browser_window *bw, struct gui_window *existing, gui_window_create_flags flags); + static void static_destroy(struct gui_window *gw); +}; + + +/** + * netsurf window class constructor + */ +NS_Window::NS_Window(int W, int H, struct browser_window *bw) + : Fl_Double_Window(W,H), m_bw(bw) +{ + int scrlsize = Fl::scrollbar_size(); + int splitx = (nsoption_int(toolbar_status_size) * W) / 10000; + int urlbarh = scrlsize * 2; + + callback(static_close_callback, (void *)this); + + // url bar + m_nsurlbar = new NS_URLBar(0, 0, W, urlbarh, bw); + + // browser drawing canvas widget + m_nswidget = new NS_Widget(0, + m_nsurlbar->h(), + W - scrlsize, + H - scrlsize - urlbarh, + bw); + + // vertical scrollbar + m_vscrollbar = new Fl_Scrollbar(m_nswidget->w(), + m_nsurlbar->h(), + scrlsize, + m_nswidget->h()); + m_vscrollbar->callback(static_vscroll_callback, (void *)m_nswidget); + m_vscrollbar->value(0, m_nswidget->h(), 0, m_nswidget->h()); + + // horizontal scrollbar + m_hscrollbar = new Fl_Scrollbar(splitx, + m_nswidget->y() + m_nswidget->h(), + m_nswidget->w() - splitx, + scrlsize); + m_hscrollbar->type(FL_HORIZONTAL); + m_hscrollbar->callback(static_hscroll_callback, (void *)m_nswidget); + m_hscrollbar->value(0, m_nswidget->w(), 0, m_nswidget->w()); + + // status text + m_status = new Fl_Output(0, m_hscrollbar->y(), splitx, scrlsize); + end(); + + resizable(m_nswidget); +} + + +/** + * fltk window has been closed + */ +void NS_Window::close_callback(Fl_Widget *w) +{ + browser_window_destroy(m_bw); +} + + + + +/** + * set the status text + */ +void NS_Window::set_status(const char *text) +{ + m_status->value(text); +} + + +/** + * set the window title text + */ +void NS_Window::set_title(const char *text) +{ + label(text); +} + + +/** + * set the current position of the scroll bars + */ +nserror NS_Window::set_scroll(const struct rect *rect) +{ + m_vscrollbar->value(rect->y0); + m_hscrollbar->value(rect->x0); + + m_nswidget->vscroll_callback(m_vscrollbar); + m_nswidget->hscroll_callback(m_hscrollbar); + + return NSERROR_OK; +} + + +/** + * Set the extent of the underlying canvas + */ +nserror NS_Window::set_extent(int ew, int eh) +{ + m_hscrollbar->value(0, w(), 0, ew); + m_vscrollbar->value(0, h(), 0, eh); + + return NSERROR_OK; +} + + +/* static methods */ + +/** + * static window close fltk callback which calls the instance + */ +void NS_Window::static_close_callback(Fl_Widget *w, void *f) +{ + ((NS_Window *)f)->close_callback(w); +} + +/** + * static vertical scrollbar fltk callback which calls the instance + */ +void NS_Window::static_vscroll_callback(Fl_Widget *w, void *f) +{ + ((NS_Widget *)f)->vscroll_callback((Fl_Scrollbar *)w); +} + +/** + * static horizontal scrollbar fltk callback which calls the instance + */ +void NS_Window::static_hscroll_callback(Fl_Widget *w, void *f) +{ + ((NS_Widget *)f)->hscroll_callback((Fl_Scrollbar *)w); +} + + +/** + * Set the status bar message of a browser window. + * + * \param g gui_window to update + * \param text new status text + */ +void NS_Window::static_set_status(struct gui_window *gw, const char *text) +{ + ((NS_Window *)gw->window)->set_status(text); +} + + +/** + * Set the title of a window. + * + * \param gw The gui window to set title of. + * \param title new window title + */ +void NS_Window::static_set_title(struct gui_window *gw, const char *title) +{ + ((NS_Window *)gw->window)->set_title(title); +} + /** * Get the scroll position of a browser window. @@ -246,17 +489,17 @@ nsfltk_window_invalidate(struct gui_window *gw, const struct rect *rect) * \param sy receives y ordinate of point at top-left of window * \return true iff successful */ -static bool nsfltk_window_get_scroll(struct gui_window *gw, int *sx, int *sy) +bool NS_Window::static_get_scroll(struct gui_window *gw, int *sx, int *sy) { - return false; + return gw->window->m_nswidget->get_scroll(sx, sy); } /** * Set the scroll position of a browser window. * - * scrolls the viewport to ensure the specified rectangle of - * the content is shown. + * scrolls the viewport to ensure the specified rectangle of the + * content is shown. * If the rectangle is of zero size i.e. x0 == x1 and y0 == y1 * the contents will be scrolled so the specified point in the * content is at the top of the viewport. @@ -268,10 +511,80 @@ static bool nsfltk_window_get_scroll(struct gui_window *gw, int *sx, int *sy) * \param rect The rectangle to ensure is shown. * \return NSERROR_OK on success or appropriate error code. */ -static nserror -nsfltk_window_set_scroll(struct gui_window *gw, const struct rect *rect) +nserror +NS_Window::static_set_scroll(struct gui_window *gw, const struct rect *rect) { - return NSERROR_OK; + return gw->window->set_scroll(rect); +} + + +/** + * Set the navigation url. + * + * \param gw window to update. + * \param url The url to use as icon. + */ +nserror NS_Window::static_set_url(struct gui_window *gw, struct nsurl *url) +{ + return gw->window->m_nsurlbar->set_url(url); +} + + +/** + * Miscellaneous event occurred for a window + * + * This is used to inform the frontend of window events which + * require no additional parameters. + * + * \param gw The gui window the event occurred for + * \param event Which event has occurred. + * \return NSERROR_OK if the event was processed else error code. + */ +nserror +NS_Window::static_event(struct gui_window *gw, enum gui_window_event event) +{ + nserror res; + + switch (event) { + case GW_EVENT_UPDATE_EXTENT: + { + int w, h; + + res = browser_window_get_extents(gw->window->m_bw, true, &w, &h); + if (res == NSERROR_OK) { + res = (gw->window)->set_extent(w, h); + } + break; + } + default: + res = NSERROR_OK; + break; + } + return res; +} + + +/** + * Invalidate an area of a window. + * + * The specified area of the window should now be considered + * out of date. If the area is NULL the entire window must be + * invalidated. It is expected that the windowing system will + * then subsequently cause redraw/expose operations as + * necessary. + * + * \note the frontend should not attempt to actually start the + * redraw operations as a result of this callback because the + * core redraw functions may already be threaded. + * + * \param gw The gui window to invalidate. + * \param rect area to redraw or NULL for the entire window area + * \return NSERROR_OK on success or appropriate error code + */ +nserror +NS_Window::static_invalidate(struct gui_window *gw, const struct rect *rect) +{ + return gw->window->m_nswidget->invalidate(rect); } @@ -289,47 +602,80 @@ nsfltk_window_set_scroll(struct gui_window *gw, const struct rect *rect) * \return NSERROR_OK on success and width and height updated * else error code. */ -static nserror -nsfltk_window_get_dimensions(struct gui_window *gw, int *width, int *height) +nserror +NS_Window::static_get_dimensions(struct gui_window *gw, int *width, int *height) { - NS_Widget *nswidget; - nswidget = gw->window->get_nswidget(); - - *width = nswidget->w(); - *height = nswidget->h(); - - return NSERROR_OK; + return gw->window->m_nswidget->get_dimensions(width, height); } /** - * Miscellaneous event occurred for a window + * Create and open a gui window for a browsing context. * - * This is used to inform the frontend of window events which - * require no additional parameters. + * The implementing front end must create a context suitable + * for it to display a window referred to as the "gui window". * - * \param gw The gui window the event occurred for - * \param event Which event has occurred. - * \return NSERROR_OK if the event was processed else error code. + * The frontend will be expected to request the core redraw + * areas of the gui window which have become invalidated + * either from toolkit expose events or as a result of a + * invalidate() call. + * + * Most core operations used by the frontend concerning browser + * windows require passing the browser window context therefor + * the gui window must include a reference to the browser + * window passed here. + * + * If GW_CREATE_CLONE flag is set existing is non-NULL. + * + * \param bw The core browsing context associated with the gui window + * \param existing An existing gui_window, may be NULL. + * \param flags flags to control the gui window creation. + * \return gui window, or NULL on error. */ -static nserror -nsfltk_window_event(struct gui_window *gw, enum gui_window_event event) +struct gui_window * +NS_Window::static_create(struct browser_window *bw, + struct gui_window *existing, + gui_window_create_flags flags) { - return NSERROR_OK; + struct gui_window *gw; + gw = (struct gui_window *)calloc(1, sizeof(struct gui_window)); + + if (gw != NULL) { + gw->window = new NS_Window(800,600, bw); + + gw->window->show(); + } + + return gw; } +/** + * Destroy previously created gui window + * + * \param gw The gui window to destroy. + */ +void NS_Window::static_destroy(struct gui_window *gw) +{ + Fl::delete_widget(gw->window); + free(gw); +} + + +/** + * window operations table for fltk frontend + */ static struct gui_window_table window_table = { - .create = nsfltk_window_create, - .destroy = nsfltk_window_destroy, - .invalidate = nsfltk_window_invalidate, - .get_scroll = nsfltk_window_get_scroll, - .set_scroll = nsfltk_window_set_scroll, - .get_dimensions = nsfltk_window_get_dimensions, - .event = nsfltk_window_event, - .set_title = NULL, - .set_url = NULL, + .create = NS_Window::static_create, + .destroy = NS_Window::static_destroy, + .invalidate = NS_Window::static_invalidate, + .get_scroll = NS_Window::static_get_scroll, + .set_scroll = NS_Window::static_set_scroll, + .get_dimensions = NS_Window::static_get_dimensions, + .event = NS_Window::static_event, + .set_title = NS_Window::static_set_title, + .set_url = NS_Window::static_set_url, .set_icon = NULL, - .set_status = NULL, + .set_status = NS_Window::static_set_status, .set_pointer = NULL, .place_caret = NULL, .drag_start = NULL, -- cgit v1.2.3