]> git.lyx.org Git - lyx.git/blob - src/mathed/math_symbols.C
133834774b5c51c5b2f3b2089a7cd04d43145807
[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 "debug.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            lyxerr << "Error: Bitmaps not created!" << endl;
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 //   lyxerr << "data[" << 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 //      lyxerr << "dots[" << 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                 lyxerr << "Math error: attempt to write on a wrong "
369                         "class of inset." << endl;
370    }
371 }
372
373 BitmapMenu* sym_menu=0;
374
375 void  create_symbol_menues(FD_panel *symb_form)
376 {
377    FL_OBJECT* obj; 
378    BitmapMenu* menu;
379    
380    sym_menu = menu = new BitmapMenu(2, symb_form->greek);
381    obj = menu->AddBitmap(MM_GREEK, 6, 2, Greek_width, Greek_height, 
382                            Greek_bits);         
383    fl_set_bmtable_maxitems(obj, 11);
384    obj = menu->AddBitmap(MM_GREEK, 7, 4, greek_width, greek_height,
385                            greek_bits); 
386    menu->Create();
387    
388    menu = new BitmapMenu(1, symb_form->boperator, menu);
389    obj = menu->AddBitmap(MM_BOP, 4, 8, bop_width, bop_height,
390                          bop_bits);      
391    fl_set_bmtable_maxitems(obj, 31);
392    menu->Create();   
393       
394    menu = new BitmapMenu(1, symb_form->brelats, menu);
395    obj = menu->AddBitmap(MM_BRELATS, 4, 9, brel_width, brel_height, 
396                          brel_bits);        
397    fl_set_bmtable_maxitems(obj, 35);       
398    menu->Create();
399    
400    menu = new BitmapMenu(3, symb_form->arrow, menu);
401    obj = menu->AddBitmap(MM_ARROW, 5, 4, arrow_width, arrow_height,
402                          arrow_bits);
403    obj = menu->AddBitmap(MM_ARROW, 2, 4, larrow_width, larrow_height, 
404                          larrow_bits, False);          
405    fl_set_bmtable_maxitems(obj, 7);
406    obj = menu->AddBitmap(MM_ARROW, 2, 2, darrow_width, darrow_height, 
407                          darrow_bits);
408    menu->Create(); 
409      
410    menu = new BitmapMenu(1, symb_form->varsize, menu);
411     obj = menu->AddBitmap(MM_VARSIZE, 3, 5, varsz_width, varsz_height, 
412                          varsz_bits);         
413    fl_set_bmtable_maxitems(obj, 14);
414    menu->Create();
415       
416    menu = new BitmapMenu(2, symb_form->misc, menu);
417      obj = menu->AddBitmap(MM_MISC, 5, 6, misc_width, misc_height,
418                            misc_bits);         
419      fl_set_bmtable_maxitems(obj, 29);
420      obj = menu->AddBitmap(MM_DOTS, 4, 1, dots_width, dots_height, 
421                            dots_bits);         
422    menu->Create();
423 }
424
425 static
426 char** pixmapFromBitmapData(char const *s, int wx, int hx)
427 {
428     int i, id;
429     char** data=0;
430     
431     id=-1;
432     
433     for (i=0; i<6; i++) {
434         char const **latex_str = 0;
435         switch (i) {
436          case 0: latex_str = latex_greek; break;
437          case 1: latex_str = latex_bop; break;
438          case 2: latex_str = latex_brel; break;
439          case 3: latex_str = latex_arrow; break;
440          case 4: latex_str = latex_varsz; break;
441          case 5: latex_str = latex_misc; break;
442         }
443         
444         for (int k = 0; latex_str[k][0]>' '; k++) {
445             if (strcmp(latex_str[k], s)==0) {
446                 id = k;
447                 break;
448             }
449         }
450         if (id>=0) break;
451     }
452     if (i<6 && id>=0) {
453         char *bdata = 0;
454         int w = 0, h = 0, dw = 0, dh = 0;
455
456         lyxerr[Debug::MATHED] << "Imando " << i << ", " << id << endl;
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