From: Tomáš E. <eb...@dr...> - 2011-02-07 03:51:15
|
From: Tomáš Ebenlendr <eb...@uc...> Move the algorithm to calculate sizes of tabs and bar to separate file. Add framework to allow more named algorithms. Allow switching such algorithms using style. --- ioncore/Makefile | 2 +- ioncore/frame-draw.c | 108 ++++------------------- ioncore/frame-tabs-recalc.c | 206 +++++++++++++++++++++++++++++++++++++++++++ ioncore/frame-tabs-recalc.h | 54 +++++++++++ ioncore/frame.c | 49 ++-------- ioncore/frame.h | 6 +- 6 files changed, 291 insertions(+), 134 deletions(-) create mode 100644 ioncore/frame-tabs-recalc.c create mode 100644 ioncore/frame-tabs-recalc.h diff --git a/ioncore/Makefile b/ioncore/Makefile index de7529d..6e0b865 100644 --- a/ioncore/Makefile +++ b/ioncore/Makefile @@ -24,7 +24,7 @@ SOURCES=binding.c conf-bindings.c cursor.c event.c exec.c focus.c \ pholder.c mplexpholder.c llist.c basicpholder.c sizepolicy.c \ stacking.c group.c grouppholder.c group-cw.c navi.c \ group-ws.c float-placement.c framedpholder.c \ - return.c detach.c screen-notify.c + return.c detach.c screen-notify.c frame-tabs-recalc.c LUA_SOURCES=\ ioncore_ext.lua ioncore_luaext.lua ioncore_bindings.lua \ diff --git a/ioncore/frame-draw.c b/ioncore/frame-draw.c index 086304c..7ee2491 100644 --- a/ioncore/frame-draw.c +++ b/ioncore/frame-draw.c @@ -224,80 +224,12 @@ void frame_clear_shape(WFrame *frame) } -#define CF_TAB_MAX_TEXT_X_OFF 10 - - -static void frame_shaped_recalc_bar_size(WFrame *frame, bool complete) -{ - int bar_w, textw=0, tmaxw=frame->tab_min_w, tmp=0; - WLListIterTmp itmp; - WRegion *sub; - const char *displayname; - GrBorderWidths bdw; - char *title; - uint bdtotal; - int i, m; - - if(frame->bar_brush==NULL) - return; - - m=FRAME_MCOUNT(frame); - bar_w=frame->bar_max_width_q*REGION_GEOM(frame).w; - - if(m>0){ - grbrush_get_border_widths(frame->bar_brush, &bdw); - bdtotal=((m-1)*(bdw.tb_ileft+bdw.tb_iright+bdw.spacing) - +bdw.right+bdw.left); - - FRAME_MX_FOR_ALL(sub, frame, itmp){ - displayname=region_displayname(sub); - if(displayname==NULL) - continue; - - textw=grbrush_get_text_width(frame->bar_brush, - displayname, strlen(displayname)); - if(textw>tmaxw) - tmaxw=textw; - } - - if(bar_w<frame->tab_min_w && - REGION_GEOM(frame).w>frame->tab_min_w) - bar_w=frame->tab_min_w; - - tmp=bar_w-bdtotal-m*tmaxw; - - if(tmp>0){ - /* No label truncation needed, good. See how much can be padded. */ - tmp/=m*2; - if(tmp>CF_TAB_MAX_TEXT_X_OFF) - tmp=CF_TAB_MAX_TEXT_X_OFF; - bar_w=(tmaxw+tmp*2)*m+bdtotal; - }else{ - /* Some labels must be truncated */ - } - }else{ - if(bar_w<frame->tab_min_w) bar_w=frame->tab_min_w; - } - - if(complete || frame->bar_w!=bar_w){ - frame->bar_w=bar_w; - frame_set_shape(frame); - } -} - - -static int init_title(WFrame *frame, int i) +static void free_title(WFrame *frame, int i) { - int textw; - if(frame->titles[i].text!=NULL){ free(frame->titles[i].text); frame->titles[i].text=NULL; } - - textw=frame_nth_tab_iw((WFrame*)frame, i); - frame->titles[i].iw=textw; - return textw; } @@ -307,19 +239,25 @@ void frame_recalc_bar(WFrame *frame, bool complete) WLListIterTmp tmp; WRegion *sub; char *title; + bool set_shape; if(frame->bar_brush==NULL || frame->titles==NULL) return; - - if(frame->barmode==FRAME_BAR_SHAPED) - frame_shaped_recalc_bar_size(frame, complete); - else if(complete) - frame_clear_shape(frame); + + set_shape=frame->tabs_params.alg(frame,complete); + + if(set_shape) { + if(frame->barmode==FRAME_BAR_SHAPED) + frame_set_shape(frame); + else + frame_clear_shape(frame); + } i=0; if(FRAME_MCOUNT(frame)==0){ - textw=init_title(frame, i); + free_title(frame, i); + textw=frame->titles[i].iw; if(textw>0){ title=grbrush_make_label(frame->bar_brush, TR("<empty frame>"), textw); @@ -329,7 +267,8 @@ void frame_recalc_bar(WFrame *frame, bool complete) } FRAME_MX_FOR_ALL(sub, frame, tmp){ - textw=init_title(frame, i); + free_title(frame, i); + textw=frame->titles[i].iw; if(textw>0){ title=region_make_label(sub, textw, frame->bar_brush); frame->titles[i].text=title; @@ -426,21 +365,8 @@ void frame_brushes_updated(WFrame *frame) frame->bar_h=bdw.top+bdw.bottom+fnte.max_height; } - /* shaped mode stuff */ - frame->tab_min_w=100; - frame->bar_max_width_q=0.95; - - if(grbrush_get_extra(frame->brush, "floatframe_tab_min_w", - 'i', &(frame->tab_min_w))){ - if(frame->tab_min_w<=0) - frame->tab_min_w=1; - } - - if(grbrush_get_extra(frame->brush, "floatframe_bar_max_w_q", - 'd', &(frame->bar_max_width_q))){ - if(frame->bar_max_width_q<=0.0 || frame->bar_max_width_q>1.0) - frame->bar_max_width_q=1.0; - } + /* tabs and bar width calculation stuff */ + frame_tabs_calc_brushes_updated(frame); } diff --git a/ioncore/frame-tabs-recalc.c b/ioncore/frame-tabs-recalc.c new file mode 100644 index 0000000..b6aba01 --- /dev/null +++ b/ioncore/frame-tabs-recalc.c @@ -0,0 +1,206 @@ +/* + * notion/ioncore/frame-tabs-recalc.c + * + * Copyright (c) Tuomo Valkonen 1999-2009. + * Copyright (c) Tomas Ebenlendr 2011. + * + * See the included file LICENSE for details. + */ +#include <string.h> + +#include "common.h" +#include "names.h" +#include "frame.h" +#include "framep.h" +#include "frame-draw.h" +#include "frame-tabs-recalc.h" + + +/*{{{ Common functions */ + + +/* + * Temporarily store actual title widths (without truncation) in + * frame->titles[*].iw, when calculating tabs widths and bar width. After the + * algorithm returns it has to set frame->titles[*].iw to the proper values. + * + * This function is generic for all algorithms. + */ +static void get_titles_text_width(WFrame *frame) +{ + int i=0; + WLListIterTmp itmp; + WRegion *sub; + const char *displayname; + + /* Assume frame->bar_brush != NULL. + Assume FRAME_MCOUNT(frame) > 0 */ + + FRAME_MX_FOR_ALL(sub, frame, itmp){ + displayname=region_displayname(sub); + if(displayname==NULL) + frame->titles[i].iw=0; + else + frame->titles[i].iw=grbrush_get_text_width(frame->bar_brush, + displayname, strlen(displayname)); + i++; + } +} + +/*}}}*/ + +/*{{{ Equal tab sizes algorithm + * This gives tabs equal sizes (up to 1 pixel). + */ +static void frame_tabs_width_calculate_equal(WFrame *frame) +{ + WRectangle bg; + GrBorderWidths bdw=GR_BORDER_WIDTHS_INIT; + int i,m=frame->titles_n; + uint w; + + frame_bar_geom(frame, &bg); + grbrush_get_border_widths(frame->bar_brush, &bdw); + + /* Remove borders */ + w=bg.w-bdw.left-bdw.right-(bdw.tb_ileft+bdw.tb_iright+bdw.spacing)*(m-1); + + if(w<=0){ + for(i=0;i<m;i++) + frame->titles[i].iw=0; + }else{ + for(i=0;i<m;i++) + /* Get i:th tab's portion of free area */ + frame->titles[i].iw=((i+1)*w)/m-(i*w)/m; + } +} + +/* + Equal tab sizes algorithm. + Calculate size of the bar of a shaped (i.e., floating) frame. +*/ +static int frame_shaped_recalc_bar_size_equal(WFrame *frame) +{ + int bar_w, textw=0, tmaxw=frame->tabs_params.tab_min_w, tmp=0; + GrBorderWidths bdw; + uint bdtotal; + int i, m; + + m=FRAME_MCOUNT(frame); + bar_w=frame->tabs_params.bar_max_width_q*REGION_GEOM(frame).w; + + if(m>0){ + grbrush_get_border_widths(frame->bar_brush, &bdw); + bdtotal=((m-1)*(bdw.tb_ileft+bdw.tb_iright+bdw.spacing) + +bdw.right+bdw.left); + + get_titles_text_width(frame); + for(i=0;i<m;i++) + if(frame->titles[i].iw>tmaxw) + tmaxw=frame->titles[i].iw; + + if(bar_w<frame->tabs_params.tab_min_w && + REGION_GEOM(frame).w>frame->tabs_params.tab_min_w) + bar_w=frame->tabs_params.tab_min_w; + + tmp=bar_w-bdtotal-m*tmaxw; + + if(tmp>0){ + /* No label truncation needed, good. See how much can be padded. */ + tmp/=m*2; + if(tmp>frame->tabs_params.requested_pad) + tmp=frame->tabs_params.requested_pad; + bar_w=(tmaxw+tmp*2)*m+bdtotal; + }else{ + /* Some labels must be truncated */ + } + }else{ + if(bar_w<frame->tabs_params.tab_min_w) bar_w=frame->tabs_params.tab_min_w; + } + + return bar_w; +} + +static bool tab_sizes_equal(WFrame * frame, bool complete) +{ + int bar_w; + + if(frame->barmode==FRAME_BAR_SHAPED){ + bar_w=frame_shaped_recalc_bar_size_equal(frame); + if((frame->bar_w!=bar_w)){ + frame->bar_w=bar_w; + complete=TRUE; + } + } + frame_tabs_width_calculate_equal(frame); + return complete; +} + + + + + +/*}}}*/ + +DECLFUNPTRMAP(TabCalcPtr); + +static StringTabCalcPtrMap frame_tabs_width_algorithms[] = { + { "equal", tab_sizes_equal }, + END_STRINGPTRMAP +}; + +static TabCalcPtr default_frame_tabs_width_algorithm=tab_sizes_equal; + + + +static void param_init(TabCalcParams *pars) +{ + pars->tab_min_w=100; + pars->bar_max_width_q=0.95; + pars->requested_pad=10; + pars->alg=default_frame_tabs_width_algorithm; +} + +void frame_tabs_calc_brushes_updated(WFrame *frame) +{ + char *str; + TabCalcPtr alg; + TabCalcParams *pars=&(frame->tabs_params); + + param_init(pars); + + if(grbrush_get_extra(frame->brush, "floatframe_tab_min_w", + 'i', &(pars->tab_min_w)) || + grbrush_get_extra(frame->brush, "frame_tab_min_w", + 'i', &(pars->tab_min_w))){ + if(pars->tab_min_w<=0) + pars->tab_min_w=1; + } + + if(grbrush_get_extra(frame->brush, "floatframe_bar_max_w_q", + 'd', &(pars->bar_max_width_q))){ + if(pars->bar_max_width_q<=0.0 || pars->bar_max_width_q>1.0) + pars->bar_max_width_q=1.0; + } + + if(grbrush_get_extra(frame->brush, "frame_tab_padding", + 'i', &(pars->requested_pad))){ + if(pars->requested_pad<=0) + pars->requested_pad=1; + } + + if(grbrush_get_extra(frame->brush, "frame_tab_width_alg", + 's', &str)){ + alg=STRINGFUNPTRMAP_VALUE(TabCalcPtr, + frame_tabs_width_algorithms, + str, NULL); + + if(alg!=NULL) + frame->tabs_params.alg=alg; + } +} + +void frame_tabs_width_recalc_init(WFrame *frame) +{ + param_init(&(frame->tabs_params)); +} diff --git a/ioncore/frame-tabs-recalc.h b/ioncore/frame-tabs-recalc.h new file mode 100644 index 0000000..2472aac --- /dev/null +++ b/ioncore/frame-tabs-recalc.h @@ -0,0 +1,54 @@ +/* + * notion/ioncore/frame-tabs-recalc.h + * + * Copyright (c) Tomas Ebenlendr 2011. + * + * See the included file LICENSE for details. + */ + +#ifndef NOTION_IONCORE_FRAME_TABS_RECALC_H +#define NOTION_IONCORE_FRAME_TABS_RECALC_H + +#include "libtu/map.h" +#include "libtu/obj.h" + +/* Compute inner widths of tabs and width of shaped bar. + * There will be more algorithms to do this, thus here + * is prototype of the called function. + * + * Requirements: + * + * If complete is set and frame->barmode==FRAME_BAR_SHAPED + * then frame->bar_w has to be updated. + * return TRUE if bar_w changed (i.e, new value != old value) + * return the value of 'complete' on normal run. + * frame_set_shape or frame_clear_shape is called when TRUE is returned. + * + * The function is called only if + * frame->bar_brush != NULL && frame->titles != NULL + */ +typedef bool (*TabCalcPtr)(WFrame *frame, bool complete); + +/* Gets the identifier of the algorithm. */ +const char *frame_get_tabs_sizes_algorithm(WFrame *frame); + +/* Sets the algorithm based on the identifier. + * Returns -1 on failure, 1 on successfull change, 0 on success but no change + * If 1 is returned, frame_bar_recalc and frame_bar_draw should be called. + */ +int frame_do_set_tabs_sizes_algorithm(WFrame *frame, const char *algstr); + +INTRSTRUCT(TabCalcParams); +DECLSTRUCT(TabCalcParams){ + TabCalcPtr alg; + /* Maximum size of shaped bar. */ + double bar_max_width_q; + /* Requested size of the tab. */ + int tab_min_w; + /* Requested empty space to be added before and after text. */ + int requested_pad; +}; + +void frame_tabs_calc_brushes_updated(WFrame *frame); +void frame_tabs_width_recalc_init(WFrame *frame); +#endif /* NOTION_IONCORE_FRAME_TABS_RECALC_H */ diff --git a/ioncore/frame.c b/ioncore/frame.c index 3598351..ce865d5 100644 --- a/ioncore/frame.c +++ b/ioncore/frame.c @@ -100,8 +100,7 @@ bool frame_init(WFrame *frame, WWindow *parent, const WFitParams *fp, frame->brush=NULL; frame->bar_brush=NULL; frame->mode=mode; - frame->tab_min_w=0; - frame->bar_max_width_q=1.0; + frame_tabs_width_recalc_init(frame); gr_stylespec_init(&frame->baseattr); @@ -282,49 +281,22 @@ int frame_nth_tab_x(WFrame *frame, int n) } -static int frame_nth_tab_w_iw(WFrame *frame, int n, bool inner) +int frame_nth_tab_w(WFrame *frame, int n) { - WRectangle bg; GrBorderWidths bdw=GR_BORDER_WIDTHS_INIT; - int m=FRAME_MCOUNT(frame); - uint w; - - frame_bar_geom(frame, &bg); - - if(m==0) - m=1; - if(frame->bar_brush!=NULL) - grbrush_get_border_widths(frame->bar_brush, &bdw); - - /* Remove borders */ - w=bg.w-bdw.left-bdw.right-(bdw.tb_ileft+bdw.tb_iright+bdw.spacing)*(m-1); - - if(w<=0) + if (n>frame->titles_n){ + fprintf(stderr,"WARNING: we should not be here, please contact notion developers\n"); return 0; - - /* Get n:th tab's portion of free area */ - w=(((n+1)*w)/m-(n*w)/m); - - /* Add n:th tab's borders back */ - if(!inner){ - w+=(n==0 ? bdw.left : bdw.tb_ileft); - w+=(n==m-1 ? bdw.right : bdw.tb_iright+bdw.spacing); } + if(frame->titles[n].iw==0) return 0; /* Too small tab. */ - return w; -} - - -int frame_nth_tab_w(WFrame *frame, int n) -{ - return frame_nth_tab_w_iw(frame, n, FALSE); -} - + if(frame->bar_brush!=NULL) + grbrush_get_border_widths(frame->bar_brush, &bdw); -int frame_nth_tab_iw(WFrame *frame, int n) -{ - return frame_nth_tab_w_iw(frame, n, TRUE); + return frame->titles[n].iw + + (n==0 ? bdw.left : bdw.tb_ileft) + + (n==frame->titles_n-1 ? bdw.right : bdw.tb_iright+bdw.spacing); } @@ -373,7 +345,6 @@ static void frame_free_titles(WFrame *frame) static void do_init_title(WFrame *frame, int i, WRegion *sub) { frame->titles[i].text=NULL; - frame->titles[i].iw=frame_nth_tab_iw(frame, i); gr_stylespec_init(&frame->titles[i].attr); diff --git a/ioncore/frame.h b/ioncore/frame.h index d69c279..048a1d5 100644 --- a/ioncore/frame.h +++ b/ioncore/frame.h @@ -20,6 +20,7 @@ #include "gr.h" #include "rectangle.h" #include "sizehint.h" +#include "frame-tabs-recalc.h" #define FRAME_SAVED_VERT 0x0008 #define FRAME_SAVED_HORIZ 0x0010 @@ -75,8 +76,8 @@ DECLCLASS(WFrame){ /* Bar stuff */ WFrameBarMode barmode; int bar_w, bar_h; - double bar_max_width_q; - int tab_min_w; + /* Parameters to calculate tab sizes. */ + TabCalcParams tabs_params; }; @@ -103,7 +104,6 @@ extern void frame_inactivated(WFrame *frame); /* Tabs */ extern int frame_nth_tab_w(WFrame *frame, int n); -extern int frame_nth_tab_iw(WFrame *frame, int n); extern int frame_nth_tab_x(WFrame *frame, int n); extern int frame_tab_at_x(WFrame *frame, int x); extern void frame_update_attr_nth(WFrame *frame, int i); -- 1.7.1 |