ebik
Sun, 15 Mar 2009 08:25:32 -0700
Here I send patch for proportional tab sizes.
The patch itself is not acceptable because of two (interdependent)
issues:
1.) I haven't time to examine source code to optimize for speed, and
correct flow. (See using of 'complete' flag of
grbrush_draw_textboxes, etc.)
2.) It is the 'first shot' programming, i.e. it just works, but the
code itself is rather ugly (e.g., I haven't put the new function
in header file.)
But I haven't time for cleaning the code for next month or two, so I
send the patch as is.
--------------------------------------------------------------------
The algorithm now works in following way (I omit some border
widths here in the description as well as rounding errors.):
* There are two constants:
- float_tab_min_w (former tab_min_w, default 100)
... that is soft minimum width
- propor_tab_min_w (new, default 30, I did not write code for
redefinig) ... that is hard minimum width
Let "n" be number of tabs.
* If n*propor_tab_min_w is greater than space allocated to tabs
( ~ width of the frame in tiled workspace ), then tabs get sizes
proportionaly like it was before this patch.
|<--->| ... propor_tab_min_w
_____________________________________________
|T|A|B|S|_|T|H|A|T|_|A|R|E|_|T|O|O|_|M|A|N|Y|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Else each tab gets at least propor_tab_min_w (even if it contains
shorter label).
* Now we set max_width to propor_tab_min_w, and we keep incrementing
max_width until all tabs have their width or we use all the space
reserved for tabs. In the latter case we stop and assign the widths
to the tabs.
|<--->| ... propor_tab_min_w
|<-------------->| ... float_tab_min_w
_____________________________________________
| tab | x |a long ta...|another l...| xx |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* At this point all tabs have sizes of their labels (but at least
propor_tab_min_w), but we may have some space left, now
flow_tab_min_w comes to play. We set min_width to propor_tab_min_w
and again we increment it until float_tab_min_w or all the space
reserved for tabs is used. In the latter case we again stop and
assign the widths.
|<-------------->| ... float_tab_min_w
_____________________________________________
|here is a long tab| tab | x |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Now, each tab has at least float_tab_min_w width. If the frame is
floating, then the tab sizes are used. If not, then remaining space
is distributed among tabs, where we want padded space to be same
for all tabs (but we don't shorten tabs that have float_tab_min_w
width)
|<-------------->| ... float_tab_min_w
tiled:
_____________________________________________
| tab | here is a long tab |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
float:
_______________________________________
| tab | here is a long tab |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
diff -rN -ubp old-ion-3plus/ioncore/frame.c new-ion-3plus/ioncore/frame.c
--- old-ion-3plus/ioncore/frame.c 2009-03-15 11:57:04.000000000 +0100
+++ new-ion-3plus/ioncore/frame.c 2009-03-15 11:57:04.000000000 +0100
@@ -100,7 +100,8 @@ bool frame_init(WFrame *frame, WWindow *
frame->brush=NULL;
frame->bar_brush=NULL;
frame->mode=mode;
- frame->tab_min_w=0;
+ frame->float_tab_min_w=0;
+ frame->propor_tab_min_w=0;
frame->bar_max_width_q=1.0;
gr_stylespec_init(&frame->baseattr);
@@ -282,29 +283,61 @@ int frame_nth_tab_x(WFrame *frame, int n
}
+void frame_get_max_width_and_elastic(WFrame * frame,int bar_w,int *maxw,int *elastic,int *minw);//FIXME
+
static int frame_nth_tab_w_iw(WFrame *frame, int n, bool inner)
{
WRectangle bg;
GrBorderWidths bdw=GR_BORDER_WIDTHS_INIT;
int m=FRAME_MCOUNT(frame);
+ int maxw,elastic,textw,minw;
uint w;
+ WRegion *sub;
+ const char * p;
- frame_bar_geom(frame, &bg);
+//fprintf(stderr,"HERE\n");
- if(m==0)
- m=1;
+ frame_bar_geom(frame, &bg);
if(frame->bar_brush!=NULL)
grbrush_get_border_widths(frame->bar_brush, &bdw);
+ if(m==0){
+ m=1;
+ w=bg.w-bdw.left-bdw.right;
+ }else{
+ frame_get_max_width_and_elastic(frame, bg.w, &maxw, &elastic, &minw);
+ if ((maxw > 0) && (maxw <= frame->propor_tab_min_w)) {
/* Remove borders */
w=bg.w-bdw.left-bdw.right-(bdw.tb_ileft+bdw.tb_iright+bdw.spacing)*(m-1);
-
+//fprintf(stderr,"HEREmin maxw:%i minw:%i totalw:%i pad:%i w:%i (????)\n",maxw,minw,bg.w,elastic,w);
if(w<=0)
return 0;
-
/* Get n:th tab's portion of free area */
w=(((n+1)*w)/m-(n*w)/m);
+ }else{
+
+ /* Get n:th tab's portion of elastic area */
+ elastic=(((n+1)*elastic)/m-(n*elastic)/m);
+
+ sub = mplex_mx_nth((WMPlex*)frame, n);
+ p=region_displayname(sub);
+ if(p==NULL)
+ textw=0;
+ else
+ textw=grbrush_get_text_width(frame->bar_brush,
+ p, strlen(p));
+ if (textw<minw)
+ textw=minw;
+ if (textw<frame->propor_tab_min_w)
+ textw=frame->propor_tab_min_w;
+
+ if (maxw>0 && (textw>maxw))
+ textw=maxw;
+ w=elastic+textw;
+//fprintf(stderr,"HEREsub %p maxw:%i minw:%i totalw:%i pad:%i w:%i (%s)\n",(void *)sub,maxw,minw,bg.w,elastic,w,p);
+ }
+ }
/* Add n:th tab's borders back */
if(!inner){
@@ -312,6 +345,7 @@ static int frame_nth_tab_w_iw(WFrame *fr
w+=(n==m-1 ? bdw.right : bdw.tb_iright+bdw.spacing);
}
+//fprintf(stderr,"THERE\n");
return w;
}
diff -rN -ubp old-ion-3plus/ioncore/frame-draw.c new-ion-3plus/ioncore/frame-draw.c
--- old-ion-3plus/ioncore/frame-draw.c 2009-03-15 11:57:04.000000000 +0100
+++ new-ion-3plus/ioncore/frame-draw.c 2009-03-15 11:57:04.000000000 +0100
@@ -225,10 +225,11 @@ void frame_clear_shape(WFrame *frame)
#define CF_TAB_MAX_TEXT_X_OFF 10
+void frame_get_max_width_and_elastic(WFrame * frame,int bar_w,int *maxw,int *elastic, int *minw);//FIXME
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=0, textw, w, tmaxw, tminw, tmp=0;
WLListIterTmp itmp;
WRegion *sub;
const char *p;
@@ -241,43 +242,41 @@ static void frame_shaped_recalc_bar_size
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_get_max_width_and_elastic(frame, bar_w, &tmaxw, &tmp, &tminw);
+//fprintf(stderr," * WID total:%i maxw:%i minw:%i elastic:%i m:%i\n",bar_w,tmaxw,tminw,tmp,m);
+ if ((tmaxw < 0) && (tminw == frame->float_tab_min_w)) {
+ /* No label truncation needed, good. See how much can be padded. */
+ w=bar_w-tmp;
FRAME_MX_FOR_ALL(sub, frame, itmp){
p=region_displayname(sub);
if(p==NULL)
continue;
- textw=grbrush_get_text_width(frame->bar_brush,
- p, strlen(p));
- if(textw>tmaxw)
- tmaxw=textw;
+ textw=2*CF_TAB_MAX_TEXT_X_OFF+
+ grbrush_get_text_width(frame->bar_brush,
+ p, strlen(p))-
+ frame->float_tab_min_w;
+//fprintf(stderr," * WID addtextw:%i\n",textw);
+ if (textw>=2*CF_TAB_MAX_TEXT_X_OFF)
+ w+=2*CF_TAB_MAX_TEXT_X_OFF;
+ else if (textw >=0)
+ w+=textw;
}
+ if (bar_w>w)/*Padded to much*/
+ bar_w=w;
- 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;
-
- 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{
+ } else {
/* 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->float_tab_min_w)
+ bar_w=frame->float_tab_min_w;
}
if(complete || frame->bar_w!=bar_w){
@@ -302,9 +301,133 @@ static int init_title(WFrame *frame, int
}
+/* Proportional tabs algorithm:
+ * Sort tabs by text sizes.
+ * From smallest to largest do:
+ * Compare current tab width with remaining width (incl. current)
+ divided by no. of remaining tabs (incl. current).
+ * If larger or equal, then set maximum width to the number computed
+ above and set elastic space to zero (resp. to remain after division).
+ (Return.)
+ * If smaller, subctract current width from remaining width and
+ subtract one from no. of remaining tabs. If this is the last
+ tab, then set additional padding to remaining width divided
+ by total number of tabs.
+
+ Do not use w for shaped frames.
+*/
+void frame_get_max_width_and_elastic(WFrame * frame,int bar_w,int *maxw,int *elastic, int *minw){
+ /* Dummy implementation O(n^2), instead of O(n*log(n)) */
+ int textw=0,tmp,tmaxw,tminw=frame->propor_tab_min_w;
+ WLListIterTmp itmp;
+ WRegion *sub;
+ const char *p;
+ GrBorderWidths bdw;
+ //char *title;
+ uint bdtotal,curw,nextw;
+ int i, m, n;
+
+ m=FRAME_MCOUNT(frame);
+ *minw=0;
+
+// if(frame->bar_brush==NULL)
+// *elastic=0;
+// *maxw=-1;
+//fprintf(stderr,"ZERR\n");
+// return;
+ 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);
+ tmp = bar_w - bdtotal;
+//fprintf(stderr,"TMPST:%i barw:%i bdt:%i\n",tmp,bar_w,bdtotal);
+
+ curw=0;
+ n=m;
+
+ while (n>0) {
+ nextw=(uint)-1;/*FIXME: MAXINT*/
+ if ((signed)curw*n >= tmp) {
+ /*Remainig tabs are too large => equal width.*/
+ *maxw=tmp/n;
+ *elastic=tmp-(*maxw)*n;
+//fprintf(stderr,"TRUNC maxw:%i elastic:%i tmp:%i n:%i\n",*maxw,*elastic,tmp,n);
+ return;
+ }
+ FRAME_MX_FOR_ALL(sub, frame, itmp){
+ p=region_displayname(sub);
+ if(p==NULL)
+ continue;
+
+ textw=grbrush_get_text_width(frame->bar_brush,
+ p, strlen(p));
+ if (textw<tminw)
+ textw=tminw;
+ if((unsigned)textw == curw){
+//fprintf(stderr,"TW:%i (%s)\n",textw,p);
+ tmp-=textw;
+ n--;
+ } else if((unsigned)textw>curw){
+ if ((unsigned)textw<nextw)
+ nextw=textw;
+ }
+ }
+ curw = nextw;
+ }
+//fprintf(stderr,"TMP elastic:%i\n",tmp);
+
+ n=0;
+ curw=0;
+ /*We have some padding left. Try to enlarge small tabs*/
+ while (n<m) {
+ nextw=(uint)-1;/*FIXME: MAXINT*/
+ FRAME_MX_FOR_ALL(sub, frame, itmp){
+ p=region_displayname(sub);
+ if(p==NULL)
+ continue;
+
+ textw=grbrush_get_text_width(frame->bar_brush,
+ p, strlen(p));
+ if (textw<tminw)
+ textw=tminw;
+ if((unsigned)textw == curw){
+ n++;
+ } else if((unsigned)textw>curw){
+ if ((unsigned)textw<nextw)
+ nextw=textw;
+ }
+ }
+ if (nextw>(unsigned)frame->float_tab_min_w)
+ nextw=frame->float_tab_min_w;
+//fprintf(stderr,"TMP --- tmp:%i n:%i curw:%i nextw:%i min:%i\n",tmp,n,curw,nextw,*minw);
+ if (n*(nextw-curw)<(unsigned)tmp) {
+ /*we can extend small tabs to 'nextw'*/
+ *minw=nextw;
+ tmp-=n*(nextw-curw);
+//fprintf(stderr,"TMPSUBGO tmp:%i n:%i curw:%i nextw:%i min:%i\n",tmp,n,curw,nextw,*minw);
+ } else {
+ /*we can extend small tabs only to 'curw+tmp/n'*/
+ *minw+=tmp/n;
+ tmp-=(*minw-curw)*n;
+//fprintf(stderr,"TMPSUBBRK tmp:%i n:%i curw:%i nextw:%i min:%i\n",tmp,n,curw,nextw,*minw);
+ break;
+ }
+ if (nextw==(unsigned)frame->float_tab_min_w)
+ break;
+ curw=nextw;
+ }
+
+//fprintf(stderr,"TMP elastic:%i min:%i\n",tmp,*minw);
+ *elastic=tmp;
+ } else {
+ *elastic=0;
+ }
+ *maxw=-1;
+}
+
void frame_recalc_bar(WFrame *frame, bool complete)
{
- int textw, i;
+ int textw, i, maxw, padding;
WLListIterTmp tmp;
WRegion *sub;
char *title;
@@ -357,7 +480,8 @@ void frame_draw_bar(const WFrame *frame,
grbrush_init_attr(frame->bar_brush, &frame->baseattr);
grbrush_draw_textboxes(frame->bar_brush, &geom, frame->titles_n,
- frame->titles, complete);
+ //frame->titles, complete);
+ frame->titles, TRUE);
grbrush_end(frame->bar_brush);
}
@@ -427,14 +551,17 @@ void frame_brushes_updated(WFrame *frame
frame->bar_h=bdw.top+bdw.bottom+fnte.max_height;
}
+ //FIXME
+ frame->propor_tab_min_w=30;
+
/* shaped mode stuff */
- frame->tab_min_w=100;
+ frame->float_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;
+ 'i', &(frame->float_tab_min_w))){
+ if(frame->float_tab_min_w<=0)
+ frame->float_tab_min_w=1;
}
if(grbrush_get_extra(frame->brush, "floatframe_bar_max_w_q",
diff -rN -ubp old-ion-3plus/ioncore/frame.h new-ion-3plus/ioncore/frame.h
--- old-ion-3plus/ioncore/frame.h 2009-03-15 11:57:04.000000000 +0100
+++ new-ion-3plus/ioncore/frame.h 2009-03-15 11:57:04.000000000 +0100
@@ -76,7 +76,8 @@ DECLCLASS(WFrame){
WFrameBarMode barmode;
int bar_w, bar_h;
double bar_max_width_q;
- int tab_min_w;
+ int float_tab_min_w;
+ int propor_tab_min_w;
};