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