|
View:
New views
4 Messages
—
Rating Filter:
Alert me
|
|
|
fine-tune drag'n'drop in a treeHi,
I'm playing around with the TreeStore, but I'm unable to obtain the effects I want. Let's assume I have this tree: -- 1 -- 1.1 -- 1.1.1 -- 1.1.2 -- 1.2 -- 1.2.1 -- 1.2.2 -- 2 I want to be able to do these: * move (1) after (2) or (2) in front of (1) * move (1.1) after (1.2) or (1.2) in front of (1.1) * move (1.1) or (1.2) under (2) * (1.1.1), (1.1.2), (1.2.1) and (1.2.2) should not be draggable * (1.1) and (1.2) should always be attached to (1) or (2) * (2) or (1) should always stay under the root I have so far created a TreeStore with a model that has a Gtk::TreeModelColumn<int> m_level member. I have set m_level to 1 for (1) and (2) and with 2 for (1.1) and (1.2). The "unmovable" rows has this set to 0. I was able to restrict this way what rows can be dragged via row_draggable_vfunc. But I'm unable to controll the dropping mechanism correctly. That is: * I can't attach (1.1) or (1.2) * move (2) in front of (1) if I drop it over (1) * move (1) after (2) if I drop (1) over (2) * move (1.1) as the last item if I drop it over (1) Any help would be appreciated. I have attached the code I've wrote so far. Thanx, Johnny [treewindow.cc] #include "treewindow.h" #include <iostream> TreeModel::TreeModel() { // From the GTMM Book: // // "We can't just call Gtk::TreeModel(m_columns) in the initializer list // because m_columns does not exist when the base class constructor runs. // And we can't have a static m_columns instance, because that would be // instantiated before the gtk type system. // So, we use this method, which should only be used just after creation!" // set_column_types(m_columns); } Glib::RefPtr<TreeModel> TreeModel::create() { return Glib::RefPtr<TreeModel> (new TreeModel); } bool TreeModel::row_draggable_vfunc(const Gtk::TreeModel::Path& path) const { TreeModel* model = const_cast<TreeModel*>(this); const_iterator iter = model->get_iter(path); if(iter) { Row row = *iter; std::cout << "row_draggable_vfunc:" << " id: " << row[m_columns.m_id] << " level: " << row[m_columns.m_level] << std::endl; return (row[m_columns.m_level] > 0); } std::cout << "row_draggable_vfunc: false - no row" << std::endl; return false; } bool TreeModel::row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& selection_data) const { // obtain the row being dragged Glib::RefPtr<Gtk::TreeModel> ref_model = Glib::RefPtr<Gtk::TreeModel>(const_cast<TreeModel*>(this)); ref_model->reference(); Gtk::TreeModel::Path orig; Gtk::TreeModel::Path::get_from_selection_data(selection_data, ref_model, orig); const_iterator orig_iter = ref_model->get_iter(orig); if(orig_iter) { Row orig_row = *orig_iter; std::cout << "\torig: " << " id: " << orig_row[m_columns.m_id] << " level: " << orig_row[m_columns.m_level] << std::endl; TreeModel* model = const_cast<TreeModel*>(this); const_iterator dest_iter = model->get_iter(dest); if(dest_iter) { Row dest_row = *dest_iter; std::cout << "\tdest: " << " id: " << dest_row[m_columns.m_id] << " level: " << dest_row[m_columns.m_level] << std::endl; return (orig_row[m_columns.m_level] > 0 && dest_row[m_columns.m_level] > 0); } } std::cout << "row_drop_possible_vfunc: false - no row" << std::endl; return false; } // bool TreeModel::drag_data_received_vfunc(const Gtk::TreeModel::Path & dest, const Gtk::SelectionData & selection_data) // { // return true; // } TreeWindow::TreeWindow(BaseObjectType* object, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade) : Gtk::Window(object) { // connect button signals Gtk::Button* btn = 0; refGlade->get_widget("quitbtn", btn); if(!btn) throw std::runtime_error("quitbtn not found"); btn->signal_clicked().connect(sigc::mem_fun(*this, &TreeWindow::on_quitbtn)); btn = 0; refGlade->get_widget("dumpbtn", btn); if(!btn) throw std::runtime_error("dumpbtn not found"); btn->signal_clicked().connect(sigc::mem_fun(*this, &TreeWindow::on_dumpbtn)); Gtk::TreeView* view = 0; refGlade->get_widget("treeview", view); if(!view) throw std::runtime_error("treeview not found"); // create model and connect to the view m_model = TreeModel::create(); TreeModel::ModelColumns& cols = m_model->m_columns; view->set_model(m_model); // set model data Gtk::TreeModel::Row row = *(m_model->append()); row[cols.m_id] = 1; row[cols.m_name] = "foo1"; row[cols.m_level] = 1; Gtk::TreeModel::Row row2 = *(m_model->append(row.children())); row2[cols.m_id] = 11; row2[cols.m_name] = "foo1.1"; row2[cols.m_level] = 2; row2 = *(m_model->append(row.children())); row2[cols.m_id] = 12; row2[cols.m_name] = "foo1.2"; row2[cols.m_level] = 2; Gtk::TreeModel::Row row3 = *(m_model->append(row2.children())); row3[cols.m_id] = 121; row3[cols.m_name] = "foo1.2.1"; row3[cols.m_level] = 0; row3 = *(m_model->append(row2.children())); row3[cols.m_id] = 122; row3[cols.m_name] = "foo1.2.2"; row3[cols.m_level] = 0; row2 = *(m_model->append(row.children())); row2[cols.m_id] = 13; row2[cols.m_name] = "foo1.3"; row2[cols.m_level] = 2; row = *(m_model->append()); row[cols.m_id] = 2; row[cols.m_name] = "bar2"; row[cols.m_level] = 1; // show the columns view->append_column("ID", cols.m_id); view->append_column("Name", cols.m_name); for(int i=0; i< view->get_columns().size(); ++i) { Gtk::TreeViewColumn* p = view->get_column(i); p->set_reorderable(); } } TreeWindow::~TreeWindow() { } void TreeWindow::on_quitbtn() { hide(); } void TreeWindow::on_dumpbtn() { std::cout << "Dumping the model" << std::endl; typedef Gtk::TreeModel::Children TChildren; TChildren children = m_model->children(); for(TChildren::iterator it = children.begin(); it != children.end(); ++it) { Gtk::TreeModel::Row row = *it; std::cout << "\t" << row[m_model->m_columns.m_id] << ", " << row[m_model->m_columns.m_name] << std::endl; } } [treewindow.h] #ifndef TREEWINDOW_H #define TREEWINDOW_H #include <gtkmm.h> #include <libglademm.h> class TreeModel: public Gtk::TreeStore { public: class ModelColumns : public Gtk::TreeModel::ColumnRecord { public: ModelColumns() { add(m_id); add(m_name); add(m_level); } Gtk::TreeModelColumn<int> m_id; Gtk::TreeModelColumn<Glib::ustring> m_name; Gtk::TreeModelColumn<int> m_level; }; static Glib::RefPtr<TreeModel> create(); ModelColumns m_columns; private: TreeModel(); // overide drag_n_drop virtual functions bool row_draggable_vfunc(const Gtk::TreeModel::Path& path) const; bool row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& selection_data) const; // bool drag_data_received_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& selection_data); }; class TreeWindow: public Gtk::Window { public: TreeWindow(BaseObjectType* object, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade); ~TreeWindow(); private: Glib::RefPtr<TreeModel> m_model; void on_quitbtn(); void on_dumpbtn(); }; #endif <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> <!--Generated with glade3 3.4.4 on Wed Apr 30 20:56:12 2008 --> <glade-interface> <widget class="GtkWindow" id="TreeWindow"> <property name="default_width">400</property> <property name="default_height">200</property> <child> <widget class="GtkVBox" id="vbox1"> <property name="visible">True</property> <child> <widget class="GtkScrolledWindow" id="scrolledwindow1"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> <child> <widget class="GtkTreeView" id="treeview"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="headers_clickable">True</property> <property name="reorderable">True</property> <property name="rules_hint">True</property> <property name="enable_tree_lines">True</property> </widget> </child> </widget> </child> <child> <widget class="GtkHButtonBox" id="hbuttonbox1"> <property name="visible">True</property> <property name="layout_style">GTK_BUTTONBOX_SPREAD</property> <child> <widget class="GtkButton" id="dumpbtn"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="label" translatable="yes">Dump Model</property> <property name="response_id">0</property> </widget> </child> <child> <widget class="GtkButton" id="quitbtn"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="label" translatable="yes">Quit</property> <property name="response_id">0</property> </widget> <packing> <property name="position">1</property> </packing> </child> </widget> <packing> <property name="expand">False</property> <property name="padding">5</property> <property name="position">1</property> </packing> </child> </widget> </child> </widget> </glade-interface> [treemain.cc] #include "treewindow.h" #include <iostream> int main(int argc, char *argv[]) { Gtk::Main kit(argc, argv); Glib::RefPtr<Gnome::Glade::Xml> refXml; try { refXml = Gnome::Glade::Xml::create(SOURCE_DIR "/treemain.glade"); } catch(const Gnome::Glade::XmlError& ex) { std::cerr << ex.what() << std::endl; return 1; } TreeWindow* window = 0; refXml->get_widget_derived("TreeWindow", window); if(window) { kit.run(*window); } else { std::cerr << "Window template not found." << std::endl; return 1; } return 0; } _______________________________________________ gtkmm-list mailing list gtkmm-list@... http://mail.gnome.org/mailman/listinfo/gtkmm-list |
|
|
Re: fine-tune drag'n'drop in a treeOn Sat, 2008-05-03 at 13:29 +0300, Ionutz Borcoman wrote:
> Hi, > > I'm playing around with the TreeStore, but I'm unable to obtain the effects I > want. > > Let's assume I have this tree: > > -- 1 > -- 1.1 > -- 1.1.1 > -- 1.1.2 > -- 1.2 > -- 1.2.1 > -- 1.2.2 > -- 2 > > I want to be able to do these: > * move (1) after (2) or (2) in front of (1) > * move (1.1) after (1.2) or (1.2) in front of (1.1) > * move (1.1) or (1.2) under (2) > * (1.1.1), (1.1.2), (1.2.1) and (1.2.2) should not be draggable > * (1.1) and (1.2) should always be attached to (1) or (2) > * (2) or (1) should always stay under the root > > I have so far created a TreeStore with a model that has a > Gtk::TreeModelColumn<int> m_level member. > > I have set m_level to 1 for (1) and (2) and with 2 for (1.1) and (1.2). > The "unmovable" rows has this set to 0. > > I was able to restrict this way what rows can be dragged via > row_draggable_vfunc. But I'm unable to controll the dropping mechanism > correctly. You can do this by overriding the row_drop_possible_vfunc() virtual method. You can then add any logic you like, usually examining the relevant model data for that row. I do that in Glom's (ugly) layout dialog. For instance, text items can be dropped into group items, but not into other text items: http://svn.gnome.org/viewvc/glom/trunk/glom/mode_data/treestore_layout.h?view=markup http://svn.gnome.org/viewvc/glom/trunk/glom/mode_data/treestore_layout.cc?view=markup It works well, so we should probably mention in the documentation. > That is: > * I can't attach (1.1) or (1.2) > * move (2) in front of (1) if I drop it over (1) > * move (1) after (2) if I drop (1) over (2) > * move (1.1) as the last item if I drop it over (1) > > Any help would be appreciated. I have attached the code I've wrote so far. > > Thanx, > > Johnny -- murrayc@... www.murrayc.com www.openismus.com _______________________________________________ gtkmm-list mailing list gtkmm-list@... http://mail.gnome.org/mailman/listinfo/gtkmm-list |
|
|
Re: fine-tune drag'n'drop in a treeOn Wednesday 07 May 2008 2:25:22 pm Murray Cumming wrote:
> On Sat, 2008-05-03 at 13:29 +0300, Ionutz Borcoman wrote: > You can do this by overriding the row_drop_possible_vfunc() virtual > method. You can then add any logic you like, usually examining the > relevant model data for that row. > > I do that in Glom's (ugly) layout dialog. For instance, text items can > be dropped into group items, but not into other text items: > http://svn.gnome.org/viewvc/glom/trunk/glom/mode_data/treestore_layout.h?vi >ew=markup > http://svn.gnome.org/viewvc/glom/trunk/glom/mode_data/treestore_layout.cc?v >iew=markup > > It works well, so we should probably mention in the documentation. After some more testing with the example from gtkmm tutorial I have managed to find the effect I was looking for - I had simply to return false when the parent row is top level or empty: Gtk::TreeModel::Path dest_parent = dest; bool dest_is_not_top_level = dest_parent.up(); if(!dest_is_not_top_level || dest_parent.empty()) { return false; } Can somebody please explain when these cases happen? I assume I get dest_is_not_top_level if the item is the root item, but when do I get dest_parent.empty()? Other question related with the D&D in a tree (not critical, but nice to have): how can I change the cursor displayed during the drag? For example to display an image, or to add a "+" or "-" to the current image displayed. And thanx for all of you that stopped me falling to the dark side of qt :-D Cheers, Johnny _______________________________________________ gtkmm-list mailing list gtkmm-list@... http://mail.gnome.org/mailman/listinfo/gtkmm-list |
|
|
Re: fine-tune drag'n'drop in a treeOn Thu, May 8, 2008 at 9:10 AM, Ionutz Borcoman <iborco@...> wrote:
> On Wednesday 07 May 2008 2:25:22 pm Murray Cumming wrote: > > On Sat, 2008-05-03 at 13:29 +0300, Ionutz Borcoman wrote: > > > You can do this by overriding the row_drop_possible_vfunc() virtual > > method. You can then add any logic you like, usually examining the > > relevant model data for that row. > > > > I do that in Glom's (ugly) layout dialog. For instance, text items can > > be dropped into group items, but not into other text items: > > http://svn.gnome.org/viewvc/glom/trunk/glom/mode_data/treestore_layout.h?vi > >ew=markup > > http://svn.gnome.org/viewvc/glom/trunk/glom/mode_data/treestore_layout.cc?v > >iew=markup > > > > It works well, so we should probably mention in the documentation. > > After some more testing with the example from gtkmm tutorial I have managed to > find the effect I was looking for - I had simply to return false when the > parent row is top level or empty: > > Gtk::TreeModel::Path dest_parent = dest; > bool dest_is_not_top_level = dest_parent.up(); > if(!dest_is_not_top_level || dest_parent.empty()) > { > return false; > } > > Can somebody please explain when these cases happen? I assume I get > dest_is_not_top_level if the item is the root item, but when do I get > dest_parent.empty()? > > Other question related with the D&D in a tree (not critical, but nice to > have): how can I change the cursor displayed during the drag? For example to > display an image, or to add a "+" or "-" to the current image displayed. > > And thanx for all of you that stopped me falling to the dark side of qt :-D > > Cheers, > > Johnny You might find Gdk::Window::pointer_grab() to be useful for changing the cursor (combined with pointer_ungrab() when you want to change it back). Alternately, if that's not flexible enough, you can probably use the Gdk::Cursor class more directly in combination with 'drag-motion' signals and something like Gtk::TreeView::get_path_at_pos() (If you want to change the cursor based on which model item the mouse is currently above). Hope that helps. -- jonner _______________________________________________ gtkmm-list mailing list gtkmm-list@... http://mail.gnome.org/mailman/listinfo/gtkmm-list |
| Free Forum Powered by Nabble | Forum Help |