]> git.lyx.org Git - lyx.git/blob - src/mathed/math_symbols.C
use more std::functors add some of my own, some change to fl_display etc. read the...
[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                 static_cast<InsetFormula*>(current_view->theLockingInset())->LocalDispatch(current_view, LFUN_SELFINSERT, tmp);
354          else
355                 lyxerr << "Math error: attempt to write on a wrong "
356                         "class of inset." << endl;
357       return true;
358    }
359    return false;
360 }
361
362
363 void math_insert_symbol(string const & s)
364 {
365    if (current_view->available())   {
366       if (!current_view->theLockingInset()) {
367          InsetFormula * new_inset = new InsetFormula();
368          current_view->beforeChange();
369          current_view->insertInset(new_inset);
370 //       Update(1);//BUG
371          new_inset->Edit(current_view, 0, 0, 0);
372          new_inset->InsertSymbol(current_view, s);
373       } else
374         if (current_view->theLockingInset()->LyxCode() == Inset::MATH_CODE)
375                 static_cast<InsetFormula*>(current_view->theLockingInset())->InsertSymbol(current_view, s);
376         else 
377                 lyxerr << "Math error: attempt to write on a wrong "
378                         "class of inset." << endl;
379    }
380 }
381
382
383 BitmapMenu * sym_menu= 0;
384
385 void  create_symbol_menues(FD_panel * symb_form)
386 {
387    FL_OBJECT * obj; 
388    BitmapMenu * menu;
389    
390    sym_menu = menu = new BitmapMenu(2, symb_form->greek);
391    obj = menu->AddBitmap(MM_GREEK, 6, 2, Greek_width, Greek_height, 
392                            Greek_bits);         
393    fl_set_bmtable_maxitems(obj, 11);
394    obj = menu->AddBitmap(MM_GREEK, 7, 4, greek_width, greek_height,
395                            greek_bits); 
396    menu->Create();
397    
398    menu = new BitmapMenu(1, symb_form->boperator, menu);
399    obj = menu->AddBitmap(MM_BOP, 4, 8, bop_width, bop_height,
400                          bop_bits);      
401    fl_set_bmtable_maxitems(obj, 31);
402    menu->Create();   
403       
404    menu = new BitmapMenu(1, symb_form->brelats, menu);
405    obj = menu->AddBitmap(MM_BRELATS, 4, 9, brel_width, brel_height, 
406                          brel_bits);        
407    fl_set_bmtable_maxitems(obj, 35);       
408    menu->Create();
409    
410    menu = new BitmapMenu(3, symb_form->arrow, menu);
411    obj = menu->AddBitmap(MM_ARROW, 5, 4, arrow_width, arrow_height,
412                          arrow_bits);
413    obj = menu->AddBitmap(MM_ARROW, 2, 4, larrow_width, larrow_height, 
414                          larrow_bits, False);          
415    fl_set_bmtable_maxitems(obj, 7);
416    obj = menu->AddBitmap(MM_ARROW, 2, 2, darrow_width, darrow_height, 
417                          darrow_bits);
418    menu->Create(); 
419      
420    menu = new BitmapMenu(1, symb_form->varsize, menu);
421     obj = menu->AddBitmap(MM_VARSIZE, 3, 5, varsz_width, varsz_height, 
422                          varsz_bits);         
423    fl_set_bmtable_maxitems(obj, 14);
424    menu->Create();
425       
426    menu = new BitmapMenu(2, symb_form->misc, menu);
427      obj = menu->AddBitmap(MM_MISC, 5, 6, misc_width, misc_height,
428                            misc_bits);         
429      fl_set_bmtable_maxitems(obj, 29);
430      obj = menu->AddBitmap(MM_DOTS, 4, 1, dots_width, dots_height, 
431                            dots_bits);         
432    menu->Create();
433 }
434
435 static
436 char const ** pixmapFromBitmapData(char const * s, int wx, int hx)
437 {
438     int i;
439     char const ** data = 0;
440     
441     int id = -1;
442     
443     for (i = 0; i < 6; ++i) {
444         char const ** latex_str = 0;
445         switch (i) {
446          case 0: latex_str = latex_greek; break;
447          case 1: latex_str = latex_bop; break;
448          case 2: latex_str = latex_brel; break;
449          case 3: latex_str = latex_arrow; break;
450          case 4: latex_str = latex_varsz; break;
451          case 5: latex_str = latex_misc; break;
452         }
453         
454         for (int k = 0; latex_str[k][0] > ' '; ++k) {
455             if (strcmp(latex_str[k], s) == 0) {
456                 id = k;
457                 break;
458             }
459         }
460         if (id >= 0) break;
461     }
462     if (i < 6 && id >= 0) {
463         unsigned char const * bdata = 0;
464         int w = 0, h = 0, dw = 0, dh = 0;
465
466         lyxerr[Debug::MATHED] << "Imando " << i << ", " << id << endl;
467         switch (i) {
468          case 0: 
469             if (id<= 10) {
470                 w = Greek_width;
471                 h = Greek_height;
472                 bdata = Greek_bits;
473                 dw = 6;  dh = 2;
474             } else {
475                 w = greek_width;
476                 h = greek_height;
477                 bdata = greek_bits;
478                 dw = 7;  dh = 4;
479                 id -= 11;
480             }
481             break;
482          case 1:
483             w = bop_width;
484             h = bop_height;
485             bdata = bop_bits;
486             dw = 4;  dh = 8;
487             break;
488          case 2:
489             w = brel_width;
490             h = brel_height;
491             bdata = brel_bits;
492             dw = 4;  dh = 9;
493             break;
494          case 3:
495             if (id<20) {                
496                 w = arrow_width;
497                 h = arrow_height;
498                 bdata = arrow_bits;
499                 dw = 5;  dh = 4;
500             } else if (id>28) {         
501                 w = darrow_width;
502                 h = darrow_height;
503                 bdata = darrow_bits;
504                 dw = 2;  dh = 2;
505                 id -= 29;
506             } else {            
507                 w = larrow_width;
508                 h = larrow_height;
509                 bdata = larrow_bits;
510                 dw = 2;  dh = 4;
511                 id -= 20;
512             }
513             break;
514          case 4:
515             w = varsz_width;
516             h = varsz_height;
517             bdata = varsz_bits;
518             dw = 3;  dh = 5;
519             break;
520          case 5:
521             w = misc_width;
522             h = misc_height;
523             bdata = misc_bits;
524             dw = 5;  dh = 6;
525             break;
526         }
527         int ww = w/dw, hh = h/dh, x, y;
528    
529         XImage * xima = XCreateImage(fl_get_display(), 0, 1, XYBitmap, 0, 
530                                     const_cast<char*>(reinterpret_cast<char const *>(bdata)), w, h, 8, 0);
531         xima->byte_order = LSBFirst;
532         xima->bitmap_bit_order = LSBFirst;
533         x = (id % dw)*ww;
534         y = (id/dw)*hh;
535         if (ww > wx) ww = wx;
536         if (hh > hx) hh = hx;
537         XImage * sbima = XSubImage(xima, x, y, ww, hh);
538         XpmCreateDataFromImage(fl_get_display(), const_cast<char***>(&data), sbima, sbima, 0);
539         
540         // Dirty hack to get blue symbols quickly
541         char * sx = const_cast<char*>(strstr(data[2], "FFFFFFFF"));
542         if (sx) {
543             for (int k = 0; k < 8; ++k) sx[k] = '0';
544         }
545
546 //      XDestroyImage(xima);
547     }
548
549     return data;
550 }
551