]> git.lyx.org Git - lyx.git/blob - src/mathed/math_symbols.C
read the ChangeLog... no huge changes .. but some might get reversed...
[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 short greek_kb_flag;
43
44 extern BufferView * current_view;
45
46 /* Bitmaps */
47 #include "greek.xbm"
48 #include "arrows.xbm"
49 #include "brel.xbm"
50 #include "bop.xbm"
51 #include "misc.xbm"           
52 #include "varsz.xbm"           
53 #include "dots.xbm"
54
55 /* Latex code for those bitmaps */
56 static char const * latex_greek[] =  {
57    "Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi",
58    "Sigma", "Upsilon", "Phi", "Psi", "Omega",
59    "alpha", "beta", "gamma", "delta", "epsilon", "varepsilon", "zeta",
60    "eta", "theta", "vartheta", "iota", "kappa", "lambda", "mu",
61    "nu", "xi", "pi", "varpi", "rho", "sigma", "varsigma",
62    "tau", "upsilon", "phi", "varphi", "chi", "psi", "omega", ""
63 };
64
65 static char const * latex_brel[] = {
66   "leq", "geq", "equiv", "models", 
67   "prec", "succ", "sim", "perp", 
68   "preceq", "succeq", "simeq", "mid", 
69   "ll", "gg", "asymp", "parallel", 
70   "subset", "supset", "approx", "smile", 
71   "subseteq", "supseteq", "cong", "frown", 
72   "sqsubseteq", "sqsupseteq", "doteq", "neq", 
73   "in", "ni", "propto", "notin", 
74   "vdash", "dashv", "bowtie", ""
75 };
76
77 static char const * latex_arrow[] = {
78   "downarrow", "leftarrow", "Downarrow", "Leftarrow", 
79   "hookleftarrow", "rightarrow", "uparrow", "Rightarrow", "Uparrow",
80   "hookrightarrow", "updownarrow", "Leftrightarrow", "leftharpoonup", 
81   "rightharpoonup", "rightleftharpoons", "leftrightarrow", "Updownarrow", 
82   "leftharpoondown", "rightharpoondown", "mapsto",
83   "Longleftarrow", "Longrightarrow", "Longleftrightarrow", 
84   "longleftrightarrow", "longleftarrow", "longrightarrow", "longmapsto",
85   "nwarrow", "nearrow", "swarrow", "searrow",  "",
86 };
87
88 char const * latex_varsz[] = {
89 "sum", "int", "oint", 
90 "prod", "coprod", "bigsqcup", 
91 "bigotimes", "bigodot", "bigoplus", 
92 "bigcap", "bigcup", "biguplus", 
93 "bigvee", "bigwedge", ""
94 };
95
96 static char const * latex_bop[] = {   
97   "pm", "cap", "diamond", "oplus", 
98   "mp", "cup", "bigtriangleup", "ominus", 
99   "times", "uplus", "bigtriangledown", "otimes", 
100   "div", "sqcap", "triangleright", "oslash", 
101   "cdot", "sqcup", "triangleleft", "odot", 
102   "star", "vee", "amalg", "bigcirc", 
103   "setminus", "wedge", "dagger", "circ", 
104   "bullet", "wr", "ddagger", ""
105 };
106
107 static char const * latex_misc[] = {
108   "nabla", "partial", "infty", "prime", "ell", 
109   "emptyset", "exists", "forall", "imath",  "jmath",
110   "Re", "Im", "aleph", "wp", "hbar", 
111   "angle", "top", "bot", "Vert", "neg", 
112   "flat", "natural", "sharp", "surd", "triangle", 
113   "diamondsuit", "heartsuit", "clubsuit", "spadesuit", "" 
114 };
115
116 static char const * latex_dots[] = { 
117    "ldots", "cdots", "vdots", "ddots"
118 };
119
120 static signed char latin2greek[] =  {
121   0, 1, 25, 3, 4, 23, 2, 7, 10, 24, 11, 12, 13, 14, -1, 16, 8, 18,
122   19, 21, 22, 17, 27, 15, 26, 6
123 };
124  
125 static signed char Latin2Greek[] =  {
126  -1, -1, -1, 1, -1, 8, 0, -1, -1, -1, -1, 3, -1, -1, -1,
127  5, 2, -1, 6, -1, 7, -1, 10, 4, 9, -1
128 }; 
129
130 extern char const ** mathed_get_pixmap_from_icon(int d);
131 extern "C" void math_cb(FL_OBJECT*, long);
132 static char const ** pixmapFromBitmapData(char const *, int, int);
133 void math_insert_symbol(char const * s);
134 Bool math_insert_greek(char const c);
135
136 BitmapMenu * BitmapMenu::active = 0;
137
138 BitmapMenu::BitmapMenu(int n,  FL_OBJECT * bt, BitmapMenu * prevx): nb(n)
139 {
140    w = h = 0;
141    form = 0;
142    i = 0;
143    ww = 2 * FL_abs(FL_BOUND_WIDTH);
144    x = y = ww;
145    y += 8;
146    bitmap = new FL_OBJECTP[nb];
147    button = bt;
148    button->u_vdata = this;
149    prev = prevx;
150    next = 0;
151    if (prev)
152      prev->next = this;
153 }
154
155
156 BitmapMenu::~BitmapMenu()
157 {
158         delete next;
159         if (form->visible) Hide();
160         fl_free_form(form);  
161         delete[] bitmap;
162 }
163
164
165 void BitmapMenu::Hide()
166 {
167    fl_hide_form(form);
168    fl_set_button(button, 0);
169    active = 0;
170 }
171
172
173 void BitmapMenu::Show()
174 {
175    if (active)
176      active->Hide();
177    active = this;
178    //   int x = button->form->x + button->x, y = button->form->y + button->y;
179    //   fl_set_form_position(form, x, y + button->h);
180    fl_set_button(button, 1);
181    fl_show_form(form, FL_PLACE_MOUSE, FL_NOBORDER, "");
182 }
183
184 FL_OBJECT *
185 BitmapMenu::AddBitmap(int id, int nx, int ny, int bw, int bh, unsigned char const * data, Bool vert)
186 {
187    if (i >= nb)
188      return 0;
189    int wx = bw+ww/2, wy = bh+ww/2;
190    wx += (wx % nx);
191    wy += (wy % ny); 
192    FL_OBJECT * obj = fl_create_bmtable(1, x, y, wx, wy, "");   
193    fl_set_object_callback(obj, math_cb, id);
194    fl_set_object_lcol(obj, FL_BLUE);    
195    fl_set_object_boxtype(obj, FL_UP_BOX);   
196    fl_set_bmtable_data(obj, nx, ny, bw, bh, data);
197    if (vert) { 
198       y += wy + 8;
199       h = max(y, h);
200       w = max(x + wx + ww, w);
201    } else  {
202       x += wx + 8;
203       w = max(x, w);
204       h = max(y + wy + ww, h);
205    }
206    bitmap[i++] = obj;
207    return obj;
208 }
209
210 void BitmapMenu::Create()
211 {
212    if (i < nb)  {
213            lyxerr << "Error: Bitmaps not created!" << endl;
214       return;
215    }
216    form = fl_bgn_form(FL_UP_BOX, w, h);   
217    for (i = 0; i < nb; ++i) {
218       fl_add_object(form, bitmap[i]);
219       bitmap[i]->u_vdata = this;
220    }
221    fl_end_form();
222    fl_register_raw_callback(form, KeyPressMask, C_peek_event);
223 }
224
225 int BitmapMenu::GetIndex(FL_OBJECT* ob)
226 {
227    if (active == this) {
228       int k = 0;
229       for (i = 0; i < nb; ++i) {
230          if (bitmap[i] == ob) 
231            return k+fl_get_bmtable(ob);
232          k += fl_get_bmtable_maxitems(bitmap[i]);
233       }
234    }
235    return -1;
236 }
237
238 int peek_event(FL_FORM * /*form*/, void *xev)
239 {
240    if (BitmapMenu::active == 0)
241      return 0;
242   
243    if(static_cast<XEvent *>(xev)->type == ButtonPress)
244    {
245          BitmapMenu::active->Hide();
246          return 1;
247    }
248    if(static_cast<XEvent *>(xev)->type == KeyPress)
249    {
250       char c[5];
251       KeySym keysym;
252       XLookupString(&static_cast<XEvent *>(xev)->xkey, &c[0], 5, &keysym, 0);
253       if (keysym == XK_Left) 
254         BitmapMenu::active->Prev(); else
255       if (keysym == XK_Right) 
256         BitmapMenu::active->Next(); 
257       else 
258         BitmapMenu::active->Hide();
259       return 1;
260    }
261    return 0;  
262 }
263
264 // This is just a wrapper.
265 extern "C" int C_peek_event(FL_FORM *form, void *ptr) {
266   return peek_event(form, ptr);
267 }
268
269
270 extern "C" void math_cb(FL_OBJECT* ob, long data)
271 {
272    BitmapMenu * menu = static_cast<BitmapMenu*>(ob->u_vdata);
273    int i = menu->GetIndex(ob);   
274    char const *s = 0;
275
276 //   lyxerr << "data[" << data << "]";
277    if (i<0) return;
278    switch (data)  {
279     case MM_GREEK: 
280       s = latex_greek[i]; 
281       break;
282     case MM_ARROW: 
283       s = latex_arrow[i]; 
284       break;  
285     case MM_BRELATS: 
286       s = latex_brel[i]; 
287       break;  
288     case MM_BOP: 
289       s = latex_bop[i]; 
290       break;  
291     case MM_VARSIZE: 
292       s = latex_varsz[i];  
293       break;
294     case MM_MISC: 
295       s = latex_misc[i];  
296       break;
297     case MM_DOTS: 
298 //      lyxerr << "dots[" << latex_dots[i] << " " << i << "]";
299       s = latex_dots[i-29];  
300       break;
301    }
302   
303    if (s)  {
304       if (current_view->available() && lyxrc->display_shortcuts) {
305           current_view->owner()->getMiniBuffer()->Set("Inserting symbol ", s);
306       }
307       current_view->owner()->getLyXFunc()->Dispatch(LFUN_INSERT_MATH, s);
308    }      
309    if (menu)  
310      menu->Hide(); 
311 }
312
313 char const ** get_pixmap_from_symbol(char const * arg, int wx, int hx)
314 {
315    char const ** data = 0;                  
316    latexkeys * l = in_word_set (arg, strlen(arg));
317    if (!l) 
318     return 0;
319     
320    switch (l->token) {
321     case LM_TK_FRAC:
322       data = mathed_get_pixmap_from_icon(MM_FRAC);
323       break;
324     case LM_TK_SQRT: 
325       data = mathed_get_pixmap_from_icon(MM_SQRT);
326       break;
327     case LM_TK_BIGSYM:
328     case LM_TK_SYM:
329        // I have to use directly the bitmap data since the
330        // bitmap tables are not yet created when this
331        // function is called.
332        data = pixmapFromBitmapData(arg, wx, hx);
333        break;
334    }
335    
336    return data;
337 }
338
339 Bool math_insert_greek(char const c)
340 {
341    int i;
342    char const * s= 0;
343    
344    if ('A' <= c && c <= 'Z') {
345       if ((i = Latin2Greek[c - 'A']) >= 0)
346         s = latex_greek[i];
347    }   
348    if ('a'<= c && c<= 'z') {
349       if ((i= latin2greek[c - 'a'])>= 0)
350         s = latex_greek[i+11];
351    }
352    if (s) {
353       math_insert_symbol(s);
354       if (greek_kb_flag<2) {
355          greek_kb_flag = 0;
356          current_view->unlockInset(current_view->the_locking_inset);
357       }
358       return True;
359    } else
360      return False; 
361 }
362
363
364 void math_insert_symbol(char const * s)
365 {
366    if (current_view->available())   {
367       if (!current_view->the_locking_inset) {
368          InsetFormula * new_inset = new InsetFormula();
369          current_view->beforeChange();
370          current_view->insertInset(new_inset);
371 //       Update(1);//BUG
372          new_inset->Edit(current_view, 0, 0, 0);
373          new_inset->InsertSymbol(current_view, s);
374       } else
375         if (current_view->the_locking_inset->LyxCode() == Inset::MATH_CODE)
376                 static_cast<InsetFormula*>(current_view->the_locking_inset)->InsertSymbol(current_view, s);
377         else 
378                 lyxerr << "Math error: attempt to write on a wrong "
379                         "class of inset." << endl;
380    }
381 }
382
383
384 BitmapMenu * sym_menu= 0;
385
386 void  create_symbol_menues(FD_panel * symb_form)
387 {
388    FL_OBJECT * obj; 
389    BitmapMenu * menu;
390    
391    sym_menu = menu = new BitmapMenu(2, symb_form->greek);
392    obj = menu->AddBitmap(MM_GREEK, 6, 2, Greek_width, Greek_height, 
393                            Greek_bits);         
394    fl_set_bmtable_maxitems(obj, 11);
395    obj = menu->AddBitmap(MM_GREEK, 7, 4, greek_width, greek_height,
396                            greek_bits); 
397    menu->Create();
398    
399    menu = new BitmapMenu(1, symb_form->boperator, menu);
400    obj = menu->AddBitmap(MM_BOP, 4, 8, bop_width, bop_height,
401                          bop_bits);      
402    fl_set_bmtable_maxitems(obj, 31);
403    menu->Create();   
404       
405    menu = new BitmapMenu(1, symb_form->brelats, menu);
406    obj = menu->AddBitmap(MM_BRELATS, 4, 9, brel_width, brel_height, 
407                          brel_bits);        
408    fl_set_bmtable_maxitems(obj, 35);       
409    menu->Create();
410    
411    menu = new BitmapMenu(3, symb_form->arrow, menu);
412    obj = menu->AddBitmap(MM_ARROW, 5, 4, arrow_width, arrow_height,
413                          arrow_bits);
414    obj = menu->AddBitmap(MM_ARROW, 2, 4, larrow_width, larrow_height, 
415                          larrow_bits, False);          
416    fl_set_bmtable_maxitems(obj, 7);
417    obj = menu->AddBitmap(MM_ARROW, 2, 2, darrow_width, darrow_height, 
418                          darrow_bits);
419    menu->Create(); 
420      
421    menu = new BitmapMenu(1, symb_form->varsize, menu);
422     obj = menu->AddBitmap(MM_VARSIZE, 3, 5, varsz_width, varsz_height, 
423                          varsz_bits);         
424    fl_set_bmtable_maxitems(obj, 14);
425    menu->Create();
426       
427    menu = new BitmapMenu(2, symb_form->misc, menu);
428      obj = menu->AddBitmap(MM_MISC, 5, 6, misc_width, misc_height,
429                            misc_bits);         
430      fl_set_bmtable_maxitems(obj, 29);
431      obj = menu->AddBitmap(MM_DOTS, 4, 1, dots_width, dots_height, 
432                            dots_bits);         
433    menu->Create();
434 }
435
436 static
437 char const ** pixmapFromBitmapData(char const * s, int wx, int hx)
438 {
439     int i;
440     char const ** data = 0;
441     
442     int id = -1;
443     
444     for (i = 0; i < 6; ++i) {
445         char const ** latex_str = 0;
446         switch (i) {
447          case 0: latex_str = latex_greek; break;
448          case 1: latex_str = latex_bop; break;
449          case 2: latex_str = latex_brel; break;
450          case 3: latex_str = latex_arrow; break;
451          case 4: latex_str = latex_varsz; break;
452          case 5: latex_str = latex_misc; break;
453         }
454         
455         for (int k = 0; latex_str[k][0] > ' '; ++k) {
456             if (strcmp(latex_str[k], s) == 0) {
457                 id = k;
458                 break;
459             }
460         }
461         if (id >= 0) break;
462     }
463     if (i < 6 && id >= 0) {
464         unsigned char const * bdata = 0;
465         int w = 0, h = 0, dw = 0, dh = 0;
466
467         lyxerr[Debug::MATHED] << "Imando " << i << ", " << id << endl;
468         switch (i) {
469          case 0: 
470             if (id<= 10) {
471                 w = Greek_width;
472                 h = Greek_height;
473                 bdata = Greek_bits;
474                 dw = 6;  dh = 2;
475             } else {
476                 w = greek_width;
477                 h = greek_height;
478                 bdata = greek_bits;
479                 dw = 7;  dh = 4;
480                 id -= 11;
481             }
482             break;
483          case 1:
484             w = bop_width;
485             h = bop_height;
486             bdata = bop_bits;
487             dw = 4;  dh = 8;
488             break;
489          case 2:
490             w = brel_width;
491             h = brel_height;
492             bdata = brel_bits;
493             dw = 4;  dh = 9;
494             break;
495          case 3:
496             if (id<20) {                
497                 w = arrow_width;
498                 h = arrow_height;
499                 bdata = arrow_bits;
500                 dw = 5;  dh = 4;
501             } else if (id>28) {         
502                 w = darrow_width;
503                 h = darrow_height;
504                 bdata = darrow_bits;
505                 dw = 2;  dh = 2;
506                 id -= 29;
507             } else {            
508                 w = larrow_width;
509                 h = larrow_height;
510                 bdata = larrow_bits;
511                 dw = 2;  dh = 4;
512                 id -= 20;
513             }
514             break;
515          case 4:
516             w = varsz_width;
517             h = varsz_height;
518             bdata = varsz_bits;
519             dw = 3;  dh = 5;
520             break;
521          case 5:
522             w = misc_width;
523             h = misc_height;
524             bdata = misc_bits;
525             dw = 5;  dh = 6;
526             break;
527         }
528         int ww = w/dw, hh = h/dh, x, y;
529    
530         XImage * xima = XCreateImage(fl_display, 0, 1, XYBitmap, 0, 
531                                     const_cast<char*>(reinterpret_cast<char const *>(bdata)), w, h, 8, 0);
532         xima->byte_order = LSBFirst;
533         xima->bitmap_bit_order = LSBFirst;
534         x = (id % dw)*ww;
535         y = (id/dw)*hh;
536         if (ww > wx) ww = wx;
537         if (hh > hx) hh = hx;
538         XImage * sbima = XSubImage(xima, x, y, ww, hh);
539         XpmCreateDataFromImage(fl_display, const_cast<char***>(&data), sbima, sbima, 0);
540         
541         // Dirty hack to get blue symbols quickly
542         char * sx = strstr(data[2], "FFFFFFFF");
543         if (sx) {
544             for (int k = 0; k < 8; ++k) sx[k] = '0';
545         }
546
547 //      XDestroyImage(xima);
548     }
549
550     return data;
551 }
552