/** * @file * Pencil aux toolbar */ /* Authors: * MenTaLguY * Lauris Kaplinski * bulia byak * Frank Felfe * John Cliff * David Turner * Josh Andler * Jon A. Cruz * Maximilian Albert * Tavmjong Bah * Abhishek Sharma * Kris De Gussem * * Copyright (C) 2004 David Turner * Copyright (C) 2003 MenTaLguY * Copyright (C) 1999-2011 authors * Copyright (C) 2001-2002 Ximian, Inc. * * Released under GNU GPL, read the file 'COPYING' for more information */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "pencil-toolbar.h" #include "desktop.h" #include "selection.h" #include "toolbox.h" #include "ink-action.h" #include "ink-radio-action.h" #include "ink-toggle-action.h" #include "live_effects/lpe-bspline.h" #include "live_effects/lpe-powerstroke.h" #include "live_effects/lpe-simplify.h" #include "live_effects/lpe-spiro.h" #include "live_effects/lpeobject-reference.h" #include "live_effects/lpeobject.h" #include "display/curve.h" #include "object/sp-shape.h" #include "ui/icon-names.h" #include "ui/tools-switch.h" #include "ui/tools/pen-tool.h" #include "ui/uxmanager.h" #include "ui/widget/ink-select-one-action.h" #include "widgets/ege-adjustment-action.h" #include "widgets/spinbutton-events.h" using Inkscape::UI::UXManager; using Inkscape::UI::ToolboxFactory; using Inkscape::UI::PrefPusher; //######################## //## Pen/Pencil ## //######################## static void sp_flatten_spiro_bspline(GtkWidget * /*widget*/, GObject *obj); /* This is used in generic functions below to share large portions of code between pen and pencil tool */ static Glib::ustring const freehand_tool_name(GObject *dataKludge) { SPDesktop *desktop = static_cast(g_object_get_data(dataKludge, "desktop")); return ( tools_isactive(desktop, TOOLS_FREEHAND_PEN) ? "/tools/freehand/pen" : "/tools/freehand/pencil" ); } static void freehand_mode_changed(GObject* tbl, int mode) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setInt(freehand_tool_name(tbl) + "/freehand-mode", mode); if (mode == 1 || mode == 2) { gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "flatten_spiro_bspline") ), true ); } else { gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "flatten_spiro_bspline") ), false ); } if (mode == 2) { gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "flatten_simplify") ), false ); gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "simplify") ), false ); } else { gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "flatten_simplify") ), true ); gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "simplify") ), true ); } } static void use_pencil_pressure(InkToggleAction* itact, GObject *dataKludge) { bool pressure = gtk_toggle_action_get_active( GTK_TOGGLE_ACTION(itact) ); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setBool(freehand_tool_name(dataKludge) + "/pressure", pressure); if (pressure) { gtk_action_set_visible( GTK_ACTION( g_object_get_data(dataKludge, "minpressure") ), true ); gtk_action_set_visible( GTK_ACTION( g_object_get_data(dataKludge, "maxpressure") ), true ); InkSelectOneAction* act = static_cast( g_object_get_data( dataKludge, "shape_action" ) ); act->set_visible (false); } else { gtk_action_set_visible( GTK_ACTION( g_object_get_data(dataKludge, "minpressure") ), false ); gtk_action_set_visible( GTK_ACTION( g_object_get_data(dataKludge, "maxpressure") ), false ); InkSelectOneAction* act = static_cast( g_object_get_data( dataKludge, "shape_action" ) ); act->set_visible (true); } } static void sp_add_freehand_mode_toggle(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil) { /* Freehand mode toggle buttons */ Inkscape::Preferences *prefs = Inkscape::Preferences::get(); guint freehandMode = prefs->getInt(( tool_is_pencil ? "/tools/freehand/pencil/freehand-mode" : "/tools/freehand/pen/freehand-mode" ), 0); GtkIconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); InkSelectOneActionColumns columns; Glib::RefPtr store = Gtk::ListStore::create(columns); Gtk::TreeModel::Row row; row = *(store->append()); row[columns.col_label ] = _("Bezier"); row[columns.col_tooltip ] = _("Create regular Bezier path"); row[columns.col_icon ] = INKSCAPE_ICON("path-mode-bezier"); row[columns.col_sensitive] = true; row = *(store->append()); row[columns.col_label ] = _("Spiro"); row[columns.col_tooltip ] = _("Create Spiro path"); row[columns.col_icon ] = INKSCAPE_ICON("path-mode-spiro"); row[columns.col_sensitive] = true; row = *(store->append()); row[columns.col_label ] = _("BSpline"); row[columns.col_tooltip ] = _("Create BSpline path"); row[columns.col_icon ] = INKSCAPE_ICON("path-mode-bspline"); row[columns.col_sensitive] = true; if (!tool_is_pencil) { row = *(store->append()); row[columns.col_label ] = _("Zigzag"); row[columns.col_tooltip ] = _("Create a sequence of straight line segments"); row[columns.col_icon ] = INKSCAPE_ICON("path-mode-polyline"); row[columns.col_sensitive] = true; row = *(store->append()); row[columns.col_label ] = _("Paraxial"); row[columns.col_tooltip ] = _("Create a sequence of paraxial line segments"); row[columns.col_icon ] = INKSCAPE_ICON("path-mode-polyline-paraxial"); row[columns.col_sensitive] = true; } InkSelectOneAction* act = InkSelectOneAction::create( tool_is_pencil ? "FreehandModeActionPencil" : "FreehandModeActionPen", _("Mode"), // Label _("Mode of new lines drawn by this tool"), // Tooltip "Not Used", // Icon store ); // Tree store act->use_radio( true ); act->use_label( true ); act->set_active( freehandMode ); gtk_action_group_add_action( mainActions, GTK_ACTION( act->gobj() )); // g_object_set_data( dataKludge, "flat_action", act ); act->signal_changed().connect(sigc::bind<0>(sigc::ptr_fun(&freehand_mode_changed), holder)); /* LPE bspline spiro flatten */ InkAction* inky = ink_action_new( tool_is_pencil ? "FlattenSpiroBsplinePencil" : "FlattenSpiroBsplinePen", _("LPE spiro or bspline flatten"), _("LPE spiro or bspline flatten"), INKSCAPE_ICON("flatten"), GTK_ICON_SIZE_SMALL_TOOLBAR ); g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_flatten_spiro_bspline), holder ); gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); g_object_set_data( holder, "flatten_spiro_bspline", inky ); if (freehandMode == 1 || freehandMode == 2) { gtk_action_set_visible( GTK_ACTION( g_object_get_data(holder, "flatten_spiro_bspline") ), true ); } else { gtk_action_set_visible( GTK_ACTION( g_object_get_data(holder, "flatten_spiro_bspline") ), false ); } } static void freehand_change_shape(GObject *dataKludge, int shape) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setInt(freehand_tool_name(dataKludge) + "/shape", shape); } static void freehand_simplify_lpe(InkToggleAction* itact, GObject *dataKludge) { bool simplify = gtk_toggle_action_get_active( GTK_TOGGLE_ACTION(itact) ); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setBool(freehand_tool_name(dataKludge) + "/simplify", simplify); gtk_action_set_visible( GTK_ACTION( g_object_get_data(dataKludge, "flatten_simplify") ), simplify ); if (simplify) { gtk_action_set_visible( GTK_ACTION( g_object_get_data(dataKludge, "flatten_simplify") ), true ); } else { gtk_action_set_visible( GTK_ACTION( g_object_get_data(dataKludge, "flatten_simplify") ), false ); } } static void freehand_add_advanced_shape_options(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil) { /*advanced shape options */ Inkscape::Preferences *prefs = Inkscape::Preferences::get(); std::vector freehand_shape_dropdown_items_list = { const_cast(C_("Freehand shape", "None")), _("Triangle in"), _("Triangle out"), _("Ellipse"), _("From clipboard"), _("Bend from clipboard"), _("Last applied") }; InkSelectOneActionColumns columns; Glib::RefPtr store = Gtk::ListStore::create(columns); Gtk::TreeModel::Row row; for (auto item:freehand_shape_dropdown_items_list) { row = *(store->append()); row[columns.col_label ] = item; row[columns.col_tooltip ] = (""); row[columns.col_icon ] = "NotUsed"; row[columns.col_sensitive] = true; } InkSelectOneAction* act = InkSelectOneAction::create( tool_is_pencil ? "SetPencilShapeAction" : "SetPenShapeAction", // Name _("Shape"), // Label _("Shape of new paths drawn by this tool"), // Tooltip "Not Used", // Icon store ); // Tree store act->use_radio( false ); act->use_icon( false ); act->use_label( true ); act->use_group_label( true ); int shape = prefs->getInt( (tool_is_pencil ? "/tools/freehand/pencil/shape" : "/tools/freehand/pen/shape" ), 0); act->set_active( shape ); gtk_action_group_add_action( mainActions, GTK_ACTION( act->gobj() )); g_object_set_data( holder, "shape_action", act ); bool hide = prefs->getInt("/tools/freehand/pencil/freehand-mode", 0) == 3 || (tool_is_pencil && prefs->getBool("/tools/freehand/pencil/pressure", false)); act->set_visible( !hide ); act->signal_changed().connect(sigc::bind<0>(sigc::ptr_fun(&freehand_change_shape), holder)); } void sp_pen_toolbox_prep(SPDesktop * /*desktop*/, GtkActionGroup* mainActions, GObject* holder) { sp_add_freehand_mode_toggle(mainActions, holder, false); freehand_add_advanced_shape_options(mainActions, holder, false); } static void sp_pencil_tb_defaults(GtkWidget * /*widget*/, GObject *obj) { GtkWidget *tbl = GTK_WIDGET(obj); GtkAdjustment *adj; // fixme: make settable gdouble tolerance = 4; adj = GTK_ADJUSTMENT(g_object_get_data(obj, "tolerance")); gtk_adjustment_set_value(adj, tolerance); #if !GTK_CHECK_VERSION(3,18,0) gtk_adjustment_value_changed(adj); #endif spinbutton_defocus(tbl); } static void sp_flatten_spiro_bspline(GtkWidget * /*widget*/, GObject *obj) { SPDesktop *desktop = static_cast(g_object_get_data(obj, "desktop")); auto selected = desktop->getSelection()->items(); SPLPEItem* lpeitem = NULL; for (auto it(selected.begin()); it != selected.end(); ++it){ lpeitem = dynamic_cast(*it); if (lpeitem && lpeitem->hasPathEffect()){ PathEffectList lpelist = lpeitem->getEffectList(); PathEffectList::iterator i; for (i = lpelist.begin(); i != lpelist.end(); ++i) { LivePathEffectObject *lpeobj = (*i)->lpeobject; if (lpeobj) { Inkscape::LivePathEffect::Effect *lpe = lpeobj->get_lpe(); if (dynamic_cast(lpe) || dynamic_cast(lpe)) { SPShape * shape = dynamic_cast(lpeitem); if(shape){ SPCurve * c = shape->getCurveBeforeLPE(); lpe->doEffect(c); lpeitem->setCurrentPathEffect(*i); if (lpelist.size() > 1){ lpeitem->removeCurrentPathEffect(true); shape->setCurveBeforeLPE(c); } else { lpeitem->removeCurrentPathEffect(false); shape->setCurve(c,0); } break; } } } } } } if (lpeitem) { desktop->getSelection()->remove(lpeitem->getRepr()); desktop->getSelection()->add(lpeitem->getRepr()); sp_lpe_item_update_patheffect(lpeitem, false, false); } } static void sp_simplify_flatten(GtkWidget * /*widget*/, GObject *obj) { SPDesktop *desktop = static_cast(g_object_get_data(obj, "desktop")); auto selected = desktop->getSelection()->items(); SPLPEItem* lpeitem = NULL; for (auto it(selected.begin()); it != selected.end(); ++it){ lpeitem = dynamic_cast(*it); if (lpeitem && lpeitem->hasPathEffect()){ PathEffectList lpelist = lpeitem->getEffectList(); PathEffectList::iterator i; for (i = lpelist.begin(); i != lpelist.end(); ++i) { LivePathEffectObject *lpeobj = (*i)->lpeobject; if (lpeobj) { Inkscape::LivePathEffect::Effect *lpe = lpeobj->get_lpe(); if (dynamic_cast(lpe)) { SPShape * shape = dynamic_cast(lpeitem); if(shape){ SPCurve * c = shape->getCurveBeforeLPE(); lpe->doEffect(c); lpeitem->setCurrentPathEffect(*i); if (lpelist.size() > 1){ lpeitem->removeCurrentPathEffect(true); shape->setCurveBeforeLPE(c); } else { lpeitem->removeCurrentPathEffect(false); shape->setCurve(c,0); } break; } } } } } } if (lpeitem) { desktop->getSelection()->remove(lpeitem->getRepr()); desktop->getSelection()->add(lpeitem->getRepr()); sp_lpe_item_update_patheffect(lpeitem, false, false); } } static void sp_minpressure_value_changed(GtkAdjustment *adj, GObject *tbl) { // quit if run by the attr_changed listener if (g_object_get_data( tbl, "freeze" )) { return; } Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setDouble( "/tools/freehand/pencil/minpressure", gtk_adjustment_get_value(adj)); } static void sp_maxpressure_value_changed(GtkAdjustment *adj, GObject *tbl) { // quit if run by the attr_changed listener if (g_object_get_data( tbl, "freeze" )) { return; } Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setDouble( "/tools/freehand/pencil/maxpressure", gtk_adjustment_get_value(adj)); } static void sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tbl) { // quit if run by the attr_changed listener if (g_object_get_data( tbl, "freeze" )) { return; } // in turn, prevent listener from responding Inkscape::Preferences *prefs = Inkscape::Preferences::get(); g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); prefs->setDouble("/tools/freehand/pencil/tolerance", gtk_adjustment_get_value(adj)); g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); SPDesktop *desktop = static_cast(g_object_get_data(tbl, "desktop")); auto selected = desktop->getSelection()->items(); for (auto it(selected.begin()); it != selected.end(); ++it){ SPLPEItem* lpeitem = dynamic_cast(*it); if (lpeitem && lpeitem->hasPathEffect()){ Inkscape::LivePathEffect::Effect* simplify = lpeitem->getPathEffectOfType(Inkscape::LivePathEffect::SIMPLIFY); if(simplify){ Inkscape::LivePathEffect::LPESimplify *lpe_simplify = dynamic_cast(simplify->getLPEObj()->get_lpe()); if (lpe_simplify) { double tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0); tol = tol/(100.0*(102.0-tol)); std::ostringstream ss; ss << tol; Inkscape::LivePathEffect::Effect* powerstroke = lpeitem->getPathEffectOfType(Inkscape::LivePathEffect::POWERSTROKE); bool simplified = false; if(powerstroke){ Inkscape::LivePathEffect::LPEPowerStroke *lpe_powerstroke = dynamic_cast(powerstroke->getLPEObj()->get_lpe()); if(lpe_powerstroke){ lpe_powerstroke->getRepr()->setAttribute("is_visible", "false"); sp_lpe_item_update_patheffect(lpeitem, false, false); SPShape *sp_shape = dynamic_cast(lpeitem); if (sp_shape) { guint previous_curve_length = sp_shape->getCurve()->get_segment_count(); lpe_simplify->getRepr()->setAttribute("threshold", ss.str()); sp_lpe_item_update_patheffect(lpeitem, false, false); simplified = true; guint curve_length = sp_shape->getCurve()->get_segment_count(); std::vector ts = lpe_powerstroke->offset_points.data(); double factor = (double)curve_length/ (double)previous_curve_length; for (size_t i = 0; i < ts.size(); i++) { ts[i][Geom::X] = ts[i][Geom::X] * factor; } lpe_powerstroke->offset_points.param_setValue(ts); } lpe_powerstroke->getRepr()->setAttribute("is_visible", "true"); sp_lpe_item_update_patheffect(lpeitem, false, false); } } if(!simplified){ lpe_simplify->getRepr()->setAttribute("threshold", ss.str()); } } } } } } /* class PencilToleranceObserver : public Inkscape::Preferences::Observer { public: PencilToleranceObserver(Glib::ustring const &path, GObject *x) : Observer(path), _obj(x) { g_object_set_data(_obj, "prefobserver", this); } virtual ~PencilToleranceObserver() { if (g_object_get_data(_obj, "prefobserver") == this) { g_object_set_data(_obj, "prefobserver", NULL); } } virtual void notify(Inkscape::Preferences::Entry const &val) { GObject* tbl = _obj; if (g_object_get_data( tbl, "freeze" )) { return; } g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); GtkAdjustment * adj = GTK_ADJUSTMENT(g_object_get_data(tbl, "tolerance")); double v = val.getDouble(adj->value); gtk_adjustment_set_value(adj, v); g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); } private: GObject *_obj; }; */ void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) { sp_add_freehand_mode_toggle(mainActions, holder, true); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); EgeAdjustmentAction* eact = 0; /* min pressure */ { eact = create_adjustment_action( "MinPressureAction", _("Min pressure"), _("Min:"), _("Min percent of pressure"), "/tools/freehand/pencil/minpressure", 0, GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, 0, 100, 1, 0, 0, 0, 0, sp_minpressure_value_changed, NULL, 0 ,0); gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); g_object_set_data( holder, "minpressure", eact ); if (prefs->getInt("/tools/freehand/pencil/freehand-mode", 0) == 3) { gtk_action_set_visible( GTK_ACTION(eact), true ); } else { gtk_action_set_visible( GTK_ACTION(eact), false ); } } /* max pressure */ { eact = create_adjustment_action( "MaxPressureAction", _("Max pressure"), _("Max:"), _("Max percent of pressure"), "/tools/freehand/pencil/maxpressure", 100, GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, 0, 100, 1, 0, 0, 0, 0, sp_maxpressure_value_changed, NULL, 0 ,0); gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); g_object_set_data( holder, "maxpressure", eact ); if (prefs->getInt("/tools/freehand/pencil/freehand-mode", 0) == 3) { gtk_action_set_visible( GTK_ACTION(eact), true ); } else { gtk_action_set_visible( GTK_ACTION(eact), false ); } } /* Use pressure */ { InkToggleAction* itact = ink_toggle_action_new( "PencilPressureAction", _("Use pressure input"), _("Use pressure input"), INKSCAPE_ICON("draw-use-pressure"), GTK_ICON_SIZE_SMALL_TOOLBAR ); bool pressure = prefs->getBool(freehand_tool_name(holder) + "/pressure", false); gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(itact), pressure ); g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(use_pencil_pressure), holder) ; gtk_action_group_add_action( mainActions, GTK_ACTION(itact) ); if (pressure) { gtk_action_set_visible( GTK_ACTION( g_object_get_data(holder, "minpressure") ), true ); gtk_action_set_visible( GTK_ACTION( g_object_get_data(holder, "maxpressure") ), true ); } else { gtk_action_set_visible( GTK_ACTION( g_object_get_data(holder, "minpressure") ), false ); gtk_action_set_visible( GTK_ACTION( g_object_get_data(holder, "maxpressure") ), false ); } } /* Tolerance */ { gchar const* labels[] = {_("(many nodes, rough)"), _("(default)"), 0, 0, 0, 0, _("(few nodes, smooth)")}; gdouble values[] = {1, 10, 20, 30, 50, 75, 100}; eact = create_adjustment_action( "PencilToleranceAction", _("Smoothing:"), _("Smoothing: "), _("How much smoothing (simplifying) is applied to the line"), "/tools/freehand/pencil/tolerance", 3.0, GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-pencil", 1, 100.0, 0.5, 1.0, labels, values, G_N_ELEMENTS(labels), sp_pencil_tb_tolerance_value_changed, NULL /*unit tracker*/, 1, 2); ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); } /* advanced shape options */ freehand_add_advanced_shape_options(mainActions, holder, true); /* Reset */ { InkAction* inky = ink_action_new( "PencilResetAction", _("Defaults"), _("Reset pencil parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), INKSCAPE_ICON("edit-clear"), GTK_ICON_SIZE_SMALL_TOOLBAR ); g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_pencil_tb_defaults), holder ); gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); } /* LPE simplify based tolerance */ { InkToggleAction* itact = ink_toggle_action_new( "PencilLpeSimplify", _("LPE based interactive simplify"), _("LPE based interactive simplify"), INKSCAPE_ICON("interactive_simplify"), GTK_ICON_SIZE_SMALL_TOOLBAR ); gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(itact), prefs->getInt("/tools/freehand/pencil/simplify", 0) ); g_object_set_data( holder, "simplify", itact ); g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(freehand_simplify_lpe), holder) ; gtk_action_group_add_action( mainActions, GTK_ACTION(itact) ); guint freehandMode = prefs->getInt("/tools/freehand/pencil/freehand-mode", 0); if (freehandMode == 2) { gtk_action_set_visible( GTK_ACTION( g_object_get_data(holder, "simplify") ), false ); } else { gtk_action_set_visible( GTK_ACTION( g_object_get_data(holder, "simplify") ), true ); } } /* LPE simplify flatten */ { InkAction* inky = ink_action_new( "PencilLpeSimplifyFlatten", _("LPE simplify flatten"), _("LPE simplify flatten"), INKSCAPE_ICON("flatten"), GTK_ICON_SIZE_SMALL_TOOLBAR ); g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_simplify_flatten), holder ); gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); g_object_set_data( holder, "flatten_simplify", inky ); guint freehandMode = prefs->getInt("/tools/freehand/pencil/freehand-mode", 0); if (freehandMode == 2 || !prefs->getInt("/tools/freehand/pencil/simplify", 0)) { gtk_action_set_visible( GTK_ACTION( g_object_get_data(holder, "flatten_simplify") ), false ); } else { gtk_action_set_visible( GTK_ACTION( g_object_get_data(holder, "flatten_simplify") ), true ); } } g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); } /* Local Variables: mode:c++ c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil fill-column:99 End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :