diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ui/dialog/filter-effects-dialog.cpp | 382 | ||||
| -rw-r--r-- | src/ui/dialog/filter-effects-dialog.h | 31 |
2 files changed, 253 insertions, 160 deletions
diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index f6c61791b..c9cef7aea 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -187,63 +187,68 @@ void FilterEffectsDialog::FilterModifier::filter_name_edited(const Glib::ustring try_id_change((SPObject*)(*i)[_columns.filter], text); } -/*** PrimitiveList ***/ -class CellRendererConnection : public Gtk::CellRenderer +FilterEffectsDialog::CellRendererConnection::CellRendererConnection() + : Glib::ObjectBase(typeid(CellRendererConnection)), + _primitive(*this, "primitive", 0) { -public: - CellRendererConnection() - { - - } - - Glib::PropertyProxy<int> property_connection(); - - static int input_count(const SPFilterPrimitive* prim) - { - /*TODO*/ +} - if(!prim) - return 0; - /*else if(SP_IS_FEBLEND(prim) || SP_IS_FECOMPOSITE(prim) || SP_IS_FEDISPLACEMENTMAP(prim)) - return 2;*/ - else - return 1; - } +Glib::PropertyProxy<void*> FilterEffectsDialog::CellRendererConnection::property_primitive() +{ + return _primitive.get_proxy(); +} - static const int size = 32; -protected: - virtual void get_size_vfunc(Gtk::Widget& widget, const Gdk::Rectangle* cell_area, - int* x_offset, int* y_offset, int* width, int* height) const - { - if(x_offset) - (*x_offset) = 0; - if(y_offset) - (*y_offset) = 0; - if(width) - (*width) = size; - if(height) - (*height) = size; +int FilterEffectsDialog::CellRendererConnection::input_count(const SPFilterPrimitive* prim) +{ + if(!prim) + return 0; + else if(SP_IS_FEBLEND(prim) || SP_IS_FECOMPOSITE(prim) || SP_IS_FEDISPLACEMENTMAP(prim)) + return 2; + else + return 1; +} + +void FilterEffectsDialog::CellRendererConnection::get_size_vfunc( + Gtk::Widget& widget, const Gdk::Rectangle* cell_area, + int* x_offset, int* y_offset, int* width, int* height) const +{ + PrimitiveList& primlist = dynamic_cast<PrimitiveList&>(widget); + + if(x_offset) + (*x_offset) = 0; + if(y_offset) + (*y_offset) = 0; + if(width) + (*width) = size * primlist.primitive_count(); + if(height) { + // Scale the height depending on the number of inputs, unless it's + // the first primitive, in which case their are no connections + SPFilterPrimitive* prim = (SPFilterPrimitive*)_primitive.get_value(); + (*height) = primlist.is_first(prim) ? size : size * input_count(prim); } -}; +} +/*** PrimitiveList ***/ FilterEffectsDialog::PrimitiveList::PrimitiveList(FilterEffectsDialog& d) : _dialog(d), _in_drag(0) { add_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); - _primitive_model = Gtk::ListStore::create(_primitive_columns); + _model = Gtk::ListStore::create(_columns); + + // TODO: reenable this once it is possible to modify the order in the backend + //set_reorderable(true); - set_reorderable(true); - set_model(_primitive_model); - append_column(_("_Type"), _primitive_columns.type); + set_model(_model); + append_column(_("_Type"), _columns.type); signal_selection_changed().connect(sigc::mem_fun(*this, &PrimitiveList::queue_draw)); CellRendererConnection* cell = new CellRendererConnection; - int cols_count = append_column("Connections", *cell);/* - Gtk::TreeViewColumn* pColumn = get_column(cols_count - 1); - if(pColumn) - pColumn->add_attribute(cell->property_connection(), _columns.con);*/ + int cols_count = append_column("Connections", *cell); + Gtk::TreeViewColumn* col = get_column(cols_count - 1); + if(col) + col->add_attribute(cell->property_primitive(), _columns.primitive); } Glib::SignalProxy0<void> FilterEffectsDialog::PrimitiveList::signal_selection_changed() @@ -259,7 +264,7 @@ void FilterEffectsDialog::PrimitiveList::update() const SPFilterPrimitive* active_prim = get_selected(); bool active_found = false; - _primitive_model->clear(); + _model->clear(); if(f) { _dialog._primitive_box.set_sensitive(true); @@ -269,11 +274,11 @@ void FilterEffectsDialog::PrimitiveList::update() prim_obj = prim_obj->next) { SPFilterPrimitive *prim = SP_FILTER_PRIMITIVE(prim_obj); if(prim) { - Gtk::TreeModel::Row row = *_primitive_model->append(); - row[_primitive_columns.primitive] = prim; - row[_primitive_columns.type_id] = FPConverter.get_id_from_name(prim->repr->name()); - row[_primitive_columns.type] = FPConverter.get_label(row[_primitive_columns.type_id]); - row[_primitive_columns.id] = SP_OBJECT_ID(prim); + Gtk::TreeModel::Row row = *_model->append(); + row[_columns.primitive] = prim; + row[_columns.type_id] = FPConverter.get_id_from_name(prim->repr->name()); + row[_columns.type] = FPConverter.get_label(row[_columns.type_id]); + row[_columns.id] = SP_OBJECT_ID(prim); if(prim == active_prim) { get_selection()->select(row); @@ -282,8 +287,8 @@ void FilterEffectsDialog::PrimitiveList::update() } } - if(!active_found && _primitive_model->children().begin()) - get_selection()->select(_primitive_model->children().begin()); + if(!active_found && _model->children().begin()) + get_selection()->select(_model->children().begin()); } else { _dialog._primitive_box.set_sensitive(false); @@ -300,7 +305,7 @@ SPFilterPrimitive* FilterEffectsDialog::PrimitiveList::get_selected() if(_dialog._filter_modifier.get_selected_filter()) { Gtk::TreeModel::iterator i = get_selection()->get_selected(); if(i) - return (*i)[_primitive_columns.primitive]; + return (*i)[_columns.primitive]; } return 0; @@ -308,9 +313,9 @@ SPFilterPrimitive* FilterEffectsDialog::PrimitiveList::get_selected() void FilterEffectsDialog::PrimitiveList::select(SPFilterPrimitive* prim) { - for(Gtk::TreeIter i = _primitive_model->children().begin(); - i != _primitive_model->children().end(); ++i) { - if((*i)[_primitive_columns.primitive] == prim) + for(Gtk::TreeIter i = _model->children().begin(); + i != _model->children().end(); ++i) { + if((*i)[_columns.primitive] == prim) get_selection()->select(i); } } @@ -319,132 +324,184 @@ bool FilterEffectsDialog::PrimitiveList::on_expose_event(GdkEventExpose* e) { Gtk::TreeView::on_expose_event(e); - const int sz = CellRendererConnection::size; SPFilterPrimitive* prim = get_selected(); - if(prim) { - int row_index = 0; - for(Gtk::TreeIter row = get_model()->children().begin(); - row != get_model()->children().end(); ++row, ++row_index) { - const int inputs = CellRendererConnection::input_count(prim); - for(int i = 0; i < inputs; ++i) { - Gdk::Rectangle rct, clip(&e->area); - get_cell_area(get_model()->get_path(row), *get_column(1), rct); - const int x = rct.get_x() + sz / 4 + sz * i; - const int y = rct.get_y() + sz / 4; - const bool on_sel_row = (*row)[_primitive_columns.primitive] == prim; - - // Check mouse state - int mx, my; - Gdk::ModifierType mask; - get_bin_window()->get_pointer(mx, my, mask); - //const bool inside = mx >= x && my >= y && mx <= x + sz / 2 && my <= y + sz / 2; - - get_bin_window()->draw_rectangle(get_style()->get_black_gc(), on_sel_row, x, y, sz / 2, sz / 2); - - // draw input connection(s) - if(on_sel_row) { - if(i == 0 && _in_drag != 1) - draw_connection(find_result(row), x + sz / 4, y + sz / 4); - else if(i == 1 && _in_drag != 2) { - /*if(SP_IS_FEBLEND(prim)) - \ draw_connection(SP_FEBLEND(prim)->in2, x + sz / 4, y + sz / 4);*/ - } - else if(_in_drag > 0) { - draw_connection(row, mx, my); - } - } - } + int row_index = 0; + int row_count = get_model()->children().size(); + int fheight = 0; + for(Gtk::TreeIter row = get_model()->children().begin(); + row != get_model()->children().end(); ++row, ++row_index) { + Gdk::Rectangle rct, clip(&e->area); + get_cell_area(get_model()->get_path(row), *get_column(1), rct); + const int x = rct.get_x(), y = rct.get_y(), h = rct.get_height(); + + // For calculating the width of cells, the height of the first row is used + if(row_index == 0) + fheight = h; + + // Check mouse state + int mx, my; + Gdk::ModifierType mask; + get_bin_window()->get_pointer(mx, my, mask); + + // Outline the bottom of the connection area + const int outline_x = x + fheight * (row_count - row_index); + get_bin_window()->draw_line(get_style()->get_dark_gc(Gtk::STATE_NORMAL), + x, y + h, outline_x, y + h); + + // The first row can't have any inputs + if(row_index == 0) + continue; + + // Side outline + get_bin_window()->draw_line(get_style()->get_dark_gc(Gtk::STATE_NORMAL), + outline_x, y, outline_x, y + h); + + std::vector<Gdk::Point> con_poly; + int con_drag_y; + bool inside; + // Draw "in" shape + inside = do_connection_node(row, 0, con_poly, mx, my); + con_drag_y = con_poly[2].get_y(); + get_bin_window()->draw_polygon(inside && mask & GDK_BUTTON1_MASK ? + get_style()->get_dark_gc(Gtk::STATE_NORMAL) : + get_style()->get_dark_gc(Gtk::STATE_ACTIVE), + inside, con_poly); + // Draw "in" connection + draw_connection(find_result(row, SP_ATTR_IN), outline_x, con_poly[2].get_y(), row_count); + + const SPFilterPrimitive* row_prim = (*row)[_columns.primitive]; + if(CellRendererConnection::input_count(row_prim) == 2) { + // Draw "in2" shape + inside = do_connection_node(row, 1, con_poly, mx, my); + if(_in_drag == 2) + con_drag_y = con_poly[2].get_y(); + get_bin_window()->draw_polygon(inside && mask & GDK_BUTTON1_MASK ? + get_style()->get_dark_gc(Gtk::STATE_NORMAL) : + get_style()->get_dark_gc(Gtk::STATE_ACTIVE), + inside, con_poly); + // Draw "in2" connection + draw_connection(find_result(row, SP_ATTR_IN2), outline_x, con_poly[2].get_y(), row_count); } - } - - return true; -} -const Gtk::TreeIter FilterEffectsDialog::PrimitiveList::find_result(const Gtk::TreeIter& start) -{ - const int image = ((SPFilterPrimitive*)(*start)[_primitive_columns.primitive])->image_in; - Gtk::TreeIter target = _primitive_model->children().end(); - - if(image >= 0) { - for(Gtk::TreeIter i = _primitive_model->children().begin(); - i != start; ++i) { - if(((SPFilterPrimitive*)(*i)[_primitive_columns.primitive])->image_out == image) - target = i; + // Draw drag connection + if(row_prim == prim && _in_drag) { + get_bin_window()->draw_line(get_style()->get_black_gc(), outline_x, con_drag_y, + mx, con_drag_y); + get_bin_window()->draw_line(get_style()->get_black_gc(), mx, con_drag_y, mx, my); } } - return target; + return true; } -void FilterEffectsDialog::PrimitiveList::draw_connection(const Gtk::TreeIter& input, const int x, const int y) +void FilterEffectsDialog::PrimitiveList::draw_connection(const Gtk::TreeIter& input, const int x1, const int y1, + const int row_count) { - if(input != _primitive_model->children().end()) { + if(input != _model->children().end()) { Gdk::Rectangle rct; - const int sz = CellRendererConnection::size; + + get_cell_area(get_model()->get_path(_model->children().begin()), *get_column(1), rct); + const int fheight = rct.get_height(); get_cell_area(get_model()->get_path(input), *get_column(1), rct); + const int row_index = find_index(input); + const int x2 = rct.get_x() + fheight * (row_count - row_index) - fheight / 2; + const int y2 = rct.get_y() + rct.get_height(); - get_bin_window()->draw_line(get_style()->get_black_gc(), x, y, - rct.get_x() + sz / 2, rct.get_y() + sz / 2); + // Draw an 'L'-shaped connection + get_bin_window()->draw_line(get_style()->get_black_gc(), x1, y1, x2, y1); + get_bin_window()->draw_line(get_style()->get_black_gc(), x2, y1, x2, y2); } } -// Gets (row, col) of the filter primitive input located at (x,y) -bool FilterEffectsDialog::PrimitiveList::get_coords_at_pos(const int x, const int y, int& row, - int& col, SPFilterPrimitive **prim) +// Creates a triangle outline of the connection node and returns true if (x,y) is inside the node +bool FilterEffectsDialog::PrimitiveList::do_connection_node(const Gtk::TreeIter& row, const int input, + std::vector<Gdk::Point>& points, + const int ix, const int iy) { - Gtk::TreePath path; - Gtk::TreeViewColumn* treecol; Gdk::Rectangle rct; - int cx, cy; - if(get_path_at_pos(x, y, path, treecol, cx, cy)) { - get_cell_area(path, *treecol, rct); - - if(x >= rct.get_x() && y >= rct.get_y() && - x <= rct.get_x() + rct.get_width() && y <= rct.get_y() + rct.get_height()) { - if(treecol == get_column(1)) { - col = (x - rct.get_x()) / CellRendererConnection::size + 1; - if(col > 0 && col <= 2) { - row = 0; - Gtk::TreeIter key = _primitive_model->get_iter(path); - for(Gtk::TreeIter i = _primitive_model->children().begin(); - i != _primitive_model->children().end(); ++i, ++row) { - if(key == i) - break; - } - if(prim) - (*prim) = (*key)[_primitive_columns.primitive]; - return true; - } - } + get_cell_area(get_model()->get_path(_model->children().begin()), *get_column(1), rct); + const int h = rct.get_height(); + + get_cell_area(_model->get_path(row), *get_column(1), rct); + + const int x = rct.get_x() + h * (_model->children().size() - find_index(row)); + const int con_w = (int)(h * 0.35f); + const int con_y = rct.get_y() + h / 2 - con_w + input * h; + points.clear(); + points.push_back(Gdk::Point(x, con_y)); + points.push_back(Gdk::Point(x, con_y + con_w * 2)); + points.push_back(Gdk::Point(x - con_w, con_y + con_w)); + + return ix >= x - h && iy >= con_y && ix <= x && iy <= points[1].get_y(); +} + +const Gtk::TreeIter FilterEffectsDialog::PrimitiveList::find_result(const Gtk::TreeIter& start, + const SPAttributeEnum attr) +{ + SPFilterPrimitive* prim = (*start)[_columns.primitive]; + Gtk::TreeIter target = _model->children().end(); + int image; + + if(attr == SP_ATTR_IN) + image = prim->image_in; + else if(attr == SP_ATTR_IN2) { + if(SP_IS_FEBLEND(prim)) + image = SP_FEBLEND(prim)->in2; + else if(SP_IS_FECOMPOSITE(prim)) + image = SP_FECOMPOSITE(prim)->in2; + /*else if(SP_IS_FEDISPLACEMENTMAP(prim)) + image = SP_FEDISPLACEMENTMAP(prim)->in2;*/ + else + return target; + } + else + return target; + + if(image >= 0) { + for(Gtk::TreeIter i = _model->children().begin(); + i != start; ++i) { + if(((SPFilterPrimitive*)(*i)[_columns.primitive])->image_out == image) + target = i; } } - - return false; + + return target; +} + +int FilterEffectsDialog::PrimitiveList::find_index(const Gtk::TreeIter& target) +{ + int i = 0; + for(Gtk::TreeIter iter = _model->children().begin(); + iter != target; ++iter, ++i); + return i; } bool FilterEffectsDialog::PrimitiveList::on_button_press_event(GdkEventButton* e) { - int row, col; + Gtk::TreePath path; + Gtk::TreeViewColumn* col; + const int x = (int)e->x, y = (int)e->y; + int cx, cy; - if(get_coords_at_pos((int)e->x, (int)e->y, row, col, 0)) { - _in_drag = col; - - queue_draw(); + if(get_path_at_pos(x, y, path, col, cx, cy)) { + std::vector<Gdk::Point> points; + if(do_connection_node(_model->get_iter(path), 0, points, x, y)) + _in_drag = 1; + else if(do_connection_node(_model->get_iter(path), 1, points, x, y)) + _in_drag = 2; + + queue_draw(); } - if(_in_drag) - return true; - else - return Gtk::TreeView::on_button_press_event(e); + return Gtk::TreeView::on_button_press_event(e); } bool FilterEffectsDialog::PrimitiveList::on_motion_notify_event(GdkEventMotion* e) { - if(_in_drag) - queue_draw(); + queue_draw(); return Gtk::TreeView::on_motion_notify_event(e); } @@ -454,9 +511,12 @@ bool FilterEffectsDialog::PrimitiveList::on_button_release_event(GdkEventButton* SPFilterPrimitive *prim = get_selected(), *target; if(_in_drag && prim) { - int row, col; - - if(get_coords_at_pos((int)e->x, (int)e->y, row, col, &target) && target != prim) { + Gtk::TreePath path; + Gtk::TreeViewColumn* col; + int cx, cy; + + if(get_path_at_pos((int)e->x, (int)e->y, path, col, cx, cy)) { + target = (*_model->get_iter(path))[_columns.primitive]; Inkscape::XML::Node *repr = SP_OBJECT_REPR(target); // Make sure the target has a result const gchar *gres = repr->attribute("result"); @@ -466,7 +526,10 @@ bool FilterEffectsDialog::PrimitiveList::on_button_release_event(GdkEventButton* repr->setAttribute("result", result.c_str()); } - SP_OBJECT_REPR(prim)->setAttribute("in", result.c_str()); + if(_in_drag == 1) + SP_OBJECT_REPR(prim)->setAttribute("in", result.c_str()); + else if(_in_drag == 2) + SP_OBJECT_REPR(prim)->setAttribute("in2", result.c_str()); } _in_drag = 0; @@ -490,12 +553,11 @@ bool FilterEffectsDialog::PrimitiveList::on_button_release_event(GdkEventButton* // Reorder the filter primitives to match the list order void FilterEffectsDialog::PrimitiveList::on_drag_end(const Glib::RefPtr<Gdk::DragContext>&) { - int ndx = 0; SPFilter* filter = _dialog._filter_modifier.get_selected_filter(); - for(Gtk::TreeModel::iterator iter = _primitive_model->children().begin(); - iter != _primitive_model->children().end(); ++iter) { - SPFilterPrimitive* prim = (*iter)[_primitive_columns.primitive]; + for(Gtk::TreeModel::iterator iter = _model->children().begin(); + iter != _model->children().end(); ++iter) { + SPFilterPrimitive* prim = (*iter)[_columns.primitive]; if(prim) ;//reorder_primitive(filter, prim->repr->position(), ndx); /* FIXME */ } @@ -503,6 +565,16 @@ void FilterEffectsDialog::PrimitiveList::on_drag_end(const Glib::RefPtr<Gdk::Dra sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Reorder filter primitive")); } +int FilterEffectsDialog::PrimitiveList::primitive_count() const +{ + return _model->children().size(); +} + +bool FilterEffectsDialog::PrimitiveList::is_first(const SPFilterPrimitive* prim) const +{ + return (*_model->children().begin())[_columns.primitive] == prim; +} + /*** SettingsGroup ***/ FilterEffectsDialog::SettingsGroup::SettingsGroup() { diff --git a/src/ui/dialog/filter-effects-dialog.h b/src/ui/dialog/filter-effects-dialog.h index 6b1f48895..199e7d9ca 100644 --- a/src/ui/dialog/filter-effects-dialog.h +++ b/src/ui/dialog/filter-effects-dialog.h @@ -81,6 +81,22 @@ private: Gtk::TreeModelColumn<Glib::ustring> id; }; + class CellRendererConnection : public Gtk::CellRenderer + { + public: + CellRendererConnection(); + Glib::PropertyProxy<void*> property_primitive(); + static int input_count(const SPFilterPrimitive* prim); + + static const int size = 24; + protected: + virtual void get_size_vfunc(Gtk::Widget& widget, const Gdk::Rectangle* cell_area, + int* x_offset, int* y_offset, int* width, int* height) const; + private: + // void* should be SPFilterPrimitive*, some weirdness with properties prevents this + Glib::Property<void*> _primitive; + }; + class PrimitiveList : public Gtk::TreeView { public: @@ -93,6 +109,9 @@ private: SPFilterPrimitive* get_selected(); void select(SPFilterPrimitive *prim); + + int primitive_count() const; + bool is_first(const SPFilterPrimitive*) const; protected: bool on_expose_event(GdkEventExpose*); bool on_button_press_event(GdkEventButton*); @@ -100,13 +119,15 @@ private: bool on_button_release_event(GdkEventButton*); void on_drag_end(const Glib::RefPtr<Gdk::DragContext>&); private: - bool get_coords_at_pos(const int x, const int y, int& row, int& col, SPFilterPrimitive **prim); - const Gtk::TreeIter find_result(const Gtk::TreeIter& start); - void draw_connection(const Gtk::TreeIter&, const int x, const int y); + bool do_connection_node(const Gtk::TreeIter& row, const int input, std::vector<Gdk::Point>& points, + const int ix, const int iy); + const Gtk::TreeIter find_result(const Gtk::TreeIter& start, const SPAttributeEnum attr); + int find_index(const Gtk::TreeIter& target); + void draw_connection(const Gtk::TreeIter&, const int x1, const int y1, const int row_count); FilterEffectsDialog& _dialog; - Glib::RefPtr<Gtk::ListStore> _primitive_model; - PrimitiveColumns _primitive_columns; + Glib::RefPtr<Gtk::ListStore> _model; + PrimitiveColumns _columns; Glib::RefPtr<Gtk::Menu> _primitive_menu; int _in_drag; }; |
