Remove unused variables
[notion.git] / mod_query / listing.c
blob661ab5a205ca466646b526f6a4aa896302d48ac3
1 /*
2 * ion/mod_query/listing.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <string.h>
10 #include <limits.h>
12 #include <ioncore/common.h>
13 #include <ioncore/global.h>
14 #include <ioncore/gr.h>
15 #include <ioncore/strings.h>
16 #include "listing.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)
27 int maxw=0, w, i;
29 for(i=0; i<nstrs; i++){
30 w=grbrush_get_text_width(brush, strs[i], strlen(strs[i]));
31 if(w>maxw)
32 maxw=w;
35 return maxw;
39 static int getbeg(GrBrush *brush, int maxw, char *str, int l, int *wret)
41 int n=0, nprev=0, w;
42 GrFontExtents fnte;
44 if(maxw<=0){
45 *wret=0;
46 return 0;
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;
55 n=0;
56 while(n2>0){
57 n+=str_nextoff(str, n);
58 n2--;
62 w=grbrush_get_text_width(brush, str, n);
63 nprev=n;
64 *wret=w;
66 while(w<=maxw){
67 *wret=w;
68 nprev=n;
69 n+=str_nextoff(str, n);
70 if(n==nprev)
71 break;
72 w=grbrush_get_text_width(brush, str, n);
75 return nprev;
79 static void reset_iteminfo(WListingItemInfo *iinf)
81 iinf->n_parts=1;
82 if(iinf->part_lens!=NULL){
83 free(iinf->part_lens);
84 iinf->part_lens=NULL;
89 static void string_do_calc_parts(GrBrush *brush, int maxw, char *str, int l,
90 WListingItemInfo *iinf,
91 int wrapw, int ciw)
93 int i=iinf->n_parts, l2=l, w;
94 int rmaxw=maxw-(i==0 ? 0 : ciw);
96 iinf->n_parts++;
98 w=grbrush_get_text_width(brush, str, l);
100 if(w>rmaxw){
101 l2=getbeg(brush, rmaxw-wrapw, str, l, &w);
102 if(l2<=0)
103 l2=1;
106 if(l2<l){
107 string_do_calc_parts(brush, maxw, str+l2, l-l2, iinf, wrapw, ciw);
108 }else{
109 int *p=(int*)realloc(iinf->part_lens, iinf->n_parts*sizeof(int));
110 if(p==NULL){
111 reset_iteminfo(iinf);
112 }else{
113 iinf->part_lens=p;
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);
128 iinf->n_parts=0;
129 iinf->len=strlen(str);
131 if(maxw<=0)
132 reset_iteminfo(iinf);
133 else
134 string_do_calc_parts(brush, maxw, str, iinf->len, iinf, wrapw, ciw);
138 static void draw_multirow(GrBrush *brush, int x, int y, int h,
139 char *str, WListingItemInfo *iinf,
140 int maxw, int ciw, int wrapw)
142 int i, l;
144 if(iinf==NULL){
145 grbrush_draw_string(brush, x, y, str, strlen(str), TRUE);
146 return;
149 assert(iinf->n_parts>=1);
150 if(iinf->part_lens==NULL){
151 assert(iinf->n_parts==1);
152 l=iinf->len;
153 }else{
154 l=iinf->part_lens[0];
157 grbrush_draw_string(brush, x, y, str, l, TRUE);
159 for(i=1; i<iinf->n_parts; i++){
160 grbrush_draw_string(brush, x+maxw-wrapw, y, "\\", 1, TRUE);
162 y+=h;
163 str+=l;
164 if(i==1){
165 x+=ciw;
166 maxw-=ciw;
168 l=iinf->part_lens[i];
170 grbrush_draw_string(brush, x, y, str, l, TRUE);
175 static int col_fit(int w, int itemw, int spacing)
177 int ncol=1;
178 int tmp=w-itemw;
179 itemw+=spacing;
181 if(tmp>0)
182 ncol+=tmp/itemw;
184 return ncol;
187 static bool one_row_up(WListing *l, int *ip, int *rp)
189 int i=*ip, r=*rp;
191 if(r>0){
192 (*rp)--;
193 return TRUE;
196 if(i==0)
197 return FALSE;
199 (*ip)--;
200 *rp=ITEMROWS(l, i-1)-1;
201 return TRUE;
205 static bool one_row_down(WListing *l, int *ip, int *rp)
207 int i=*ip, r=*rp;
208 int ir=ITEMROWS(l, i);
210 if(r<ir-1){
211 (*rp)++;
212 return TRUE;
215 if(i==l->nitemcol-1)
216 return FALSE;
218 (*ip)++;
219 *rp=0;
220 return TRUE;
224 void setup_listing(WListing *l, char **strs, int nstrs, bool onecol)
226 if(l->strs!=NULL)
227 deinit_listing(l);
229 l->iteminfos=ALLOC_N(WListingItemInfo, nstrs);
230 l->strs=strs;
231 l->nstrs=nstrs;
232 l->onecol=onecol;
233 l->selected_str=-1;
237 void fit_listing(GrBrush *brush, const WRectangle *geom, WListing *l)
239 int ncol, nrow=0, visrow=INT_MAX;
240 int i, maxw, w, h;
241 GrFontExtents fnte;
242 GrBorderWidths bdw;
244 grbrush_get_font_extents(brush, &fnte);
245 grbrush_get_border_widths(brush, &bdw);
247 w=geom->w-bdw.left-bdw.right;
248 h=geom->h-bdw.top-bdw.bottom;
250 maxw=strings_maxw(brush, l->strs, l->nstrs);
251 l->itemw=maxw+COL_SPACING;
252 l->itemh=fnte.max_height;
254 if(l->onecol)
255 ncol=1;
256 else
257 ncol=col_fit(w, l->itemw-COL_SPACING, COL_SPACING);
259 if(l->iteminfos!=NULL){
260 for(i=0; i<l->nstrs; i++){
261 if(ncol!=1){
262 reset_iteminfo(&(l->iteminfos[i]));
263 l->iteminfos[i].len=strlen(l->strs[i]);
264 }else{
265 string_calc_parts(brush, w, l->strs[i], &(l->iteminfos[i]));
267 nrow+=l->iteminfos[i].n_parts;
269 }else{
270 nrow=l->nstrs;
273 if(ncol>1){
274 nrow=l->nstrs/ncol+(l->nstrs%ncol ? 1 : 0);
275 l->nitemcol=nrow;
276 }else{
277 l->nitemcol=l->nstrs;
280 if(l->itemh>0)
281 visrow=h/l->itemh;
283 if(visrow>nrow)
284 visrow=nrow;
286 l->ncol=ncol;
287 l->nrow=nrow;
288 l->visrow=visrow;
289 l->toth=visrow*l->itemh;
291 #if 0
292 l->firstitem=l->nitemcol-1;
293 l->firstoff=ITEMROWS(l, l->nitemcol-1)-1;
294 for(i=1; i<visrow; i++)
295 one_row_up(l, &(l->firstitem), &(l->firstoff));
296 #else
297 l->firstitem=0;
298 l->firstoff=0;
299 #endif
304 void deinit_listing(WListing *l)
306 if(l->strs==NULL)
307 return;
309 while(l->nstrs--){
310 free(l->strs[l->nstrs]);
311 if(l->iteminfos!=NULL)
312 reset_iteminfo(&(l->iteminfos[l->nstrs]));
315 free(l->strs);
316 l->strs=NULL;
318 if(l->iteminfos!=NULL){
319 free(l->iteminfos);
320 l->iteminfos=NULL;
325 void init_listing(WListing *l)
327 l->nstrs=0;
328 l->strs=NULL;
329 l->iteminfos=NULL;
330 l->nstrs=0;
331 l->selected_str=-1;
332 l->onecol=TRUE;
333 l->itemw=0;
334 l->itemh=0;
335 l->ncol=0;
336 l->nrow=0;
337 l->nitemcol=0;
338 l->visrow=0;
339 l->toth=0;
343 static void do_draw_listing(GrBrush *brush, const WRectangle *geom,
344 WListing *l, GrAttr selattr, int mode)
346 int wrapw=grbrush_get_text_width(brush, "\\", 1);
347 int ciw=grbrush_get_text_width(brush, CONT_INDENT, CONT_INDENT_LEN);
348 int r, c, i, x, y;
349 GrFontExtents fnte;
351 if(l->nitemcol==0 || l->visrow==0)
352 return;
354 grbrush_get_font_extents(brush, &fnte);
356 x=0;
357 c=0;
358 while(1){
359 y=geom->y+fnte.baseline;
360 i=l->firstitem+c*l->nitemcol;
361 r=-l->firstoff;
362 y+=r*l->itemh;
363 while(r<l->visrow){
364 if(i>=l->nstrs)
365 return;
367 if(mode>=0 ||
368 l->selected_str==i ||
369 LISTING_DRAW_GET_SELECTED(mode)==i){
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);
382 y+=l->itemh*ITEMROWS(l, i);
383 r+=ITEMROWS(l, i);
384 i++;
386 x+=l->itemw;
387 c++;
392 static int prevsel=-1;
394 static bool filteridx_sel(WListing *l, int i)
396 return (i==prevsel || i==l->selected_str);
400 void draw_listing(GrBrush *brush, const WRectangle *geom,
401 WListing *l, int mode, GrAttr selattr)
403 WRectangle geom2;
404 GrBorderWidths bdw;
406 grbrush_begin(brush, geom, GRBRUSH_AMEND|GRBRUSH_KEEP_ATTR
407 |GRBRUSH_NEED_CLIP);
409 if(mode==LISTING_DRAW_COMPLETE)
410 grbrush_clear_area(brush, geom);
412 grbrush_draw_border(brush, geom);
414 grbrush_get_border_widths(brush, &bdw);
416 geom2.x=geom->x+bdw.left;
417 geom2.y=geom->y+bdw.top;
418 geom2.w=geom->w-bdw.left-bdw.right;
419 geom2.h=geom->h-bdw.top-bdw.bottom;
421 do_draw_listing(brush, &geom2, l, selattr, mode);
423 grbrush_end(brush);
427 static bool do_scrollup_listing(WListing *l, int n)
429 int i=l->firstitem;
430 int r=l->firstoff;
431 bool ret=FALSE;
433 while(n>0){
434 if(!one_row_up(l, &i, &r))
435 break;
436 ret=TRUE;
437 n--;
440 l->firstitem=i;
441 l->firstoff=r;
443 return ret;
447 static bool do_scrolldown_listing(WListing *l, int n)
449 int i=l->firstitem;
450 int r=l->firstoff;
451 int br=r, bi=i;
452 int bc=l->visrow;
453 bool ret=FALSE;
455 while(--bc>0)
456 one_row_down(l, &bi, &br);
458 while(n>0){
459 if(!one_row_down(l, &bi, &br))
460 break;
461 one_row_down(l, &i, &r);
462 ret=TRUE;
463 n--;
466 l->firstitem=i;
467 l->firstoff=r;
469 return ret;
473 bool scrollup_listing(WListing *l)
475 return do_scrollup_listing(l, l->visrow);
479 bool scrolldown_listing(WListing *l)
481 return do_scrolldown_listing(l, l->visrow);
485 static int listing_first_row_of_item(WListing *l, int i)
487 int fci=i%l->nitemcol, j;
488 int r=0;
490 for(j=0; j<fci; j++)
491 r+=ITEMROWS(l, j);
493 return r;
497 static int listing_first_visible_row(WListing *l)
499 return listing_first_row_of_item(l, l->firstitem)+l->firstoff;
503 int listing_select(WListing *l, int i)
505 int irow, frow, lrow;
506 int redraw;
508 redraw=LISTING_DRAW_SELECTED(l->selected_str);
510 if(i<0){
511 l->selected_str=-1;
512 return redraw;
515 assert(i<l->nstrs);
517 l->selected_str=i;
519 /* Adjust visible area */
521 irow=listing_first_row_of_item(l, i);
522 frow=listing_first_visible_row(l);
524 while(irow<frow){
525 one_row_up(l, &(l->firstitem), &(l->firstoff));
526 frow--;
527 redraw=LISTING_DRAW_COMPLETE;
530 irow+=ITEMROWS(l, i)-1;
531 lrow=frow+l->visrow-1;
533 while(irow>lrow){
534 one_row_down(l, &(l->firstitem), &(l->firstoff));
535 lrow++;
536 redraw=LISTING_DRAW_COMPLETE;
539 return redraw;