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>
41 using boost::shared_ptr;
50 using support::compare_ascii_no_case;
55 const int standardspacing = 2; // the usual space between items
56 const int sepspace = 6; // extra space
57 const int buttonwidth = 30; // the standard button width
58 const int height = 30; // the height of all items in the toolbar
62 XFormsView::Position getPosition(ToolbarBackend::Flags const & flags)
64 if (flags & ToolbarBackend::TOP)
65 return XFormsView::Top;
66 if (flags & ToolbarBackend::BOTTOM)
67 return XFormsView::Bottom;
68 if (flags & ToolbarBackend::LEFT)
69 return XFormsView::Left;
70 if (flags & ToolbarBackend::RIGHT)
71 return XFormsView::Right;
72 return XFormsView::Top;
76 LyXTextClass const & getTextClass(LyXView const & lv)
78 return lv.buffer()->params().getLyXTextClass();
84 XFormsToolbar::toolbarItem::toolbarItem()
93 XFormsToolbar::toolbarItem::~toolbarItem()
99 void XFormsToolbar::toolbarItem::kill_icon()
102 // XForms will take care of cleaning up the other pixmap
103 XFreePixmap(fl_get_display(), unused_pixmap);
113 XFormsToolbar::toolbarItem &
114 XFormsToolbar::toolbarItem::operator=(toolbarItem const & ti)
119 // If we already have an icon, release it.
120 // But we don't copy the icon from ti
129 void XFormsToolbar::toolbarItem::generateInactivePixmaps()
131 if (!icon || icon->objclass != FL_PIXMAPBUTTON)
134 // Store the existing (active) pixmap.
135 fl_get_pixmap_pixmap(icon, &active_pixmap, &mask);
137 if (active_pixmap == 0 || mask == 0)
140 // Ascertain the width and height of the pixmap.
141 Display * display = fl_get_display();
144 unsigned int uidummy;
148 XGetGeometry(display, active_pixmap, &win, &idummy, &idummy,
149 &width, &height, &uidummy, &uidummy);
151 // Produce a darker shade of the button background as the
152 // inactive color. Note the 'hsv.v - 0.2'.
153 unsigned int r, g, b;
154 fl_getmcolor(FL_PIXMAPBUTTON_COL1, &r, &g, &b);
155 HSVColor hsv(RGBColor(r, g, b));
156 hsv.v = std::max(0.0, hsv.v - 0.2);
157 string const inactive_color = X11hexname(RGBColor(hsv));
159 // Generate an XPM dataset for a uniformly-colored pixmap with
160 // the same dimensions as active_pixmap.
162 // The data set has the form:
163 // "<width> <height> <ncolors> <chars per pixel>",
164 // "o c <inactive_color>",
165 // "oooooooooooooooo", // <width> 'o' chars.
166 // repeated <height> times.
167 std::ostringstream line1_ss;
168 line1_ss << width << ' ' << height << " 1 1";
169 string const line1 = line1_ss.str();
170 string const line2 = "o c " + inactive_color;
171 string const data(width, 'o');
172 vector<char *> inactive_data(height + 2,
173 const_cast<char *>(data.c_str()));
174 inactive_data[0] = const_cast<char *>(line1.c_str());
175 inactive_data[1] = const_cast<char *>(line2.c_str());
177 char ** raw_inactive_data = &*inactive_data.begin();
179 // Generate a pixmap of this data set.
180 // Together with 'mask' above, this is sufficient to display
181 // an inactive version of our active_pixmap.
182 Screen * screen = ScreenOfDisplay(display, fl_screen);
184 XpmCreatePixmapFromData(display, XRootWindowOfScreen(screen),
185 raw_inactive_data, &inactive_pixmap, 0, 0);
188 } // namespace frontend
192 Toolbars::ToolbarPtr make_toolbar(ToolbarBackend::Toolbar const & tbb,
195 using lyx::frontend::XFormsToolbar;
196 return Toolbars::ToolbarPtr(new XFormsToolbar(tbb, owner));
203 XFormsToolbar::XFormsToolbar(ToolbarBackend::Toolbar const & tbb,
205 : toolbar_buttons_(0),
206 owner_(static_cast<XFormsView &>(o)),
207 tooltip_(new Tooltips)
209 position_ = getPosition(tbb.flags);
210 BoxList & boxlist = owner_.getBox(position_)->children();
211 toolbar_ = boxlist.push_back(Box(0,0));
213 // If the toolbar is horizontal, then it contains three
214 // vertically-aligned Boxes,the center one of which is to
215 // contain the buttons, aligned horizontally.
216 // The other two provide some visual padding.
218 // If it is vertical, then this is swapped around.
220 Box::Orientation const toolbar_orientation =
221 (position_ == XFormsView::Left ||
222 position_ == XFormsView::Right)
223 ? Box::Vertical : Box::Horizontal;
225 Box::Orientation const padding_orientation =
226 (toolbar_orientation == Box::Vertical)
227 ? Box::Horizontal : Box::Vertical;
229 toolbar_->set(padding_orientation);
231 // A bit of a hack, but prevents 'M-x' causing the addition of
234 (tbb.name == "minibuffer") ?
235 0 : 2 + abs(fl_get_border_width());
237 toolbar_->children().push_back(Box(padding, padding));
239 shared_ptr<Box> toolbar_center = toolbar_->children().push_back(Box(0,0));
240 toolbar_center->set(toolbar_orientation);
241 toolbar_buttons_ = &toolbar_center->children();
243 toolbar_->children().push_back(Box(padding, padding));
245 owner_.metricsUpdated.connect(boost::bind(&WidgetMap::updateMetrics,
248 // Populate the toolbar.
249 ToolbarBackend::item_iterator it = tbb.items.begin();
250 ToolbarBackend::item_iterator end = tbb.items.end();
251 for (; it != end; ++it)
252 add(it->first, it->second);
256 XFormsToolbar::~XFormsToolbar()
258 fl_freeze_form(owner_.getForm());
260 // G++ vector does not have clear defined
262 toollist_.erase(toollist_.begin(), toollist_.end());
264 fl_unfreeze_form(owner_.getForm());
272 void C_ToolbarCB(FL_OBJECT * ob, long ac)
274 if (!ob || !ob->u_vdata)
277 XFormsToolbar * ptr = static_cast<XFormsToolbar *>(ob->u_vdata);
278 XFormsView & owner = ptr->owner_;
279 owner.getLyXFunc().dispatch(ptr->funcs[ac]);
287 void XFormsToolbar::hide(bool update_metrics)
289 if (!toolbar_->visible())
292 toolbar_->set(Box::Invisible);
294 owner_.updateMetrics();
298 void XFormsToolbar::show(bool update_metrics)
300 if (toolbar_->visible())
303 toolbar_->set(Box::Visible);
306 owner_.updateMetrics();
310 void XFormsToolbar::add(FuncRequest const & func, string const & tooltip)
315 switch (func.action) {
316 case ToolbarBackend::SEPARATOR:
317 toolbar_buttons_->push_back(Box(sepspace, sepspace));
320 case ToolbarBackend::MINIBUFFER:
322 // XForms uses the same widget to display the buffer messages
323 // and to input commands.
326 case ToolbarBackend::LAYOUTS:
327 layout_.reset(new XLayoutBox(owner_, *this));
333 toolbar_buttons_->push_back(Box(standardspacing,
337 fl_add_pixmapbutton(FL_NORMAL_BUTTON,
340 widgets_.add(obj, *toolbar_buttons_, buttonwidth, height);
342 fl_set_object_resize(obj, FL_RESIZE_ALL);
345 if (position_ == XFormsView::Top ||
346 position_ == XFormsView::Left)
347 gravity = NorthWestGravity;
348 else if (position_ == XFormsView::Right)
349 gravity = NorthEastGravity;
350 else if (position_ == XFormsView::Bottom)
351 gravity = SouthWestGravity;
353 fl_set_object_gravity(obj, gravity, gravity);
355 Funcs::iterator fit = funcs.insert(funcs.end(), func);
356 int const index = distance(funcs.begin(), fit);
357 fl_set_object_callback(obj, C_ToolbarCB, index);
358 // Remove the blue feedback rectangle
359 fl_set_pixmapbutton_focus_outline(obj, 0);
361 tooltip_->init(obj, tooltip);
363 // The view that this object belongs to.
366 string const xpm = toolbarbackend.getIcon(func);
367 fl_set_pixmapbutton_file(obj, xpm.c_str());
372 toollist_.push_back(item);
376 void XFormsToolbar::update()
378 ToolbarList::iterator p = toollist_.begin();
379 ToolbarList::iterator end = toollist_.end();
380 for (; p != end; ++p) {
384 FuncStatus const status =
385 owner_.getLyXFunc().getStatus(p->func);
387 if (status.onoff(true)) {
388 // I'd like to use a different color
389 // here, but then the problem is to
390 // know how to use transparency with
391 // Xpm library. It seems pretty
392 // complicated to me (JMarc)
393 fl_set_object_color(p->icon, FL_LEFT_BCOL, FL_BLUE);
394 fl_set_object_boxtype(p->icon, FL_DOWN_BOX);
396 fl_set_object_color(p->icon, FL_MCOL, FL_BLUE);
397 fl_set_object_boxtype(p->icon, FL_UP_BOX);
400 // This must go here rather than in XFormsToolbar::add, else
401 // LyX aborts with a BadPixmap error.
402 if (!p->active_pixmap)
403 p->generateInactivePixmaps();
405 if (status.enabled()) {
406 fl_activate_object(p->icon);
407 fl_set_pixmap_pixmap(p->icon,
410 p->unused_pixmap = p->inactive_pixmap;
412 fl_deactivate_object(p->icon);
413 fl_set_pixmap_pixmap(p->icon,
416 p->unused_pixmap = p->active_pixmap;
420 bool const enable = owner_.getLyXFunc().
421 getStatus(FuncRequest(LFUN_LAYOUT)).enabled();
424 layout_->setEnabled(enable);
431 void C_LayoutBoxSelectedCB(FL_OBJECT * ob, long)
433 if (!ob || !ob->u_vdata)
435 XLayoutBox * ptr = static_cast<XLayoutBox *>(ob->u_vdata);
442 XLayoutBox::XLayoutBox(LyXView & owner, XFormsToolbar & toolbar)
445 toolbar.toolbar_buttons_->push_back(Box(standardspacing, 0));
447 combox_ = fl_add_combox(FL_DROPLIST_COMBOX,
448 0, 0, 135, height, "");
450 toolbar.widgets_.add(combox_, *toolbar.toolbar_buttons_, 135, height);
452 fl_set_combox_browser_height(combox_, 400);
453 fl_set_object_boxtype(combox_, FL_DOWN_BOX);
454 fl_set_object_color(combox_, FL_MCOL, FL_MCOL);
455 fl_set_object_gravity(combox_, FL_NorthWest, FL_NorthWest);
456 fl_set_object_resize(combox_, FL_RESIZE_ALL);
458 combox_->u_vdata = this;
459 fl_set_object_callback(combox_, C_LayoutBoxSelectedCB, 0);
463 void XLayoutBox::set(string const & layout)
465 LyXTextClass const & tc = getTextClass(owner_);
467 string const layoutname = _(tc[layout]->name());
469 int const nnames = fl_get_combox_maxitems(combox_);
470 for (int i = 1; i <= nnames; ++i) {
471 string const name = fl_get_combox_line(combox_, i);
472 if (name == layoutname) {
473 fl_set_combox(combox_, i);
480 void XLayoutBox::update()
482 LyXTextClass const & tc = getTextClass(owner_);
484 fl_clear_combox(combox_);
486 LyXTextClass::const_iterator it = tc.begin();
487 LyXTextClass::const_iterator const end = tc.end();
488 for (; it != end; ++it) {
489 // ignore obsolete entries
490 if ((*it)->obsoleted_by().empty()) {
491 string const & name = _((*it)->name());
492 fl_addto_combox(combox_, name.c_str());
496 // we need to do this.
497 fl_redraw_object(combox_);
501 void XLayoutBox::clear()
503 fl_clear_combox(combox_);
504 fl_redraw_object(combox_);
508 void XLayoutBox::open()
510 fl_show_combox_browser(combox_);
514 void XLayoutBox::setEnabled(bool enable)
516 lyx::frontend::setEnabled(combox_, enable);
520 void XLayoutBox::selected()
522 string const layoutguiname = getString(combox_);
524 layoutSelected(owner_, layoutguiname);
527 } // namespace frontend