2 * ion/mod_query/listing.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * Ion is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
15 #include <ioncore/common.h>
16 #include <ioncore/global.h>
17 #include <ioncore/gr.h>
18 #include <ioncore/strings.h>
22 #define COL_SPACING 16
23 #define CONT_INDENT "xx"
24 #define CONT_INDENT_LEN 2
25 #define ITEMROWS(L, R) ((L)->iteminfos==NULL ? 1 : (L)->iteminfos[R].n_parts)
28 static int strings_maxw(GrBrush *brush, char **strs, int nstrs)
32 for(i=0; i<nstrs; i++){
33 w=grbrush_get_text_width(brush, strs[i], strlen(strs[i]));
42 static int getbeg(GrBrush *brush, int maxw, char *str, int l, int *wret)
52 grbrush_get_font_extents(brush, &fnte);
54 if(fnte.max_width!=0){
55 /* Do an initial skip. */
56 int n2=maxw/fnte.max_width;
60 n+=str_nextoff(str, n);
65 w=grbrush_get_text_width(brush, str, n);
72 n+=str_nextoff(str, n);
75 w=grbrush_get_text_width(brush, str, n);
82 static void reset_iteminfo(WListingItemInfo *iinf)
85 if(iinf->part_lens!=NULL){
86 free(iinf->part_lens);
92 static void string_do_calc_parts(GrBrush *brush, int maxw, char *str, int l,
93 WListingItemInfo *iinf,
96 int i=iinf->n_parts, l2=l, w;
97 int rmaxw=maxw-(i==0 ? 0 : ciw);
101 w=grbrush_get_text_width(brush, str, l);
104 l2=getbeg(brush, rmaxw-wrapw, str, l, &w);
110 string_do_calc_parts(brush, maxw, str+l2, l-l2, iinf, wrapw, ciw);
112 int *p=(int*)realloc(iinf->part_lens, iinf->n_parts*sizeof(int));
114 reset_iteminfo(iinf);
120 if(iinf->part_lens!=NULL)
121 iinf->part_lens[i]=l2;
125 static void string_calc_parts(GrBrush *brush, int maxw, char *str,
126 WListingItemInfo *iinf)
128 int wrapw=grbrush_get_text_width(brush, "\\", 1);
129 int ciw=grbrush_get_text_width(brush, CONT_INDENT, CONT_INDENT_LEN);
133 iinf->len=strlen(str);
136 reset_iteminfo(iinf);
138 string_do_calc_parts(brush, maxw, str, iinf->len, iinf, wrapw, ciw);
142 static void draw_multirow(GrBrush *brush, int x, int y, int h,
143 char *str, WListingItemInfo *iinf,
144 int maxw, int ciw, int wrapw)
149 grbrush_draw_string(brush, x, y, str, strlen(str), TRUE);
153 assert(iinf->n_parts>=1);
154 if(iinf->part_lens==NULL){
155 assert(iinf->n_parts==1);
158 l=iinf->part_lens[0];
161 grbrush_draw_string(brush, x, y, str, l, TRUE);
163 for(i=1; i<iinf->n_parts; i++){
164 grbrush_draw_string(brush, x+maxw-wrapw, y, "\\", 1, TRUE);
172 l=iinf->part_lens[i];
174 grbrush_draw_string(brush, x, y, str, l, TRUE);
179 static int col_fit(int w, int itemw, int spacing)
191 static bool one_row_up(WListing *l, int *ip, int *rp)
194 int ir=ITEMROWS(l, i);
205 *rp=ITEMROWS(l, i-1)-1;
210 static bool one_row_down(WListing *l, int *ip, int *rp)
213 int ir=ITEMROWS(l, i);
229 void setup_listing(WListing *l, char **strs, int nstrs, bool onecol)
234 l->iteminfos=ALLOC_N(WListingItemInfo, nstrs);
242 void fit_listing(GrBrush *brush, const WRectangle *geom, WListing *l)
244 int ncol, nrow=0, visrow=INT_MAX;
249 grbrush_get_font_extents(brush, &fnte);
250 grbrush_get_border_widths(brush, &bdw);
252 w=geom->w-bdw.left-bdw.right;
253 h=geom->h-bdw.top-bdw.bottom;
255 maxw=strings_maxw(brush, l->strs, l->nstrs);
256 l->itemw=maxw+COL_SPACING;
257 l->itemh=fnte.max_height;
262 ncol=col_fit(w, l->itemw-COL_SPACING, COL_SPACING);
264 if(l->iteminfos!=NULL){
265 for(i=0; i<l->nstrs; i++){
267 reset_iteminfo(&(l->iteminfos[i]));
268 l->iteminfos[i].len=strlen(l->strs[i]);
270 string_calc_parts(brush, w, l->strs[i], &(l->iteminfos[i]));
272 nrow+=l->iteminfos[i].n_parts;
279 nrow=l->nstrs/ncol+(l->nstrs%ncol ? 1 : 0);
282 l->nitemcol=l->nstrs;
294 l->toth=visrow*l->itemh;
297 l->firstitem=l->nitemcol-1;
298 l->firstoff=ITEMROWS(l, l->nitemcol-1)-1;
299 for(i=1; i<visrow; i++)
300 one_row_up(l, &(l->firstitem), &(l->firstoff));
309 void deinit_listing(WListing *l)
317 free(l->strs[l->nstrs]);
318 if(l->iteminfos!=NULL)
319 reset_iteminfo(&(l->iteminfos[l->nstrs]));
325 if(l->iteminfos!=NULL){
332 void init_listing(WListing *l)
350 static void do_draw_listing(GrBrush *brush, const WRectangle *geom,
351 WListing *l, GrAttr selattr)
353 int wrapw=grbrush_get_text_width(brush, "\\", 1);
354 int ciw=grbrush_get_text_width(brush, CONT_INDENT, CONT_INDENT_LEN);
358 if(l->nitemcol==0 || l->visrow==0)
361 grbrush_get_font_extents(brush, &fnte);
366 y=geom->y+fnte.baseline;
367 i=l->firstitem+c*l->nitemcol;
374 if(i==l->selected_str)
375 grbrush_set_attr(brush, selattr);
377 draw_multirow(brush, geom->x+x, y, l->itemh, l->strs[i],
378 (l->iteminfos!=NULL ? &(l->iteminfos[i]) : NULL),
379 geom->w-x, ciw, wrapw);
381 if(i==l->selected_str)
382 grbrush_unset_attr(brush, selattr);
384 y+=l->itemh*ITEMROWS(l, i);
394 void draw_listing(GrBrush *brush, const WRectangle *geom,
395 WListing *l, bool complete, GrAttr selattr)
400 grbrush_begin(brush, geom, GRBRUSH_AMEND|GRBRUSH_KEEP_ATTR
404 grbrush_clear_area(brush, geom);
406 grbrush_draw_border(brush, geom);
408 grbrush_get_border_widths(brush, &bdw);
410 geom2.x=geom->x+bdw.left;
411 geom2.y=geom->y+bdw.top;
412 geom2.w=geom->w-bdw.left-bdw.right;
413 geom2.h=geom->h-bdw.top-bdw.bottom;
415 do_draw_listing(brush, &geom2, l, selattr);
421 static bool do_scrollup_listing(WListing *l, int n)
428 if(!one_row_up(l, &i, &r))
441 static bool do_scrolldown_listing(WListing *l, int n)
450 one_row_down(l, &bi, &br);
453 if(!one_row_down(l, &bi, &br))
455 one_row_down(l, &i, &r);
467 bool scrollup_listing(WListing *l)
469 return do_scrollup_listing(l, l->visrow);
473 bool scrolldown_listing(WListing *l)
475 return do_scrolldown_listing(l, l->visrow);
479 static int listing_first_row_of_item(WListing *l, int i)
481 int fci=i%l->nitemcol, j;
491 static int listing_first_visible_row(WListing *l)
493 return listing_first_row_of_item(l, l->firstitem)+l->firstoff;
497 bool listing_select(WListing *l, int i)
499 int irow, frow, lrow;
500 bool complredraw=FALSE;
511 /* Adjust visible area */
513 irow=listing_first_row_of_item(l, i);
514 frow=listing_first_visible_row(l);
517 one_row_up(l, &(l->firstitem), &(l->firstoff));
522 irow+=ITEMROWS(l, i)-1;
523 lrow=frow+l->visrow-1;
526 one_row_down(l, &(l->firstitem), &(l->firstoff));