]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/bmtable.c
fix crash with "save as"
[lyx.git] / src / frontends / xforms / bmtable.c
1 /**
2  * \file bmtable.c
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  *
8  * Full author contact details are available in file CREDITS
9  *
10  * Implementation of the XForms object bmtable.
11  *
12  * A bitmap table uses a single bitmap to simulate a 2d array
13  * of bitmap buttons. It can be used to build bitmap menus.
14  */
15
16 #include <config.h>
17
18 #ifdef __GNUG__
19 #pragma implementation
20 #endif
21
22 #include <stdlib.h>
23 #include "bmtable.h"
24 #include XPM_H_LOCATION
25
26 #if defined(__cplusplus)
27 extern "C"
28 {
29 #endif
30
31 typedef struct   {
32   int nx, ny;   /**< Dimensions of the table */
33   int dx, dy;   /**< Size of each item */
34    int bx, by;   /**< Bitmap's position */
35    int bw, bh;   /**< Bitmap dimensions */
36    unsigned char const * bdata;  /**< Bitmap data */
37    int maxi;     /**< Number of items */
38    int i;        /**< Current position */
39    int mousebut; /**< mouse button pushed */
40    Pixmap pix;   /**< Pixmap from data (temporal) */
41 } BMTABLE_SPEC;
42
43
44 int handle_bitmaptable(FL_OBJECT * ob, int event, FL_Coord mx,
45                        FL_Coord my, int key, void * xev);
46
47
48 FL_OBJECT * fl_create_bmtable(int type, FL_Coord x, FL_Coord y,
49                               FL_Coord w, FL_Coord h, char const * label)
50 {
51    FL_OBJECT * ob;
52
53    ob = fl_make_object(FL_BMTABLE, type, x, y, w, h, label, handle_bitmaptable);
54    ob->boxtype = FL_BMTABLE_BOXTYPE;
55    ob->spec = fl_calloc(1, sizeof(BMTABLE_SPEC));
56    ((BMTABLE_SPEC *)ob->spec)->pix = 0;
57    ((BMTABLE_SPEC *)ob->spec)->bdata = 0;
58    ((BMTABLE_SPEC *)ob->spec)->mousebut = -1;
59    return ob;
60 }
61
62
63 FL_OBJECT *fl_add_bmtable(int type, FL_Coord x, FL_Coord y,
64                               FL_Coord w, FL_Coord h, char const *label)
65 {
66    FL_OBJECT *ob;
67
68    ob = fl_create_bmtable(type, x, y, w, h, label);
69    fl_add_object(fl_current_form, ob);
70
71    return ob;
72 }
73
74
75 static void draw_bitmaptable(FL_OBJECT *ob)
76 {
77         int i, j, lx;
78         FL_Coord mx, my;
79         FL_Coord xx, yy, ww, hh;
80         BMTABLE_SPEC * sp = (BMTABLE_SPEC *)ob->spec;
81         GC gc = fl_state[fl_get_vclass()].gc[0];
82         if (!sp) return;
83
84         /* draw the bounding box first */
85         lx = sp->maxi % sp->nx;
86         fl_drw_box(ob->boxtype, ob->x, ob->y, ob->w, ob->h, ob->col1, ob->bw);
87         if (lx) {
88                 i = FL_abs(ob->bw);
89                 xx = ob->x + sp->dx * lx + i;
90                 yy = ob->y + (sp->ny - 1) * sp->dy + i;
91                 ww = ob->x + ob->w - xx - i;
92                 hh = ob->y + ob->h - yy - i;
93                 fl_drw_frame(FL_DOWN_FRAME, xx, yy, ww, hh, ob->col1, ob->bw);
94                 fl_rectf(xx, yy, ww + i, hh + i, ob->col1);
95         }
96
97         /* draw the background bitmap */
98         if (sp->bdata)  {
99                 if (!sp->pix) {
100                         sp->pix = XCreatePixmapFromBitmapData(fl_get_display(), fl_winget(),
101                                                               (char*)sp->bdata,
102                                                                sp->bw, sp->bh,
103                                         fl_get_flcolor(ob->lcol), fl_get_flcolor(ob->col1),
104                                                                /*DefaultDepth(fl_get_display(), DefaultScreen(fl_get_display()))*/ fl_state[fl_get_vclass()].depth);
105                         XFlush(fl_get_display());
106                 }
107         }
108         if (sp->pix) {
109                 /* Adjust position */
110                 if (sp->bx < FL_abs(ob->bw) + 1) {
111                         xx = FL_abs(ob->bw) - sp->bx + 1;
112                         mx = ob->x + FL_abs(ob->bw) + 1;
113                 } else  {
114                         xx = 0;
115                         mx = ob->x + sp->bx;
116                 }
117                 if (sp->by < FL_abs(ob->bw) + 1)  {
118                         yy = FL_abs(ob->bw) - sp->by + 1;
119                         my = ob->y + FL_abs(ob->bw) + 1;
120                 } else   {
121                         yy = 0;
122                         my = ob->y + sp->by;
123                 }
124                 ww = (mx + sp->bw < ob->x + ob->w - FL_abs(ob->bw)) ?
125                         sp->bw: ob->x + ob->w - FL_abs(ob->bw) - mx;
126                 hh = (my + sp->bh < ob->y + ob->h - FL_abs(ob->bw)) ?
127                         sp->bh: ob->y + ob->h - FL_abs(ob->bw) - my;
128
129                 i = FL_abs(ob->bw);
130                 j = hh - ((lx) ? sp->dy+2*i: 0);
131                 XCopyArea(fl_get_display(), sp->pix, fl_winget(), gc, xx, yy, ww, j, mx, my);
132                 XFlush(fl_get_display());
133                 if (lx) {
134                         XCopyArea(fl_get_display(), sp->pix, fl_winget(), gc, xx,
135                                           yy+j, lx*sp->dx-2*i, hh-j, mx, my+j);
136                         XFlush(fl_get_display());
137                 }
138         }
139
140
141         /* draw the grid if type > FLAT */
142         if (ob->type > FL_BMTABLE_FLAT)  {
143                 mx = ob->x + ob->w;
144                 my = ob->y + ob->h;
145                 ww = ob->w;
146                 for (yy= ob->y; yy<= my; yy+= sp->dy) {
147                         if (ob->boxtype!= FL_FLAT_BOX && (yy == ob->y || yy>my-sp->dy))
148                                 continue;
149                         if (lx>0 && yy>= my-sp->dy - sp->dy/2)
150                                 ww = lx*sp->dx;
151                         fl_diagline(ob->x, yy, ww, 1, FL_BOTTOM_BCOL);
152                         fl_diagline(ob->x, yy+1, ww-2, 1, FL_TOP_BCOL);
153                 }
154                 hh = ob->h;
155                 for (xx= ob->x; xx<= mx; xx+= sp->dx)  {
156                         if (ob->boxtype!= FL_FLAT_BOX && (xx == ob->x || xx>mx-sp->dx))
157                                 continue;
158                         if (lx>0 && xx>= ob->x + lx * sp->dx)
159                                 hh = (sp->ny - 1) * sp->dy;
160                         fl_diagline(xx, ob->y, 1, hh, FL_RIGHT_BCOL);
161                         fl_diagline(xx+1, ob->y + 1, 1, hh - 2, FL_LEFT_BCOL);
162                 }
163         }
164
165         /* Simulate a pushed button */
166         if (ob->pushed && 0 <= sp->i && sp->i < sp->maxi)  {
167                 i = sp->i % sp->nx;
168                 j = sp->i/sp->nx;
169                 ww = sp->dx-2*FL_abs(ob->bw);
170                 hh = sp->dy-2*FL_abs(ob->bw);
171                 xx = ob->x + sp->dx*i + FL_abs(ob->bw);
172                 yy = ob->y + sp->dy*j + FL_abs(ob->bw);
173                 fl_drw_frame(FL_DOWN_FRAME, xx, yy, ww, hh, ob->col1, ob->bw);
174         }
175 }
176
177
178 int handle_bitmaptable(FL_OBJECT * ob, int event, FL_Coord mx,
179                                   FL_Coord my, int key, void * xev)
180 {
181         int i, j;
182         BMTABLE_SPEC * sp = (BMTABLE_SPEC *)ob->spec;
183
184         switch (event)  {
185     case FL_DRAW:
186                 draw_bitmaptable(ob);
187                 break;
188     case FL_MOUSE:
189                 if (!ob->belowmouse) {    /* This never happens. Why? */
190                         sp->i = -1;
191                         fl_redraw_object(ob);
192                         break;
193                 }
194                 i = (mx - ob->x)/sp->dx;  j = (my - ob->y)/sp->dy;
195                 if (i>= 0 && i< sp->nx && j>= 0 && j< sp->ny)   {
196                         i += j*sp->nx;
197                         if (i >= sp->maxi) i = -1;
198                         if (sp->i !=  i)  {
199                                 sp->i = i;
200                                 fl_redraw_object(ob);
201                         }
202                 }
203                 break;
204     case FL_PUSH:
205                 sp->mousebut = key;
206                 i = (mx - ob->x)/sp->dx + ((my - ob->y)/sp->dy)*sp->nx;
207                 if (0 <= i && i < sp->maxi)  {
208                         sp->i =  i;
209                         fl_redraw_object(ob);
210                 } else
211                         sp->i =  -1;
212                 break;
213     case FL_RELEASE:
214                 fl_redraw_object(ob);
215                 return 1;
216     case FL_FREEMEM:
217             if (sp->pix) {
218                     XFreePixmap(fl_get_display(), sp->pix);
219                     XFlush(fl_get_display());
220             }
221                 fl_free(((BMTABLE_SPEC*)ob->spec));
222                 break;
223         }
224         return 0;
225 }
226
227
228 /*
229  * The table has nx columns of dx width each and ny rows of dy height each.
230  * Initially the position of the firts item is supposed to be the same that
231  * the object position (x, y), and the number of items is supposed to be
232  * exactly nx*ny.
233  *
234  * The user could change these later. See below.
235  */
236 void fl_set_bmtable_data(FL_OBJECT * ob, int nx, int ny, int bw, int bh,
237                         unsigned char const * bdata)
238 {
239    BMTABLE_SPEC * sp = (BMTABLE_SPEC *)ob->spec;
240    if (sp) {
241      sp->nx = nx;
242      sp->ny = ny;
243      sp->bx = FL_abs(ob->bw);
244      sp->by = FL_abs(ob->bw);
245      sp->dx = ob->w/nx;
246      sp->dy = ob->h/ny;
247      sp->i = -1;
248      sp->maxi = sp->nx * sp->ny;
249      sp->bw = bw;
250      sp->bh = bh;
251      sp->bdata = bdata;
252    }
253 }
254
255
256 void fl_set_bmtable_pixmap_data(FL_OBJECT * ob, int nx, int ny,
257                         char ** pdata)
258 {
259         BMTABLE_SPEC * sp = (BMTABLE_SPEC *)ob->spec;
260         if (sp) {
261                 Pixmap dummy_shapemask = 0;
262                 XpmAttributes dumb_attributes = { 0 };
263                 sp->nx = nx;
264                 sp->ny = ny;
265                 sp->bx = FL_abs(ob->bw);
266                 sp->by = FL_abs(ob->bw);
267                 sp->dx = ob->w/nx;
268                 sp->dy = ob->h/ny;
269                 sp->i = -1;
270                 sp->maxi = sp->nx * sp->ny;
271                 sp->bdata = 0;
272                 dumb_attributes.colormap = fl_state[fl_get_vclass()].colormap;
273                 dumb_attributes.closeness = 30000;
274                 dumb_attributes.valuemask = XpmColormap | XpmCloseness;
275                 if (XCreatePixmapFromData(fl_get_display(), fl_winget(), pdata,
276                                           &(sp->pix), &dummy_shapemask,
277                                           &dumb_attributes) == XpmSuccess) {
278                         sp->bw = dumb_attributes.width;
279                         sp->bh = dumb_attributes.height;
280                         XpmFreeAttributes(&dumb_attributes);
281                         if (dummy_shapemask) {
282                                 XFreePixmap(fl_get_display(), dummy_shapemask);
283                         }
284                 }
285         }
286 }
287
288
289 /*
290  *  This function works only for X11R6 or later
291  */
292 #if XlibSpecificationRelease > 5
293
294 void fl_set_bmtable_file(FL_OBJECT * ob, int nx, int ny, char const * filename)
295 {
296    int xh;
297    int yh;
298    unsigned int bw;
299    unsigned int bh;
300    unsigned char * bdata;
301
302    if (XReadBitmapFileData(filename, &bw, &bh,
303                           &bdata, &xh, &yh) == BitmapSuccess)
304      fl_set_bmtable_data(ob, nx, ny, bw, bh, bdata);
305    XFlush(fl_get_display());
306 }
307
308 #else
309
310 void fl_set_bmtable_file(FL_OBJECT * ob, int nx, int ny, char const * filename)
311 {
312   fprintf(stderr, "Set bmtable file: Sorry, I need X11 release 6 to do "
313            "work!\n");
314 }
315
316 #endif
317
318
319
320 void fl_set_bmtable_pixmap_file(FL_OBJECT *ob, int nx, int ny, char const *filename)
321 {
322   /* extern Colormap color_map; */
323         BMTABLE_SPEC *sp = (BMTABLE_SPEC *)ob->spec;
324         if (sp) {
325                 Pixmap dummy_shapemask = 0;
326                 XpmAttributes dumb_attributes = { 0 };
327                 sp->nx = nx;
328                 sp->ny = ny;
329                 sp->bx = FL_abs(ob->bw);
330                 sp->by = FL_abs(ob->bw);
331                 sp->dx = ob->w/nx;
332                 sp->dy = ob->h/ny;
333                 sp->i = -1;
334                 sp->maxi = sp->nx * sp->ny;
335                 sp->bdata = 0;
336
337                 dumb_attributes.colormap = fl_state[fl_get_vclass()].colormap;
338                 dumb_attributes.closeness = 30000;
339                 dumb_attributes.valuemask = XpmColormap | XpmCloseness;
340
341                 if (XReadPixmapFile(fl_get_display(), fl_winget(), (char *)filename,
342                                     &(sp->pix), &dummy_shapemask,
343                                     &dumb_attributes) == XpmSuccess) {
344                         sp->bw = dumb_attributes.width;
345                         sp->bh = dumb_attributes.height;
346                         XpmFreeAttributes(&dumb_attributes);
347                         if (dummy_shapemask) {
348                                 XFreePixmap(fl_get_display(), dummy_shapemask);
349                         }
350                 }
351                 /* XFlush(fl_get_display()); */
352         }
353 }
354
355
356 /*
357  * This function allows to adjust the position of the first item and its
358  * size (dx, dy). The input values are incremental, not absolute.
359  */
360 void fl_set_bmtable_adjust(FL_OBJECT *ob, int px, int py, int dx, int dy)
361 {
362    BMTABLE_SPEC *sp = (BMTABLE_SPEC *)ob->spec;
363    if (sp) {
364      sp->bx += px;
365      sp->by += py;
366      sp->dx += dx;
367      sp->dy += dy;
368    }
369 }
370
371 /*
372  * This function returns the table's selected position.
373  */
374 int fl_get_bmtable(FL_OBJECT *ob)
375 {
376    if ((BMTABLE_SPEC *)ob->spec)
377      return  ((BMTABLE_SPEC *)ob->spec)->i;
378    else
379      return 0;
380 }
381
382
383 /*
384  * You can change the max number of items if you want.
385  */
386 void fl_set_bmtable_maxitems(FL_OBJECT * ob, int i)
387 {
388    if (i > 0 && (BMTABLE_SPEC *)ob->spec)
389      ((BMTABLE_SPEC *)ob->spec)->maxi = i;
390 }
391
392
393 int fl_get_bmtable_maxitems(FL_OBJECT * ob)
394 {
395    if ((BMTABLE_SPEC *)ob->spec)
396      return  ((BMTABLE_SPEC *)ob->spec)->maxi;
397    else
398      return 0;
399 }
400
401
402 void fl_replace_bmtable_item(FL_OBJECT * ob, int id, int cw, int ch, char * data)
403 {
404    fprintf(stderr, "Replace bmtable item: Sorry, not yet implemented!\n");
405 }
406
407
408 void fl_get_bmtable_item(FL_OBJECT * ob, int id, int * cw, int * ch, char * data)
409 {
410    fprintf(stderr, "Get bmtable item: Sorry, not yet implemented!\n");
411 }
412
413 void fl_set_bmtable(FL_OBJECT * ob, int pushed, int pos)
414 {
415    if ((BMTABLE_SPEC *)ob->spec)
416      ((BMTABLE_SPEC *)ob->spec)->i = (pushed) ? pos: -1;
417 }
418
419
420 int fl_get_bmtable_numb(FL_OBJECT *ob)
421 {
422    if ((BMTABLE_SPEC *)ob->spec)
423      return ((BMTABLE_SPEC *)ob->spec)->mousebut;
424    else
425      return 0;
426 }
427
428
429 Pixmap fl_get_bmtable_pixmap(FL_OBJECT * ob)
430 {
431    if ((BMTABLE_SPEC *)ob->spec)
432      return ((BMTABLE_SPEC *)ob->spec)->pix;
433    else
434      return 0;
435 }
436
437
438 void fl_draw_bmtable_item(FL_OBJECT * ob, int i, Drawable d, int xx, int yy)
439 {
440    int x;
441    int y;
442    int w;
443    int h;
444    GC gc = fl_state[fl_get_vclass()].gc[0];
445    BMTABLE_SPEC * sp = (BMTABLE_SPEC *)ob->spec;
446
447    if (sp && sp->pix) {
448       x = (i % sp->nx)*sp->dx + FL_abs(ob->bw);
449       y = (i/sp->nx)*sp->dy + FL_abs(ob->bw);
450       w = sp->dx-2*FL_abs(ob->bw);
451       h = sp->dy-2*FL_abs(ob->bw);
452       XCopyArea(fl_get_display(), sp->pix, d, gc, x, y, w, h, xx, yy);
453       XFlush(fl_get_display());
454    }
455 }
456
457 /* Free the current bitmap and pixmap in preparation for installing a new one */
458 void fl_free_bmtable_bitmap(FL_OBJECT * ob)
459 {
460   BMTABLE_SPEC * sp = (BMTABLE_SPEC *)ob->spec;
461
462   /* dump the temporary pixmap */
463   if (sp && sp->pix) {
464     XFreePixmap(fl_get_display(), sp->pix);
465     XFlush(fl_get_display());
466     sp->pix = 0;
467   }
468
469   /* and free the space taken by bdata etc. */
470   if (sp && sp->bdata) {
471     fl_free((void*)sp->bdata);
472     sp->bdata = 0;
473   }
474 }
475
476 /* Free the current pixmap in preparation for installing a new one */
477 /* This is needed when using data instead of files to set bitmaps  */
478 void fl_free_bmtable_pixmap(FL_OBJECT *ob)
479 {
480   BMTABLE_SPEC * sp = (BMTABLE_SPEC *)ob->spec;
481
482   /* dump the temporary pixmap */
483   if (sp && sp->pix) {
484     XFreePixmap(fl_get_display(), sp->pix);
485     XFlush(fl_get_display());
486     sp->pix = 0;
487   }
488 }
489
490 #if defined(__cplusplus)
491 }
492 #endif