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