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