Jitterbug no more.
[fvwm.git] / modules / FvwmScript / Widgets / List.c
blob9c82b0e67fdc2d036ec3a987a3c45e40d7a4f2e0
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 #include "config.h"
19 #include "libs/fvwmlib.h"
20 #include "libs/ColorUtils.h"
21 #include "libs/Graphics.h"
22 #include "Tools.h"
24 #define BdWidth 2 /* Border width */
25 #define SbWidth 15 /* ScrollBar width */
28 * Fonction pour Liste / Functions for the List
30 void InitList(struct XObj *xobj)
32 unsigned long mask;
33 XSetWindowAttributes Attr;
34 int minw,minh,resize=0;
35 int NbVisCell,NbCell;
37 /* Enregistrement des couleurs et de la police / fonts and colors */
38 if (xobj->colorset >= 0) {
39 xobj->TabColor[fore] = Colorset[xobj->colorset].fg;
40 xobj->TabColor[back] = Colorset[xobj->colorset].bg;
41 xobj->TabColor[hili] = Colorset[xobj->colorset].hilite;
42 xobj->TabColor[shad] = Colorset[xobj->colorset].shadow;
43 } else {
44 xobj->TabColor[fore] = GetColor(xobj->forecolor);
45 xobj->TabColor[back] = GetColor(xobj->backcolor);
46 xobj->TabColor[hili] = GetColor(xobj->hilicolor);
47 xobj->TabColor[shad] = GetColor(xobj->shadcolor);
50 mask = 0;
51 Attr.background_pixel = xobj->TabColor[back];
52 mask |= CWBackPixel;
53 Attr.cursor = XCreateFontCursor(dpy,XC_hand2);
54 mask |= CWCursor; /* Curseur pour la fenetre / Window cursor */
55 xobj->win = XCreateWindow(dpy, *xobj->ParentWin,
56 xobj->x, xobj->y, xobj->width, xobj->height, 0,
57 CopyFromParent, InputOutput, CopyFromParent,
58 mask, &Attr);
60 xobj->gc = fvwmlib_XCreateGC(dpy, xobj->win, 0, NULL);
61 XSetForeground(dpy, xobj->gc, xobj->TabColor[fore]);
62 XSetLineAttributes(dpy, xobj->gc, 1, LineSolid, CapRound, JoinMiter);
64 if ((xobj->Ffont = FlocaleLoadFont(dpy, xobj->font, ScriptName)) == NULL)
66 fprintf(stderr, "%s: Couldn't load font. Exiting!\n", ScriptName);
67 exit(1);
69 if (xobj->Ffont->font != NULL)
70 XSetFont(dpy, xobj->gc, xobj->Ffont->font->fid);
72 /* Calcul de la taille du widget *
73 * Taille minimum: une ligne ou ascenseur visible */
74 /* Computation of the size of the widget *
75 * min size: one line or a visible elevator */
76 minh = 8 + 3*BdWidth + 3*(xobj->Ffont->height + 3);
77 if (xobj->height<minh)
79 xobj->height = minh;
80 resize = 1;
82 minw = 12 + 3*BdWidth +SbWidth +75;
83 if (xobj->width<minw)
85 xobj->width = minw;
86 resize = 1;
88 if (resize)
89 XResizeWindow(dpy, xobj->win, xobj->width, xobj->height);
90 if (xobj->colorset >= 0)
91 SetWindowBackground(dpy, xobj->win, xobj->width, xobj->height,
92 &Colorset[xobj->colorset], Pdepth,
93 xobj->gc, True);
95 /* Calcul de la premiere cellule visible */
96 /* Computation of the first visible cell */
97 NbVisCell = (xobj->height - 2 - 3*BdWidth) / (xobj->Ffont->height + 3);
98 NbCell = CountOption(xobj->title);
99 if (NbCell > NbVisCell)
101 if (xobj->value2 > (NbCell - NbVisCell + 1))
102 xobj->value2 = NbCell - NbVisCell + 1;
103 if ((xobj->value2 < 1) || (xobj->value2 < 0))
104 xobj->value2 = 1;
106 else
107 xobj->value2 = 1;
108 XSelectInput(dpy, xobj->win, ExposureMask);
111 void DrawVSbList(struct XObj *xobj, int NbCell, int NbVisCell, int press)
113 XRectangle r;
114 int PosTh,SizeTh;
116 r.y = 2+BdWidth;
117 r.x = xobj->width - (6+BdWidth) -SbWidth;
118 r.height = xobj->height - r.y - 2*BdWidth;
119 r.width = SbWidth + 4;
120 DrawReliefRect(r.x, r.y, r.width, r.height, xobj, shad, hili);
122 /* Calcul du rectangle pour les fleches *
123 * Compute the rectangle for the arrows */
124 r.x = r.x + 2;
125 r.y = r.y + 2;
126 r.width = r.width - 4;
127 r.height = r.height - 4;
129 /* Dessin de la fleche haute / Draw the up arrow */
130 DrawArrowN(xobj, r.x + 1, r.y + 1, press==1);
131 DrawArrowS(xobj, r.x + 1, r.y + r.height - 14, press==2);
133 /* Calcul du rectangle pour le pouce*/
134 r.y = r.y + 13;
135 r.height = r.height - 26;
137 /* Effacement */
138 XClearArea(dpy, xobj->win, r.x, r.y+1, r.width, r.height-2, False);
140 /* Dessin du pouce */
141 if (NbVisCell < NbCell)
142 SizeTh = (NbVisCell * (r.height-8) / NbCell) + 8;
143 else
144 SizeTh = r.height;
145 PosTh = (xobj->value2 - 1) * (r.height - 8) / NbCell;
146 DrawReliefRect(r.x, r.y + PosTh, r.width, SizeTh, xobj, hili, shad);
149 void DrawCellule(
150 struct XObj *xobj, int NbCell, int NbVisCell, int HeightCell,
151 int asc, XEvent *evp)
153 XRectangle r,inter;
154 char *Title;
155 int i;
156 int do_draw = True;
158 /* text clipping */
159 r.x = 4 + BdWidth + 4;
160 r.y = 4 + BdWidth;
161 r.width = xobj->width - 16 - SbWidth - BdWidth - 6;
162 r.height = xobj->height - r.y - 4 - 2*BdWidth;
164 for (i = xobj->value2; i < xobj->value2 + NbVisCell; i++)
166 Title = (char*)GetMenuTitle(xobj->title, i);
167 do_draw = True;
168 if (evp)
170 if (!frect_get_intersection(
171 r.x - 2, r.y + (i - xobj->value2)*HeightCell + 2,
172 r.width + 4, HeightCell-2,
173 evp->xexpose.x, evp->xexpose.y,
174 evp->xexpose.width, evp->xexpose.height,
175 &inter))
177 do_draw = False;
180 else
182 inter.x = r.x - 2; /* r.x */
183 inter.y = r.y + (i-xobj->value2)*HeightCell + 2;
184 inter.width = r.width + 4;
185 inter.height = HeightCell-2;
187 if (!do_draw)
189 continue;
191 if (strlen(Title)!=0)
193 int x = GetXTextPosition(
194 xobj, r.width,
195 FlocaleTextWidth(xobj->Ffont,Title,strlen(Title)),
196 r.x, 0, -r.x);
197 int y = (i - xobj->value2) * HeightCell + asc + 2 + r.y;
199 if (xobj->value == i)
201 /* hili is better than shad.*/
202 XSetForeground(dpy, xobj->gc, xobj->TabColor[hili]);
203 XFillRectangle(
204 dpy, xobj->win, xobj->gc,
205 inter.x, inter.y, inter.width, inter.height);
206 MyDrawString(
207 dpy, xobj, xobj->win, x, y, Title, fore, back,
208 shad, !xobj->flags[1], &r, evp);
210 else
212 XClearArea(
213 dpy, xobj->win,
214 inter.x, inter.y, inter.width, inter.height,
215 False);
216 MyDrawString(
217 dpy, xobj, xobj->win, x, y, Title, fore, hili,
218 back, !xobj->flags[1], &r, evp);
221 else
223 XClearArea(
224 dpy, xobj->win,
225 inter.x, inter.y, inter.width, inter.height,
226 False);
228 if (Title != NULL)
229 free(Title);
233 void DestroyList(struct XObj *xobj)
235 XFreeGC(dpy, xobj->gc);
236 XDestroyWindow(dpy, xobj->win);
239 void DrawList(struct XObj *xobj, XEvent *evp)
241 int NbVisCell,NbCell;
242 int HeightCell;
243 XRectangle r;
245 /* Dessin du contour / */
246 DrawReliefRect(0, 0, xobj->width, xobj->height, xobj, hili, shad);
248 /* Dessin du contour de la liste */
249 r.x = 2 + BdWidth;
250 r.y = r.x;
251 r.width = xobj->width - r.x - 4 - 2*BdWidth - SbWidth;
252 r.height = xobj->height - r.y - 2*BdWidth;
253 DrawReliefRect(r.x, r.y, r.width, r.height, xobj, shad, hili);
255 /* Calcul du nombre de cellules visibles */
256 HeightCell = xobj->Ffont->height + 3;
257 NbVisCell = r.height/HeightCell;
258 NbCell = CountOption(xobj->title);
259 if (NbCell > NbVisCell)
261 if (xobj->value2 > (NbCell - NbVisCell + 1))
262 xobj->value2 = NbCell - NbVisCell + 1;
263 if ((xobj->value2 < 1) || (xobj->value2 < 0))
264 xobj->value2 = 1;
266 else
267 xobj->value2 = 1;
270 /* Dessin des cellules */
271 DrawCellule(
272 xobj, NbCell, NbVisCell, HeightCell,
273 /*FlocaleGetMinOffset(xobj->Ffont, ROTATION_0)*/
274 xobj->Ffont->ascent,
275 evp);
277 /* Dessin de l'ascenseur vertical */
278 DrawVSbList(xobj, NbCell, NbVisCell, 0);
282 void EvtMouseList(struct XObj *xobj, XButtonEvent *EvtButton)
284 XRectangle rect,rectT;
285 XPoint pt;
286 int x1,y1,x2,y2;
287 Window Win1,Win2;
288 unsigned int modif;
289 int In = 1;
290 static XEvent event;
291 int NbVisCell,NbCell,HeightCell,NPosCell,PosMouse;
292 fd_set in_fdset;
294 pt.x = EvtButton->x-xobj->x;
295 pt.y = EvtButton->y-xobj->y;
297 HeightCell = xobj->Ffont->height + 3;
298 NbVisCell = (xobj->height-6-BdWidth)/HeightCell;
299 NbCell = CountOption(xobj->title);
301 /* Clic dans une cellule */
302 rect.x = 4 + BdWidth;
303 rect.y = rect.x;
304 rect.width = xobj->width - rect.x - 10 - 2*BdWidth - SbWidth;
305 rect.height = xobj->height -rect.y - 4 - 2*BdWidth;
306 if(PtInRect(pt,rect))
308 /* Determination de la cellule */
309 pt.y = pt.y - rect.y;
310 NPosCell = xobj->value2 + (pt.y/(xobj->Ffont->height+3));
311 if (NPosCell > CountOption(xobj->title))
312 NPosCell = 0;
313 else if (NPosCell >= xobj->value2 + NbVisCell)
315 NPosCell--;
317 if (NPosCell != xobj->value)
319 xobj->value = NPosCell;
320 DrawList(xobj,NULL);
322 SendMsg(xobj, SingleClic);
323 return ;
326 /* Clic fleche haute asc vertical */
327 rect.y = 5 + BdWidth;
328 rect.x = xobj->width - (6+BdWidth) - SbWidth+3;
329 rect.height = 12;
330 rect.width = 12;
331 if(PtInRect(pt,rect))
333 DrawVSbList(xobj, NbCell, NbVisCell, 1);
336 FQueryPointer(dpy, *xobj->ParentWin, &Win1, &Win2,
337 &x1, &y1, &x2, &y2, &modif);
338 pt.y = y2- xobj->y;
339 pt.x = x2- xobj->x;
340 if (PtInRect(pt,rect))
342 if (In)
344 Wait(8);
345 xobj->value2--;
346 if (xobj->value2 < 1)
347 xobj->value2 = 1;
348 else
350 DrawCellule(xobj, NbCell, NbVisCell, HeightCell,
351 xobj->Ffont->ascent, NULL);
352 DrawVSbList(xobj, NbCell, NbVisCell, 1);
355 else
357 In = 1;
358 DrawVSbList(xobj, NbCell, NbVisCell, 1);
359 xobj->value2--;
360 if (xobj->value2 < 1)
361 xobj->value2 = 1;
362 else
363 DrawCellule(xobj, NbCell, NbVisCell, HeightCell,
364 xobj->Ffont->ascent, NULL);
367 else
369 if (In)
371 In = 0;
372 DrawVSbList(xobj, NbCell, NbVisCell, 0);
375 FD_ZERO(&in_fdset);
376 FD_SET(x_fd, &in_fdset);
377 select(32, SELECT_FD_SET_CAST &in_fdset, NULL, NULL, NULL);
379 while (!FCheckTypedEvent(dpy, ButtonRelease, &event));
380 DrawVSbList(xobj, NbCell, NbVisCell, 0);
381 return;
384 /* Clic flache basse asc vertical */
385 rect.y = xobj->height - 2*BdWidth -16;
386 if(PtInRect(pt,rect))
388 DrawVSbList(xobj, NbCell, NbVisCell, 2);
391 FQueryPointer(dpy, *xobj->ParentWin, &Win1, &Win2,
392 &x1, &y1, &x2, &y2, &modif);
393 pt.y = y2 - xobj->y;
394 pt.x = x2 - xobj->x;
395 if (PtInRect(pt, rect))
397 if (In)
399 Wait(8);
400 if (xobj->value2 <= NbCell-NbVisCell)
402 xobj->value2++;
403 DrawCellule(xobj, NbCell, NbVisCell, HeightCell,
404 xobj->Ffont->ascent, NULL);
405 DrawVSbList(xobj, NbCell, NbVisCell, 2);
408 else
410 In = 1;
411 DrawVSbList(xobj, NbCell, NbVisCell, 2);
412 if (xobj->value2 <= NbCell-NbVisCell)
414 xobj->value2++;
415 DrawCellule(xobj, NbCell, NbVisCell, HeightCell,
416 xobj->Ffont->ascent, NULL);
420 else
422 if (In)
424 In = 0;
425 DrawVSbList(xobj, NbCell, NbVisCell, 0);
428 FD_ZERO(&in_fdset);
429 FD_SET(x_fd, &in_fdset);
430 select(32, SELECT_FD_SET_CAST &in_fdset, NULL, NULL, NULL);
432 while (!FCheckTypedEvent(dpy, ButtonRelease, &event));
433 DrawVSbList(xobj, NbCell, NbVisCell, 0);
434 return;
437 /* clic sur la zone pouce de l'ascenseur de l'ascenseur */
438 rect.y = 17 + BdWidth;
439 rect.x = xobj->width - (6+BdWidth) - SbWidth + 2;
440 rect.height = xobj->height - rect.y - 19 - 2*BdWidth;
441 rect.width = SbWidth;
442 if(PtInRect(pt,rect))
444 /* Clic dans le pouce */
445 rectT.x = rect.x;
446 rectT.y = rect.y + (xobj->value2 - 1) * (rect.height - 8) / NbCell;
447 if (NbVisCell<NbCell)
448 rectT.height = NbVisCell * (rect.height-8) / NbCell+8;
449 else
450 rectT.height = rect.height;
451 rectT.width = rect.width;
452 if(PtInRect(pt,rectT))
454 PosMouse = pt.y - rectT.y - HeightCell / 2 + 2;
457 FQueryPointer(dpy, *xobj->ParentWin, &Win1, &Win2,
458 &x1, &y1, &x2, &y2, &modif);
459 /* Calcul de l'id de la premiere cellule */
460 pt.y = y2-xobj->y - PosMouse;
461 NPosCell = (pt.y - rect.y)*NbCell / (rect.height);
463 if (NPosCell < 1) NPosCell = 1;
464 if (NbCell > NbVisCell)
466 if (NPosCell > (NbCell - NbVisCell + 1))
467 NPosCell = NbCell - NbVisCell + 1;
469 else
470 NPosCell = 1;
471 if (xobj->value2 != NPosCell)
473 xobj->value2 = NPosCell;
474 DrawCellule(
475 xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent,
476 NULL);
477 DrawVSbList(xobj, NbCell, NbVisCell, 0);
479 FD_ZERO(&in_fdset);
480 FD_SET(x_fd, &in_fdset);
481 select(32, SELECT_FD_SET_CAST &in_fdset, NULL, NULL, NULL);
483 while (!FCheckTypedEvent(dpy, ButtonRelease, &event));
485 else if (pt.y < rectT.y)
487 NPosCell = xobj->value2 - NbVisCell;
488 if (NPosCell < 1)
489 NPosCell = 1;
490 if (xobj->value2 != NPosCell)
492 xobj->value2 = NPosCell;
493 DrawCellule(
494 xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
495 DrawVSbList(xobj, NbCell, NbVisCell, 0);
498 else if (pt.y > rectT.y + rectT.height)
500 NPosCell = xobj->value2+NbVisCell;
501 if (NbCell>NbVisCell)
503 if (NPosCell > (NbCell - NbVisCell + 1))
504 NPosCell = NbCell - NbVisCell + 1;
506 else
507 NPosCell = 1;
508 if (xobj->value2 != NPosCell)
510 xobj->value2 = NPosCell;
511 DrawCellule(
512 xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
513 DrawVSbList(xobj, NbCell, NbVisCell, 0);
519 void EvtKeyList(struct XObj *xobj, XKeyEvent *EvtKey)
521 KeySym ks;
522 unsigned char buf[10];
523 int NbVisCell,NbCell,HeightCell,NPosCell;
524 Window Win1,Win2;
525 int x1,y1,x2,y2;
526 unsigned int modif;
527 XRectangle rect;
528 XPoint pt;
530 HeightCell = xobj->Ffont->height + 3;
531 NbVisCell = (xobj->height - 6 - BdWidth) / HeightCell;
532 NbCell = CountOption(xobj->title);
533 FQueryPointer(dpy, xobj->win, &Win1, &Win2, &x1, &y1, &x2, &y2, &modif);
534 pt.x = x2;
535 pt.y = y2;
536 rect.x = 4 + BdWidth;
537 rect.y = rect.x;
538 rect.width = xobj->width - rect.x -10 - 2*BdWidth - SbWidth;
539 rect.height= xobj->height - rect.y - 4 - 2*BdWidth;
541 /* Recherche du charactere */
542 XLookupString(EvtKey, (char *)buf, sizeof(buf), &ks, NULL);
544 if (ks == XK_Return)
546 if(PtInRect(pt,rect))
548 /* Determination de la cellule */
549 pt.y = pt.y - rect.y;
550 NPosCell = xobj->value2 + (pt.y/(xobj->Ffont->height + 3));
551 if (NPosCell > CountOption(xobj->title))
552 NPosCell = 0;
553 else if (NPosCell >= xobj->value2 + NbVisCell)
555 NPosCell--;
557 if (NPosCell != xobj->value)
559 xobj->value = NPosCell;
560 DrawList(xobj,NULL);
562 SendMsg(xobj, SingleClic);
565 else if (ks == XK_Up)
567 if (xobj->value2 == 1)
569 if(PtInRect(pt,rect))
571 /* Determination de la cellule */
572 pt.y= pt.y - rect.y;
573 NPosCell = xobj->value2+(pt.y/(xobj->Ffont->height + 3));
574 if (NPosCell > CountOption(xobj->title))
575 NPosCell = 0;
576 if (NPosCell > 1)
578 FWarpPointer(dpy, None, None, 0, 0, 0, 0, 0, -HeightCell);
582 else
584 xobj->value2--;
585 DrawCellule(
586 xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
587 DrawVSbList(xobj, NbCell, NbVisCell, 0);
590 else if (ks == XK_Down)
592 if (xobj->value2 > NbCell-NbVisCell)
594 if(PtInRect(pt,rect))
596 /* Determination de la cellule */
597 pt.y = pt.y - rect.y;
598 NPosCell = xobj->value2 + (pt.y/(xobj->Ffont->height + 3));
599 if (NPosCell > CountOption(xobj->title))
600 NPosCell = 0;
601 if (NPosCell < NbCell && NPosCell > 0)
603 FWarpPointer(dpy, None, None, 0, 0, 0, 0, 0, HeightCell);
607 else
609 xobj->value2++;
610 DrawCellule(
611 xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
612 DrawVSbList(xobj, NbCell, NbVisCell, 0);
615 else if (ks == XK_Prior && xobj->value2 > 1)
617 xobj->value2 = xobj->value2 - NbVisCell;
618 if (xobj->value2 < 1)
619 xobj->value2 = 1;
620 DrawCellule(
621 xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
622 DrawVSbList(xobj, NbCell, NbVisCell, 0);
624 else if (ks == XK_Next && xobj->value2 <= NbCell-NbVisCell)
626 xobj->value2 = xobj->value2 + NbVisCell;
627 if (xobj->value2 > NbCell - NbVisCell + 1)
628 xobj->value2 = NbCell - NbVisCell + 1;
629 DrawCellule(
630 xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
631 DrawVSbList(xobj, NbCell, NbVisCell, 0);
633 else if (ks == XK_Home)
635 if (xobj->value2 > 1)
637 xobj->value2 = 1;
638 DrawCellule(
639 xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
640 DrawVSbList(xobj, NbCell, NbVisCell, 0);
643 else if (ks == XK_End)
645 if (xobj->value2 < NbCell - NbVisCell + 1)
647 xobj->value2 = NbCell - NbVisCell + 1;
648 DrawCellule(
649 xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
650 DrawVSbList(xobj, NbCell, NbVisCell, 0);
656 void ProcessMsgList(struct XObj *xobj, unsigned long type, unsigned long *body)