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