1 /*
2  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
3  *
4  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5  *
6  * This file may be distributed under the terms of the Q Public License
7  * as defined by Trolltech AS of Norway and appearing in the file
8  * LICENSE.QPL included in the packaging of this file.
9  *
10  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/tdgtlist.c,v 1.8 2011/05/16 16:22:00 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_TDGTLIST_C_
22 
23 #include "tgifdefs.h"
24 #include "patchlvl.h"
25 
26 #include "auxtext.e"
27 #include "choose.e"
28 #include "color.e"
29 #include "cursor.e"
30 #include "dialog.e"
31 #include "drawing.e"
32 #include "font.e"
33 #include "mainloop.e"
34 #include "menu.e"
35 #include "msg.e"
36 #include "pattern.e"
37 #include "raster.e"
38 #include "rect.e"
39 #include "scroll.e"
40 #include "setup.e"
41 #include "strtbl.e"
42 #include "tdgtlist.e"
43 #include "tidget.e"
44 #include "util.e"
45 
46 static void RedrawTdgtList ARGS_DECL((TidgetInfo *pti));
47 static int TdgtListEventHandler ARGS_DECL((TidgetInfo *pti, XEvent *input,
48                 TidgetInfo *handling_pti));
49 static int IsTdgtListEvent ARGS_DECL((TidgetInfo *pti, XEvent *input,
50                 TidgetInfo **ppti_handler_tidget_return));
51 static void DestroyTdgtList ARGS_DECL((TidgetInfo *pti));
52 static void MapTdgtList ARGS_DECL((TidgetInfo *pti));
53 static void TdgtListMoveResize ARGS_DECL((TidgetInfo *pti, int x, int y,
54                 int w, int h));
55 static int TdgtListSendCmd ARGS_DECL((TidgetInfo *pti, int cmd_type,
56                 int cmd_arg, void *pv_cmd_userdata));
57 
58 static int gnListFontHeight=0;
59 static int gnListFontWidth=0;
60 static int gnListFontAsc=0;
61 static int gnListFontDes=0;
62 static XFontStruct *gnListFontPtr=NULL;
63 
64 /* --------------------- Utility Functions --------------------- */
65 
66 static
FreeListItemInfo(pListItemInfo)67 void FreeListItemInfo(pListItemInfo)
68    ListItemInfo *pListItemInfo;
69 {
70    UtilFree(pListItemInfo->buf);
71    free(pListItemInfo);
72 }
73 
74 /* --------------------- RedrawTdgtList() --------------------- */
75 
76 static
RedrawTdgtListItem(pTdgtList,index,pListItemInfo)77 void RedrawTdgtListItem(pTdgtList, index, pListItemInfo)
78    TdgtList *pTdgtList;
79    int index;
80    ListItemInfo *pListItemInfo;
81 {
82    ListInfo *pListInfo=(&pTdgtList->list_info);
83    int len=0, top=0, end=0, checkbox_cols=0, text_left=0, box_offset=0, box_w=0;
84    int selected=(index==pListInfo->marked_index);
85    int length=ListLength(&pListInfo->list);
86    XGCValues values;
87 
88    if (!pTdgtList->can_select) selected = FALSE;
89    top = gnListFontAsc+1;
90    if (pListInfo->first_index+pListInfo->num_visible_lines > length) {
91       end = length;
92    } else {
93       end = pListInfo->first_index + pListInfo->num_visible_lines;
94    }
95    if (pListInfo->p_check_array != NULL &&
96          pListInfo->p_check_array->num_cols > 0) {
97       checkbox_cols = pListInfo->p_check_array->num_cols;
98       text_left = checkbox_cols*ROW_HEIGHT;
99       box_offset = 1;
100       box_w = (ROW_HEIGHT-((box_offset+1)<<1));
101    }
102    if (pTdgtList->multicolor) {
103       if (selected) {
104       } else {
105          char *buf=NULL;
106          XFontStruct *font_ptr=NULL;
107          int font_asc=0;
108          TidgetDrawMsgStringFunc *pf_draw_string_func=NULL;
109 
110          len = strlen(pListItemInfo->nick_name)+strlen(pListItemInfo->buf)+8;
111          buf = (char*)malloc(len*sizeof(char));
112          if (buf == NULL) FailAllocMessage();
113          if (*pListItemInfo->nick_name == '\0') {
114             sprintf(buf, "%s", pListItemInfo->buf);
115          } else {
116             sprintf(buf, "%s : %s", pListItemInfo->nick_name,
117                   pListItemInfo->buf);
118          }
119          TidgetGetFontInfoGivenStyle(pListItemInfo->font_style, &font_ptr,
120                NULL, NULL, &font_asc, NULL);
121 
122          values.foreground = myBgPixel;
123          values.background = myFgPixel;
124          values.function = GXcopy;
125          values.fill_style = FillSolid;
126          XChangeGC(mainDisplay, gTidgetManager.gc,
127                GCForeground | GCBackground | GCFunction | GCFillStyle, &values);
128          XFillRectangle(mainDisplay, pTdgtList->dsp_win,
129                revNameGC, 0,
130                (index-pListInfo->first_index)*ROW_HEIGHT,
131                ITEM_LEN*defaultFontWidth, ROW_HEIGHT);
132 
133          switch (pListItemInfo->font_style) {
134          case STYLE_NR:
135             if (msgFontPtr != NULL) {
136                XSetFont(mainDisplay, gTidgetManager.gc, msgFontPtr->fid);
137             }
138             pf_draw_string_func = DrawMsgString;
139             break;
140          case STYLE_BR:
141             if (boldMsgFontPtr != NULL) {
142                XSetFont(mainDisplay, gTidgetManager.gc, boldMsgFontPtr->fid);
143             }
144             pf_draw_string_func = DrawBoldMsgString;
145             break;
146          case STYLE_NI:
147             if (italicMsgFontPtr != NULL) {
148                XSetFont(mainDisplay, gTidgetManager.gc, italicMsgFontPtr->fid);
149             }
150             pf_draw_string_func = DrawItalicMsgString;
151             break;
152          case STYLE_BI:
153             if (boldItalicMsgFontPtr != NULL) {
154                XSetFont(mainDisplay, gTidgetManager.gc,
155                      boldItalicMsgFontPtr->fid);
156             }
157             pf_draw_string_func = DrawBoldItalicMsgString;
158             break;
159          }
160          values.foreground = ((pListItemInfo->color_index == INVALID) ?
161                myFgPixel : colorPixels[pListItemInfo->color_index]);
162          values.background = myBgPixel;
163          values.function = GXcopy;
164          values.fill_style = FillSolid;
165          XChangeGC(mainDisplay, gTidgetManager.gc,
166                GCForeground |GCBackground |  GCFunction | GCFillStyle, &values);
167 
168          (pf_draw_string_func)(mainDisplay, pTdgtList->dsp_win,
169                gTidgetManager.gc, text_left,
170                (index-pListInfo->first_index)*ROW_HEIGHT+top, buf, strlen(buf));
171 
172          TidgetManagerResetGC();
173 
174          free(buf);
175       }
176    } else {
177       if (selected) {
178          values.foreground = myFgPixel;
179          values.background = myBgPixel;
180       } else {
181          values.foreground = myBgPixel;
182          values.background = myFgPixel;
183       }
184       values.function = GXcopy;
185       values.fill_style = FillSolid;
186       XChangeGC(mainDisplay, gTidgetManager.gc,
187             GCForeground | GCBackground | GCFunction | GCFillStyle, &values);
188       XFillRectangle(mainDisplay, pTdgtList->dsp_win, gTidgetManager.gc, 0,
189             (index-pListInfo->first_index)*ROW_HEIGHT,
190             ITEM_LEN*defaultFontWidth, ROW_HEIGHT);
191       len = strlen(pListInfo->entries[index]);
192       DrawMsgString(mainDisplay, pTdgtList->dsp_win, gTidgetManager.gc,
193             text_left, (index-pListInfo->first_index)*ROW_HEIGHT+top,
194             pListInfo->entries[index], len);
195       TidgetManagerResetGC();
196    }
197    if (checkbox_cols > 0) {
198       int col=0, cur_x=0;
199 
200       if (selected) {
201          values.foreground = myFgPixel;
202          values.background = myBgPixel;
203       } else {
204          values.foreground = myBgPixel;
205          values.background = myFgPixel;
206       }
207       values.function = GXcopy;
208       values.fill_style = FillSolid;
209       XChangeGC(mainDisplay, gTidgetManager.gc,
210             GCForeground | GCBackground | GCFunction | GCFillStyle, &values);
211       for (col=0; col < pListInfo->p_check_array->num_cols; col++) {
212          DrawCheckbox(mainDisplay, pTdgtList->dsp_win, gTidgetManager.gc,
213                cur_x+box_offset,
214                (index-pListInfo->first_index)*ROW_HEIGHT+top-box_w,
215                box_w, box_w, pListInfo->p_check_array->value[col][index]);
216          cur_x += ROW_HEIGHT;
217       }
218       TidgetManagerResetGC();
219    }
220 }
221 
222 static
RedrawTdgtListScrollWindow(pTdgtList)223 void RedrawTdgtListScrollWindow(pTdgtList)
224    TdgtList *pTdgtList;
225 {
226    ListInfo *pListInfo=(&pTdgtList->list_info);
227    double frac=(double)0, start_frac=(double)0;
228    int block_h=0, block_start=0;
229    int length=ListLength(&pListInfo->list);
230 
231    start_frac = (length > 0) ?  (double)((double)(pListInfo->first_index) /
232          (double)length) : ((double)0.0);
233    /* starting pixel */
234    block_start = (int)(pTdgtList->scr_area_h * start_frac);
235 
236    if (length > pListInfo->num_visible_lines) {
237       frac = (double)((double)pListInfo->num_visible_lines / (double)(length));
238    } else {
239       frac = 1.0;
240    }
241    if (pListInfo->first_index+pListInfo->num_visible_lines >= length) {
242       block_h = pTdgtList->scr_area_h - block_start;
243    } else {
244       block_h = (int)(pTdgtList->scr_area_h * frac);
245    }
246    TgDrawScrollBar(mainDisplay, pTdgtList->scr_win, VERT_SCROLLBAR,
247          0, 0, scrollBarW, pTdgtList->scr_area_h, start_frac,
248          pListInfo->num_visible_lines, length);
249 }
250 
251 static
RedrawTdgtListDspWindow(pTdgtList)252 void RedrawTdgtListDspWindow(pTdgtList)
253    TdgtList *pTdgtList;
254 {
255    ListInfo *pListInfo=(&pTdgtList->list_info);
256    int length=ListLength(&pListInfo->list);
257    int i=0, end=0;
258    XGCValues values;
259 
260    if (pListInfo->first_index+pListInfo->num_visible_lines > length) {
261       end = length;
262    } else {
263       end = pListInfo->first_index + pListInfo->num_visible_lines;
264    }
265    values.foreground = myBgPixel;
266    values.background = myFgPixel;
267    values.function = GXcopy;
268    values.fill_style = FillSolid;
269    XChangeGC(mainDisplay, gTidgetManager.gc,
270          GCForeground | GCBackground | GCFunction | GCFillStyle, &values);
271    XFillRectangle(mainDisplay, pTdgtList->dsp_win, gTidgetManager.gc, 0, 0,
272          pTdgtList->dsp_win_info.w, pTdgtList->dsp_win_info.h);
273    TidgetManagerResetGC();
274 
275    if (pTdgtList->multicolor) {
276       CVListElem *pElem=NULL;
277 
278       for (i=0, pElem=ListFirst(&pListInfo->list);
279             i < pListInfo->first_index && pElem != NULL;
280             i++, pElem=ListNext(&pListInfo->list, pElem)) {
281       }
282       for (i=pListInfo->first_index; i < end && pElem != NULL;
283             i++, pElem=ListNext(&pListInfo->list, pElem)) {
284          ListItemInfo *pListItemInfo=(ListItemInfo*)(pElem->obj);
285 
286          RedrawTdgtListItem(pTdgtList, i, pListItemInfo);
287       }
288    } else {
289       for (i=pListInfo->first_index; i < end; i++) {
290          RedrawTdgtListItem(pTdgtList, i, NULL);
291       }
292    }
293 }
294 
295 static
RedrawTdgtListBaseWindow(pTdgtList)296 void RedrawTdgtListBaseWindow(pTdgtList)
297    TdgtList *pTdgtList;
298 {
299    if (threeDLook) {
300       struct BBRec bbox;
301 
302       SetBBRec(&bbox, 0, 0, pTdgtList->pti->tci.win_info.w,
303             pTdgtList->pti->tci.win_info.h);
304       TgDrawThreeDButton(mainDisplay, pTdgtList->pti->tci.win,
305             gTidgetManager.gc, &bbox, TGBS_LOWRED, 2, FALSE);
306       TidgetManagerResetGC();
307    }
308 }
309 
310 static
RedrawTdgtList(pti)311 void RedrawTdgtList(pti)
312    TidgetInfo *pti;
313 {
314    TdgtList *pTdgtList=(TdgtList*)(pti->tidget);
315 
316    XEvent ev;
317 
318    RedrawTdgtListScrollWindow(pTdgtList);
319    RedrawTdgtListDspWindow(pTdgtList);
320    RedrawTdgtListBaseWindow(pTdgtList);
321 
322    while (XCheckWindowEvent(mainDisplay, pTdgtList->pti->tci.win, ExposureMask,
323          &ev)) ;
324 }
325 
326 /* --------------------- TdgtListEventHandler() --------------------- */
327 
328 static
TdgtListScrollItemCallback(pv_userdata)329 int TdgtListScrollItemCallback(pv_userdata)
330    void *pv_userdata;
331    /* returns TRUE to cancel scrolling */
332 {
333    TdgtList *pTdgtList=((TdgtList*)pv_userdata);
334    ListInfo *pListInfo=(&pTdgtList->list_info);
335    int num_visible_lines=pListInfo->num_visible_lines;
336    int length=ListLength(&pListInfo->list);
337 
338    if (pTdgtList->scr_dir == SCRL_UP) {
339       if (pListInfo->first_index == 0) return FALSE;
340       pListInfo->first_index--;
341    } else {
342       if (length <= num_visible_lines ||
343             pListInfo->first_index+num_visible_lines == length) {
344          return FALSE;
345       }
346       pListInfo->first_index++;
347    }
348    RedrawTdgtList(pTdgtList->pti);
349    XSync(mainDisplay, False);
350 
351    return FALSE;
352 }
353 
354 static
TdgtListScrollPageCallback(pv_userdata)355 int TdgtListScrollPageCallback(pv_userdata)
356    void *pv_userdata;
357    /* returns TRUE to cancel scrolling */
358 {
359    TdgtList *pTdgtList=((TdgtList*)pv_userdata);
360    ListInfo *pListInfo=(&pTdgtList->list_info);
361    int num_visible_lines=pListInfo->num_visible_lines;
362    int length=ListLength(&pListInfo->list);
363 
364    if (pTdgtList->scr_dir == SCRL_UP) {
365       if (pListInfo->first_index == 0) return FALSE;
366       pListInfo->first_index -= num_visible_lines;
367       if (pListInfo->first_index < 0) pListInfo->first_index = 0;
368    } else {
369       if (length <= num_visible_lines ||
370             pListInfo->first_index+num_visible_lines == length) {
371          return FALSE;
372       }
373       pListInfo->first_index += num_visible_lines;
374       if (pListInfo->first_index+num_visible_lines >= length) {
375          pListInfo->first_index = length-num_visible_lines;
376       }
377    }
378    RedrawTdgtList(pTdgtList->pti);
379    XSync(mainDisplay, False);
380 
381    return FALSE;
382 }
383 
384 static
DoTdgtListBtnScroll(pTdgtList,scroll_page,scr_dir,pbbox)385 int DoTdgtListBtnScroll(pTdgtList, scroll_page, scr_dir, pbbox)
386    TdgtList *pTdgtList;
387    int scroll_page, scr_dir;
388    struct BBRec *pbbox;
389    /* returns TRUE if done scrolling */
390 {
391    ListInfo *pListInfo=(&pTdgtList->list_info);
392    int num_visible_lines=pListInfo->num_visible_lines;
393    int length=ListLength(&pListInfo->list);
394    ScrollBtnCallbackInfo sbci;
395 
396    pTdgtList->scr_dir = scr_dir;
397    memset(&sbci, 0, sizeof(ScrollBtnCallbackInfo));
398 
399    if (scroll_page) {
400       sbci.ms = 200;
401       sbci.pv_userdata = pTdgtList;
402       sbci.pf_scroll_btn_callback = TdgtListScrollPageCallback;
403       if (TgPressButtonLoop(mainDisplay, pTdgtList->scr_win, NULL,
404             &sbci)) {
405          if (scr_dir == SCRL_UP) {
406             if (pListInfo->first_index == 0) return TRUE;
407             pListInfo->first_index -= num_visible_lines;
408             if (pListInfo->first_index < 0) pListInfo->first_index = 0;
409          } else {
410             if (length <= num_visible_lines ||
411                   pListInfo->first_index+num_visible_lines == length) {
412                return TRUE;
413             }
414             pListInfo->first_index += num_visible_lines;
415             if (pListInfo->first_index+num_visible_lines >= length) {
416                pListInfo->first_index = length-num_visible_lines;
417             }
418          }
419       }
420    } else {
421       sbci.ms = 50;
422       sbci.pv_userdata = pTdgtList;
423       sbci.pf_scroll_btn_callback = TdgtListScrollItemCallback;
424       if (TgPressButtonLoop(mainDisplay, pTdgtList->scr_win, pbbox, &sbci)) {
425          if (scr_dir == SCRL_UP) {
426             if (pListInfo->first_index == 0) return TRUE;
427             pListInfo->first_index--;
428          } else {
429             if (length <= num_visible_lines ||
430                   pListInfo->first_index+num_visible_lines == length) {
431                return TRUE;
432             }
433             pListInfo->first_index++;
434          }
435       }
436    }
437    return FALSE;
438 }
439 
440 static
DoDragInTdgtList(pTdgtList,button_ev,btn_y,btn_offset)441 void DoDragInTdgtList(pTdgtList, button_ev, btn_y, btn_offset)
442    TdgtList *pTdgtList;
443    XButtonEvent *button_ev;
444    int btn_y, btn_offset;
445 {
446    ListInfo *pListInfo=(&pTdgtList->list_info);
447    int length=ListLength(&pListInfo->list);
448    int num_visible_lines=pListInfo->num_visible_lines;
449    double frac=(double)0, start_frac=(double)0;
450    int block_h=0, block_start=0, done=FALSE;
451 
452    if (length <= num_visible_lines) return;
453 
454    frac = (double)((double)num_visible_lines / (double)(length));
455    block_h = (int)(pTdgtList->scr_area_h * frac);
456 
457    if (length > pListInfo->num_visible_lines) {
458       frac = (double)((double)pListInfo->num_visible_lines / (double)(length));
459       block_h = (int)(((double)(pTdgtList->scr_area_h-(scrollBarW<<1))) * frac);
460    } else {
461       frac = 1.0;
462       block_h = pTdgtList->scr_area_h-(scrollBarW<<1);
463    }
464    if (threeDLook) {
465       block_start = button_ev->y+btn_offset;;
466       start_frac = (double)((double)(block_start-scrollBarW) /
467             (double)(pTdgtList->scr_area_h-(scrollBarW<<1)));
468       if (block_start+block_h >= pTdgtList->scr_area_h-scrollBarW) {
469          pListInfo->first_index = length - num_visible_lines;
470       } else {
471          pListInfo->first_index = (int)(length * start_frac);
472       }
473    } else {
474       block_start = button_ev->y;
475       start_frac = (double)((double)(block_start) /
476             (double)(pTdgtList->scr_area_h));
477       if (block_start+block_h >= pTdgtList->scr_area_h) {
478          pListInfo->first_index = length - num_visible_lines;
479       } else {
480          pListInfo->first_index = (int)(length * start_frac);
481       }
482    }
483    RedrawTdgtList(pTdgtList->pti);
484 
485    XGrabPointer(mainDisplay, pTdgtList->scr_win, False,
486          PointerMotionMask | ButtonReleaseMask, GrabModeAsync,
487          GrabModeAsync, None, handCursor, CurrentTime);
488 
489    while (!done) {
490       XEvent ev;
491 
492       XNextEvent(mainDisplay, &ev);
493 
494       if (ev.type == Expose || ev.type == VisibilityNotify) {
495          ExposeEventHandler(&ev, TRUE);
496       } else if (ev.type == ButtonRelease) {
497          XUngrabPointer(mainDisplay, CurrentTime);
498          if (debugNoPointerGrab) XSync(mainDisplay, False);
499          done = TRUE;
500       } else if (ev.type == MotionNotify) {
501          int new_name_first=0, y=ev.xmotion.y;
502 
503          if (threeDLook) {
504             y += btn_offset;
505             start_frac = (double)(((double)(y-scrollBarW)) /
506                  ((double)(pTdgtList->scr_area_h-(scrollBarW<<1))));
507 
508             if (y <= scrollBarW) {
509                new_name_first = 0;
510             } else if (y+block_h >= pTdgtList->scr_area_h-scrollBarW) {
511                new_name_first = length - num_visible_lines;
512             } else {
513                new_name_first = (int)(length * start_frac);
514             }
515          } else {
516             start_frac = (double)(((double)y) /
517                  ((double)pTdgtList->scr_area_h));
518 
519             if (y <= 0) {
520                new_name_first = 0;
521             } else if (y+block_h >= pTdgtList->scr_area_h) {
522                new_name_first = length - num_visible_lines;
523             } else {
524                new_name_first = (int)(length * start_frac);
525             }
526          }
527          if (pListInfo->first_index != new_name_first) {
528             pListInfo->first_index = new_name_first;
529             RedrawTdgtList(pTdgtList->pti);
530          }
531          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
532       }
533    }
534 }
535 
536 static
TdgtListScrollHandler(pTdgtList,button_ev)537 void TdgtListScrollHandler(pTdgtList, button_ev)
538    TdgtList *pTdgtList;
539    XButtonEvent *button_ev;
540 {
541    ListInfo *pListInfo=(&pTdgtList->list_info);
542    int length=ListLength(&pListInfo->list);
543    int do_drag=FALSE, btn_offset=0;
544 
545    if (!threeDLook && button_ev->button == Button3 &&
546          button_ev->type == ButtonPress) {
547       if (DoTdgtListBtnScroll(pTdgtList,
548             ((button_ev->state & (ShiftMask|ControlMask)) != 0),
549             SCRL_UP, NULL)) {
550          return;
551       }
552    } else if (!threeDLook && button_ev->button == Button1 &&
553          button_ev->type == ButtonPress) {
554       if (DoTdgtListBtnScroll(pTdgtList,
555             ((button_ev->state & (ShiftMask|ControlMask)) != 0),
556             SCRL_DN, NULL)) {
557          return;
558       }
559    } else if (button_ev->button == Button1 && button_ev->type == ButtonPress) {
560       if (button_ev->y < scrollBarW ||
561             button_ev->y >= pTdgtList->scr_area_h-scrollBarW) {
562          int which=INVALID;
563          struct BBRec bbox;
564 
565          if (button_ev->y < scrollBarW) {
566             which = SCRL_UP;
567             SetBBRec(&bbox, 0, 0, scrollBarW, scrollBarW);
568          } else {
569             which = SCRL_DN;
570             SetBBRec(&bbox, 0, pTdgtList->scr_area_h-scrollBarW, scrollBarW,
571                   pTdgtList->scr_area_h);
572          }
573          if (DoTdgtListBtnScroll(pTdgtList, FALSE, which, &bbox)) {
574             return;
575          }
576       } else {
577          double start_frac=(double)0;
578          int hit=0;
579 
580          start_frac = (length > 0) ?
581                (double)((double)(pListInfo->first_index) / (double)length) :
582                ((double)0.0);
583          hit = TgGetScrollHit(button_ev->x, button_ev->y, VERT_SCROLLBAR,
584                scrollBarW, pTdgtList->scr_area_h, start_frac,
585                pListInfo->num_visible_lines, length, &btn_offset);
586          if (hit == 0) {
587             do_drag = TRUE;
588          } else {
589             if (DoTdgtListBtnScroll(pTdgtList, TRUE,
590                   (hit < 0 ? SCRL_UP : SCRL_DN), NULL)) {
591                return;
592             }
593          }
594       }
595    } else if (!threeDLook && button_ev->button == Button2 &&
596          button_ev->type == ButtonPress) {
597       do_drag = TRUE;
598    }
599    if (do_drag) {
600       DoDragInTdgtList(pTdgtList, button_ev, button_ev->y, btn_offset);
601    } else {
602       RedrawTdgtList(pTdgtList->pti);
603    }
604 }
605 
606 static
TdgtListDspHandler(pTdgtList,button_ev)607 int TdgtListDspHandler(pTdgtList, button_ev)
608    TdgtList *pTdgtList;
609    XButtonEvent *button_ev;
610 {
611    if (enableMouseWheel &&
612          (button_ev->button == Button4 || button_ev->button == Button5)) {
613       int which=INVALID;
614       struct BBRec bbox;
615 
616       if (button_ev->button == Button4) {
617          which = SCRL_UP;
618          SetBBRec(&bbox, 0, 0, scrollBarW, scrollBarW);
619       } else if (button_ev->button == Button5) {
620          which = SCRL_DN;
621          SetBBRec(&bbox, 0, pTdgtList->scr_area_h-scrollBarW, scrollBarW,
622                pTdgtList->scr_area_h);
623       }
624       if (which != INVALID) {
625          DoTdgtListBtnScroll(pTdgtList, FALSE, which, &bbox);
626          RedrawTdgtList(pTdgtList->pti);
627       }
628       return INVALID;
629    } else if (button_ev->button != Button1) {
630       return INVALID;
631    }
632    return INVALID;
633 }
634 
635 static
TdgtListControlChar(pTdgtList,key_ev,key_sym)636 int TdgtListControlChar(pTdgtList, key_ev, key_sym)
637    TdgtList *pTdgtList;
638    XKeyEvent *key_ev;
639    KeySym key_sym;
640 {
641    ListInfo *pListInfo=(&pTdgtList->list_info);
642    int length=ListLength(&pListInfo->list);
643    int num_visible_lines=pListInfo->num_visible_lines;
644    int i=0;
645 
646    if (key_ev->state & ControlMask) {
647       switch (key_sym) {
648       case XK_Left: return (BAD);
649       case XK_KP_Left: return (BAD);
650       case XK_Up: key_sym = ((unsigned long)'b')&0xff; break;
651       case XK_KP_Up: key_sym = ((unsigned long)'b')&0xff; break;
652       case XK_Right: return (BAD);
653       case XK_KP_Right: return (BAD);
654       case XK_Down: key_sym = ((unsigned long)'f')&0xff; break;
655       case XK_KP_Down: key_sym = ((unsigned long)'f')&0xff; break;
656       case XK_Page_Up: key_sym = ((unsigned long)'b')&0xff; break;
657       case XK_KP_Page_Up: key_sym = ((unsigned long)'b')&0xff; break;
658       case XK_Page_Down: key_sym = ((unsigned long)'f')&0xff; break;
659       case XK_KP_Page_Down: key_sym = ((unsigned long)'f')&0xff; break;
660       }
661    } else {
662       switch (key_sym) {
663       case XK_Left: return BAD;
664       case XK_KP_Left: return BAD;
665       case XK_Up: key_sym = ((unsigned long)'k')&0xff; break;
666       case XK_KP_Up: key_sym = ((unsigned long)'k')&0xff; break;
667       case XK_Right: return BAD;
668       case XK_KP_Right: return BAD;
669       case XK_Down: key_sym = ((unsigned long)'j')&0xff; break;
670       case XK_KP_Down: key_sym = ((unsigned long)'j')&0xff; break;
671       case XK_Page_Up: key_sym = ((unsigned long)'b')&0xff; break;
672       case XK_KP_Page_Up: key_sym = ((unsigned long)'b')&0xff; break;
673       case XK_Page_Down: key_sym = ((unsigned long)'f')&0xff; break;
674       case XK_KP_Page_Down: key_sym = ((unsigned long)'f')&0xff; break;
675       }
676    }
677    switch (key_sym&0xff) {
678    case 'w': /* erase */
679    case 'y':
680       return INVALID;
681    case 'n': /* down one */
682    case 'j':
683       if (pTdgtList->can_select) {
684          /*
685           * i = (pni->marked_index < length-1) ?
686           *       pni->marked_index+1 : length-1;
687           */
688       } else {
689          if (length > num_visible_lines) {
690             if (pListInfo->first_index+num_visible_lines < length) {
691                pListInfo->first_index++;
692             }
693          }
694       }
695       break;
696    case 'p': /* up one */
697    case 'k':
698       if (pTdgtList->can_select) {
699          /*
700           * i = (pni->marked_index>0) ? pni->marked_index-1 : 0;
701           */
702       } else {
703          if (length > num_visible_lines) {
704             if (pListInfo->first_index > 0) {
705                pListInfo->first_index--;
706             }
707          }
708       }
709       break;
710    case 'd': /* down one page */
711    case 'f':
712       if (pTdgtList->can_select) {
713          /*
714           * if (pni->marked_index==INVALID) {
715           *    i = (length <= num_visible_lines) ?  length-1 :
716           *          num_visible_lines;
717           * } else if (pni->marked_index < length-num_visible_lines) {
718           *    i = pni->marked_index+num_visible_lines;
719           * } else {
720           *    i = length-1;
721           * }
722           */
723       } else {
724          if (length > num_visible_lines) {
725             if (pListInfo->first_index+num_visible_lines < length) {
726                pListInfo->first_index += num_visible_lines;
727                if (pListInfo->first_index + num_visible_lines > length) {
728                   pListInfo->first_index = length - num_visible_lines;
729                }
730             }
731          }
732       }
733       break;
734    case 'u': /* up one page */
735    case 'b':
736       if (pTdgtList->can_select) {
737          /*
738           * i = (pni->marked_index > (num_visible_lines-1)) ?
739           *       pni->marked_index-num_visible_lines : 0;
740           */
741       } else {
742          pListInfo->first_index -= num_visible_lines;
743          if (pListInfo->first_index < 0) pListInfo->first_index = 0;
744       }
745       break;
746    default: return BAD;
747    }
748    return i;
749 }
750 
751 static
SpecialKeyInTdgtList(pTdgtList,key_ev,key_sym,pn_changing,pn_selected_btn_index)752 void SpecialKeyInTdgtList(pTdgtList, key_ev, key_sym, pn_changing,
753       pn_selected_btn_index)
754    TdgtList *pTdgtList;
755    XKeyEvent *key_ev;
756    KeySym key_sym;
757    int *pn_changing, *pn_selected_btn_index;
758 {
759    ListInfo *pListInfo=(&pTdgtList->list_info);
760    int saved_first=pListInfo->first_index;
761    int saved_marked=pListInfo->marked_index;
762    int rc=TdgtListControlChar(pTdgtList, key_ev, key_sym);
763 
764    if (rc == BAD || rc == INVALID) return;
765 
766    if (saved_first != pListInfo->first_index ||
767          saved_marked != pListInfo->marked_index) {
768       RedrawTdgtList(pTdgtList->pti);
769    }
770 }
771 
772 static XComposeStatus c_stat;
773 
774 static
KeyPressInTdgtList(pTdgtList,key_ev,pn_changing,pn_selected_btn_index)775 int KeyPressInTdgtList(pTdgtList, key_ev, pn_changing, pn_selected_btn_index)
776    TdgtList *pTdgtList;
777    XKeyEvent *key_ev;
778    int *pn_changing, *pn_selected_btn_index;
779 {
780    ListInfo *pListInfo=(&pTdgtList->list_info);
781    int length=ListLength(&pListInfo->list);
782    char buf[80];
783    KeySym key_sym;
784    int has_ch=FALSE;
785 
786    has_ch = XLookupString(key_ev, buf, sizeof(buf), &key_sym, &c_stat);
787    TranslateKeys(buf, &key_sym);
788 
789    if ((key_ev->state & ControlMask) && key_sym == XK_j) {
790       SpecialKeyInTdgtList(pTdgtList, key_ev, key_sym, pn_changing,
791             pn_selected_btn_index);
792    } else if (CharIsCRorLF(key_ev, buf, key_sym, &has_ch)) {
793       if (pTdgtList->can_select) {
794          /*
795           * if (pni->def_btn_id != INVALID) {
796           *    *pn_changing = FALSE;
797           *    *pn_selected_btn_index = GetBtnIndexFromBtnId(pni->def_btn_id);
798           * }
799           */
800       } else {
801          return FALSE;
802       }
803    } else if (CharIsESC(key_ev, buf, key_sym, &has_ch)) {
804       if (pTdgtList->can_select) {
805          /*
806           * *pn_changing = FALSE;
807           * *pn_selected_btn_index = GetBtnIndexFromBtnId(BUTTON_CANCEL);
808           */
809       }
810    } else if (CharIsBSorDEL(key_ev, buf, key_sym, &has_ch, FALSE)) {
811       if (pTdgtList->can_select) {
812          /*
813           * if (pni->edit_style == NAMES_SELECT_FILE &&
814           *       (pni->faking_dot_dot || pni->pop_from_root)) {
815           *    *pn_changing = FALSE;
816           *    *pn_selected_btn_index = INVALID;
817           * } else {
818           *    BackSpaceInNames(pn_changing, pn_selected_btn_index);
819           * }
820           */
821       }
822    } else if (CharIsTAB(key_ev, buf, key_sym, &has_ch)) {
823       if (pTdgtList->can_select) {
824          /* should tab out of focus?! */
825       }
826    } else if (length != 0 && ((key_sym>'\040' && key_sym<='\177' &&
827          (key_ev->state & ControlMask)) || key_sym==XK_Up ||
828          key_sym==XK_Down || key_sym==XK_KP_Up || key_sym==XK_KP_Down ||
829          key_sym==XK_Page_Up || key_sym==XK_KP_Page_Up ||
830          key_sym==XK_Page_Down || key_sym==XK_KP_Page_Down)) {
831       SpecialKeyInTdgtList(pTdgtList, key_ev, key_sym, pn_changing,
832             pn_selected_btn_index);
833    } else if (key_sym>='\040' && key_sym<='\177' && length != 0) {
834       if (pTdgtList->can_select) {
835          /*
836           * CharInNames(buf, pn_changing, pn_selected_btn_index);
837           */
838       }
839       return FALSE;
840    }
841    return TRUE;
842 }
843 
844 static
ButtonPressInTdgtList(pTdgtList,button_ev,pn_changing,pn_selected_btn_index)845 void ButtonPressInTdgtList(pTdgtList, button_ev, pn_changing,
846       pn_selected_btn_index)
847    TdgtList *pTdgtList;
848    XButtonEvent *button_ev;
849    int *pn_changing, *pn_selected_btn_index;
850 {
851    if (button_ev->window == pTdgtList->scr_win) {
852       TdgtListScrollHandler(pTdgtList, button_ev);
853    } else if (button_ev->window == pTdgtList->dsp_win) {
854       int double_clicked=(TdgtListDspHandler(pTdgtList, button_ev)!=INVALID);
855 
856       if (double_clicked) {
857          /* do something here */
858       }
859       if (pTdgtList->can_select) {
860          /* do something here */
861       }
862    }
863 }
864 
865 static
TdgtListEventHandler(pti,input,handling_pti)866 int TdgtListEventHandler(pti, input, handling_pti)
867    TidgetInfo *pti, *handling_pti;
868    XEvent *input;
869 {
870    TdgtList *pTdgtList=(TdgtList*)(pti->tidget);
871 
872    if (pti != handling_pti) return FALSE;
873 
874    if (input->type == Expose) {
875       RedrawTdgtList(pTdgtList->pti);
876    } else if (input->type == KeyPress) {
877       if (pTdgtList->can_select) {
878          /* KeyPressInTdgtList(pTdgtList, &changing, &selected_btn_index); */
879       } else {
880          return KeyPressInTdgtList(pTdgtList, &input->xkey, NULL, NULL);
881       }
882    } else if (input->type == ButtonPress) {
883       if (pTdgtList->can_select) {
884          /* ButtonPressInTdgtList(pTdgtList, &changing, &selected_btn_index); */
885       } else {
886          ButtonPressInTdgtList(pTdgtList, &input->xbutton, NULL, NULL);
887       }
888    }
889    return TRUE;
890 }
891 
892 /* --------------------- IsTdgtListEvent() --------------------- */
893 
894 static
IsTdgtListEvent(pti,input,ppti_handler_tidget_return)895 int IsTdgtListEvent(pti, input, ppti_handler_tidget_return)
896    TidgetInfo *pti, **ppti_handler_tidget_return;
897    XEvent *input;
898 {
899    TdgtList *pTdgtList=(TdgtList*)(pti->tidget);
900 
901    if (input->xany.window == pTdgtList->pti->tci.win ||
902          input->xany.window == pTdgtList->dsp_win ||
903          input->xany.window == pTdgtList->scr_win) {
904       *ppti_handler_tidget_return = pti;
905       return TRUE;
906    }
907    return FALSE;
908 }
909 
910 /* --------------------- DestroyTdgtList() --------------------- */
911 
912 static
DestroyTdgtList(pti)913 void DestroyTdgtList(pti)
914    TidgetInfo *pti;
915 {
916    TdgtList *pTdgtList=(TdgtList*)(pti->tidget);
917 
918    TdgtListReset(pTdgtList);
919 
920    free(pTdgtList);
921 }
922 
923 /* --------------------- MapTdgtList() --------------------- */
924 
925 static
MapTdgtList(pti)926 void MapTdgtList(pti)
927    TidgetInfo *pti;
928 {
929    TdgtList *pTdgtList=(TdgtList*)(pti->tidget);
930 
931 #ifdef MAPBEFORESELECT
932    XMapWindow(mainDisplay, pTdgtList->pti->tci.win);
933    XSelectInput(mainDisplay, pTdgtList->pti->tci.win, ExposureMask);
934 
935    XMapWindow(mainDisplay, pTdgtList->dsp_win);
936    XSelectInput(mainDisplay, pTdgtList->dsp_win, KeyPressMask |
937          ButtonPressMask | ExposureMask);
938 
939    XMapWindow(mainDisplay, pTdgtList->scr_win);
940    XSelectInput(mainDisplay, pTdgtList->scr_win, KeyPressMask |
941          ButtonPressMask | ExposureMask);
942 #else
943    XSelectInput(mainDisplay, pTdgtList->pti->tci.win, ExposureMask);
944    XMapWindow(mainDisplay, pTdgtList->pti->tci.win);
945 
946    XSelectInput(mainDisplay, pTdgtList->dsp_win, KeyPressMask |
947          ButtonPressMask | ExposureMask);
948    XMapWindow(mainDisplay, pTdgtList->dsp_win);
949 
950    XSelectInput(mainDisplay, pTdgtList->scr_win, KeyPressMask |
951          ButtonPressMask | ExposureMask);
952    XMapWindow(mainDisplay, pTdgtList->scr_win);
953 #endif
954 }
955 
956 /* --------------------- TdgtListMoveResize() --------------------- */
957 
958 static
TdgtListMoveResize(pti,x,y,w,h)959 void TdgtListMoveResize(pti, x, y, w, h)
960    TidgetInfo *pti;
961    int x, y, w, h;
962 {
963    TdgtList *pTdgtList=(TdgtList*)(pti->tidget);
964 
965    pTdgtList->pti->tci.win_info.x = x;
966    pTdgtList->pti->tci.win_info.y = y;
967    pTdgtList->pti->tci.win_info.w = w;
968    pTdgtList->pti->tci.win_info.h = h;
969 
970    pTdgtList->pti->tci.content_w =
971          w-(windowPadding<<1)-pTdgtList->pti->tci.h_pad;
972    pTdgtList->pti->tci.content_h =
973          h-(windowPadding<<1)-pTdgtList->pti->tci.v_pad;
974    XMoveResizeWindow(mainDisplay, pTdgtList->pti->tci.win, x, y, w, h);
975 
976    pTdgtList->dsp_win_info.x = windowPadding;
977    pTdgtList->dsp_win_info.y = windowPadding;
978    pTdgtList->dsp_win_info.w = w-(windowPadding<<1)-scrollBarW;
979    pTdgtList->dsp_win_info.h = h-(windowPadding<<1);
980    XMoveResizeWindow(mainDisplay, pTdgtList->dsp_win, pTdgtList->dsp_win_info.x,
981          pTdgtList->dsp_win_info.y, pTdgtList->dsp_win_info.w,
982          pTdgtList->dsp_win_info.h);
983 
984    pTdgtList->scr_win_info.x = w-windowPadding-scrollBarW;
985    pTdgtList->scr_win_info.y = windowPadding;
986    pTdgtList->scr_win_info.w = scrollBarW;
987    pTdgtList->scr_win_info.h = h-(windowPadding<<1);
988    XMoveResizeWindow(mainDisplay, pTdgtList->scr_win, pTdgtList->scr_win_info.x,
989          pTdgtList->scr_win_info.y, pTdgtList->scr_win_info.w,
990          pTdgtList->scr_win_info.h);
991 }
992 
993 /* --------------------- TdgtListSendCmd() --------------------- */
994 
995 static
TdgtListSendCmd(pti,cmd_type,cmd_arg,pv_cmd_userdata)996 int TdgtListSendCmd(pti, cmd_type, cmd_arg, pv_cmd_userdata)
997    TidgetInfo *pti;
998    int cmd_type, cmd_arg;
999    void *pv_cmd_userdata;
1000 {
1001    TdgtList *pTdgtList=(TdgtList*)(pti->tidget);
1002 
1003    if (pTdgtList != NULL) {
1004    }
1005    return FALSE;
1006 }
1007 
1008 /* --------------------- TdgtListReset() --------------------- */
1009 
TdgtListReset(pTdgtList)1010 void TdgtListReset(pTdgtList)
1011    TdgtList *pTdgtList;
1012 {
1013    ListInfo *pListInfo=(&pTdgtList->list_info);
1014    CVListElem *pElem=NULL;
1015 
1016    TdgtListCleanUpEntries(pTdgtList);
1017 
1018    for (pElem=ListFirst(&pListInfo->list); pElem != NULL;
1019          pElem=ListNext(&pListInfo->list, pElem)) {
1020       ListItemInfo *pListItemInfo=(ListItemInfo*)(pElem->obj);
1021 
1022       FreeListItemInfo(pListItemInfo);
1023    }
1024    ListUnlinkAll(&pListInfo->list);
1025 }
1026 
1027 /* --------------------- CreateTdgtList() --------------------- */
1028 
1029 static
TdgtListCalcHeight(num_visible_lines,pn_content_h)1030 void TdgtListCalcHeight(num_visible_lines, pn_content_h)
1031    int num_visible_lines, *pn_content_h;
1032 {
1033    int h=(num_visible_lines*ROW_HEIGHT);
1034 
1035    if (pn_content_h != NULL) *pn_content_h = h;
1036 }
1037 
CreateTdgtList(parent_win,parent_tidgetinfo,ctl_id,x,y,w,h_pad,v_pad,num_visible_lines,can_select,multicolor,auto_scroll_on_insert)1038 TdgtList *CreateTdgtList(parent_win, parent_tidgetinfo, ctl_id, x, y, w, h_pad,
1039       v_pad, num_visible_lines, can_select, multicolor, auto_scroll_on_insert)
1040    Window parent_win;
1041    TidgetInfo *parent_tidgetinfo;
1042    int ctl_id, x, y, w, h_pad, v_pad, num_visible_lines, auto_scroll_on_insert;
1043 {
1044    int bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel), h=0, content_h=0;
1045    TdgtList *pTdgtList=NULL;
1046 
1047    TdgtListCalcHeight(num_visible_lines, &content_h);
1048 
1049    h = content_h + (windowPadding<<1) + (v_pad<<1);
1050 
1051    pTdgtList = (TdgtList*)malloc(sizeof(TdgtList));
1052    if (pTdgtList == NULL) FailAllocMessage();
1053    memset(pTdgtList, 0, sizeof(TdgtList));
1054 
1055    pTdgtList->pti = NewTidgetInfo(parent_tidgetinfo, TIDGET_TYPE_LIST,
1056          pTdgtList, ctl_id, NULL);
1057    if ((pTdgtList->pti->tci.win=XCreateSimpleWindow(mainDisplay, parent_win,
1058          x, y, w, h, brdrW, myBorderPixel, bg_pixel)) == 0) {
1059       FailToCreateWindowMessage("CreateTdgtList()", NULL, TRUE);
1060    }
1061    XSelectInput(mainDisplay, pTdgtList->pti->tci.win, ExposureMask);
1062    SetTidgetInfoBasic(pTdgtList->pti, TIDGET_TYPE_LIST, pTdgtList, parent_win,
1063          x, y, w, h, h_pad, v_pad, TGBS_LOWRED, NULL);
1064    TidgetSetCallbacks(pTdgtList->pti,
1065          RedrawTdgtList, TdgtListEventHandler, IsTdgtListEvent, DestroyTdgtList,
1066          MapTdgtList, TdgtListMoveResize, TdgtListSendCmd);
1067 
1068    CVListInit(&pTdgtList->list_info.list);
1069 
1070    /* Note: scrollBarW accounts for windowPadding */
1071    if ((pTdgtList->dsp_win=XCreateSimpleWindow(mainDisplay,
1072          pTdgtList->pti->tci.win, windowPadding, windowPadding,
1073          w-(windowPadding<<1)-scrollBarW, h-(windowPadding<<1), brdrW,
1074          myBorderPixel, bg_pixel)) == 0) {
1075       FailToCreateWindowMessage("CreateTdgtList()", NULL, TRUE);
1076    }
1077    XSelectInput(mainDisplay, pTdgtList->dsp_win, KeyPressMask |
1078          ButtonPressMask | ExposureMask);
1079    pTdgtList->dsp_win_info.x = windowPadding;
1080    pTdgtList->dsp_win_info.y = windowPadding;
1081    pTdgtList->dsp_win_info.w = w-(windowPadding<<1)-scrollBarW;
1082    pTdgtList->dsp_win_info.h = h-(windowPadding<<1);
1083 
1084    if ((pTdgtList->scr_win=XCreateSimpleWindow(mainDisplay,
1085          pTdgtList->pti->tci.win, w-windowPadding-scrollBarW, windowPadding,
1086          scrollBarW, h-(windowPadding<<1), brdrW, myBorderPixel, bg_pixel)) ==
1087          0) {
1088       FailToCreateWindowMessage("CreateTdgtList()", NULL, TRUE);
1089    }
1090    XSelectInput(mainDisplay, pTdgtList->scr_win, KeyPressMask |
1091          ButtonPressMask | ExposureMask);
1092    pTdgtList->scr_win_info.x = w-windowPadding-scrollBarW;
1093    pTdgtList->scr_win_info.y = windowPadding;
1094    pTdgtList->scr_win_info.w = scrollBarW;
1095    pTdgtList->scr_win_info.h = h-(windowPadding<<1);
1096 
1097    pTdgtList->list_info.num_visible_lines = num_visible_lines;
1098    pTdgtList->can_select = can_select;
1099    pTdgtList->multicolor = (colorDisplay ? multicolor : FALSE);
1100    pTdgtList->auto_scroll_on_insert = auto_scroll_on_insert;
1101 
1102    pTdgtList->scr_area_h = num_visible_lines*ROW_HEIGHT;
1103 
1104    return pTdgtList;
1105 }
1106 
1107 /* --------------------- TdgtListCleanUpEntries() --------------------- */
1108 
TdgtListCleanUpEntries(pTdgtList)1109 int TdgtListCleanUpEntries(pTdgtList)
1110    TdgtList *pTdgtList;
1111 {
1112    ListInfo *pListInfo=(&pTdgtList->list_info);
1113    int length=ListLength(&pListInfo->list);
1114 
1115    if (pListInfo->entries != NULL) {
1116       int i=0;
1117 
1118       for (i=0; i < length; i++) {
1119          UtilFree(pListInfo->entries[i]);
1120       }
1121       free(pListInfo->entries);
1122       pListInfo->entries = NULL;
1123    }
1124    return TRUE;
1125 }
1126 
1127 /* --------------------- TdgtListUpdateEntries() --------------------- */
1128 
TdgtListUpdateEntries(pTdgtList)1129 int TdgtListUpdateEntries(pTdgtList)
1130    TdgtList *pTdgtList;
1131 {
1132    ListInfo *pListInfo=(&pTdgtList->list_info);
1133    CVListElem *pElem=NULL;
1134    int length=ListLength(&pListInfo->list), index=0;
1135 
1136    if (pListInfo->entries != NULL) {
1137       TdgtListCleanUpEntries(pTdgtList);
1138    }
1139    pListInfo->entries = (char**)malloc(length*sizeof(char*));
1140    if (pListInfo->entries == NULL) FailAllocMessage();
1141    memset(pListInfo->entries, 0, length*sizeof(char*));
1142 
1143    for (pElem=ListFirst(&pListInfo->list); pElem != NULL;
1144          pElem=ListNext(&pListInfo->list, pElem), index++) {
1145       ListItemInfo *pListItemInfo=(ListItemInfo*)(pElem->obj);
1146 
1147       pListInfo->entries[index] = UtilStrDup(pListItemInfo->buf);
1148       if (pListInfo->entries[index] == NULL) FailAllocMessage();
1149    }
1150    return TRUE;
1151 }
1152 
1153 /* --------------------- TdgtListScrollToBottom() --------------------- */
1154 
TdgtListScrollToBottom(pTdgtList)1155 int TdgtListScrollToBottom(pTdgtList)
1156    TdgtList *pTdgtList;
1157 {
1158    ListInfo *pListInfo=(&pTdgtList->list_info);
1159    int length=ListLength(&pListInfo->list);
1160 
1161    if (pListInfo->num_visible_lines < length) {
1162       pListInfo->first_index = length - pListInfo->num_visible_lines;
1163    } else {
1164       pListInfo->first_index = 0;
1165    }
1166    return TRUE;
1167 }
1168 
1169 /* --------------------- TdgtListInsertString() --------------------- */
1170 
TdgtListInsertString(pTdgtList,buf)1171 int TdgtListInsertString(pTdgtList, buf)
1172    TdgtList *pTdgtList;
1173    char *buf;
1174 {
1175    ListInfo *pListInfo=(&pTdgtList->list_info);
1176    ListItemInfo *pListItemInfo=(ListItemInfo*)malloc(sizeof(ListItemInfo));
1177 
1178    if (pListItemInfo == NULL) FailAllocMessage();
1179    memset(pListItemInfo, 0, sizeof(ListItemInfo));
1180 
1181    *pListItemInfo->nick_name = '\0';
1182    pListItemInfo->color_index = colorIndex;
1183    pListItemInfo->font_style = STYLE_NR;
1184    pListItemInfo->buf = UtilStrDup(buf);
1185    if (pListItemInfo->buf == NULL) FailAllocMessage();
1186 
1187    TdgtListCleanUpEntries(pTdgtList);
1188    ListAppend(&pListInfo->list, pListItemInfo);
1189 
1190    if (pTdgtList->auto_scroll_on_insert) {
1191       TdgtListScrollToBottom(pTdgtList);
1192    }
1193    TdgtListUpdateEntries(pTdgtList);
1194    RedrawTdgtList(pTdgtList->pti);
1195 
1196    return TRUE;
1197 }
1198 
TdgtListInsertListItemInfo(pTdgtList,pListItemInfo)1199 int TdgtListInsertListItemInfo(pTdgtList, pListItemInfo)
1200    TdgtList *pTdgtList;
1201    ListItemInfo *pListItemInfo;
1202 {
1203    ListInfo *pListInfo=(&pTdgtList->list_info);
1204 
1205    TdgtListCleanUpEntries(pTdgtList);
1206    ListAppend(&pListInfo->list, pListItemInfo);
1207 
1208    if (pTdgtList->auto_scroll_on_insert) {
1209       TdgtListScrollToBottom(pTdgtList);
1210    }
1211    TdgtListUpdateEntries(pTdgtList);
1212    RedrawTdgtList(pTdgtList->pti);
1213 
1214    return TRUE;
1215 }
1216 
TdgtListSetAutoScrollOnInsert(pTdgtList,auto_scroll_on_insert)1217 int TdgtListSetAutoScrollOnInsert(pTdgtList, auto_scroll_on_insert)
1218    TdgtList *pTdgtList;
1219    int auto_scroll_on_insert;
1220 {
1221    pTdgtList->auto_scroll_on_insert = auto_scroll_on_insert;
1222    return TRUE;
1223 }
1224 
TdgtListGetAutoScrollOnInsert(pTdgtList)1225 int TdgtListGetAutoScrollOnInsert(pTdgtList)
1226    TdgtList *pTdgtList;
1227 {
1228    return pTdgtList->auto_scroll_on_insert;
1229 }
1230 
1231 /* --------------------- Init & Clean Up --------------------- */
1232 
InitTdgtList()1233 int InitTdgtList()
1234 {
1235    if (msgFontSet == NULL && msgFontPtr == NULL) {
1236       gnListFontHeight = defaultFontHeight;
1237       gnListFontWidth = defaultFontWidth;
1238       gnListFontAsc = defaultFontAsc;
1239       gnListFontDes = defaultFontDes;
1240       gnListFontPtr = defaultFontPtr;
1241    } else {
1242       gnListFontHeight = msgFontHeight;
1243       gnListFontWidth = msgFontWidth;
1244       gnListFontAsc = msgFontAsc;
1245       gnListFontDes = msgFontDes;
1246       gnListFontPtr = msgFontPtr;
1247    }
1248    return TRUE;
1249 }
1250 
CleanUpTdgtList()1251 void CleanUpTdgtList()
1252 {
1253    gnListFontHeight = gnListFontWidth = gnListFontAsc = gnListFontDes = 0;
1254    gnListFontPtr = NULL;
1255 }
1256 
1257