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
);
129 iinf
->len
=strlen(str
);
132 reset_iteminfo(iinf
);
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
)
145 grbrush_draw_string(brush
, x
, y
, str
, strlen(str
), TRUE
);
149 assert(iinf
->n_parts
>=1);
150 if(iinf
->part_lens
==NULL
){
151 assert(iinf
->n_parts
==1);
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
);
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
)
187 static bool one_row_up(WListing
*l
, int *ip
, int *rp
)
200 *rp
=ITEMROWS(l
, i
-1)-1;
205 static bool one_row_down(WListing
*l
, int *ip
, int *rp
)
208 int ir
=ITEMROWS(l
, i
);
224 void setup_listing(WListing
*l
, char **strs
, int nstrs
, bool onecol
)
229 l
->iteminfos
=ALLOC_N(WListingItemInfo
, nstrs
);
237 void fit_listing(GrBrush
*brush
, const WRectangle
*geom
, WListing
*l
)
239 int ncol
, nrow
=0, visrow
=INT_MAX
;
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
;
257 ncol
=col_fit(w
, l
->itemw
-COL_SPACING
, COL_SPACING
);
259 if(l
->iteminfos
!=NULL
){
260 for(i
=0; i
<l
->nstrs
; i
++){
262 reset_iteminfo(&(l
->iteminfos
[i
]));
263 l
->iteminfos
[i
].len
=strlen(l
->strs
[i
]);
265 string_calc_parts(brush
, w
, l
->strs
[i
], &(l
->iteminfos
[i
]));
267 nrow
+=l
->iteminfos
[i
].n_parts
;
274 nrow
=l
->nstrs
/ncol
+(l
->nstrs
%ncol
? 1 : 0);
277 l
->nitemcol
=l
->nstrs
;
289 l
->toth
=visrow
*l
->itemh
;
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
));
304 void deinit_listing(WListing
*l
)
310 free(l
->strs
[l
->nstrs
]);
311 if(l
->iteminfos
!=NULL
)
312 reset_iteminfo(&(l
->iteminfos
[l
->nstrs
]));
318 if(l
->iteminfos
!=NULL
){
325 void init_listing(WListing
*l
)
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
);
351 if(l
->nitemcol
==0 || l
->visrow
==0)
354 grbrush_get_font_extents(brush
, &fnte
);
359 y
=geom
->y
+fnte
.baseline
;
360 i
=l
->firstitem
+c
*l
->nitemcol
;
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
);
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
)
406 grbrush_begin(brush
, geom
, GRBRUSH_AMEND
|GRBRUSH_KEEP_ATTR
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
);
427 static bool do_scrollup_listing(WListing
*l
, int n
)
434 if(!one_row_up(l
, &i
, &r
))
447 static bool do_scrolldown_listing(WListing
*l
, int n
)
456 one_row_down(l
, &bi
, &br
);
459 if(!one_row_down(l
, &bi
, &br
))
461 one_row_down(l
, &i
, &r
);
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
;
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
;
508 redraw
=LISTING_DRAW_SELECTED(l
->selected_str
);
519 /* Adjust visible area */
521 irow
=listing_first_row_of_item(l
, i
);
522 frow
=listing_first_visible_row(l
);
525 one_row_up(l
, &(l
->firstitem
), &(l
->firstoff
));
527 redraw
=LISTING_DRAW_COMPLETE
;
530 irow
+=ITEMROWS(l
, i
)-1;
531 lrow
=frow
+l
->visrow
-1;
534 one_row_down(l
, &(l
->firstitem
), &(l
->firstoff
));
536 redraw
=LISTING_DRAW_COMPLETE
;