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