]> git.lyx.org Git - lyx.git/blob - src/mathed/math_symbols.C
Hopefully fix the problem with stateText() in lyxfont.C
[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: 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 #include "lyxfunc.h"
36
37 #include "formula.h"
38
39 #include "math_panel.h"                 
40 #include "math_parser.h"
41
42 using std::max;
43 using std::endl;
44 using std::ostream;
45
46 extern short greek_kb_flag;
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 const ** mathed_get_pixmap_from_icon(int d);
135 extern "C" void math_cb(FL_OBJECT*, long);
136 static char const ** 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 {
144    w = h = 0;
145    form = 0;
146    i = 0;
147    ww = 2 * FL_abs(FL_BOUND_WIDTH);
148    x = y = ww;
149    y += 8;
150    bitmap = new FL_OBJECTP[nb];
151    button = bt;
152    button->u_vdata = this;
153    prev = prevx;
154    next = 0;
155    if (prev)
156      prev->next = this;
157 }
158
159
160 BitmapMenu::~BitmapMenu()
161 {
162         delete next;
163         if (form->visible) Hide();
164         fl_free_form(form);  
165         delete[] bitmap;
166 }
167
168
169 void BitmapMenu::Hide()
170 {
171    fl_hide_form(form);
172    fl_set_button(button, 0);
173    active = 0;
174 }
175
176
177 void BitmapMenu::Show()
178 {
179    if (active)
180      active->Hide();
181    active = this;
182    //   int x = button->form->x + button->x, y = button->form->y + button->y;
183    //   fl_set_form_position(form, x, y + button->h);
184    fl_set_button(button, 1);
185    fl_show_form(form, FL_PLACE_MOUSE, FL_NOBORDER, "");
186 }
187
188 FL_OBJECT *
189 BitmapMenu::AddBitmap(int id, int nx, int ny, int bw, int bh, unsigned char const * data, Bool vert)
190 {
191    if (i >= nb)
192      return 0;
193    int wx = bw+ww/2, wy = bh+ww/2;
194    wx += (wx % nx);
195    wy += (wy % ny); 
196    FL_OBJECT * obj = fl_create_bmtable(1, x, y, wx, wy, "");   
197    fl_set_object_callback(obj, math_cb, id);
198    fl_set_object_lcol(obj, FL_BLUE);    
199    fl_set_object_boxtype(obj, FL_UP_BOX);   
200    fl_set_bmtable_data(obj, nx, ny, bw, bh, data);
201    if (vert) { 
202       y += wy + 8;
203       h = max(y, h);
204       w = max(x + wx + ww, w);
205    } else  {
206       x += wx + 8;
207       w = max(x, w);
208       h = max(y + wy + ww, h);
209    }
210    bitmap[i++] = obj;
211    return obj;
212 }
213
214 void BitmapMenu::Create()
215 {
216    if (i < nb)  {
217            lyxerr << "Error: Bitmaps not created!" << endl;
218       return;
219    }
220    form = fl_bgn_form(FL_UP_BOX, w, h);   
221    for (i = 0; i < nb; ++i) {
222       fl_add_object(form, bitmap[i]);
223       bitmap[i]->u_vdata = this;
224    }
225    fl_end_form();
226    fl_register_raw_callback(form, KeyPressMask, C_peek_event);
227 }
228
229 int BitmapMenu::GetIndex(FL_OBJECT* ob)
230 {
231    if (active == this) {
232       int k = 0;
233       for (i = 0; i < nb; ++i) {
234          if (bitmap[i] == ob) 
235            return k+fl_get_bmtable(ob);
236          k += fl_get_bmtable_maxitems(bitmap[i]);
237       }
238    }
239    return -1;
240 }
241
242 int peek_event(FL_FORM * /*form*/, void *xev)
243 {
244    if (BitmapMenu::active == 0)
245      return 0;
246   
247    if(static_cast<XEvent *>(xev)->type == ButtonPress)
248    {
249          BitmapMenu::active->Hide();
250          return 1;
251    }
252    if(static_cast<XEvent *>(xev)->type == KeyPress)
253    {
254       char c[5];
255       KeySym keysym;
256       XLookupString(&static_cast<XEvent *>(xev)->xkey, &c[0], 5, &keysym, 0);
257       if (keysym == XK_Left) 
258         BitmapMenu::active->Prev(); else
259       if (keysym == XK_Right) 
260         BitmapMenu::active->Next(); 
261       else 
262         BitmapMenu::active->Hide();
263       return 1;
264    }
265    return 0;  
266 }
267
268 // This is just a wrapper.
269 extern "C" int C_peek_event(FL_FORM *form, void *ptr) {
270   return peek_event(form, ptr);
271 }
272
273
274 extern "C" void math_cb(FL_OBJECT* ob, long data)
275 {
276    BitmapMenu * menu = static_cast<BitmapMenu*>(ob->u_vdata);
277    int i = menu->GetIndex(ob);   
278    char const *s = 0;
279
280 //   lyxerr << "data[" << data << "]";
281    if (i<0) return;
282    switch (data)  {
283     case MM_GREEK: 
284       s = latex_greek[i]; 
285       break;
286     case MM_ARROW: 
287       s = latex_arrow[i]; 
288       break;  
289     case MM_BRELATS: 
290       s = latex_brel[i]; 
291       break;  
292     case MM_BOP: 
293       s = latex_bop[i]; 
294       break;  
295     case MM_VARSIZE: 
296       s = latex_varsz[i];  
297       break;
298     case MM_MISC: 
299       s = latex_misc[i];  
300       break;
301     case MM_DOTS: 
302 //      lyxerr << "dots[" << latex_dots[i] << " " << i << "]";
303       s = latex_dots[i-29];  
304       break;
305    }
306   
307    if (s)  {
308       if (current_view->available() && lyxrc.display_shortcuts) {
309           current_view->owner()->getMiniBuffer()->Set("Inserting symbol ", s);
310       }
311       current_view->owner()->getLyXFunc()->Dispatch(LFUN_INSERT_MATH, s);
312    }      
313    if (menu)  
314      menu->Hide(); 
315 }
316
317 char const ** get_pixmap_from_symbol(char const * arg, int wx, int hx)
318 {
319    char const ** data = 0;                  
320    latexkeys * l = in_word_set (arg, strlen(arg));
321    if (!l) 
322     return 0;
323     
324    switch (l->token) {
325     case LM_TK_FRAC:
326       data = mathed_get_pixmap_from_icon(MM_FRAC);
327       break;
328     case LM_TK_SQRT: 
329       data = mathed_get_pixmap_from_icon(MM_SQRT);
330       break;
331     case LM_TK_BIGSYM:
332     case LM_TK_SYM:
333        // I have to use directly the bitmap data since the
334        // bitmap tables are not yet created when this
335        // function is called.
336        data = pixmapFromBitmapData(arg, wx, hx);
337        break;
338    }
339    
340    return data;
341 }
342
343 Bool math_insert_greek(char const c)
344 {
345    int i;
346    char const * s= 0;
347    
348    if ('A' <= c && c <= 'Z') {
349       if ((i = Latin2Greek[c - 'A']) >= 0)
350         s = latex_greek[i];
351    }   
352    if ('a'<= c && c<= 'z') {
353       if ((i= latin2greek[c - 'a'])>= 0)
354         s = latex_greek[i+11];
355    }
356    if (s) {
357       math_insert_symbol(s);
358       if (greek_kb_flag<2) {
359          greek_kb_flag = 0;
360          current_view->unlockInset(current_view->the_locking_inset);
361       }
362       return True;
363    } else
364      return False; 
365 }
366
367
368 void math_insert_symbol(char const * s)
369 {
370    if (current_view->available())   {
371       if (!current_view->the_locking_inset) {
372          InsetFormula * new_inset = new InsetFormula();
373          current_view->beforeChange();
374          current_view->insertInset(new_inset);
375 //       Update(1);//BUG
376          new_inset->Edit(current_view, 0, 0, 0);
377          new_inset->InsertSymbol(current_view, s);
378       } else
379         if (current_view->the_locking_inset->LyxCode() == Inset::MATH_CODE)
380                 static_cast<InsetFormula*>(current_view->the_locking_inset)->InsertSymbol(current_view, s);
381         else 
382                 lyxerr << "Math error: attempt to write on a wrong "
383                         "class of inset." << endl;
384    }
385 }
386
387
388 BitmapMenu * sym_menu= 0;
389
390 void  create_symbol_menues(FD_panel * symb_form)
391 {
392    FL_OBJECT * obj; 
393    BitmapMenu * menu;
394    
395    sym_menu = menu = new BitmapMenu(2, symb_form->greek);
396    obj = menu->AddBitmap(MM_GREEK, 6, 2, Greek_width, Greek_height, 
397                            Greek_bits);         
398    fl_set_bmtable_maxitems(obj, 11);
399    obj = menu->AddBitmap(MM_GREEK, 7, 4, greek_width, greek_height,
400                            greek_bits); 
401    menu->Create();
402    
403    menu = new BitmapMenu(1, symb_form->boperator, menu);
404    obj = menu->AddBitmap(MM_BOP, 4, 8, bop_width, bop_height,
405                          bop_bits);      
406    fl_set_bmtable_maxitems(obj, 31);
407    menu->Create();   
408       
409    menu = new BitmapMenu(1, symb_form->brelats, menu);
410    obj = menu->AddBitmap(MM_BRELATS, 4, 9, brel_width, brel_height, 
411                          brel_bits);        
412    fl_set_bmtable_maxitems(obj, 35);       
413    menu->Create();
414    
415    menu = new BitmapMenu(3, symb_form->arrow, menu);
416    obj = menu->AddBitmap(MM_ARROW, 5, 4, arrow_width, arrow_height,
417                          arrow_bits);
418    obj = menu->AddBitmap(MM_ARROW, 2, 4, larrow_width, larrow_height, 
419                          larrow_bits, False);          
420    fl_set_bmtable_maxitems(obj, 7);
421    obj = menu->AddBitmap(MM_ARROW, 2, 2, darrow_width, darrow_height, 
422                          darrow_bits);
423    menu->Create(); 
424      
425    menu = new BitmapMenu(1, symb_form->varsize, menu);
426     obj = menu->AddBitmap(MM_VARSIZE, 3, 5, varsz_width, varsz_height, 
427                          varsz_bits);         
428    fl_set_bmtable_maxitems(obj, 14);
429    menu->Create();
430       
431    menu = new BitmapMenu(2, symb_form->misc, menu);
432      obj = menu->AddBitmap(MM_MISC, 5, 6, misc_width, misc_height,
433                            misc_bits);         
434      fl_set_bmtable_maxitems(obj, 29);
435      obj = menu->AddBitmap(MM_DOTS, 4, 1, dots_width, dots_height, 
436                            dots_bits);         
437    menu->Create();
438 }
439
440 static
441 char const ** pixmapFromBitmapData(char const * s, int wx, int hx)
442 {
443     int i;
444     char const ** data = 0;
445     
446     int id = -1;
447     
448     for (i = 0; i < 6; ++i) {
449         char const ** latex_str = 0;
450         switch (i) {
451          case 0: latex_str = latex_greek; break;
452          case 1: latex_str = latex_bop; break;
453          case 2: latex_str = latex_brel; break;
454          case 3: latex_str = latex_arrow; break;
455          case 4: latex_str = latex_varsz; break;
456          case 5: latex_str = latex_misc; break;
457         }
458         
459         for (int k = 0; latex_str[k][0] > ' '; ++k) {
460             if (strcmp(latex_str[k], s) == 0) {
461                 id = k;
462                 break;
463             }
464         }
465         if (id >= 0) break;
466     }
467     if (i < 6 && id >= 0) {
468         unsigned char const * bdata = 0;
469         int w = 0, h = 0, dw = 0, dh = 0;
470
471         lyxerr[Debug::MATHED] << "Imando " << i << ", " << id << endl;
472         switch (i) {
473          case 0: 
474             if (id<= 10) {
475                 w = Greek_width;
476                 h = Greek_height;
477                 bdata = Greek_bits;
478                 dw = 6;  dh = 2;
479             } else {
480                 w = greek_width;
481                 h = greek_height;
482                 bdata = greek_bits;
483                 dw = 7;  dh = 4;
484                 id -= 11;
485             }
486             break;
487          case 1:
488             w = bop_width;
489             h = bop_height;
490             bdata = bop_bits;
491             dw = 4;  dh = 8;
492             break;
493          case 2:
494             w = brel_width;
495             h = brel_height;
496             bdata = brel_bits;
497             dw = 4;  dh = 9;
498             break;
499          case 3:
500             if (id<20) {                
501                 w = arrow_width;
502                 h = arrow_height;
503                 bdata = arrow_bits;
504                 dw = 5;  dh = 4;
505             } else if (id>28) {         
506                 w = darrow_width;
507                 h = darrow_height;
508                 bdata = darrow_bits;
509                 dw = 2;  dh = 2;
510                 id -= 29;
511             } else {            
512                 w = larrow_width;
513                 h = larrow_height;
514                 bdata = larrow_bits;
515                 dw = 2;  dh = 4;
516                 id -= 20;
517             }
518             break;
519          case 4:
520             w = varsz_width;
521             h = varsz_height;
522             bdata = varsz_bits;
523             dw = 3;  dh = 5;
524             break;
525          case 5:
526             w = misc_width;
527             h = misc_height;
528             bdata = misc_bits;
529             dw = 5;  dh = 6;
530             break;
531         }
532         int ww = w/dw, hh = h/dh, x, y;
533    
534         XImage * xima = XCreateImage(fl_display, 0, 1, XYBitmap, 0, 
535                                     const_cast<char*>(reinterpret_cast<char const *>(bdata)), w, h, 8, 0);
536         xima->byte_order = LSBFirst;
537         xima->bitmap_bit_order = LSBFirst;
538         x = (id % dw)*ww;
539         y = (id/dw)*hh;
540         if (ww > wx) ww = wx;
541         if (hh > hx) hh = hx;
542         XImage * sbima = XSubImage(xima, x, y, ww, hh);
543         XpmCreateDataFromImage(fl_display, const_cast<char***>(&data), sbima, sbima, 0);
544         
545         // Dirty hack to get blue symbols quickly
546         char * sx = strstr(data[2], "FFFFFFFF");
547         if (sx) {
548             for (int k = 0; k < 8; ++k) sx[k] = '0';
549         }
550
551 //      XDestroyImage(xima);
552     }
553
554     return data;
555 }
556