Event Propagation problem



Hi!
First of all I want to say sorry for the long post, but the existing code is long to explain.
According to the Event Propagation lesson from the Grkmm Programming book, one even that happens in a widget can be handled by it by connecting the correspondent signal to the event handler. If the handler returns true, the event isn't propagated upstream to the parent containers of the widget.

I'm having troubles obtaining the intended result:

On one side, during the construction of the main instance of the application I define some shortcuts for certain actions:

App::App(int *argc, char ***argv):
    Gtk::Main(argc,argv)
{
    //
    // Other stuff here
    //
    // Example: This accel key will map the 'home' key to the 'seek-begin' action
    Gtk::AccelKey accel_key("Home", "<Actions>/canvasview/seek-begin");
    Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod());
    //
}


On the other hand I have the following related clases:

A) A tree store:
class CanvasTreeStore : virtual public Gtk::TreeStore
This tree store has a member that adds a cell renderer value instance for a given column.

CellRenderer_ValueBase* CanvasTreeStore::add_cell_renderer_value(Gtk::TreeView::Column* column)

B) A cell renderer: class CellRenderer_ValueBase : public Gtk::CellRendererText
The is a speialized renderer to render the Value Base on the cell.
It has a pointer to a widget called ValueBase_Entry:

ValueBase_Entry *value_entry;

when the start_editing_vfunc is called a ValueBase_Entry is created, filled and returned as Gtk::CellEditable*

Gtk::CellEditable*
CellRenderer_ValueBase::start_editing_vfunc(
    GdkEvent* event __attribute__ ((unused)),
    Gtk::Widget& widget,
    const Glib::ustring& path,
    const Gdk::Rectangle& background_area __attribute__ ((unused)),
    const Gdk::Rectangle& cell_area __attribute__ ((unused)),
    Gtk::CellRendererState flags __attribute__ ((unused)))
{
// Other stuff here...
    value_entry=manage(new ValueBase_Entry());
    value_entry->set_path(path);
    value_entry->set_parent(&widget);
    value_entry->set_value(data);
    value_entry->signal_editing_done().connect(sigc::mem_fun(*this, &CellRenderer_ValueBase::on_value_editing_done));
    return value_entry;
}

c) A cell editable class:

class studio::ValueBase_Entry : public Gtk::EventBox, public Gtk::CellEditable

This class is also a EventBox (to handle events) since the CellEditable isn't a Gtk::Widget derived one.
In this class there is a pointer to a specialized widget that is a HBox with many widgets to edit the value:

Widget_ValueBase *valuewidget;
this is created when the cell editable is created and added to it:

valuewidget=manage(new class Widget_ValueBase());
valuewidget->inside_cellrenderer();
add(*valuewidget);
valuewidget->show();

D) A container with many widgets inside:

class Widget_ValueBase : public Gtk::HBox

This container has some editable widgets:

Widget_Vector *vector_widget;
Gtk::SpinButton *real_widget;
Gtk::Adjustment real_adjustment;
Gtk::SpinButton *integer_widget;
Gtk::Adjustment integer_adjustment;
Gtk::SpinButton *angle_widget;
Gtk::Adjustment angle_adjustment;
Gtk::CheckButton *bool_widget;
Widget_ColorEdit *color_widget;
Widget_CanvasChooser *canvas_widget;
Widget_Enum *enum_widget;
Widget_Filename *filename_widget;
Widget_Time *time_widget;
Gtk::Entry *string_widget;
Widget_Distance *distance_widget;

This is the constructor, where all the widgets are created and packed to the HBox.

Widget_ValueBase::Widget_ValueBase():
    Glib::ObjectBase    (typeid(Widget_ValueBase)),
    Gtk::HBox(),
    real_adjustment(0,-2000000000,2000000000,0.05,0.05,0),
    integer_adjustment(0,-2000000000,2000000000,1,1,0),
    angle_adjustment(0,-2000000000,2000000000,1,1,0)
{
    set_no_show_all();
    label=manage(new class Gtk::Label("Unknown Datatype"));
    pack_start(*label);
    label->show();
    vector_widget=manage(new class Widget_Vector());
    pack_start(*vector_widget);
    color_widget=manage(new class Widget_ColorEdit());
    pack_start(*color_widget);
    enum_widget=manage(new class Widget_Enum());
    pack_start(*enum_widget);
    real_widget=manage(new class Gtk::SpinButton(real_adjustment,0.05,DIGITS));
    pack_start(*real_widget);
    integer_widget=manage(new class Gtk::SpinButton(integer_adjustment,1,0));
    pack_start(*integer_widget);
    angle_widget=manage(new class Gtk::SpinButton(angle_adjustment,15,2));
    pack_start(*angle_widget);
    bool_widget=manage(new class Gtk::CheckButton());
    pack_start(*bool_widget);
    string_widget=manage(new class Gtk::Entry());
    pack_start(*string_widget);
    canvas_widget=manage(new class Widget_CanvasChooser());
    pack_start(*canvas_widget);
    filename_widget=manage(new class Widget_Filename());
    pack_start(*filename_widget);
    time_widget=manage(new class Widget_Time());
    pack_start(*time_widget);
    distance_widget=manage(new class Widget_Distance());
    pack_start(*distance_widget);

    vector_widget->signal_activate().connect(sigc::mem_fun(*this,&Widget_ValueBase::activate));
    color_widget->signal_activate().connect(sigc::mem_fun(*this,&Widget_ValueBase::activate));
    enum_widget->signal_changed().connect(sigc::mem_fun(*this,&Widget_ValueBase::activate));
    real_widget->signal_activate().connect(sigc::mem_fun(*this,&Widget_ValueBase::activate));
    integer_widget->signal_activate().connect(sigc::mem_fun(*this,&Widget_ValueBase::activate));
    angle_widget->signal_activate().connect(sigc::mem_fun(*this,&Widget_ValueBase::activate));
    string_widget->signal_activate().connect(sigc::mem_fun(*this,&Widget_ValueBase::activate));
    canvas_widget->signal_activate().connect(sigc::mem_fun(*this,&Widget_ValueBase::activate));
    filename_widget->signal_activate().connect(sigc::mem_fun(*this,&Widget_ValueBase::activate));
    time_widget->signal_activate().connect(sigc::mem_fun(*this,&Widget_ValueBase::activate));
    distance_widget->signal_activate().connect(sigc::mem_fun(*this,&Widget_ValueBase::activate));
}

initially all the widgets are hidden and the Widget_ValueBase shows nothing.
When the cell renderer is starting to be edited, it pases the 'data' to the ValueBase_Entry using the set_value() member function:

value_entry->set_value(data);

which calls the set_value of the ValueBase_Entry

void ValueBase_Entry::set_value(const synfig::ValueBase &data)
{
    if(valuewidget)
        valuewidget->set_value(data);
}

which calls the set_value() of the Widget_ValueBase class:

void
Widget_ValueBase::set_value(const synfig::ValueBase &data)
{
    label->hide();
    vector_widget->hide();
    real_widget->hide();
    integer_widget->hide();
    bool_widget->hide();
    color_widget->hide();
    string_widget->hide();
    canvas_widget->hide();
    enum_widget->hide();
    angle_widget->hide();
    filename_widget->hide();
    time_widget->hide();
    distance_widget->hide();
    value=data;
    try{
    switch(value.get_type())
    {
    case ValueBase::TYPE_VECTOR:
        vector_widget->set_canvas(canvas);
        vector_widget->set_value(value.get(Vector()));
        vector_widget->show();
        break;
    case ValueBase::TYPE_REAL:
        if(( child_param_desc.get_is_distance() || param_desc.get_is_distance() )&& canvas)
        {
            Distance dist(value.get(Real()),Distance::SYSTEM_UNITS);
            dist.convert(App::distance_system,canvas->rend_desc());
            distance_widget->set_value(dist);
            distance_widget->show();
        }
        else
        {
            real_widget->set_value(value.get(Real()));
            real_widget->show();
        }
        break;
    case ValueBase::TYPE_TIME:
        if(canvas)time_widget->set_fps(canvas->rend_desc().get_frame_rate());
        time_widget->set_value(value.get(Time()));
        time_widget->show();
        break;
    case ValueBase::TYPE_ANGLE:
        angle_widget->set_value(Angle::deg(value.get(Angle())).get());
        angle_widget->show();
        break;
    case ValueBase::TYPE_INTEGER:
        {
            String child_param_hint(child_param_desc.get_hint());
            String param_hint(param_desc.get_hint());
            if(child_param_hint!="enum" && param_hint!="enum")
            {
                integer_widget->set_value(value.get(int()));
                integer_widget->show();
            }
            else
            {
                if(child_param_hint=="enum")
                    enum_widget->set_param_desc(child_param_desc);
                else
                    enum_widget->set_param_desc(param_desc);
                enum_widget->set_value(value.get(int()));
                enum_widget->show();
            }
        }
        break;
    case ValueBase::TYPE_CANVAS:
        assert(canvas);
        canvas_widget->set_parent_canvas(canvas);
        canvas_widget->set_value(value.get(etl::loose_handle<synfig::Canvas>()));
        canvas_widget->show();
        break;
    case ValueBase::TYPE_BOOL:
        bool_widget->set_active(value.get(bool()));
        bool_widget->show();
        break;
    case ValueBase::TYPE_STRING:
        if(child_param_desc.get_hint()!="filename" && param_desc.get_hint()!="filename")
        {
            string_widget->set_text(value.get(string()));
            string_widget->show();
        }
        else
        {
            filename_widget->set_value(value.get(string()));
            filename_widget->show();
        }
        break;
    case ValueBase::TYPE_COLOR:
            {
        color_widget->set_value(value.get(synfig::Color()));
        color_widget->show();
        }
        break;
    default:
        label->show();
        break;
    }
    }catch(...) { synfig::error(__FILE__":%d: Caught something that was thrown",__LINE__); }
}

Notice that all the widgets are hidden except the one given by the type.

And now my problem:

When I'm editing the Widget_ValueBase (an of the widgets contained by the HBox) the shorcuts of the applications are applied.
I've tried to use the techniques of the event propagation of the keyboard and mouse buttons events but the action is ejecuted always.
For example I tried:
Add to ValueBaseEntry constructor this code:

ValueBase_Entry::ValueBase_Entry():
    Glib::ObjectBase  (typeid(ValueBase_Entry)),
    Gtk::EventBox     (),
    Gtk::CellEditable ()
{
    parent=0;
    edit_done_called=false;
    valuewidget=manage(new class Widget_ValueBase());
    valuewidget->inside_cellrenderer();
    add(*valuewidget);
    valuewidget->show();
    // ADDED LINES/////////////
    add_events(
          Gdk::KEY_PRESS_MASK
        | Gdk::KEY_RELEASE_MASK
        | Gdk::BUTTON_PRESS_MASK
        | Gdk::BUTTON_RELEASE_MASK
        | Gdk::SCROLL_MASK
        );
    valuewidget->signal_key_press_event().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::on_key_event));
    valuewidget->signal_key_release_event().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::on_key_event));
    valuewidget->signal_button_press_event().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::on_button_event));
    valuewidget->signal_button_release_event().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::on_button_event));
    valuewidget->signal_scroll_event().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::on_scroll_event));
    signal_key_press_event().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::on_key_event));
    signal_key_release_event().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::on_key_event));
    signal_button_press_event().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::on_button_event));
    signal_button_release_event().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::on_button_event));
    signal_scroll_event().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::on_scroll_event));
    /////////////////////////
    show_all_children();
}


And the corresponding new event handlers:

bool ValueBase_Entry::on_key_event(GdkEventKey* /*event*/)
{
    synfig::info("key event handled");
    return true;
}
bool ValueBase_Entry::on_button_event(GdkEventButton* /*event*/)
{
    synfig::info("button event handled");
    return true;
}
bool ValueBase_Entry::on_scroll_event(GdkEventScroll* /*event*/)
{
    synfig::info("scroll event handled");
    return true;
}


Without success.

In theory the key event that is not processed by the Widget_ValueBase is passed to the parent, the HBox which would pass to the ValueBase_Entry which would stop the event propagation.
Why the shortcuts still begin done?
Is there a way to avoid them during the edition of the widget?

Using the same Widget_ValueBase on a pop up dialog doesn't trigger the actions when the shortcuts are pressed.

Any idea is welcome.

Thanks for reading.






[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]