diff options
author | Jorge Arellano Cid <jcid@dillo.org> | 2011-03-09 14:20:19 -0300 |
---|---|---|
committer | Jorge Arellano Cid <jcid@dillo.org> | 2011-03-09 14:20:19 -0300 |
commit | 91775fc630020de9f8505fa731272763167cb08e (patch) | |
tree | 6ab3c99c939ed6f795cf76669ed26d2edcf564b2 | |
parent | f8ec6ac86bcc3b9edda3b5edc30d436c3dae839a (diff) |
Made a brand new CustTabs class (to allow fine control of tabs).
-rw-r--r-- | src/ui.hh | 8 | ||||
-rw-r--r-- | src/uicmd.cc | 472 |
2 files changed, 165 insertions, 315 deletions
@@ -35,7 +35,7 @@ typedef enum { // Private classes class CustProgressBox; -class CustTabGroup; +class CustTabs; // Class definition ---------------------------------------------------------- @@ -115,7 +115,7 @@ public: // UI class definition ------------------------------------------------------- // class UI : public Fl_Pack { - CustTabGroup *Tabs; + CustTabs *Tabs; char *TabTooltip; Fl_Group *TopGroup; @@ -172,8 +172,8 @@ public: Fl_Widget *fullscreen_button() { return FullScreen; } void fullscreen_toggle() { FullScreen->do_callback(); } - CustTabGroup *tabs() { return Tabs; } - void tabs(CustTabGroup *tabs) { Tabs = tabs; } + CustTabs *tabs() { return Tabs; } + void tabs(CustTabs *tabs) { Tabs = tabs; } int pointerOnLink() { return PointerOnLink; } void pointerOnLink(int flag) { PointerOnLink = flag; } diff --git a/src/uicmd.cc b/src/uicmd.cc index 0c25a4f4..74cfbb7b 100644 --- a/src/uicmd.cc +++ b/src/uicmd.cc @@ -16,10 +16,11 @@ #include <stdarg.h> #include <math.h> /* for rint */ +#include <FL/Fl.H> #include <FL/Fl_Widget.H> #include <FL/Fl_Double_Window.H> -#include <FL/Fl_Tabs.H> -#include <FL/Fl_Tooltip.H> +#include <FL/Fl_Wizard.H> +#include <FL/Fl_Box.H> #include "paths.hh" #include "keys.hh" @@ -57,321 +58,193 @@ static char *save_dir = NULL; //---------------------------------------------------------------------------- -#if 0 - -#define BTN_W 25 -#define BTN_H 20 -static int btn_x; +/* + * CustTabs --------------------------------------------------------------- + */ /* - * Adds a tab-close button at the rightmost part + * stores the respective UI pointer */ -class CustShrinkTabPager : public TabGroupPager { - bool btn_hl; - TabGroup *tg; +class CustTabButton : public Fl_Button { + UI *ui_; public: - int update_positions( - TabGroup *g, int numchildren, int &selected, - int &cumulated_width, int &available_width, - int *tab_pos, int *tab_width); - virtual int which(TabGroup* g, int m_x,int m_y); - virtual TabGroupPager* clone() const; - virtual const char * mode_name() const {return "Shrink";} - virtual int id() const {return PAGER_SHRINK;} - virtual int available_width(TabGroup *g) const; - virtual bool draw_tabs(TabGroup* g, int selected, int* tab_pos, - int* tab_width) { - if (!tg) tg = g; - if (g->children() > 1) { - fltk::Rectangle r(btn_x,0,BTN_W,BTN_H); - setcolor(btn_hl ? 206 : GRAY75); - fillrect(r); - if (btn_hl) { - setcolor(FL_WHITE); - strokerect(r); - } - setcolor(GRAY10); - //fltk::setfont(fltk::getfont()->bold(), fltk::getsize()); - r.h(r.h()-2); - drawtext("X", r, ALIGN_CENTER); - return false; - } else { - // WORKAROUND: for http://fltk.org/str.php?L2062 - // By returning true we avoid a call to TabGroup::draw_tab() - // in TabGroup::draw() in case we don't show the tabs. - return true; - } - } + CustTabButton (int x,int y,int w,int h, const char* label = 0) : + Fl_Button (x,y,w,h,label) { ui_ = NULL; }; + void ui(UI *pui) { ui_ = pui; } + UI *ui(void) { return ui_; } +}; - void btn_highlight(bool flag) { - if (btn_hl != flag) { - btn_hl = flag; - if (tg) - tg->redraw(DAMAGE_VALUE); - } +/* + * Allows fine control of the tabbed interface + */ +class CustTabs : public CustGroup { + int tab_w, tab_h, tab_n; + Fl_Wizard *Wizard; + int tabcolor_inactive, tabcolor_active, curtab_idx; +public: + CustTabs (int ww, int wh, int th, const char *lbl=0) : + CustGroup(0,0,ww,th,lbl) { + tab_w = 80, tab_h = th, tab_n = 0, curtab_idx = -1; + tabcolor_active = FL_DARK_CYAN; tabcolor_inactive = 206; + //Fl_Box *w = new Fl_Box(tab_w,0,ww-tab_w,tab_h,"i n v i s i b l e"); + Fl_Box *w = new Fl_Box(0,0,0,0,"i n v i s i b l e"); + w->box(FL_NO_BOX); + resizable(0); + end(); + + Wizard = new Fl_Wizard(0,tab_h,ww,wh-tab_h); + Wizard->end(); + add_new_tab(1); }; - bool btn_highlight() { return btn_hl; }; - - CustShrinkTabPager() : TabGroupPager() { - noclip(true); - btn_hl = false; - tg = NULL; - } + int handle(int e); + UI *add_new_tab(int focus); + void remove_tab(); + Fl_Wizard *wizard(void) { return Wizard; } + int get_btn_idx(UI *ui); + void switch_tab(CustTabButton *cbtn); + void prev_tab(void); + void next_tab(void); }; -int CustShrinkTabPager::available_width(TabGroup *g) const -{ - _MSG("CustShrinkTabPager::available_width\n"); - int w = MAX (g->w() - this->slope()-1 - BTN_W, 0); - btn_x = w + 6; - return w; -} - -int CustShrinkTabPager::which(TabGroup* g, int event_x,int event_y) -{ - int H = g->tab_height(); - if (!H) return -1; - if (H < 0) { - if (event_y > g->h() || event_y < g->h()+H) return -1; - } else { - if (event_y > H || event_y < 0) return -1; - } - if (event_x < 0) return -1; - int p[128], w[128]; - int selected = g->tab_positions(p, w); - int d = (event_y-(H>=0?0:g->h()))*slope()/H; - for (int i=0; i<g->children(); i++) { - if (event_x < p[i+1]+(i<selected ? slope() - d : d)) return i; +int CustTabs::handle(int e) +{ + int ret = 0; + + //printf("CustTabs::handle e=%s\n", fl_eventnames[e]); + if (e == FL_KEYUP) { + int k = Fl::event_key(); + // We're only interested in some flags + unsigned modifier = Fl::event_state() & (FL_SHIFT | FL_CTRL | FL_ALT); + if (k == FL_Up || k == FL_Down || k == FL_Tab) { + ; + } else if (k == FL_Left || k == FL_Right) { + if (modifier == FL_SHIFT) { + (k == FL_Left) ? prev_tab() : next_tab(); + ret = 1; + } + } else if (modifier == FL_CTRL) { + if (k == ' ') { + //printf("CustTabs::handle FL_CTRL + Space\n"); + //toggle_cb(NULL, Wizard->value()); + ret = 1; + } else if (k == 't') { + add_new_tab(1); + } else if (k == 'q') { + remove_tab(); + } + } } - return -1; + + return (ret) ? ret : CustGroup::handle(e); } /* - * Prevents tabs from going over the close-tab button. - * Modified from fltk-2.0.x-r6525. + * Create a new tab with its own UI */ -int CustShrinkTabPager::update_positions( - TabGroup *g, int numchildren, int &selected, - int &cumulated_width, int &available_width, - int *tab_pos, int *tab_width) +UI *CustTabs::add_new_tab(int focus) { - available_width-=BTN_W; + char tab_label[64]; - // uh oh, they are too big, we must move them: - // special case when the selected tab itself is too big, make it fill - // cumulated_width: - int i; + current(0); + UI *new_ui = new UI(0,tab_h,Wizard->w(),Wizard->h()); + new_ui->tabs(this); + Wizard->add(new_ui); - if (tab_width[selected] >= available_width) { - tab_width[selected] = available_width; - for (i = 0; i <= selected; i++) - tab_pos[i] = 0; - for (i = selected + 1; i <= numchildren; i++) - tab_pos[i] = available_width; - return selected; - } + int ntabs = children(); + snprintf(tab_label, 64,"ctab%d", ++tab_n); + CustTabButton *btn = new CustTabButton((ntabs-1)*tab_w,0,tab_w,tab_h); + btn->copy_label(tab_label); + btn->clear_visible_focus(); + btn->box(FL_PLASTIC_ROUND_UP_BOX); + btn->color(tabcolor_active); + btn->ui(new_ui); + add(btn); + btn->redraw(); + //btn->callback(tab_btn_cb, this); - int w2[128]; + if (focus) + switch_tab(btn); + rearrange(); - for (i = 0; i < numchildren; i++) - w2[i] = tab_width[i]; - i = numchildren - 1; - int j = 0; + return new_ui; +} - int minsize = 5; +void CustTabs::remove_tab() +{ + CustTabButton *btn; + UI *ui = (UI*)Wizard->value(); - bool right = true; + // the invisible box is also a child + if (children() == 2) + exit(0); - while (cumulated_width > available_width) { - int n; // which one to shrink + // remove label button + int idx = get_btn_idx(ui); + btn = (CustTabButton*)child(idx); + idx > 1 ? prev_tab() : next_tab(); + remove(idx); + delete btn; + rearrange(); + redraw(); - if (j < selected && (!right || i <= selected)) { // shrink a left one - n = j++; - right = true; - } else if (i > selected) { // shrink a right one - n = i--; - right = false; - } else { // no more space, start making them zero - minsize = 0; - i = numchildren - 1; - j = 0; - right = true; - continue; - } - cumulated_width -= w2[n] - minsize; - w2[n] = minsize; - if (cumulated_width < available_width) { - w2[n] = available_width - cumulated_width + minsize; - cumulated_width = available_width; - break; - } - } - // re-sum the positions: - cumulated_width = 0; - for (i = 0; i < numchildren; i++) { - cumulated_width += w2[i]; - tab_pos[i+1] = cumulated_width; - } - return selected; + Wizard->remove(ui); + delete(ui); } -TabGroupPager* CustShrinkTabPager::clone() const { - return new CustShrinkTabPager(*this); +int CustTabs::get_btn_idx(UI *ui) +{ + for (int i = children()-1; i; --i) { + CustTabButton *btn = (CustTabButton*)child(i); + if (btn->ui() == ui) + return i; + } + return -1; } -#endif /* custom pager */ -//---------------------------------------------------------------------------- -/* - * For custom handling of keyboard - */ -class CustTabGroup : public Fl_Tabs { - Fl_Tooltip *toolTip; - bool tooltipEnabled; - bool buttonPushed; -public: - CustTabGroup (int x, int y, int ww, int wh, const char *lbl=0) : - Fl_Tabs(x,y,ww,wh,lbl) { - Fl_Group::current(0); - box(FL_NO_BOX); - // The parameter pager is cloned, so free it. -// CustShrinkTabPager *cp = new CustShrinkTabPager(); -// this->pager(cp); -// delete cp; - toolTip = new Fl_Tooltip; - tooltipEnabled = false; - buttonPushed = false; - }; - ~CustTabGroup() { delete toolTip; } - int handle(int e) { - // Don't focus with arrow keys - _MSG("CustTabGroup::handle %d\n", e); -// fltk::Rectangle r(btn_x,0,BTN_W,BTN_H); - if (e == FL_KEYBOARD) { - int k = Fl::event_key(); - // We're only interested in some flags - unsigned modifier = Fl::event_state() & (FL_SHIFT | FL_CTRL | FL_ALT); - if (k == FL_Up || k == FL_Down || k == FL_Tab) { - return 0; - } else if (k == FL_Left || k == FL_Right) { - if (modifier == FL_SHIFT) { - int i = find(value()); - if (k == FL_Left) {i = i ? i-1 : children()-1;} - else {i++; if (i >= children()) i = 0;} - value(child(i)); - return 1; - } - // Avoid focus change. - return 0; - } - } else if (e == FL_RELEASE) { - Fl_Widget *new_focus = which(Fl::event_x(), Fl::event_y()); - - if (new_focus && new_focus != value()) { - // Update the window title - BrowserWindow *bw = a_UIcmd_get_bw_by_widget(new_focus); - const char *title = a_History_get_title(NAV_TOP_UIDX(bw), 1); - - a_UIcmd_set_page_title(bw, title ? title : ""); - } -// custom pager -#if 0 - } else if (e == FL_MOVE) { - CustShrinkTabPager *cstp = (CustShrinkTabPager *) pager(); - if (Fl::event_inside(r) && children() > 1) { - /* We're inside the button area */ - cstp->btn_highlight(true); - if (prefs.show_tooltip) { - /* Prepare the tooltip for pop-up */ - tooltipEnabled = true; - /* We use parent() if available because we are returning 0. - * Returning without having TabGroup processing makes the - * popup event never reach 'this', but it reaches parent() */ - toolTip->enter(parent() ?parent():this, r, "Close current Tab"); - } - return 0; // Change focus - } else { - cstp->btn_highlight(false); - - if (prefs.show_tooltip) { - /* Hide the tooltip or enable it again.*/ - if (tooltipEnabled) { - tooltipEnabled = false; - toolTip->exit(); - } else { - toolTip->enable(); - } - } - } - } else if (e == FL_PUSH && Fl::event_inside(r) && - Fl::event_button() == 1 && children() > 1) { - buttonPushed = true; - return 1; /* non-zero */ - } else if (e == FL_RELEASE) { - if (Fl::event_inside(r) && Fl::event_button() == 1 && - children() > 1 && buttonPushed) { - a_UIcmd_close_bw(a_UIcmd_get_bw_by_widget(value())); - } else { - CustShrinkTabPager *cstp = (CustShrinkTabPager *) pager(); - cstp->btn_highlight(false); - } - buttonPushed = false; -#endif - } else if (e == FL_DRAG) { - /* Ignore this event */ - return 1; - } - int ret = Fl_Tabs::handle(e); +void CustTabs::switch_tab(CustTabButton *cbtn) +{ + int idx; + CustTabButton *btn; + UI *old_ui = (UI*)Wizard->value(); - if (e == FL_PUSH) { - /* WORKAROUND: FLTK raises the window on unhandled clicks, - * which we do not want. - */ - ret = 1; + if (cbtn->ui() != old_ui) { + // Set old tab label to normal color + if ((idx = get_btn_idx(old_ui)) > 0) { + btn = (CustTabButton*)child(idx); + btn->color(tabcolor_inactive); + btn->redraw(); } - return ret; + Wizard->value(cbtn->ui()); + cbtn->color(tabcolor_active); + cbtn->redraw(); } +} - void remove (Fl_Widget *w) { - Fl_Tabs::remove (w); - /* fixup resizable in case we just removed it */ - if (resizable () == w) { - if (children () > 0) - resizable (child (children () - 1)); - else - resizable (NULL); - } +void CustTabs::prev_tab() +{ + int idx; - if (children () < 2) { - box(FL_NO_BOX); - hideLabels (); - } - } + if ((idx = get_btn_idx((UI*)Wizard->value())) > 1) + switch_tab( (CustTabButton*)child(idx-1) ); +} + +void CustTabs::next_tab() +{ + int idx; + + if ((idx = get_btn_idx((UI*)Wizard->value())) > 0 && idx+1 < children()) + switch_tab( (CustTabButton*)child(idx+1) ); +} - void add (Fl_Widget *w) { - Fl_Tabs::add (w); - if (children () > 1) { - box(FL_THIN_UP_BOX); - showLabels (); - } - } - void hideLabels() { - for (int i = children () - 1; i >= 0; i--) - child(i)->resize(x(), y(), w(), h()); - } - void showLabels() { - for (int i = children () - 1; i >= 0; i--) - child(i)->resize(x(), y() + 20, w(), h() - 20); - } -}; //---------------------------------------------------------------------------- static void win_cb (Fl_Widget *w, void *cb_data) { int choice = 1; - CustTabGroup *tabs = (CustTabGroup*) cb_data; + CustTabs *tabs = (CustTabs*) cb_data; if (tabs->children () > 1) choice = a_Dialog_choice5("Window contains more than one tab.", @@ -434,26 +307,19 @@ BrowserWindow *a_UIcmd_browser_window_new(int ww, int wh, win = new Fl_Double_Window(ww, wh); Fl_Group::current(0); -//may need a handler for this -// win->shortcut(0); // Ignore Escape - CustTabGroup *DilloTabs = new CustTabGroup(0, 0, ww, wh); + CustTabs *DilloTabs = new CustTabs(ww, wh, 16); DilloTabs->selection_color(156); win->add(DilloTabs); // Create and set the UI - UI *new_ui = new UI(0, 0, ww, wh, DEFAULT_TAB_LABEL, - old_bw ? BW2UI(old_bw) : NULL); - new_ui->set_status("http://www.dillo.org/"); - new_ui->tabs(DilloTabs); - - DilloTabs->add(new_ui); - DilloTabs->resizable(new_ui); - DilloTabs->window()->resizable(new_ui); - DilloTabs->window()->show(); + UI *new_ui = DilloTabs->add_new_tab(1); + win->resizable(new_ui); + win->show(); + //DilloTabs->window()->show(); if (old_bw == NULL && prefs.xpos >= 0 && prefs.ypos >= 0) { // position the first window according to preferences - new_ui->window()->position(prefs.xpos, prefs.ypos); + DilloTabs->window()->position(prefs.xpos, prefs.ypos); } // Now create the Dw render layout and viewport @@ -492,7 +358,7 @@ BrowserWindow *a_UIcmd_browser_window_new(int ww, int wh, * Create a new Tab. * i.e the new UI and its associated BrowserWindow data structure. */ -static BrowserWindow *UIcmd_tab_new(const void *vbw) +static BrowserWindow *UIcmd_tab_new(const void *vbw, int focus) { _MSG(" UIcmd_tab_new vbw=%p\n", vbw); @@ -508,13 +374,7 @@ static BrowserWindow *UIcmd_tab_new(const void *vbw) 0, vbw); // Create and set the UI - UI *new_ui = new UI(0, 0, ui->w(), ui->h(), DEFAULT_TAB_LABEL, ui); - new_ui->tabs(ui->tabs()); - - new_ui->tabs()->add(new_ui); - new_ui->tabs()->resizable(new_ui); - new_ui->tabs()->window()->resizable(new_ui); - new_ui->tabs()->window()->show(); + UI *new_ui = ui->tabs()->add_new_tab(focus); // Now create the Dw render layout and viewport FltkPlatform *platform = new FltkPlatform (); @@ -553,14 +413,8 @@ void a_UIcmd_close_bw(void *vbw) a_Bw_stop_clients(bw, BW_Root + BW_Img + BW_Force); delete(layout); if (ui->tabs()) { - ui->tabs()->remove(ui); - if (ui->tabs()->value()) - ui->tabs()->value()->take_focus(); - else - ui->tabs()->window()->hide(); + ui->tabs()->remove_tab(); } - delete(ui); - a_Bw_free(bw); } @@ -663,11 +517,7 @@ void a_UIcmd_open_url_nw(BrowserWindow *bw, const DilloUrl *url) */ void a_UIcmd_open_url_nt(void *vbw, const DilloUrl *url, int focus) { - BrowserWindow *new_bw = UIcmd_tab_new(vbw); - - if (focus) - BW2UI(new_bw)->tabs()->value(BW2UI(new_bw)); - + BrowserWindow *new_bw = UIcmd_tab_new(vbw, focus); UIcmd_open_url_nbw(new_bw, url); } @@ -1234,7 +1084,7 @@ void a_UIcmd_set_page_title(BrowserWindow *bw, const char *label) const int size = 128; char title[size]; - if (a_UIcmd_get_bw_by_widget(BW2UI(bw)->tabs()->value()) == bw) { + if (a_UIcmd_get_bw_by_widget(BW2UI(bw)->tabs()->wizard()->value()) == bw) { // This is the focused bw, set window title if (snprintf(title, size, "Dillo: %s", label) >= size) { uint_t i = MIN(size - 4, 1 + a_Utf8_end_of_char(title, size - 8)); |