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