]> git.lyx.org Git - lyx.git/blob - src/mathed/math_symbols.C
merge from the string-switch branch and ready for a prelease.
[lyx.git] / src / mathed / math_symbols.C
1 /*
2  *  File:        math_symbols.C
3  *  Purpose:     User interface to math symbols
4  *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx>
5  *  Created:     November 1995
6  *  Version:     0.8 28/03/96
7  *  Description: Provides a GUI to introduce mathematical
8  *               symbols in lyx.
9  *
10  *  Dependencies: Xlib, XForms, Lyx
11  *
12  *  Copyright: (c) 1995, 1996, Alejandro Aguilar Sierra 
13  *
14  *   You are free to use and modify it under the terms of
15  *   the GNU General Public Licence version 2 or later.
16  */
17
18 #include <config.h>
19 #include XPM_H_LOCATION
20
21 #ifdef __GNUG__
22 #pragma implementation "math_panel.h"
23 #endif
24
25 #include <algorithm>
26
27 #include "lyx_main.h"
28 #include "buffer.h"
29 #include "BufferView.h"
30 #include "minibuffer.h"
31 #include "lyxrc.h"
32 #include "LyXView.h"
33 #include "support/lstrings.h"
34 #include "error.h"
35
36 #include "formula.h"
37
38 #include "math_panel.h"                 
39 #include "math_parser.h"
40
41 extern void SmallUpdate(signed char);
42 extern void BeforeChange();
43 extern void Update(signed char);
44 extern int UnlockInset(UpdatableInset*);
45 extern short greek_kb_flag;
46 extern MiniBuffer *minibuffer;
47
48 extern BufferView *current_view;
49
50 /* Bitmaps */
51 #include "greek.xbm"
52 #include "arrows.xbm"
53 #include "brel.xbm"
54 #include "bop.xbm"
55 #include "misc.xbm"           
56 #include "varsz.xbm"           
57 #include "dots.xbm"
58
59 /* Latex code for those bitmaps */
60 static char const *latex_greek[] =  {
61    "Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi",
62    "Sigma", "Upsilon", "Phi", "Psi", "Omega",
63    "alpha", "beta", "gamma", "delta", "epsilon", "varepsilon", "zeta",
64    "eta", "theta", "vartheta", "iota", "kappa", "lambda", "mu",
65    "nu", "xi", "pi", "varpi", "rho", "sigma", "varsigma",
66    "tau", "upsilon", "phi", "varphi", "chi", "psi", "omega", ""
67 };
68
69 static char const *latex_brel[] = {
70   "leq", "geq", "equiv", "models", 
71   "prec", "succ", "sim", "perp", 
72   "preceq", "succeq", "simeq", "mid", 
73   "ll", "gg", "asymp", "parallel", 
74   "subset", "supset", "approx", "smile", 
75   "subseteq", "supseteq", "cong", "frown", 
76   "sqsubseteq", "sqsupseteq", "doteq", "neq", 
77   "in", "ni", "propto", "notin", 
78   "vdash", "dashv", "bowtie", ""
79 };
80
81 static char const* latex_arrow[] = {
82   "downarrow", "leftarrow", "Downarrow", "Leftarrow", 
83   "hookleftarrow", "rightarrow", "uparrow", "Rightarrow", "Uparrow",
84   "hookrightarrow","updownarrow", "Leftrightarrow", "leftharpoonup", 
85   "rightharpoonup", "rightleftharpoons", "leftrightarrow", "Updownarrow", 
86   "leftharpoondown", "rightharpoondown", "mapsto",
87   "Longleftarrow", "Longrightarrow", "Longleftrightarrow", 
88   "longleftrightarrow", "longleftarrow", "longrightarrow", "longmapsto",
89   "nwarrow", "nearrow", "swarrow", "searrow",  "",
90 };
91
92 char const* latex_varsz[] = {
93 "sum", "int", "oint", 
94 "prod", "coprod", "bigsqcup", 
95 "bigotimes", "bigodot", "bigoplus", 
96 "bigcap", "bigcup", "biguplus", 
97 "bigvee", "bigwedge", ""
98 };
99
100 static char const* latex_bop[] = {   
101   "pm", "cap", "diamond", "oplus", 
102   "mp", "cup", "bigtriangleup", "ominus", 
103   "times", "uplus", "bigtriangledown", "otimes", 
104   "div", "sqcap", "triangleright", "oslash", 
105   "cdot", "sqcup", "triangleleft", "odot", 
106   "star", "vee", "amalg", "bigcirc", 
107   "setminus", "wedge", "dagger", "circ", 
108   "bullet", "wr", "ddagger", ""
109 };
110
111 static char const* latex_misc[] = {
112   "nabla", "partial", "infty", "prime", "ell", 
113   "emptyset", "exists", "forall", "imath",  "jmath",
114   "Re", "Im", "aleph", "wp", "hbar", 
115   "angle", "top", "bot", "Vert", "neg", 
116   "flat", "natural", "sharp", "surd", "triangle", 
117   "diamondsuit", "heartsuit", "clubsuit", "spadesuit", "" 
118 };
119
120 static char const* latex_dots[] = { 
121    "ldots", "cdots", "vdots", "ddots"
122 };
123
124 static signed char latin2greek[] =  {
125   0, 1, 25, 3, 4, 23, 2, 7, 10, 24, 11, 12, 13, 14, -1, 16, 8, 18,
126   19, 21, 22, 17, 27, 15, 26, 6
127 };
128  
129 static signed char Latin2Greek[] =  {
130  -1, -1, -1, 1, -1, 8, 0, -1, -1, -1, -1, 3, -1, -1, -1,
131  5, 2, -1, 6, -1, 7, -1, 10, 4, 9, -1
132 }; 
133
134 extern char** mathed_get_pixmap_from_icon(int d);
135 static void math_cb(FL_OBJECT*, long);
136 static char** pixmapFromBitmapData(char const *, int, int);
137 void math_insert_symbol(char const* s);
138 Bool math_insert_greek(char const c);
139
140 BitmapMenu *BitmapMenu::active = 0;
141
142 BitmapMenu::BitmapMenu(int n,  FL_OBJECT* bt, BitmapMenu* prevx): nb(n)  {
143    w = h = 0;
144    form = 0;
145    i = 0;
146    ww = 2*FL_abs(FL_BOUND_WIDTH);
147    x = y = ww;
148    y += 8;
149    bitmap = new FL_OBJECTP[nb];
150    button = bt;
151    button->u_vdata = this;
152    prev = prevx;
153    next = 0;
154    if (prev)
155      prev->next = this;
156 }
157
158 BitmapMenu::~BitmapMenu() {
159  if (next) delete next;
160  if (form->visible) Hide();
161  fl_free_form(form);  
162  delete[] bitmap;
163 }
164
165 void BitmapMenu::Hide()  {
166    fl_hide_form(form);
167    fl_set_button(button, 0);
168    active = 0;
169 }
170
171 void BitmapMenu::Show()  {
172    if (active)
173      active->Hide();
174    active = this;
175    //   int x = button->form->x + button->x, y = button->form->y + button->y;
176    //   fl_set_form_position(form, x, y + button->h);
177    fl_set_button(button, 1);
178    fl_show_form(form, FL_PLACE_MOUSE, FL_NOBORDER, "");
179 }
180
181 FL_OBJECT*
182 BitmapMenu::AddBitmap(int id, int nx, int ny, int bw, int bh, char* data, Bool vert)
183 {
184    if (i>=nb)
185      return 0;
186    int wx=bw+ww/2, wy=bh+ww/2;
187    wx += (wx % nx);
188    wy += (wy % ny); 
189    FL_OBJECT *obj = fl_create_bmtable(1, x, y, wx, wy, "");   
190    fl_set_object_callback(obj, math_cb, id);
191    fl_set_object_lcol(obj, FL_BLUE);    
192    fl_set_object_boxtype(obj, FL_UP_BOX);   
193    fl_set_bmtable_data(obj, nx, ny, bw, bh, data);
194    if (vert) { 
195       y += wy + 8;
196       h = max(y, h);
197       w = max(x + wx + ww, w);
198    } else  {
199       x += wx + 8;
200       w = max(x, w);
201       h = max(y + wy + ww, h);
202    }
203    bitmap[i++] = obj;
204    return obj;
205 }
206
207 void BitmapMenu::Create()
208 {
209    if (i<nb)  {
210       fprintf(stderr, "Error: Bitmaps not created!");
211       return;
212    }
213    form = fl_bgn_form(FL_UP_BOX, w, h);   
214    for (i=0; i<nb; i++) {
215       fl_add_object(form, bitmap[i]);
216       bitmap[i]->u_vdata = this;
217    }
218    fl_end_form();
219    fl_register_raw_callback(form, KeyPressMask, peek_event);
220 }
221
222 int BitmapMenu::GetIndex(FL_OBJECT* ob)
223 {
224    if (active==this) {
225       int k = 0;
226       for (i=0; i<nb; i++) {
227          if (bitmap[i]==ob) 
228            return k+fl_get_bmtable(ob);
229          k += fl_get_bmtable_maxitems(bitmap[i]);
230       }
231    }
232    return -1;
233 }
234
235 int peek_event(FL_FORM * /*form*/, void *xev)
236 {
237    if (BitmapMenu::active==0)
238      return 0;
239   
240    if(((XEvent *)xev)->type == ButtonPress)
241    {
242          BitmapMenu::active->Hide();
243          return 1;
244    }
245    if(((XEvent *)xev)->type == KeyPress)
246    {
247       char c[5];
248       KeySym keysym;
249       XLookupString(&((XEvent *)xev)->xkey, &c[0], 5, &keysym, 0);
250       if (keysym==XK_Left) 
251         BitmapMenu::active->Prev(); else
252       if (keysym==XK_Right) 
253         BitmapMenu::active->Next(); 
254       else 
255         BitmapMenu::active->Hide();
256       return 1;
257    }
258    return 0;  
259 }
260
261 static void math_cb(FL_OBJECT* ob, long data)
262 {
263    BitmapMenu* menu = (BitmapMenu*)ob->u_vdata;
264    int i = menu->GetIndex(ob);   
265    char const *s = 0;
266
267 //   fprintf(stderr, "data[%d]", data);     
268    if (i<0) return;
269    switch (data)  {
270     case MM_GREEK: 
271       s = latex_greek[i]; 
272       break;
273     case MM_ARROW: 
274       s = latex_arrow[i]; 
275       break;  
276     case MM_BRELATS: 
277       s = latex_brel[i]; 
278       break;  
279     case MM_BOP: 
280       s = latex_bop[i]; 
281       break;  
282     case MM_VARSIZE: 
283       s = latex_varsz[i];  
284       break;
285     case MM_MISC: 
286       s = latex_misc[i];  
287       break;
288     case MM_DOTS: 
289 //      fprintf(stderr, "dots[%s %d]", latex_dots[i], i);
290       s = latex_dots[i-29];  
291       break;
292    }
293   
294    if (s)  {
295       if (current_view->available() && lyxrc->display_shortcuts) {
296           minibuffer->Set("Inserting symbol ", s);
297       }
298       current_view->getOwner()->getLyXFunc()->Dispatch(LFUN_INSERT_MATH, s);
299    }      
300    if (menu)  
301      menu->Hide(); 
302 }
303
304 char** get_pixmap_from_symbol(char const *arg, int wx, int hx)
305 {
306    char** data=0;                   
307    latexkeys *l = in_word_set (arg, strlen(arg));
308    if (!l) 
309     return 0;
310     
311    switch (l->token) {
312     case LM_TK_FRAC:
313       data = mathed_get_pixmap_from_icon(MM_FRAC);
314       break;
315     case LM_TK_SQRT: 
316       data = mathed_get_pixmap_from_icon(MM_SQRT);
317       break;
318     case LM_TK_BIGSYM:
319     case LM_TK_SYM:
320        // I have to use directly the bitmap data since the
321        // bitmap tables are not yet created when this
322        // function is called.
323        data = pixmapFromBitmapData(arg, wx, hx);
324        break;
325    }
326    
327    return data;
328 }
329
330 Bool math_insert_greek(char const c)
331 {
332    int i;
333    char const *s=0;
334    
335    if ('A'<=c && c<='Z') {
336       if ((i=Latin2Greek[c - 'A'])>=0)
337         s = latex_greek[i];
338    }   
339    if ('a'<=c && c<='z') {
340       if ((i=latin2greek[c - 'a'])>=0)
341         s = latex_greek[i+11];
342    }
343    if (s) {
344       math_insert_symbol(s);
345       if (greek_kb_flag<2) {
346          greek_kb_flag = 0;
347          UnlockInset(current_view->currentBuffer()->the_locking_inset);
348       }
349       return True;
350    } else
351      return False; 
352 }
353
354 void math_insert_symbol(char const* s)
355 {
356    if (current_view->available())   {
357       if (!current_view->currentBuffer()->the_locking_inset) {
358          InsetFormula* new_inset = new InsetFormula();
359          BeforeChange();
360          current_view->currentBuffer()->insertInset(new_inset);
361 //       Update(1);//BUG
362          new_inset->Edit(0,0);
363          new_inset->InsertSymbol(s);
364       } else
365         if (current_view->currentBuffer()->the_locking_inset->LyxCode()==Inset::MATH_CODE)
366           ((InsetFormula*)current_view->currentBuffer()->the_locking_inset)->InsertSymbol(s);
367         else 
368           fprintf(stderr, "Math error: attempt to write on a wrong class of inset.\n");
369    }
370 }
371
372 BitmapMenu* sym_menu=0;
373
374 void  create_symbol_menues(FD_panel *symb_form)
375 {
376    FL_OBJECT* obj; 
377    BitmapMenu* menu;
378    
379    sym_menu = menu = new BitmapMenu(2, symb_form->greek);
380    obj = menu->AddBitmap(MM_GREEK, 6, 2, Greek_width, Greek_height, 
381                            Greek_bits);         
382    fl_set_bmtable_maxitems(obj, 11);
383    obj = menu->AddBitmap(MM_GREEK, 7, 4, greek_width, greek_height,
384                            greek_bits); 
385    menu->Create();
386    
387    menu = new BitmapMenu(1, symb_form->boperator, menu);
388    obj = menu->AddBitmap(MM_BOP, 4, 8, bop_width, bop_height,
389                          bop_bits);      
390    fl_set_bmtable_maxitems(obj, 31);
391    menu->Create();   
392       
393    menu = new BitmapMenu(1, symb_form->brelats, menu);
394    obj = menu->AddBitmap(MM_BRELATS, 4, 9, brel_width, brel_height, 
395                          brel_bits);        
396    fl_set_bmtable_maxitems(obj, 35);       
397    menu->Create();
398    
399    menu = new BitmapMenu(3, symb_form->arrow, menu);
400    obj = menu->AddBitmap(MM_ARROW, 5, 4, arrow_width, arrow_height,
401                          arrow_bits);
402    obj = menu->AddBitmap(MM_ARROW, 2, 4, larrow_width, larrow_height, 
403                          larrow_bits, False);          
404    fl_set_bmtable_maxitems(obj, 7);
405    obj = menu->AddBitmap(MM_ARROW, 2, 2, darrow_width, darrow_height, 
406                          darrow_bits);
407    menu->Create(); 
408      
409    menu = new BitmapMenu(1, symb_form->varsize, menu);
410     obj = menu->AddBitmap(MM_VARSIZE, 3, 5, varsz_width, varsz_height, 
411                          varsz_bits);         
412    fl_set_bmtable_maxitems(obj, 14);
413    menu->Create();
414       
415    menu = new BitmapMenu(2, symb_form->misc, menu);
416      obj = menu->AddBitmap(MM_MISC, 5, 6, misc_width, misc_height,
417                            misc_bits);         
418      fl_set_bmtable_maxitems(obj, 29);
419      obj = menu->AddBitmap(MM_DOTS, 4, 1, dots_width, dots_height, 
420                            dots_bits);         
421    menu->Create();
422 }
423
424 static
425 char** pixmapFromBitmapData(char const *s, int wx, int hx)
426 {
427     int i, id;
428     char** data=0;
429     
430     id=-1;
431     
432     for (i=0; i<6; i++) {
433         char const **latex_str = 0;
434         switch (i) {
435          case 0: latex_str = latex_greek; break;
436          case 1: latex_str = latex_bop; break;
437          case 2: latex_str = latex_brel; break;
438          case 3: latex_str = latex_arrow; break;
439          case 4: latex_str = latex_varsz; break;
440          case 5: latex_str = latex_misc; break;
441         }
442         
443         for (int k = 0; latex_str[k][0]>' '; k++) {
444             if (strcmp(latex_str[k], s)==0) {
445                 id = k;
446                 break;
447             }
448         }
449         if (id>=0) break;
450     }
451     if (i<6 && id>=0) {
452         char *bdata = 0;
453         int w = 0, h = 0, dw = 0, dh = 0;
454
455         lyxerr.debug(string("Imando ") + tostr(i) + ", " + tostr(id),
456                      Error::MATHED);
457         switch (i) {
458          case 0: 
459             if (id<=10) {
460                 w = Greek_width;
461                 h = Greek_height;
462                 bdata = Greek_bits;
463                 dw = 6;  dh = 2;
464             } else {
465                 w = greek_width;
466                 h = greek_height;
467                 bdata = greek_bits;
468                 dw = 7;  dh = 4;
469                 id -= 11;
470             }
471             break;
472          case 1:
473             w = bop_width;
474             h = bop_height;
475             bdata = bop_bits;
476             dw = 4;  dh = 8;
477             break;
478          case 2:
479             w = brel_width;
480             h = brel_height;
481             bdata = brel_bits;
482             dw = 4;  dh = 9;
483             break;
484          case 3:
485             if (id<20) {                
486                 w = arrow_width;
487                 h = arrow_height;
488                 bdata = arrow_bits;
489                 dw = 5;  dh = 4;
490             } else if (id>28) {         
491                 w = darrow_width;
492                 h = darrow_height;
493                 bdata = darrow_bits;
494                 dw = 2;  dh = 2;
495                 id -= 29;
496             } else {            
497                 w = larrow_width;
498                 h = larrow_height;
499                 bdata = larrow_bits;
500                 dw = 2;  dh = 4;
501                 id -= 20;
502             }
503             break;
504          case 4:
505             w = varsz_width;
506             h = varsz_height;
507             bdata = varsz_bits;
508             dw = 3;  dh = 5;
509             break;
510          case 5:
511             w = misc_width;
512             h = misc_height;
513             bdata = misc_bits;
514             dw = 5;  dh = 6;
515             break;
516         }
517         int ww = w/dw, hh = h/dh, x, y;
518    
519         XImage *xima = XCreateImage(fl_display, 0, 1, XYBitmap, 0, 
520                                     bdata, w, h, 8, 0);
521         xima->byte_order = LSBFirst;
522         xima->bitmap_bit_order = LSBFirst;
523         x = (id % dw)*ww;
524         y = (id/dw)*hh;
525         if (ww>wx) ww = wx;
526         if (hh>hx) hh = hx;
527         XImage *sbima = XSubImage(xima, x, y, ww, hh);
528         XpmCreateDataFromImage(fl_display, &data, sbima, sbima, 0);
529         
530         // Dirty hack to get blue symbols quickly
531         char *sx = strstr(data[2], "FFFFFFFF");
532         if (sx) {
533             for (int k=0; k<8; k++) sx[k] = '0';
534         }
535
536 //      XDestroyImage(xima);
537     }
538
539     return data;
540 }
541