2 * ion/mod_query/listing.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * See the included file LICENSE for details.
12 #include <ioncore/common.h>
13 #include <ioncore/global.h>
14 #include <ioncore/gr.h>
15 #include <ioncore/strings.h>
19 #define COL_SPACING 16
20 #define CONT_INDENT "xx"
21 #define CONT_INDENT_LEN 2
22 #define ITEMROWS(L, R) ((L)->iteminfos==NULL ? 1 : (L)->iteminfos[R].n_parts)
25 static int strings_maxw(GrBrush *brush, char **strs, int nstrs)
29 for(i=0; i<nstrs; i++){
30 w=grbrush_get_text_width(brush, strs[i], strlen(strs[i]));
39 static int getbeg(GrBrush *brush, int maxw, char *str, int l, int *wret)
49 grbrush_get_font_extents(brush, &fnte);
51 if(fnte.max_width!=0){
52 /* Do an initial skip. */
53 int n2=maxw/fnte.max_width;
57 n+=str_nextoff(str, n);
62 w=grbrush_get_text_width(brush, str, n);
69 n+=str_nextoff(str, n);
72 w=grbrush_get_text_width(brush, str, n);
79 static void reset_iteminfo(WListingItemInfo *iinf)
82 if(iinf->part_lens!=NULL){
83 free(iinf->part_lens);
89 static void string_do_calc_parts(GrBrush *brush, int maxw, char *str, int l,
90 WListingItemInfo *iinf,
93 int i=iinf->n_parts, l2=l, w;
94 int rmaxw=maxw-(i==0 ? 0 : ciw);
98 w=grbrush_get_text_width(brush, str, l);
101 l2=getbeg(brush, rmaxw-wrapw, str, l, &w);
107 string_do_calc_parts(brush, maxw, str+l2, l-l2, iinf, wrapw, ciw);
109 int *p=(int*)realloc(iinf->part_lens, iinf->n_parts*sizeof(int));
111 reset_iteminfo(iinf);
117 if(iinf->part_lens!=NULL)
118 iinf->part_lens[i]=l2;
122 static void string_calc_parts(GrBrush *brush, int maxw, char *str,
123 WListingItemInfo *iinf)
125 int wrapw=grbrush_get_text_width(brush, "\\", 1);
126 int ciw=grbrush_get_text_width(brush, CONT_INDENT, CONT_INDENT_LEN);
130 iinf->len=strlen(str);
133 reset_iteminfo(iinf);
135 string_do_calc_parts(brush, maxw, str, iinf->len, iinf, wrapw, ciw);
139 static void draw_multirow(GrBrush *brush, int x, int y, int h,
140 char *str, WListingItemInfo *iinf,
141 int maxw, int ciw, int wrapw)
146 grbrush_draw_string(brush, x, y, str, strlen(str), TRUE);
150 assert(iinf->n_parts>=1);
151 if(iinf->part_lens==NULL){
152 assert(iinf->n_parts==1);
155 l=iinf->part_lens[0];
158 grbrush_draw_string(brush, x, y, str, l, TRUE);
160 for(i=1; i<iinf->n_parts; i++){
161 grbrush_draw_string(brush, x+maxw-wrapw, y, "\\", 1, TRUE);
169 l=iinf->part_lens[i];
171 grbrush_draw_string(brush, x, y, str, l, TRUE);
176 static int col_fit(int w, int itemw, int spacing)
188 static bool one_row_up(WListing *l, int *ip, int *rp)
191 int ir=ITEMROWS(l, i);
202 *rp=ITEMROWS(l, i-1)-1;
207 static bool one_row_down(WListing *l, int *ip, int *rp)
210 int ir=ITEMROWS(l, i);
226 void setup_listing(WListing *l, char **strs, int nstrs, bool onecol)
231 l->iteminfos=ALLOC_N(WListingItemInfo, nstrs);
239 void fit_listing(GrBrush *brush, const WRectangle *geom, WListing *l)
241 int ncol, nrow=0, visrow=INT_MAX;
246 grbrush_get_font_extents(brush, &fnte);
247 grbrush_get_border_widths(brush, &bdw);
249 w=geom->w-bdw.left-bdw.right;
250 h=geom->h-bdw.top-bdw.bottom;
252 maxw=strings_maxw(brush, l->strs, l->nstrs);
253 l->itemw=maxw+COL_SPACING;
254 l->itemh=fnte.max_height;
259 ncol=col_fit(w, l->itemw-COL_SPACING, COL_SPACING);
261 if(l->iteminfos!=NULL){
262 for(i=0; i<l->nstrs; i++){
264 reset_iteminfo(&(l->iteminfos[i]));
265 l->iteminfos[i].len=strlen(l->strs[i]);
267 string_calc_parts(brush, w, l->strs[i], &(l->iteminfos[i]));
269 nrow+=l->iteminfos[i].n_parts;
276 nrow=l->nstrs/ncol+(l->nstrs%ncol ? 1 : 0);
279 l->nitemcol=l->nstrs;
291 l->toth=visrow*l->itemh;
294 l->firstitem=l->nitemcol-1;
295 l->firstoff=ITEMROWS(l, l->nitemcol-1)-1;
296 for(i=1; i<visrow; i++)
297 one_row_up(l, &(l->firstitem), &(l->firstoff));
306 void deinit_listing(WListing *l)
314 free(l->strs[l->nstrs]);
315 if(l->iteminfos!=NULL)
316 reset_iteminfo(&(l->iteminfos[l->nstrs]));
322 if(l->iteminfos!=NULL){
329 void init_listing(WListing *l)
347 static void do_draw_listing(GrBrush *brush, const WRectangle *geom,
348 WListing *l, GrAttr selattr)
350 int wrapw=grbrush_get_text_width(brush, "\\", 1);
351 int ciw=grbrush_get_text_width(brush, CONT_INDENT, CONT_INDENT_LEN);
355 if(l->nitemcol==0 || l->visrow==0)
358 grbrush_get_font_extents(brush, &fnte);
363 y=geom->y+fnte.baseline;
364 i=l->firstitem+c*l->nitemcol;
371 if(i==l->selected_str)
372 grbrush_set_attr(brush, selattr);
374 draw_multirow(brush, geom->x+x, y, l->itemh, l->strs[i],
375 (l->iteminfos!=NULL ? &(l->iteminfos[i]) : NULL),
376 geom->w-x, ciw, wrapw);
378 if(i==l->selected_str)
379 grbrush_unset_attr(brush, selattr);
381 y+=l->itemh*ITEMROWS(l, i);
391 void draw_listing(GrBrush *brush, const WRectangle *geom,
392 WListing *l, bool complete, GrAttr selattr)
397 grbrush_begin(brush, geom, GRBRUSH_AMEND|GRBRUSH_KEEP_ATTR
401 grbrush_clear_area(brush, geom);
403 grbrush_draw_border(brush, geom);
405 grbrush_get_border_widths(brush, &bdw);
407 geom2.x=geom->x+bdw.left;
408 geom2.y=geom->y+bdw.top;
409 geom2.w=geom->w-bdw.left-bdw.right;
410 geom2.h=geom->h-bdw.top-bdw.bottom;
412 do_draw_listing(brush, &geom2, l, selattr);
418 static bool do_scrollup_listing(WListing *l, int n)
425 if(!one_row_up(l, &i, &r))
438 static bool do_scrolldown_listing(WListing *l, int n)
447 one_row_down(l, &bi, &br);
450 if(!one_row_down(l, &bi, &br))
452 one_row_down(l, &i, &r);
464 bool scrollup_listing(WListing *l)
466 return do_scrollup_listing(l, l->visrow);
470 bool scrolldown_listing(WListing *l)
472 return do_scrolldown_listing(l, l->visrow);
476 static int listing_first_row_of_item(WListing *l, int i)
478 int fci=i%l->nitemcol, j;
488 static int listing_first_visible_row(WListing *l)
490 return listing_first_row_of_item(l, l->firstitem)+l->firstoff;
494 bool listing_select(WListing *l, int i)
496 int irow, frow, lrow;
497 bool complredraw=FALSE;
508 /* Adjust visible area */
510 irow=listing_first_row_of_item(l, i);
511 frow=listing_first_visible_row(l);
514 one_row_up(l, &(l->firstitem), &(l->firstoff));
519 irow+=ITEMROWS(l, i)-1;
520 lrow=frow+l->visrow-1;
523 one_row_down(l, &(l->firstitem), &(l->firstoff));