]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/Toolbar_pimpl.C
7718cbbe654ebd3e2e3cb38d8047be7f7e3c857d
[lyx.git] / src / frontends / xforms / Toolbar_pimpl.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2000 The LyX Team.
8  *
9  *           This file is Copyright 1996-1998
10  *           Lars Gullik Bjønnes
11  *
12  * ====================================================== */
13
14 //  Added pseudo-action handling, asierra 180296
15
16 #include <config.h>
17
18 #ifdef __GNUG__
19 #pragma implementation
20 #endif
21
22 #include "Toolbar_pimpl.h"
23 #include "lyxfunc.h"
24 #include "debug.h"
25 #include "LyXView.h"
26 #include "BufferView.h"
27 #include "buffer.h"
28 #include "LyXAction.h"
29 #include "MathsSymbols.h" 
30 #include "support/filetools.h"
31 #include "support/lstrings.h" 
32 #include "gettext.h"
33
34 using std::endl;
35
36 extern char const ** get_pixmap_from_symbol(char const * arg, int, int);
37  
38 extern LyXAction lyxaction;
39
40 // some constants
41 const int standardspacing = 2; // the usual space between items
42 const int sepspace = 6; // extra space
43 const int buttonwidth = 30; // the standard button width
44 const int height = 30; // the height of all items in the toolbar
45
46 Toolbar::Pimpl::toolbarItem::toolbarItem() {
47         action = LFUN_NOACTION;
48         icon = 0;
49 }
50
51
52 Toolbar::Pimpl::toolbarItem::~toolbarItem() {
53         clean();
54 }
55
56
57 void Toolbar::Pimpl::toolbarItem::clean() {
58         if (icon) {
59                 fl_delete_object(icon);
60                 fl_free_object(icon);
61                 icon = 0;
62         }
63 }
64
65
66 Toolbar::Pimpl::toolbarItem & 
67 Toolbar::Pimpl::toolbarItem::operator=(toolbarItem const & ti) {
68         // Are we assigning the object onto itself?
69         if (this == &ti)
70                 return *this;
71
72         // If we already have an icon, release it.
73         clean();
74     
75         // do we have to check icon too?
76         action = ti.action;
77         icon = 0; // locally we need to get the icon anew
78         
79         return *this;
80 }
81
82
83
84 Toolbar::Pimpl::Pimpl(LyXView * o, int x, int y)
85         : owner(o), sxpos(x), sypos(y)
86 {
87         combox = 0;
88 #if FL_REVISION < 89
89         bubble_timer = 0;
90 #endif
91 }
92
93
94 #if FL_REVISION < 89
95 // timer-cb for bubble-help (Matthias)
96 static 
97 void BubbleTimerCB(FL_OBJECT *, long data)
98 {
99         FL_OBJECT * ob = reinterpret_cast<FL_OBJECT*>(data);
100         // The trick we use to get the help text is to read the
101         // argument of the callback that has been registered for
102         // ToolBarCB.  (JMarc)
103         string help = _(lyxaction.helpText(ob->argument));
104         fl_show_oneliner(help.c_str(), ob->form->x + ob->x,
105                          ob->form->y + ob->y + ob->h);
106 }
107
108
109 extern "C" void C_Toolbar_BubbleTimerCB(FL_OBJECT * ob, long data)
110 {
111         BubbleTimerCB(ob, data);
112 }
113
114
115 // post_handler for bubble-help (Matthias)
116 static
117 int BubblePost(FL_OBJECT *ob, int event,
118                         FL_Coord /*mx*/, FL_Coord /*my*/,
119                         int /*key*/, void * /*xev*/)
120 {
121         FL_OBJECT * bubble_timer = reinterpret_cast<FL_OBJECT *>(ob->u_cdata);
122         
123         // We do not test for empty help here, since this can never happen
124         if (event == FL_ENTER){
125                 fl_set_object_callback(bubble_timer,
126                                        C_Toolbar_BubbleTimerCB,
127                                        reinterpret_cast<long>(ob));
128                 fl_set_timer(bubble_timer, 1);
129         }
130         else if (event != FL_MOTION){
131                 fl_set_timer(bubble_timer, 0);
132                 fl_hide_oneliner();
133         }
134         return 0;
135 }
136
137
138 extern "C" int C_Toolbar_BubblePost(FL_OBJECT * ob, int event,
139                                     FL_Coord /*mx*/, FL_Coord /*my*/, 
140                                     int key, void * xev)
141 {
142         return BubblePost(ob, event, 0, 0, key, xev);
143 }
144 #endif
145
146 // this one is not "C" because combox callbacks are really C++ %-|
147 void Toolbar::Pimpl::layoutSelectedCB(int sel, void * arg, Combox *)
148 {
149         Toolbar::Pimpl * tb = reinterpret_cast<Toolbar::Pimpl *>(arg);
150
151         tb->layoutSelected(sel);
152 }
153
154
155 void Toolbar::Pimpl::layoutSelected(int sel)
156 {
157         string const tmp = tostr(sel);
158         owner->getLyXFunc()->Dispatch(LFUN_LAYOUTNO, tmp);
159 }
160  
161
162 void Toolbar::Pimpl::activate()
163 {
164         ToolbarList::const_iterator p = toollist.begin();
165         ToolbarList::const_iterator end = toollist.end();
166         for (; p != end; ++p) {
167                 if (p->icon) {
168                         fl_activate_object(p->icon);
169                 }
170         }
171 }
172
173
174 void Toolbar::Pimpl::deactivate()
175 {
176         ToolbarList::const_iterator p = toollist.begin();
177         ToolbarList::const_iterator end = toollist.end();
178         for (; p != end; ++p) {
179                 if (p->icon) {
180                         fl_deactivate_object(p->icon);
181                 }
182         }
183 }
184
185 void Toolbar::Pimpl::update()
186 {
187         ToolbarList::const_iterator p = toollist.begin();
188         ToolbarList::const_iterator end = toollist.end();
189         for (; p != end; ++p) {
190                 if (p->icon) {
191                         int status = owner->getLyXFunc()->getStatus(p->action);
192                         if (status & LyXFunc::ToggleOn) {
193                                 // I'd like to use a different color
194                                 // here, but then the problem is to
195                                 // know how to use transparency with
196                                 // Xpm library. It seems pretty
197                                 // complicated to me (JMarc)
198                                 fl_set_object_color(p->icon, FL_LEFT_BCOL, FL_BLUE);
199                                 fl_set_object_boxtype(p->icon, FL_DOWN_BOX);
200                         } else {
201                                 fl_set_object_color(p->icon, FL_MCOL, FL_BLUE);
202                                 fl_set_object_boxtype(p->icon, FL_UP_BOX);
203                         }
204
205                         if (status & LyXFunc::Disabled) {
206                                 // Is there a way here to specify a
207                                 // mask in order to show that the
208                                 // button is disabled? (JMarc)
209                                 fl_deactivate_object(p->icon);
210                         }
211                         else
212                                 fl_activate_object(p->icon);
213                 }
214         }
215 }
216
217
218 void Toolbar::Pimpl::setLayout(int layout) {
219         if (combox)
220                 combox->select(layout+1);
221 }
222
223
224 void Toolbar::Pimpl::updateLayoutList(bool force)
225 {
226         // Update the layout display
227         if (!combox) return;
228
229         // If textclass is different, we need to update the list
230         if (combox->empty() || force) {
231                 combox->clear();
232                 LyXTextClass const & tc =
233                         textclasslist.TextClass(owner->buffer()->
234                                                 params.textclass);
235                 LyXTextClass::const_iterator end = tc.end();
236                 for (LyXTextClass::const_iterator cit = tc.begin();
237                      cit != end; ++cit) {
238                         if ((*cit).obsoleted_by().empty())
239                                 combox->addline(_((*cit).name()));
240                         else
241                                 combox->addline("@N" + _((*cit).name()));
242                 }
243         }
244         // we need to do this.
245         combox->Redraw();
246 }
247
248
249 void Toolbar::Pimpl::clearLayoutList()
250 {
251         if (combox) {
252                 combox->clear();
253                 combox->Redraw();
254         }
255 }
256
257
258 void Toolbar::Pimpl::openLayoutList()
259 {
260         if (combox)
261                 combox->Show();
262 }
263
264
265 static
266 void ToolbarCB(FL_OBJECT * ob, long ac)
267 {
268         LyXView * owner = static_cast<LyXView *>(ob->u_vdata);
269         
270         string res = owner->getLyXFunc()->Dispatch(int(ac));
271         if (!res.empty())
272                 lyxerr[Debug::GUI] << "ToolbarCB: Function returned: " 
273                                    << res << endl;
274 }
275
276
277 extern "C" void C_Toolbar_ToolbarCB(FL_OBJECT * ob, long data)
278 {
279         ToolbarCB(ob, data);
280 }
281
282
283 #if 0
284 // What are we supposed to do with that??
285 int Toolbar::get_toolbar_func(string const & func)
286 {
287         int action = lyxaction.LookupFunc(func);
288         if (action == -1) {
289                 if (func == "separator"){
290                         action = TOOL_SEPARATOR;
291                 } else if (func == "layouts"){
292                         action = TOOL_LAYOUTS;
293                 } else action = 0;
294         }
295         return action;
296 }
297 #endif
298
299
300 static
301 void setPixmap(FL_OBJECT * obj, int action, int buttonwidth, int height) {
302         string name, arg, xpm_name;
303         kb_action act;
304
305         if (lyxaction.isPseudoAction(action)) {
306                 act = lyxaction.retrieveActionArg(action, arg);
307                 name = lyxaction.getActionName(act);
308                 xpm_name = subst(name + ' ' + arg, ' ','_');
309         } else {
310                 act = (kb_action)action;
311                 name = lyxaction.getActionName(action);
312                 xpm_name = name;
313         }
314
315         string fullname = LibFileSearch("images", xpm_name, "xpm");
316
317         if (!fullname.empty()) {
318                 lyxerr[Debug::GUI] << "Full icon name is `" 
319                                        << fullname << "'" << endl;
320                 fl_set_pixmapbutton_file(obj, fullname.c_str());
321                 return;
322         }
323
324         if (act == LFUN_INSERT_MATH && !arg.empty()) {
325                 char const ** pixmap = get_pixmap_from_symbol(arg.c_str(),
326                                                         buttonwidth,
327                                                         height);
328                 if (pixmap) {
329                         lyxerr[Debug::GUI] << "Using mathed-provided icon"
330                                            << endl;
331                         fl_set_pixmapbutton_data(obj,
332                                                  const_cast<char **>(pixmap));
333                         return;
334                 }
335         }
336         
337         lyxerr << "Unable to find icon `" << xpm_name << "'" << endl;
338         fullname = LibFileSearch("images", "unknown", "xpm");
339         if (!fullname.empty()) {
340                 lyxerr[Debug::GUI] << "Using default `unknown' icon" 
341                                        << endl;
342                 fl_set_pixmapbutton_file(obj, fullname.c_str());
343         }
344 }
345
346 void Toolbar::Pimpl::set(bool doingmain)
347 {
348         // we shouldn't set if we have not cleaned
349         if (!cleaned) return;
350         
351         FL_OBJECT * obj;
352         
353         if (!doingmain) {
354                 fl_freeze_form(owner->getForm());
355                 fl_addto_form(owner->getForm());
356         }
357
358 #if FL_REVISION < 89
359         // add the time if it don't exist
360         if (bubble_timer == 0)
361                 bubble_timer = fl_add_timer(FL_HIDDEN_TIMER,
362                                             xpos, ypos, 0, 0, "Timer");
363 #endif
364         
365         ToolbarList::iterator item = toollist.begin();
366         ToolbarList::iterator end = toollist.end();
367         for (; item != end; ++item) {
368                 switch (item->action){
369                 case ToolbarDefaults::SEPARATOR:
370                         xpos += sepspace;
371                         break;
372                 case ToolbarDefaults::NEWLINE:
373                         // Not supported yet.
374                         break;
375                 case ToolbarDefaults::LAYOUTS:
376                         xpos += standardspacing;
377                         if (!combox)
378                                 combox = new Combox(FL_COMBOX_DROPLIST);
379                         combox->add(xpos, ypos, 135, height, 400);
380                         combox->setcallback(layoutSelectedCB, this);
381                         combox->resize(FL_RESIZE_ALL);
382                         combox->gravity(NorthWestGravity, NorthWestGravity);
383                         xpos += 135;
384                         break;
385                 default:
386                         xpos += standardspacing;
387                         item->icon = obj = 
388                                 fl_add_pixmapbutton(FL_NORMAL_BUTTON,
389                                                     xpos, ypos,
390                                                     buttonwidth,
391                                                     height, "");
392                         fl_set_object_resize(obj, FL_RESIZE_ALL);
393                         fl_set_object_gravity(obj,
394                                               NorthWestGravity,
395                                               NorthWestGravity);
396                         fl_set_object_callback(obj, C_Toolbar_ToolbarCB,
397                                                static_cast<long>(item->action));
398                         // Remove the blue feedback rectangle
399                         fl_set_pixmapbutton_focus_outline(obj, 0);
400
401                         // Set the tooltip
402 #if FL_REVISION >= 89
403                         string help = _(lyxaction.helpText(item->action));
404                         fl_set_object_helper(obj, help.c_str());        
405 #else
406                         fl_set_object_posthandler(obj, C_Toolbar_BubblePost);
407                         obj->u_cdata = reinterpret_cast<char *>(bubble_timer);
408 #endif
409
410                         // The view that this object belongs to.
411                         obj->u_vdata = owner;
412
413                         setPixmap(obj, item->action, buttonwidth, height);
414                         // we must remember to update the positions
415                         xpos += buttonwidth;
416                         // ypos is constant
417                         /* Here will come a check to see if the new
418                          * pos is within the bounds of the main frame,
419                          * and perhaps wrap the toolbar if not.
420                          */
421                         break;
422                 }
423         }
424
425         if (!doingmain) {
426                 fl_end_form();
427                 fl_unfreeze_form(owner->getForm());
428                 // Should be safe to do this here.
429                 owner->updateLayoutChoice();
430         }
431
432         // set the state of the icons
433         //update();
434
435         cleaned = false;
436 }
437
438
439 void Toolbar::Pimpl::add(int action, bool doclean)
440 {
441         if (doclean && !cleaned) clean();
442
443         // this is what we do if we want to add to an existing
444         // toolbar.
445         if (!doclean && owner) {
446                 // first "hide" the toolbar buttons. This is not a real hide
447                 // actually it deletes and frees the button altogether.
448                 lyxerr << "Toolbar::add: \"hide\" the toolbar buttons." 
449                        << endl;
450
451                 lightReset();
452                 
453                 fl_freeze_form(owner->getForm());
454
455                 ToolbarList::iterator p = toollist.begin();
456                 ToolbarList::iterator end = toollist.end();
457                 for (; p != end; ++p) {
458                         p->clean();
459                 }
460
461                 if (combox) {
462                         delete combox;
463                         combox = 0;
464                 }
465                 fl_unfreeze_form(owner->getForm());
466                 cleaned = true; // this is not completely true, but OK anyway
467         }
468         
469         // there exist some special actions not part of
470         // kb_action: SEPARATOR, LAYOUTS
471
472         toolbarItem newItem;
473         newItem.action = action;
474         toollist.push_back(newItem);
475 }
476
477
478 void Toolbar::Pimpl::clean()
479 {
480         //reset(); // I do not understand what this reset() is, anyway
481
482         //now delete all the objects..
483         if (owner)
484                 fl_freeze_form(owner->getForm());
485
486         // G++ vector does not have clear defined
487         //toollist.clear();
488         toollist.erase(toollist.begin(), toollist.end());
489
490         lyxerr[Debug::GUI] << "Combox: " << combox << endl;
491         if (combox) {
492                 delete combox;
493                 combox = 0;
494         }
495
496         if (owner)
497                 fl_unfreeze_form(owner->getForm());
498         lyxerr[Debug::GUI] << "toolbar cleaned" << endl;
499         cleaned = true;
500 }
501
502
503 void Toolbar::Pimpl::push(int nth)
504 {
505         lyxerr[Debug::GUI] << "Toolbar::push: trying to trigger no `"
506                                << nth << '\'' << endl;
507         
508         if (nth <= 0 || nth >= int(toollist.size())) {
509                 // item nth not found...
510                 return;
511         }
512
513         fl_trigger_object(toollist[nth - 1].icon);
514 }
515
516
517 void Toolbar::Pimpl::reset() 
518 {
519         //toollist = 0; // what is this supposed to do?
520         cleaned = false;
521         lightReset();
522 }
523
524 void Toolbar::Pimpl::lightReset() {
525         xpos = sxpos - standardspacing;
526         ypos = sypos;
527 }