2 * ion/mod_query/listing.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
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
, int mode
)
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
;
372 l
->selected_str
==i
||
373 LISTING_DRAW_GET_SELECTED(mode
)==i
){
375 if(i
==l
->selected_str
)
376 grbrush_set_attr(brush
, selattr
);
378 draw_multirow(brush
, geom
->x
+x
, y
, l
->itemh
, l
->strs
[i
],
379 (l
->iteminfos
!=NULL
? &(l
->iteminfos
[i
]) : NULL
),
380 geom
->w
-x
, ciw
, wrapw
);
382 if(i
==l
->selected_str
)
383 grbrush_unset_attr(brush
, selattr
);
386 y
+=l
->itemh
*ITEMROWS(l
, i
);
396 static int prevsel
=-1;
398 static bool filteridx_sel(WListing
*l
, int i
)
400 return (i
==prevsel
|| i
==l
->selected_str
);
404 void draw_listing(GrBrush
*brush
, const WRectangle
*geom
,
405 WListing
*l
, int mode
, GrAttr selattr
)
410 grbrush_begin(brush
, geom
, GRBRUSH_AMEND
|GRBRUSH_KEEP_ATTR
413 if(mode
==LISTING_DRAW_COMPLETE
)
414 grbrush_clear_area(brush
, geom
);
416 grbrush_draw_border(brush
, geom
);
418 grbrush_get_border_widths(brush
, &bdw
);
420 geom2
.x
=geom
->x
+bdw
.left
;
421 geom2
.y
=geom
->y
+bdw
.top
;
422 geom2
.w
=geom
->w
-bdw
.left
-bdw
.right
;
423 geom2
.h
=geom
->h
-bdw
.top
-bdw
.bottom
;
425 do_draw_listing(brush
, &geom2
, l
, selattr
, mode
);
431 static bool do_scrollup_listing(WListing
*l
, int n
)
438 if(!one_row_up(l
, &i
, &r
))
451 static bool do_scrolldown_listing(WListing
*l
, int n
)
460 one_row_down(l
, &bi
, &br
);
463 if(!one_row_down(l
, &bi
, &br
))
465 one_row_down(l
, &i
, &r
);
477 bool scrollup_listing(WListing
*l
)
479 return do_scrollup_listing(l
, l
->visrow
);
483 bool scrolldown_listing(WListing
*l
)
485 return do_scrolldown_listing(l
, l
->visrow
);
489 static int listing_first_row_of_item(WListing
*l
, int i
)
491 int fci
=i
%l
->nitemcol
, j
;
501 static int listing_first_visible_row(WListing
*l
)
503 return listing_first_row_of_item(l
, l
->firstitem
)+l
->firstoff
;
507 int listing_select(WListing
*l
, int i
)
509 int irow
, frow
, lrow
;
512 redraw
=LISTING_DRAW_SELECTED(l
->selected_str
);
523 /* Adjust visible area */
525 irow
=listing_first_row_of_item(l
, i
);
526 frow
=listing_first_visible_row(l
);
529 one_row_up(l
, &(l
->firstitem
), &(l
->firstoff
));
531 redraw
=LISTING_DRAW_COMPLETE
;
534 irow
+=ITEMROWS(l
, i
)-1;
535 lrow
=frow
+l
->visrow
-1;
538 one_row_down(l
, &(l
->firstitem
), &(l
->firstoff
));
540 redraw
=LISTING_DRAW_COMPLETE
;