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