Selecting Matching Selectors when Objects are Selected

This post explains selection of treeview rows when objects belonging to that selector row are selected.

First, the objects in the desktop selection are obtained. Next the treeview’s rows are iterated and each row’s column _colObj is obtained as:
std::vector<spobject *> objVec = row[_mColumns._colObj];

The selected object’s ID is compared with each object’s ID in objVec. If the comparison returns true, then the row whose objVec had matching objects is added to treeview selection as:
_treeView.get_selection()->select(row);

By default, only the parent rows are iterated. So a check is also performed on child rows to see if IDs match with them. Also if there is a prior selection and the current object selected does not belong to any selector, then the treeview selection is cleared using _unselect_all() function of Gtk::TreeSelection.

Screenshot from 2016-07-27 13:50:02
In the above screenshot, the object associated with second child row is selected which in turn selects the row in treeview.

Selection of Objects when Style Dialog Row is Selected

Whenever any row in Style Dialog is selected, the corresponding objects in the drawing must be selected. This was implemented quickly. First the selection prior to selecting any row is cleared. Next it is made sure that the objects are selected only when the tree column corresponding to selector label is clicked. First column with ‘+’ is avoided because it is used to add objects to selector.

Next _colObj, i.e. the column referring to corresponding objects of the selected row is used to get the objects to be added to selection.

_desktop->selection->add(obj);

obj is the object in the objVec returned by _colObj. Thus objects are added to selection. Besides it is also checked, if the row selected in the Style Dialog is a parent row or a child row. For the former case, its child rows are also iterated and those objects are also added to selection.

Case 1: When parent row is selected and it has children
Screenshot from 2016-07-27 12:58:52

Case 2: When child row is selected
Screenshot from 2016-07-27 12:59:09

There will be another case in selection when matching selector rows should be seleted when objects in the drawing are selected, which will be discussed in next post.

Adding Objects to Selector (Part 2)

Any changes in the Style Dialog like adding an object to a selector must be updated in XML representation of the drawing. Clicking ‘+’ in front of a selector adds objects to that selector.

If the selector to which object is added is a class selector, then the class attribute of the object is set to the selector name. The screenshot below shows this:

Screenshot from 2016-07-27 12:10:58

If the object is deleted by clicking ‘-‘ in front of its row, then the class attribute that was set due to the selector is unset.

Screenshot from 2016-07-27 12:11:19

This is implemented in _handleButtonEvent(GdkEventButton event). Whenever first column of the selector row that is a ‘+’ is clicked, the _desktop is checked for selection. If it is not empty, those objects are added to selector. Rows are added with their content set as:

childrow =
(_store->append(row->children()));
childrow[_mColumns._selectorLabel] = "#" + std::string(obj->getId());
childrow[_mColumns._colAddRemove] = false;
childrow[_mColumns._colObj] = _desktop->selection->list();

Finally, _styleChild i.e. the style element is obtained and _updateStyleContent() is called to update the XML representation.

Progress So Far

Not going into details in this post, I will just mention about what progress I have made in the past two weeks.

  1. Adding Objects to Selector, in XML repr too
  2. Deleting objects from Style Dialog as well as from repr (this was a tough one)
  3. Selecting all matching objects when any row(selector) in Style Dialog
  4. Selecting matching selectors when objects in the drawing are selected
  5. Opening CSS dialog on double clicking selector
  6. Populating CSS dialog with properties of selector selected in Style Dialog
  7. Make properties editable in CSS dialog and update XML repr so changes are reflected in the drawing

Besides polishing the last two above, dragging selectors along with undo-redo support is left. It has been a pleasure so far! 😀

I will dig the details on each of the above in coming posts.

Adding Objects to Selector (Part 1)

Adding objects to selector has been a long process. So far, there has been a list of selectors in the style dialog. Adding objects to selectors will from a hierarchical structure. So Gtk::ListStore is replaced by Gtk::TreeStore which supports hierarchical representation of elements in the treeview.

There are basically two things to be updated:

  1. Add objects to selectors in treeview of the dialog
  2. Updating the XML representation whenever any child was added to a selector

Point to be noted is that parent-child relationship has to be actually maintained in the former one only to depict the representation of treeview but no such thing has to be done in the latter case. I initially considered this relationship to be existing in both cases.

Well moving to the implementation part, if any object is selected in the drawing, clicking on ‘+’ button in any row should add it as a child in the row whose button was clicked. The button event in the first column of every row which is ‘+’ button is detected first via _handleButtonEvent(GdkEventButton event). The selected row whose ‘+’ is obtained as:

Gtk::TreeModel::iterator iter = refTreeSelection->get_selected();
if ( iter ) {
Gtk::TreeModel::Row row =
iter;
....
}

Also I considered the objects in each selector had to be unique which I observed from Selection Sets. Style dialog is inspired from it and I followed similar steps. I worked as per this consideration but doing so had unexpected behavior. It was sort of haphazard, objects were added to selector random number of times, irrespective of the number of clicks on ‘+’.

The ultimate goal is to replace Selections sets with CSS selectors which can not only be used for selections sets but also for CSS styling. –Tavmjong Bah

So discarding the assumption I had made, I added children to rows successfully. Another Gtk::TreeModelColumn column has been added which stores the object corresponding to the selector. The other column only stores some information associated to the object like its id which can be a selector label. Having object associated is helpful.

The row obtained above is used to append children to it. The various columns of this childrow are assigned values as shown in code snippet below:

childrow = *(_store->append(row.children()));
childrow[_mColumns._selectorLabel] = obj->getId();
childrow[_mColumns._colAddRemove] = false;
childrow[_mColumns._colObj] = obj;

Screenshot from 2016-06-30 20:19:19

Looks good. 😀

This was just end of part 1 which is adding objects to selectors in treeview of the dialog. The second part which is updating XML representation will be discussed in next post.

A Lot to be Done Yet

Undo redo support has not been added yet. Since yesterday, I have been exploring the same. Implemented a part of it by looking at undo redo implementation in Selection Sets. Some things look clear, others fuzzy. Since mid-term is near, I considered starting my last milestone before it. Little late for it. It is adding and removing objects from selectors via use of symbols in front of each row of treeview. Adding this new feature is huge.

And meanwhile today, I found another issue in implementation done so far. Yep some trivial but significant cases always hideous. Remove text from the entrybox which is used to set the name of selector and a crash. In this case, I set default text .Class1 for the selector name.

Knocking Down Two Issues

The first noticeable thing whenever the style dialog is opened is some empty space at its top.

Screenshot from 2016-06-04 22:13:55

Solved it using a function intrinsic to Inkscape’s Panel class. Just packing the _mainbox that contains all the elements of style dialog to get_contents, the unwanted space issue was solved. Well it took quite a time to figure it out!

_getContents()->pack_start(_mainBox, Gtk::PACK_EXPAND_WIDGET);

Coming next to recent implementation of deleting a selector, it worked well except in the case when the last and only remaining selector was deleted. This was because _sValue was empty and using the following statement:

_sValue.append(selValue.c_str());

actually had NULL as argument to append() function. So after clearing the _sValue, content was only appended to it if some selectors were still present in the document.

Deletion from XML Tree Done

The previous implementation of deletion from treeview was insignificant since a selector erased from treeview was saved to document because it was not removed from XML representation of the tree too.

Modification of content in the style node of XML tree is a complicated process. Tried it but not very efficient and accurate. Instead of modifying the content, I cleared the node’s content and set its value corresponding to the selectors left in the selectorVec. The vector and content are cleared using following lines:

selVec.erase(selVec.begin()+i);
_sValue.clear();

Next I will be moving to adding and deleting objects to selectors using buttons at the beginning of every row in the treeview.

From Map to Vector

Opening an existing drawing populated the style dialog but the selectors were not added to single style element. To achieve this, I played around with the map that contained selector names mapped to selector values (style attributes) of the object.

For every element that existed in the drawing already, I iterated the map of selectors. Appending each name and value to a string, the values of the resulting string were not in the order of insertion of selectors to this map. And then I learnt that maps contain key-value pairs in an ordered manner. The ordering occurs in a lexicographic manner irrespective of order of insertion of elements to it. Remember binary tree search? Well maps operate on the basis of this search algorithm.

So instead of using this map, I created a vector since order of insertion and retrieving elements has to be same.
std::map&ltstd::string, std::string>_selectorMap; std::vector<std::pair<std::string, std::string> >_selectorVec;

Modification to move from map to vector was done at all places needed. Later I obtained nodes from XML representation of the document and added the content retrieved from the vector to a new child in the XML tree.

Another Change

Click ‘+’ at the bottom, a new selector and a new style element. So each selector was added to a new style element. The change is a single style element should be there for each file and thus it can have multiple selectors. Both the earlier version and new implementation are shown below:

Screenshot from 2016-06-15 00:25:12

Screenshot from 2016-06-15 00:27:37

Setting the selectors in single style element when the dialog is to be populated with selectors from already existing drawing is in progress yet. More on previous implementation of populating the style dialog can be seen here.

Besides this implementation, I have added buttons to the treeview against each row containing selector. These ‘+’ buttons will be used to add selected objects to existing selectors instead of creating a new one every time, as per need of the user.