| 
     
      
      
      From: Tomáš E. <eb...@dr...> - 2011-02-07 03:51:13
       
   | 
I reimplemented the elastic/proportional tab widths in following patches. They are already commited in http://drak.ucw.cz/~ebik/git/notion . It is not enabled by default. It has to be selected in frame's style. See example below. I did not included the user documentation in the patches, as we have not the sources of the document "Configuring and Extending Ion with Lua". The document is GPL'ed, thus we should be able to get the sources of the document. I attach it below in the form of the example. Following should be added to your style, to allow 'elastic' algorithm. I also document here options that are already documented in the section "4.3.2 Extra fields for style `frame'" of "Configuring and Extending Ion with Lua". de.defstyle("frame", { --[[ Difference between elastic and proportional is when there is plenty free space and the frame is not shaped. Elastic wants equal sized tabs, with long titles longer. Proportional wants distribute free space equally among the tabs. ]]-- -- frame_tab_width_alg = "equal", frame_tab_width_alg = "elastic", -- frame_tab_width_alg = "proportional", --[[ Minimum size of a tab. This size is maintained as long as no other tab has to be truncated in the case of the 'proportional' or 'elastic' algorithm. Also minimun size of a tab in shaped frame (for all algorithms). ]]-- -- frame_tab_min_w = 100 --[[ Minimum size of an elastic/proportional tab. Elastic/proportional algorithms truncate other tabs rather than shortening a short tab below this size. ]]-- -- frame_propor_tab_min_w = 50 --[[ Minimum size of an elastic/proportional tab. Elastic/proportional algorithms truncate other tabs rather than shortening a short tab below this size. ]]-- -- floatframe_tab_min_w = 50 })  | 
| 
     
      
      
      From: Tomáš E. <eb...@dr...> - 2011-02-07 03:51:13
       
   | 
From: Tomáš Ebenlendr <eb...@uc...>
Only code cosmetics.
---
 ioncore/frame-draw.c |   16 +++++++---------
 1 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/ioncore/frame-draw.c b/ioncore/frame-draw.c
index 7e404c0..086304c 100644
--- a/ioncore/frame-draw.c
+++ b/ioncore/frame-draw.c
@@ -229,10 +229,10 @@ void frame_clear_shape(WFrame *frame)
 
 static void frame_shaped_recalc_bar_size(WFrame *frame, bool complete)
 {
-    int bar_w=0, textw=0, tmaxw=frame->tab_min_w, tmp=0;
+    int bar_w, textw=0, tmaxw=frame->tab_min_w, tmp=0;
     WLListIterTmp itmp;
     WRegion *sub;
-    const char *p;
+    const char *displayname;
     GrBorderWidths bdw;
     char *title;
     uint bdtotal;
@@ -242,6 +242,7 @@ static void frame_shaped_recalc_bar_size(WFrame *frame, bool complete)
         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);
@@ -249,17 +250,16 @@ static void frame_shaped_recalc_bar_size(WFrame *frame, bool complete)
                  +bdw.right+bdw.left);
 
         FRAME_MX_FOR_ALL(sub, frame, itmp){
-            p=region_displayname(sub);
-            if(p==NULL)
+            displayname=region_displayname(sub);
+            if(displayname==NULL)
                 continue;
             
             textw=grbrush_get_text_width(frame->bar_brush,
-                                         p, strlen(p));
+                                         displayname, strlen(displayname));
             if(textw>tmaxw)
                 tmaxw=textw;
         }
 
-        bar_w=frame->bar_max_width_q*REGION_GEOM(frame).w;
         if(bar_w<frame->tab_min_w && 
            REGION_GEOM(frame).w>frame->tab_min_w)
             bar_w=frame->tab_min_w;
@@ -276,9 +276,7 @@ static void frame_shaped_recalc_bar_size(WFrame *frame, bool complete)
             /* Some labels must be truncated */
         }
     }else{
-        bar_w=frame->tab_min_w;
-        if(bar_w>frame->bar_max_width_q*REGION_GEOM(frame).w)
-            bar_w=frame->bar_max_width_q*REGION_GEOM(frame).w;
+        if(bar_w<frame->tab_min_w) bar_w=frame->tab_min_w;
     }
 
     if(complete || frame->bar_w!=bar_w){
-- 
1.7.1
 | 
| 
     
      
      
      From: Tomáš E. <eb...@dr...> - 2011-02-07 03:51:15
       
   | 
From: Tomáš Ebenlendr <eb...@uc...>
Proportional and elastic algorithms for calculating widths of tabs.
---
 ioncore/frame-tabs-recalc.c |  195 +++++++++++++++++++++++++++++++++++++++++++
 ioncore/frame-tabs-recalc.h |   10 ++-
 2 files changed, 204 insertions(+), 1 deletions(-)
diff --git a/ioncore/frame-tabs-recalc.c b/ioncore/frame-tabs-recalc.c
index b6aba01..f2b6679 100644
--- a/ioncore/frame-tabs-recalc.c
+++ b/ioncore/frame-tabs-recalc.c
@@ -7,6 +7,7 @@
  * See the included file LICENSE for details.
  */
 #include <string.h>
+#include <stdlib.h> /* qsort */
 
 #include "common.h"
 #include "names.h"
@@ -142,10 +143,197 @@ static bool tab_sizes_equal(WFrame * frame, bool complete)
 
 /*}}}*/
 
+/*{{{ Proportional/Elastic tab sizes algorithms
+ *    This gives tabs sizes proportional to the contained text.
+ */
+
+/* Failsafes to 'equal' algorithm if there are more tabs.
+ * The result will be same in most cases of many tabs anyway.
+ */
+#define PROPOR_MAX_TABS 30
+
+static int intcompare (const void *a, const void *b) {
+    return *(int *)a-*(int *)b;
+}
+
+static bool tab_sizes_propor_elastic(WFrame * frame, bool complete, bool proportional)
+{
+    int bar_w, titles_total=0;
+    int titles_padded_total1=0, titles_padded_total2=0;
+    WRectangle bg;
+    GrBorderWidths bdw=GR_BORDER_WIDTHS_INIT;
+    int i, m=frame->titles_n;
+    int iw, min_w=0, max_w, w;
+    int sorted_sizes[PROPOR_MAX_TABS];
+    uint bdtotal;
+
+    if (m>PROPOR_MAX_TABS)
+        return tab_sizes_equal(frame, complete);
+
+
+    frame_bar_geom(frame, &bg);
+    grbrush_get_border_widths(frame->bar_brush, &bdw);
+
+    if (frame->barmode==FRAME_BAR_SHAPED) {
+        bar_w=frame->tabs_params.bar_max_width_q*REGION_GEOM(frame).w;
+    } else {
+        bar_w=bg.w;
+        frame->bar_w=bar_w;
+    }
+
+    get_titles_text_width(frame);
+
+    /* Calculate thresholds. */
+    for (i=0;i<m;i++) {
+        iw=sorted_sizes[i]=frame->titles[i].iw;
+        titles_total+=
+            (iw<frame->tabs_params.propor_tab_min_w ?
+             frame->tabs_params.propor_tab_min_w : iw);
+        titles_padded_total1+=
+            (iw < frame->tabs_params.propor_tab_min_w-2*frame->tabs_params.requested_pad ?
+             frame->tabs_params.propor_tab_min_w : iw+2*frame->tabs_params.requested_pad);
+        titles_padded_total2+=
+            (iw < frame->tabs_params.tab_min_w-2*frame->tabs_params.requested_pad ?
+             frame->tabs_params.tab_min_w : iw+2*frame->tabs_params.requested_pad);
+    }
+    bdtotal=((m-1)*(bdw.tb_ileft+bdw.tb_iright+bdw.spacing)
+            +bdw.right+bdw.left);
+    w=bar_w-bdtotal;
+
+    /* Do different things based on thresholds. */
+    if (m*frame->tabs_params.propor_tab_min_w>=w) {
+        /*Equal sizes (tiny tabs). Base width is zero.*/
+        for(i=0;i<m;i++)
+            frame->titles[i].iw=0;
+    } else if (titles_total>=w) {
+        /*Truncate long tabs.*/
+        qsort(sorted_sizes, m, sizeof(int), intcompare);
+        min_w=frame->tabs_params.propor_tab_min_w;
+        max_w=sorted_sizes[m-1];titles_total=0;
+        for(i=0;i<m;i++){
+            if (sorted_sizes[i]>frame->tabs_params.propor_tab_min_w)
+                break;
+            titles_total+=frame->tabs_params.propor_tab_min_w;
+        }
+        for(;i<m;i++){
+            if (titles_total+sorted_sizes[i]*(m-i)>=w) {
+                max_w=(w-titles_total)/(m-i);
+                break;
+            }
+            titles_total+=sorted_sizes[i];
+        }
+        for(i=0;i<m;i++)
+            if (frame->titles[i].iw>max_w)
+                frame->titles[i].iw=max_w;
+    } else if (titles_padded_total1>=w) {
+        /*Just a little padding.
+         *Pad equally, no tab shorter than tabs_params.propor_tab_min_w-1.
+         */
+        max_w=frame->tabs_params.propor_tab_min_w;
+equal_pad:
+        qsort(sorted_sizes, m, sizeof(int), intcompare);
+        titles_total=m*max_w;
+        i=m-1;min_w=0;
+        while((i>=0) &&
+              (sorted_sizes[i]>=max_w)){
+            titles_total+=sorted_sizes[i];
+            i--;
+        }
+        while(i>=0){
+            /*Test padding by max_w-sorted_sizes[i].*/
+            if(titles_total-(m-i-1)*sorted_sizes[i]>=w){
+                min_w=(titles_total-w)/(m-i-1);
+                break;
+            }
+            titles_total+=sorted_sizes[i];
+            i--;
+        }
+        /* After expanding to min_w: equal padding will extend short tabs to
+         * required size (+- 1pixel).
+         */
+
+    } else if (titles_padded_total2>=w) {
+        /* Expand as many short tabs as possible to equal size,
+         * they will be shorter than tabs_params.tab_min_w anyway.
+         * Long tabs should be padded by 2*tabs_params.requested_pad.
+         */
+equal_tab:
+        qsort(sorted_sizes, m, sizeof(int), intcompare);
+        min_w=0;titles_total=2*m*frame->tabs_params.requested_pad;
+        for(i=m-1;i>=0;i--){
+            if (sorted_sizes[i]*(i+1)+titles_total<=w){
+                min_w=(w-titles_total)/(i+1);
+                break;
+            }
+            titles_total+=sorted_sizes[i];
+        }
+        /* After expanding to min_w: it should remain
+         * 2*m*tabs_params.requested_pad +- m
+         */
+    } else if (frame->barmode==FRAME_BAR_SHAPED) {
+        /* Shorter bar. */
+        w=titles_padded_total2;
+        bar_w=w+bdtotal;
+        min_w=frame->tabs_params.tab_min_w-2*frame->tabs_params.requested_pad;
+        /* After expanding to min_w: it should remain
+         * 2*m*tabs_params.requested_pad exactly
+         */
+    } else {
+        if(proportional){
+            /* Pad equally, no tab shorter than tabs_params.tab_min_w-1. */
+            max_w=frame->tabs_params.tab_min_w;
+            goto equal_pad;
+        }else{
+        /* Expand as many short tabs as possible to equal size,
+         * Long tabs should be padded by 2*tabs_params.requested_pad.
+         */
+            goto equal_tab;
+        }
+    }
+    if (min_w>0) {
+        for(i=0;i<m;i++)
+            if (frame->titles[i].iw<min_w)
+                frame->titles[i].iw=min_w;
+    }
+        
+
+    /* Calculate remaining space */
+    titles_total=0;
+    for(i=0;i<m;i++)
+        titles_total+=frame->titles[i].iw;
+    w-=titles_total;
+    /* Distribute remaining space equally up to 1 pixel */
+    for(i=0;i<m;i++)
+        frame->titles[i].iw+=((i+1)*w)/m-(i*w)/m;
+
+    if((frame->bar_w!=bar_w)){
+        frame->bar_w=bar_w;
+        return TRUE;
+    }
+    return complete;
+}
+
+
+static bool tab_sizes_proportional(WFrame * frame, bool complete)
+{
+    return tab_sizes_propor_elastic(frame, complete, TRUE);
+}
+
+static bool tab_sizes_elastic(WFrame * frame, bool complete)
+{
+    return tab_sizes_propor_elastic(frame, complete, FALSE);
+}
+
+
+
+/*}}}*/
+
 DECLFUNPTRMAP(TabCalcPtr);
 
 static StringTabCalcPtrMap frame_tabs_width_algorithms[] = {
     { "equal", tab_sizes_equal },
+    { "elastic", tab_sizes_elastic },
+    { "proportional", tab_sizes_proportional },
     END_STRINGPTRMAP
 };
 
@@ -156,6 +344,7 @@ static TabCalcPtr default_frame_tabs_width_algorithm=tab_sizes_equal;
 static void param_init(TabCalcParams *pars)
 {
     pars->tab_min_w=100;
+    pars->propor_tab_min_w=50;
     pars->bar_max_width_q=0.95;
     pars->requested_pad=10;
     pars->alg=default_frame_tabs_width_algorithm;
@@ -177,6 +366,12 @@ void frame_tabs_calc_brushes_updated(WFrame *frame)
             pars->tab_min_w=1;
     }
     
+    if(grbrush_get_extra(frame->brush, "frame_propor_tab_min_w",
+                         'i', &(pars->propor_tab_min_w))){
+        if(pars->propor_tab_min_w<=0)
+            pars->propor_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)
diff --git a/ioncore/frame-tabs-recalc.h b/ioncore/frame-tabs-recalc.h
index 2472aac..2c60701 100644
--- a/ioncore/frame-tabs-recalc.h
+++ b/ioncore/frame-tabs-recalc.h
@@ -43,10 +43,18 @@ DECLSTRUCT(TabCalcParams){
     TabCalcPtr alg;
     /* Maximum size of shaped bar. */
     double bar_max_width_q;
-    /* Requested size of the tab. */
+    /* Minimum width of a tab in shaped frame.
+     * For 'proportional' and 'elastic' algorithms also minimum width of a tab
+     * provided that no title has to be truncated
+     */
     int tab_min_w;
     /* Requested empty space to be added before and after text. */
     int requested_pad;
+    /* Minimum width of a tab for 'proportional' and 'elastic' algorithms.
+     * Long titles will be truncated instead of shortening a short tab below
+     * this length.
+     */
+    int propor_tab_min_w;
 };
 
 void frame_tabs_calc_brushes_updated(WFrame *frame);
-- 
1.7.1
 | 
| 
     
      
      
      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
 | 
| 
     
      
      
      From: Tomáš E. <eb...@dr...> - 2011-02-07 03:51:15
       
   | 
From: Tomáš Ebenlendr <eb...@uc...>
If title of a tab is changed, then do complete recalculation. New
algorithms will change the tab widths on title change.
---
 ioncore/frame.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/ioncore/frame.c b/ioncore/frame.c
index ce865d5..01cd891 100644
--- a/ioncore/frame.c
+++ b/ioncore/frame.c
@@ -760,6 +760,8 @@ bool frame_set_grattr_extl(WFrame *frame, const char *attr, const char *how)
 
 void frame_managed_notify(WFrame *frame, WRegion *sub, WRegionNotify how)
 {
+    bool complete;
+
     if(how==ioncore_g.notifies.activated ||
        how==ioncore_g.notifies.inactivated ||
        how==ioncore_g.notifies.name ||
@@ -767,9 +769,11 @@ void frame_managed_notify(WFrame *frame, WRegion *sub, WRegionNotify how)
        how==ioncore_g.notifies.sub_activity ||
        how==ioncore_g.notifies.tag){
        
+        complete=how==ioncore_g.notifies.name;
+       
         frame_update_attrs(frame);
-        frame_recalc_bar(frame, FALSE);
-        frame_draw_bar(frame, FALSE);
+        frame_recalc_bar(frame, complete);
+        frame_draw_bar(frame, complete);
     }
 }
 
-- 
1.7.1
 | 
| 
     
      
      
      From: Arnout E. <no...@bz...> - 2011-02-07 22:57:57
       
   | 
On Mon, Feb 07, 2011 at 04:50:59AM +0100, Tomáš Ebenlendr wrote:
> @@ -767,9 +769,11 @@ void frame_managed_notify(WFrame *frame, WRegion *sub, WRegionNotify how)
>         how==ioncore_g.notifies.sub_activity ||
>         how==ioncore_g.notifies.tag){
>         
> +        complete=how==ioncore_g.notifies.name;
Shouldn't that use strcmp?
Arnout
 | 
| 
     
      
      
      From: Arnout E. <no...@bz...> - 2011-02-08 00:57:34
       
   | 
On Tue, Feb 08, 2011 at 12:02:00AM +0100, ebik wrote:
> The condition is just copied from place just few lines above (in the
> same function). I did not checked how and why the condition works.
Those strings are from the 'stringstore' (a libtu thing), which appear to 
be (refcounted) constants, so I guess it'd be OK to compare them with ==. 
Arnout
> On Mon, 7 Feb 2011 23:57:47 +0100
> Arnout Engelen <no...@bz...> wrote:
> 
> > On Mon, Feb 07, 2011 at 04:50:59AM +0100, Tomáš Ebenlendr wrote:
> > > @@ -767,9 +769,11 @@ void frame_managed_notify(WFrame *frame,
> > > WRegion *sub, WRegionNotify how)
> > > how==ioncore_g.notifies.sub_activity ||
> > > how==ioncore_g.notifies.tag){ 
> > > +        complete=how==ioncore_g.notifies.name;
> > 
> > Shouldn't that use strcmp?
> > 
> > 
> > Arnout
> > 
> 
> 
> -- 
>                                  Tomáš 'ebík' Ebenlendr
>                                  PF 2011.10410813039
> 
 | 
| 
     
      
      
      From: Ole J. B. <ole...@ya...> - 2011-02-08 14:31:49
       
   | 
http://folk.ntnu.no/bronner/temp/ion3/ion-doc-3.tgz should contain the latex sources (and the darcs repo). I thought I had uploaded the repo before, but apparently I had only included the html files. Sorry about that. -- Ole Jørgen Brønner On Mon, 07 Feb 2011 04:50:56 +0100, Tomáš Ebenlendr <eb...@dr...> wrote: > I did not included the user documentation in the patches, as we have not the > sources of the document "Configuring and Extending Ion with Lua". The document > is GPL'ed, thus we should be able to get the sources of the document. I attach > it below in the form of the example.  | 
| 
     
      
      
      From: Ole J. B. <ole...@ya...> - 2011-02-08 14:39:48
       
   | 
If someone managed to grab that already, it was slightly dirty. Fixed now. http://folk.ntnu.no/bronner/temp/ion3/ion-doc-3.tgz - Ole Jørgen Brønner On Tue, 08 Feb 2011 15:31:38 +0100, Ole Jørgen Brønner <ole...@ya...> wrote: > http://folk.ntnu.no/bronner/temp/ion3/ion-doc-3.tgz should contain the latex sources (and the darcs repo). I thought I had uploaded the repo before, but apparently I had only included the html files. Sorry about that.  | 
| 
     
      
      
      From: Arnout E. <no...@bz...> - 2011-02-12 00:02:58
       
   | 
The patches look good and a quick tests reveals no regressions, so I applied them, thanks! I successfully imported the documentation with history into a git repo. Unfortunately sf.net shell services are still inactive due to a recent hack attack, so I can't create a repo for the documentation there yet. This is also the reason why we don't have a working notion-commits mailinglist yet :). For the time being I put it up at: http://arnout.engelen.eu/files/dev/notion/notion-doc.git Kind regards, Arnout On Mon, Feb 07, 2011 at 04:50:56AM +0100, Tomáš Ebenlendr wrote: > I reimplemented the elastic/proportional tab widths in following patches. > They are already commited in http://drak.ucw.cz/~ebik/git/notion . > > > It is not enabled by default. It has to be selected in frame's style. See > example below. > > I did not included the user documentation in the patches, as we have not the > sources of the document "Configuring and Extending Ion with Lua". The document > is GPL'ed, thus we should be able to get the sources of the document. I attach > it below in the form of the example. > > Following should be added to your style, to allow 'elastic' algorithm. I also > document here options that are already documented in the section "4.3.2 Extra > fields for style `frame'" of "Configuring and Extending Ion with Lua". > > de.defstyle("frame", { > --[[ > Difference between elastic and proportional is when there is plenty free > space and the frame is not shaped. Elastic wants equal sized tabs, with > long titles longer. Proportional wants distribute free space equally > among the tabs. > ]]-- > -- frame_tab_width_alg = "equal", > frame_tab_width_alg = "elastic", > -- frame_tab_width_alg = "proportional", > > --[[ > Minimum size of a tab. > This size is maintained as long as no other tab has to be truncated in the > case of the 'proportional' or 'elastic' algorithm. > Also minimun size of a tab in shaped frame (for all algorithms). > ]]-- > -- frame_tab_min_w = 100 > > --[[ > Minimum size of an elastic/proportional tab. > Elastic/proportional algorithms truncate other tabs rather than shortening > a short tab below this size. > ]]-- > -- frame_propor_tab_min_w = 50 > > --[[ > Minimum size of an elastic/proportional tab. > Elastic/proportional algorithms truncate other tabs rather than shortening > a short tab below this size. > ]]-- > -- floatframe_tab_min_w = 50 > }) > > ------------------------------------------------------------------------------ > The modern datacenter depends on network connectivity to access resources > and provide services. The best practices for maximizing a physical server's > connectivity to a physical network are well understood - see how these > rules translate into the virtual world? > http://p.sf.net/sfu/oracle-sfdevnlfb > _______________________________________________ > Notion-devel mailing list > Not...@li... > https://lists.sourceforge.net/lists/listinfo/notion-devel  | 
| 
     
      
      
      From: Arnout E. <no...@bz...> - 2011-02-13 11:37:57
       
   | 
On Mon, Feb 07, 2011 at 04:50:56AM +0100, Tomáš Ebenlendr wrote: > I did not included the user documentation in the patches, as we have not the > sources of the document "Configuring and Extending Ion with Lua". The document > is GPL'ed, thus we should be able to get the sources of the document. I attach > it below in the form of the example. Added it to the documentation at http://notion.git.sourceforge.net/git/gitweb.cgi?p=notion/notion-doc;a=commit;h=612d28deda20196dd9908bec3a15abe328d56f3a I think it'd be neat to include the example somewhere, too, but I'm not sure where. Kind regards, Arnout > de.defstyle("frame", { > --[[ > Difference between elastic and proportional is when there is plenty free > space and the frame is not shaped. Elastic wants equal sized tabs, with > long titles longer. Proportional wants distribute free space equally > among the tabs. > ]]-- > -- frame_tab_width_alg = "equal", > frame_tab_width_alg = "elastic", > -- frame_tab_width_alg = "proportional", > > --[[ > Minimum size of a tab. > This size is maintained as long as no other tab has to be truncated in the > case of the 'proportional' or 'elastic' algorithm. > Also minimun size of a tab in shaped frame (for all algorithms). > ]]-- > -- frame_tab_min_w = 100 > > --[[ > Minimum size of an elastic/proportional tab. > Elastic/proportional algorithms truncate other tabs rather than shortening > a short tab below this size. > ]]-- > -- frame_propor_tab_min_w = 50 > > --[[ > Minimum size of an elastic/proportional tab. > Elastic/proportional algorithms truncate other tabs rather than shortening > a short tab below this size. > ]]-- > -- floatframe_tab_min_w = 50 > })  |