2 * \file XFormsToolbar.C
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
7 * \author Jean-Marc Lasgouttes
9 * Full author contact details are available in file CREDITS.
12 // Added pseudo-action handling, asierra 180296
16 #include "XFormsToolbar.h"
20 #include "xforms_helpers.h"
23 #include "bufferparams.h"
25 #include "funcrequest.h"
26 #include "FuncStatus.h"
30 #include "support/lstrings.h"
32 #include "lyx_forms.h"
36 #include <boost/bind.hpp>
38 using lyx::frontend::Box;
39 using lyx::frontend::BoxList;
41 using lyx::support::compare_ascii_no_case;
49 const int standardspacing = 2; // the usual space between items
50 const int sepspace = 6; // extra space
51 const int buttonwidth = 30; // the standard button width
52 const int height = 30; // the height of all items in the toolbar
56 XFormsView::Position getPosition(ToolbarBackend::Flags const & flags)
58 if (flags & ToolbarBackend::TOP)
59 return XFormsView::Top;
60 if (flags & ToolbarBackend::BOTTOM)
61 return XFormsView::Bottom;
62 if (flags & ToolbarBackend::LEFT)
63 return XFormsView::Left;
64 if (flags & ToolbarBackend::RIGHT)
65 return XFormsView::Right;
66 return XFormsView::Top;
70 LyXTextClass const & getTextClass(LyXView const & lv)
72 return lv.buffer()->params().getLyXTextClass();
78 XFormsToolbar::toolbarItem::toolbarItem()
88 XFormsToolbar::toolbarItem::~toolbarItem()
94 void XFormsToolbar::toolbarItem::kill_icon()
97 // XForms will take care of cleaning up the other pixmap
98 XFreePixmap(fl_get_display(), unused_pixmap);
109 XFormsToolbar::toolbarItem &
110 XFormsToolbar::toolbarItem::operator=(toolbarItem const & ti)
115 // If we already have an icon, release it.
116 // But we don't copy the icon from ti
125 void XFormsToolbar::toolbarItem::generateInactivePixmaps()
127 if (!icon || icon->objclass != FL_PIXMAPBUTTON)
130 // Store the existing (active) pixmap.
131 fl_get_pixmap_pixmap(icon, &active_pixmap, &active_mask);
133 if (active_pixmap == 0 || active_mask == 0)
136 // Create an XpmImage of this (active) pixmap. It's this that
137 // we're going to manipulate.
139 XpmCreateXpmImageFromPixmap(fl_get_display(),
145 // Produce a darker shade of the button background as the
146 // inactive color. Note the 'hsv.v - 0.2'.
147 unsigned int r, g, b;
148 fl_getmcolor(FL_PIXMAPBUTTON_COL1, &r, &g, &b);
149 HSVColor hsv(RGBColor(r, g, b));
150 hsv.v = std::max(0.0, hsv.v - 0.2);
151 string const inactive_color = X11hexname(RGBColor(hsv));
153 // Set all color table entries in xpm_image that aren't
154 // "none" to inactive_color
155 for (uint i = 0; i != xpm_image.ncolors; ++i) {
156 XpmColor & ct = xpm_image.colorTable[i];
158 compare_ascii_no_case("none", ct.c_color) == 0)
161 // Note that this is a c-struct, so use c memory funcs.
164 ct.c_color = (char *)malloc(inactive_color.size() + 1);
165 strcpy(ct.c_color, inactive_color.c_str());
168 // Generate pixmaps of this modified xpm_image.
169 Screen * screen = ScreenOfDisplay(fl_get_display(), fl_screen);
171 XpmCreatePixmapFromXpmImage(fl_get_display(),
172 XRootWindowOfScreen(screen),
178 XpmFreeXpmImage(&xpm_image);
182 Toolbars::ToolbarPtr make_toolbar(ToolbarBackend::Toolbar const & tbb,
185 return Toolbars::ToolbarPtr(new XFormsToolbar(tbb, owner));
189 XFormsToolbar::XFormsToolbar(ToolbarBackend::Toolbar const & tbb,
193 owner_(static_cast<XFormsView &>(o)),
194 tooltip_(new Tooltips)
196 position_ = getPosition(tbb.flags);
197 BoxList & boxlist = owner_.getBox(position_).children();
198 toolbar_ = &boxlist.push_back(Box(0,0));
200 // If the toolbar is horizontal, then it contains three
201 // vertically-aligned Boxes,the center one of which is to
202 // contain the buttons, aligned horizontally.
203 // The other two provide some visual padding.
205 // If it is vertical, then this is swapped around.
207 Box::Orientation const toolbar_orientation =
208 (position_ == XFormsView::Left ||
209 position_ == XFormsView::Right)
210 ? Box::Vertical : Box::Horizontal;
212 Box::Orientation const padding_orientation =
213 (toolbar_orientation == Box::Vertical)
214 ? Box::Horizontal : Box::Vertical;
216 toolbar_->set(padding_orientation);
218 // A bit of a hack, but prevents 'M-x' causing the addition of
221 (tbb.name == "minibuffer") ?
222 0 : 2 + abs(fl_get_border_width());
224 toolbar_->children().push_back(Box(padding, padding));
226 Box & toolbar_center = toolbar_->children().push_back(Box(0,0));
227 toolbar_center.set(toolbar_orientation);
228 toolbar_buttons_ = &toolbar_center.children();
230 toolbar_->children().push_back(Box(padding, padding));
232 using lyx::frontend::WidgetMap;
233 owner_.metricsUpdated.connect(boost::bind(&WidgetMap::updateMetrics,
236 // Populate the toolbar.
237 ToolbarBackend::item_iterator it = tbb.items.begin();
238 ToolbarBackend::item_iterator end = tbb.items.end();
239 for (; it != end; ++it)
240 add(it->first, it->second);
245 XFormsToolbar::~XFormsToolbar()
247 fl_freeze_form(owner_.getForm());
249 // G++ vector does not have clear defined
251 toollist_.erase(toollist_.begin(), toollist_.end());
253 fl_unfreeze_form(owner_.getForm());
261 void C_ToolbarCB(FL_OBJECT * ob, long ac)
263 if (!ob || !ob->u_vdata)
266 XFormsToolbar * ptr = static_cast<XFormsToolbar *>(ob->u_vdata);
267 XFormsView & owner = ptr->owner_;
268 owner.getLyXFunc().dispatch(ptr->funcs[ac], true);
276 void XFormsToolbar::hide(bool update_metrics)
278 toolbar_->set(Box::Invisible);
280 owner_.updateMetrics();
284 void XFormsToolbar::show(bool update_metrics)
286 toolbar_->set(Box::Visible);
289 owner_.updateMetrics();
293 void XFormsToolbar::add(FuncRequest const & func, string const & tooltip)
298 switch (func.action) {
299 case ToolbarBackend::SEPARATOR:
300 toolbar_buttons_->push_back(Box(sepspace, sepspace));
303 case ToolbarBackend::MINIBUFFER:
305 // XForms uses the same widget to display the buffer messages
306 // and to input commands.
309 case ToolbarBackend::LAYOUTS:
310 layout_.reset(new XLayoutBox(owner_, *this));
316 toolbar_buttons_->push_back(Box(standardspacing,
320 fl_add_pixmapbutton(FL_NORMAL_BUTTON,
323 widgets_.add(obj, *toolbar_buttons_, buttonwidth, height);
325 fl_set_object_resize(obj, FL_RESIZE_ALL);
328 if (position_ == XFormsView::Top ||
329 position_ == XFormsView::Left)
330 gravity = NorthWestGravity;
331 else if (position_ == XFormsView::Right)
332 gravity = NorthEastGravity;
333 else if (position_ == XFormsView::Bottom)
334 gravity = SouthWestGravity;
336 fl_set_object_gravity(obj, gravity, gravity);
338 Funcs::iterator fit = funcs.insert(funcs.end(), func);
339 int const index = distance(funcs.begin(), fit);
340 fl_set_object_callback(obj, C_ToolbarCB, index);
341 // Remove the blue feedback rectangle
342 fl_set_pixmapbutton_focus_outline(obj, 0);
344 tooltip_->init(obj, tooltip);
346 // The view that this object belongs to.
349 string const xpm = toolbarbackend.getIcon(func);
350 fl_set_pixmapbutton_file(obj, xpm.c_str());
355 toollist_.push_back(item);
359 void XFormsToolbar::update()
361 ToolbarList::iterator p = toollist_.begin();
362 ToolbarList::iterator end = toollist_.end();
363 for (; p != end; ++p) {
367 FuncStatus const status =
368 owner_.getLyXFunc().getStatus(p->func);
370 if (status.onoff(true)) {
371 // I'd like to use a different color
372 // here, but then the problem is to
373 // know how to use transparency with
374 // Xpm library. It seems pretty
375 // complicated to me (JMarc)
376 fl_set_object_color(p->icon, FL_LEFT_BCOL, FL_BLUE);
377 fl_set_object_boxtype(p->icon, FL_DOWN_BOX);
379 fl_set_object_color(p->icon, FL_MCOL, FL_BLUE);
380 fl_set_object_boxtype(p->icon, FL_UP_BOX);
383 // This must go here rather than in XFormsToolbar::add, else
384 // LyX aborts with a BadPixmap error.
385 if (!p->active_pixmap)
386 p->generateInactivePixmaps();
388 if (status.enabled()) {
389 fl_activate_object(p->icon);
390 fl_set_pixmap_pixmap(p->icon,
393 p->unused_pixmap = p->inactive_pixmap;
395 fl_deactivate_object(p->icon);
396 fl_set_pixmap_pixmap(p->icon,
399 p->unused_pixmap = p->active_pixmap;
403 bool const enable = owner_.getLyXFunc().
404 getStatus(FuncRequest(LFUN_LAYOUT)).enabled();
407 layout_->setEnabled(enable);
414 void C_LayoutBoxSelectedCB(FL_OBJECT * ob, long)
416 if (!ob || !ob->u_vdata)
418 XLayoutBox * ptr = static_cast<XLayoutBox *>(ob->u_vdata);
425 XLayoutBox::XLayoutBox(LyXView & owner, XFormsToolbar & toolbar)
428 toolbar.toolbar_buttons_->push_back(Box(standardspacing, 0));
430 combox_ = fl_add_combox(FL_DROPLIST_COMBOX,
431 0, 0, 135, height, "");
433 toolbar.widgets_.add(combox_, *toolbar.toolbar_buttons_, 135, height);
435 fl_set_combox_browser_height(combox_, 400);
436 fl_set_object_boxtype(combox_, FL_DOWN_BOX);
437 fl_set_object_color(combox_, FL_MCOL, FL_MCOL);
438 fl_set_object_gravity(combox_, FL_NorthWest, FL_NorthWest);
439 fl_set_object_resize(combox_, FL_RESIZE_ALL);
441 combox_->u_vdata = this;
442 fl_set_object_callback(combox_, C_LayoutBoxSelectedCB, 0);
446 void XLayoutBox::set(string const & layout)
448 LyXTextClass const & tc = getTextClass(owner_);
450 string const layoutname = _(tc[layout]->name());
452 int const nnames = fl_get_combox_maxitems(combox_);
453 for (int i = 1; i <= nnames; ++i) {
454 string const name = fl_get_combox_line(combox_, i);
455 if (name == layoutname) {
456 fl_set_combox(combox_, i);
463 void XLayoutBox::update()
465 LyXTextClass const & tc = getTextClass(owner_);
467 fl_clear_combox(combox_);
469 LyXTextClass::const_iterator it = tc.begin();
470 LyXTextClass::const_iterator const end = tc.end();
471 for (; it != end; ++it) {
472 // ignore obsolete entries
473 if ((*it)->obsoleted_by().empty()) {
474 string const & name = _((*it)->name());
475 fl_addto_combox(combox_, name.c_str());
479 // we need to do this.
480 fl_redraw_object(combox_);
484 void XLayoutBox::clear()
486 fl_clear_combox(combox_);
487 fl_redraw_object(combox_);
491 void XLayoutBox::open()
493 fl_show_combox_browser(combox_);
497 void XLayoutBox::setEnabled(bool enable)
499 ::setEnabled(combox_, enable);
503 void XLayoutBox::selected()
505 string const layoutguiname = getString(combox_);
507 LyXTextClass const & tc = getTextClass(owner_);
509 LyXTextClass::const_iterator it = tc.begin();
510 LyXTextClass::const_iterator const end = tc.end();
511 for (; it != end; ++it) {
512 string const & name = (*it)->name();
513 if (_(name) == layoutguiname) {
515 .dispatch(FuncRequest(LFUN_LAYOUT, name),
520 lyxerr << "ERROR (XLayoutBox::selected): layout not found!" << endl;