]> git.lyx.org Git - lyx.git/blob - src/mathed/math_symbols.C
first go at mathed file cleanup
[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 #include "lyxtext.h"
37
38 #include "formula.h"
39
40 #include "math_panel.h"                 
41 #include "math_parser.h"
42
43 using std::max;
44 using std::endl;
45 using std::ostream;
46
47 extern int greek_kb_flag;
48
49 extern BufferView * current_view;
50
51 /* Bitmaps */
52 #include "greek.xbm"
53 #include "arrows.xbm"
54 #include "brel.xbm"
55 #include "bop.xbm"
56 #include "misc.xbm"           
57 #include "varsz.xbm"           
58 #include "dots.xbm"
59
60 /* Latex code for those bitmaps */
61 static char const * latex_greek[] =  {
62    "Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi",
63    "Sigma", "Upsilon", "Phi", "Psi", "Omega",
64    "alpha", "beta", "gamma", "delta", "epsilon", "varepsilon", "zeta",
65    "eta", "theta", "vartheta", "iota", "kappa", "lambda", "mu",
66    "nu", "xi", "pi", "varpi", "rho", "sigma", "varsigma",
67    "tau", "upsilon", "phi", "varphi", "chi", "psi", "omega", ""
68 };
69
70 static char const * latex_brel[] = {
71   "leq", "geq", "equiv", "models", 
72   "prec", "succ", "sim", "perp", 
73   "preceq", "succeq", "simeq", "mid", 
74   "ll", "gg", "asymp", "parallel", 
75   "subset", "supset", "approx", "smile", 
76   "subseteq", "supseteq", "cong", "frown", 
77   "sqsubseteq", "sqsupseteq", "doteq", "neq", 
78   "in", "ni", "propto", "notin", 
79   "vdash", "dashv", "bowtie", ""
80 };
81
82 static char const * latex_arrow[] = {
83   "downarrow", "leftarrow", "Downarrow", "Leftarrow", 
84   "hookleftarrow", "rightarrow", "uparrow", "Rightarrow", "Uparrow",
85   "hookrightarrow", "updownarrow", "Leftrightarrow", "leftharpoonup", 
86   "rightharpoonup", "rightleftharpoons", "leftrightarrow", "Updownarrow", 
87   "leftharpoondown", "rightharpoondown", "mapsto",
88   "Longleftarrow", "Longrightarrow", "Longleftrightarrow", 
89   "longleftrightarrow", "longleftarrow", "longrightarrow", "longmapsto",
90   "nwarrow", "nearrow", "swarrow", "searrow",  "",
91 };
92
93 char const * latex_varsz[] = {
94 "sum", "int", "oint", 
95 "prod", "coprod", "bigsqcup", 
96 "bigotimes", "bigodot", "bigoplus", 
97 "bigcap", "bigcup", "biguplus", 
98 "bigvee", "bigwedge", ""
99 };
100
101 static char const * latex_bop[] = {   
102   "pm", "cap", "diamond", "oplus", 
103   "mp", "cup", "bigtriangleup", "ominus", 
104   "times", "uplus", "bigtriangledown", "otimes", 
105   "div", "sqcap", "triangleright", "oslash", 
106   "cdot", "sqcup", "triangleleft", "odot", 
107   "star", "vee", "amalg", "bigcirc", 
108   "setminus", "wedge", "dagger", "circ", 
109   "bullet", "wr", "ddagger", ""
110 };
111
112 static char const * latex_misc[] = {
113   "nabla", "partial", "infty", "prime", "ell", 
114   "emptyset", "exists", "forall", "imath",  "jmath",
115   "Re", "Im", "aleph", "wp", "hbar", 
116   "angle", "top", "bot", "Vert", "neg", 
117   "flat", "natural", "sharp", "surd", "triangle", 
118   "diamondsuit", "heartsuit", "clubsuit", "spadesuit", "" 
119 };
120
121 static char const * latex_dots[] = { 
122    "ldots", "cdots", "vdots", "ddots"
123 };
124
125 extern char const ** mathed_get_pixmap_from_icon(int d);
126 extern "C" void math_cb(FL_OBJECT*, long);
127 static char const ** pixmapFromBitmapData(char const *, int, int);
128 void math_insert_symbol(char const * s);
129 bool math_insert_greek(char c);
130
131 BitmapMenu * BitmapMenu::active = 0;
132
133 BitmapMenu::BitmapMenu(int n,  FL_OBJECT * bt, BitmapMenu * prevx)
134         : current_(0), bitmaps_(n)
135 {
136    w = h = 0;
137    form = 0;
138    ww = 2 * FL_abs(FL_BOUND_WIDTH);
139    x = y = ww;
140    y += 8;
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 }
156
157
158 void BitmapMenu::Hide()
159 {
160    fl_hide_form(form);
161    fl_set_button(button, 0);
162    active = 0;
163 }
164
165
166 void BitmapMenu::Show()
167 {
168    if (active)
169      active->Hide();
170    active = this;
171    //   int x = button->form->x + button->x, y = button->form->y + button->y;
172    //   fl_set_form_position(form, x, y + button->h);
173    fl_set_button(button, 1);
174    fl_show_form(form, FL_PLACE_MOUSE, FL_NOBORDER, "");
175 }
176
177 FL_OBJECT *
178 BitmapMenu::AddBitmap(int id, int nx, int ny, int bw, int bh,
179                       unsigned char const * data, Bool vert)
180 {
181    if (current_ >= bitmaps_.size())
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    bitmaps_[current_++] = obj;
201    return obj;
202 }
203
204 void BitmapMenu::Create()
205 {
206    if (current_ < bitmaps_.size())  {
207            lyxerr << "Error: Bitmaps not created!" << endl;
208       return;
209    }
210    form = fl_bgn_form(FL_UP_BOX, w, h);   
211    for (current_ = 0; current_ < bitmaps_.size(); ++current_) {
212       fl_add_object(form, bitmaps_[current_]);
213       bitmaps_[current_]->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 (current_ = 0; current_ < bitmaps_.size(); ++current_) {
224          if (bitmaps_[current_] == ob) 
225            return k+fl_get_bmtable(ob);
226          k += fl_get_bmtable_maxitems(bitmaps_[current_]);
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(BufferView * bv, char c)
334 {
335    if (bv->available() &&
336        (('A' <= c && c <= 'Z') ||
337         ('a'<= c && c<= 'z')))   {
338       string tmp;
339       tmp = c;
340       if (!bv->theLockingInset() || bv->theLockingInset()->IsTextInset()) {
341          int greek_kb_flag_save = greek_kb_flag;
342          InsetFormula * new_inset = new InsetFormula();
343          bv->beforeChange();
344          if (!bv->insertInset(new_inset)) {
345              delete new_inset;
346              return false;
347          }
348 //       Update(1);//BUG
349          new_inset->Edit(bv, 0, 0, 0);
350          new_inset->LocalDispatch(bv, LFUN_SELFINSERT, tmp);
351          if (greek_kb_flag_save < 2) {
352                  bv->unlockInset(new_inset); // bv->theLockingInset());
353                  bv->text->CursorRight(bv, true);
354          }
355       } else
356          if (bv->theLockingInset()->LyxCode() == Inset::MATH_CODE ||
357              bv->theLockingInset()->LyxCode() == Inset::MATHMACRO_CODE)
358                 static_cast<InsetFormula*>(bv->theLockingInset())->LocalDispatch(bv, LFUN_SELFINSERT, tmp);
359          else
360                 lyxerr << "Math error: attempt to write on a wrong "
361                         "class of inset." << endl;
362       return true;
363    }
364    return false;
365 }
366
367
368 void math_insert_symbol(BufferView * bv, string const & s)
369 {
370    if (bv->available())   {
371       if (!bv->theLockingInset() || bv->theLockingInset()->IsTextInset()) {
372          InsetFormula * new_inset = new InsetFormula();
373          bv->beforeChange();
374          if (!bv->insertInset(new_inset)) {
375              delete new_inset;
376              return;
377          }
378 //       Update(1);//BUG
379          new_inset->Edit(bv, 0, 0, 0);
380          new_inset->InsertSymbol(bv, s);
381       } else
382         if (bv->theLockingInset()->LyxCode() == Inset::MATH_CODE ||
383             bv->theLockingInset()->LyxCode() == Inset::MATHMACRO_CODE)
384                 static_cast<InsetFormula*>(bv->theLockingInset())->InsertSymbol(bv, s);
385         else 
386                 lyxerr << "Math error: attempt to write on a wrong "
387                         "class of inset." << endl;
388    }
389 }
390
391
392 BitmapMenu * sym_menu= 0;
393
394 void  create_symbol_menues(FD_panel * symb_form)
395 {
396    FL_OBJECT * obj; 
397    BitmapMenu * menu;
398    
399    sym_menu = menu = new BitmapMenu(2, symb_form->greek);
400    obj = menu->AddBitmap(MM_GREEK, 6, 2, Greek_width, Greek_height, 
401                            Greek_bits);         
402    fl_set_bmtable_maxitems(obj, 11);
403    obj = menu->AddBitmap(MM_GREEK, 7, 4, greek_width, greek_height,
404                            greek_bits); 
405    menu->Create();
406    
407    menu = new BitmapMenu(1, symb_form->boperator, menu);
408    obj = menu->AddBitmap(MM_BOP, 4, 8, bop_width, bop_height,
409                          bop_bits);      
410    fl_set_bmtable_maxitems(obj, 31);
411    menu->Create();   
412       
413    menu = new BitmapMenu(1, symb_form->brelats, menu);
414    obj = menu->AddBitmap(MM_BRELATS, 4, 9, brel_width, brel_height, 
415                          brel_bits);        
416    fl_set_bmtable_maxitems(obj, 35);       
417    menu->Create();
418    
419    menu = new BitmapMenu(3, symb_form->arrow, menu);
420    obj = menu->AddBitmap(MM_ARROW, 5, 4, arrow_width, arrow_height,
421                          arrow_bits);
422    obj = menu->AddBitmap(MM_ARROW, 2, 4, larrow_width, larrow_height, 
423                          larrow_bits, False);          
424    fl_set_bmtable_maxitems(obj, 7);
425    obj = menu->AddBitmap(MM_ARROW, 2, 2, darrow_width, darrow_height, 
426                          darrow_bits);
427    menu->Create(); 
428      
429    menu = new BitmapMenu(1, symb_form->varsize, menu);
430     obj = menu->AddBitmap(MM_VARSIZE, 3, 5, varsz_width, varsz_height, 
431                          varsz_bits);         
432    fl_set_bmtable_maxitems(obj, 14);
433    menu->Create();
434       
435    menu = new BitmapMenu(2, symb_form->misc, menu);
436      obj = menu->AddBitmap(MM_MISC, 5, 6, misc_width, misc_height,
437                            misc_bits);         
438      fl_set_bmtable_maxitems(obj, 29);
439      obj = menu->AddBitmap(MM_DOTS, 4, 1, dots_width, dots_height, 
440                            dots_bits);         
441    menu->Create();
442 }
443
444 static
445 char const ** pixmapFromBitmapData(char const * s, int wx, int hx)
446 {
447     int i;
448     char const ** data = 0;
449     
450     int id = -1;
451     
452     for (i = 0; i < 6; ++i) {
453         char const ** latex_str = 0;
454         switch (i) {
455          case 0: latex_str = latex_greek; break;
456          case 1: latex_str = latex_bop; break;
457          case 2: latex_str = latex_brel; break;
458          case 3: latex_str = latex_arrow; break;
459          case 4: latex_str = latex_varsz; break;
460          case 5: latex_str = latex_misc; break;
461         }
462         
463         for (int k = 0; latex_str[k][0] > ' '; ++k) {
464             if (strcmp(latex_str[k], s) == 0) {
465                 id = k;
466                 break;
467             }
468         }
469         if (id >= 0) break;
470     }
471     if (i < 6 && id >= 0) {
472         unsigned char const * bdata = 0;
473         int w = 0, h = 0, dw = 0, dh = 0;
474
475         lyxerr[Debug::MATHED] << "Imando " << i << ", " << id << endl;
476         switch (i) {
477          case 0: 
478             if (id<= 10) {
479                 w = Greek_width;
480                 h = Greek_height;
481                 bdata = Greek_bits;
482                 dw = 6;  dh = 2;
483             } else {
484                 w = greek_width;
485                 h = greek_height;
486                 bdata = greek_bits;
487                 dw = 7;  dh = 4;
488                 id -= 11;
489             }
490             break;
491          case 1:
492             w = bop_width;
493             h = bop_height;
494             bdata = bop_bits;
495             dw = 4;  dh = 8;
496             break;
497          case 2:
498             w = brel_width;
499             h = brel_height;
500             bdata = brel_bits;
501             dw = 4;  dh = 9;
502             break;
503          case 3:
504             if (id<20) {                
505                 w = arrow_width;
506                 h = arrow_height;
507                 bdata = arrow_bits;
508                 dw = 5;  dh = 4;
509             } else if (id>28) {         
510                 w = darrow_width;
511                 h = darrow_height;
512                 bdata = darrow_bits;
513                 dw = 2;  dh = 2;
514                 id -= 29;
515             } else {            
516                 w = larrow_width;
517                 h = larrow_height;
518                 bdata = larrow_bits;
519                 dw = 2;  dh = 4;
520                 id -= 20;
521             }
522             break;
523          case 4:
524             w = varsz_width;
525             h = varsz_height;
526             bdata = varsz_bits;
527             dw = 3;  dh = 5;
528             break;
529          case 5:
530             w = misc_width;
531             h = misc_height;
532             bdata = misc_bits;
533             dw = 5;  dh = 6;
534             break;
535         }
536         int ww = w/dw, hh = h/dh, x, y;
537    
538         XImage * xima = XCreateImage(fl_get_display(), 0, 1, XYBitmap, 0, 
539                                     const_cast<char*>(reinterpret_cast<char const *>(bdata)), w, h, 8, 0);
540         xima->byte_order = LSBFirst;
541         xima->bitmap_bit_order = LSBFirst;
542         x = (id % dw)*ww;
543         y = (id/dw)*hh;
544         if (ww > wx) ww = wx;
545         if (hh > hx) hh = hx;
546         XImage * sbima = XSubImage(xima, x, y, ww, hh);
547         XpmCreateDataFromImage(fl_get_display(), const_cast<char***>(&data), sbima, sbima, 0);
548         
549         // Dirty hack to get blue symbols quickly
550         char * sx = const_cast<char*>(strstr(data[2], "FFFFFFFF"));
551         if (sx) {
552             for (int k = 0; k < 8; ++k) sx[k] = '0';
553         }
554
555 //      XDestroyImage(xima);
556     }
557
558     return data;
559 }
560