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