New Object View
When we create a new source or filter with ParaView, we obviously want to see the object once we hit accept. With ParaView 2, there was no question as to where to put the result since there was only one place to put it. With the introduction of multiple views in ParaView 3, the appropriate view to display the pipeline object's data becomes ambiguous. ParaView 3 also supports multiple types of views, further complicating the decision making processes. Currently, the process for creating a plot from a 3D object is to create the filter, then divide up the view, then assign the view type to the new view area, then finally add the new pipeline object to the view. Although explicit, that is far too many steps to establish a new plot.
Without a user mind reading device, which is not on the current feature list of ParaView 3.0, it is impossible to always accurately predict the desired behavior of the user. We must realize that, no matter what decision making processes we use, ParaView will make mistakes. With that in mind, we have two major criteria for the process of placing new objects. First, the processes should be simple. There should be few rules to the process and the rules should be intuitive (or at least make sense). Second, the result should be easy to "fix" if ParaView makes the wrong decision.
Immediately below is the proposed set of rules for placing new pipeline objects in views. The rules are to be traversed in order until an applicable one is reached. At that time the rule is applied and the process ends. Note that although the motivation for this discussion was for placing plot-type objects, these rules are designed to be generic enough for any object type.
- #Place the new object in the currently selected view, if possible
- #Place the new object in an empty view frame, if available
- #Split the currently selected view and use the new view
The following sections are more detailed explanations of the rules as well as discussions of the ramifications and motivations for each. There is also a discussion of #corner cases for those situations in which add confusion to the interaction.
Place the new object in the currently selected view, if possible
This rule is a no-brainer. One of the views in the GUI is always selected as the "active" view. It is the view that most of the GUI components follow and where activity is supposed to take place. It would be very confusing indeed if new objects did not go into this view.
Despite the obvious nature of this rule, there are some caveats that need to be addressed.
Hiding filter inputs
It is the behavior of many filters to turn off the visibility of their input so that the new object may be seen. We should certainly follow this behavior, but we should be careful to ensure that the visibility of the input is not turned off in any other view. For example, consider the following ParaView 3 screenshot with two views both showing the same object. The view on the left is the active view.
Now, if we were to add a clip filter, the clip filter geometry should be added to the left view and the visibility of the input should be removed from the left view. The right view should be left alone. (Note that this does not currently work like it should.)
Input not visible in active window
We should get the same logical behavior even if the active view does not have the input visible (but another view might). Consider the previous example, except that the active (left) window does not show the data that we are filtering.
When the filter completes, the active view shows the filtered data along with any other data it might have been viewing. Again, any other views remain untouched.
Adding data to plots
Although all of the previous examples have to do with geometry, the rule should still be valid for plots. For example, if I have an XY-Plot view active with some probe data visible in it and then create another probe filter, the resulting data is placed in the active plot with the other data.
I can think of two open issues with this strategy. The first is that a filter like probe has a 3D widget associated with it. In the example where I want to add a second probe to an existing plot, how do I know where to put the 3D probe widget? If there is a logical place to put the 3D probe widget, what if I change the active view to use the probe filter? Will the result of the filter still go to the filter I previously made active?
The second issue is with bar charts. The current bar chart supports only one variable at a time (I think). Other bar charts (such as MS Excel) support multiple variables and we could implement something like that, but I don't know if we have a very good use case for that. Even if we did implement something like that, it's not really reasonable to assume that there will be enough consistency in the bars to group them?
If there is no way the bar chart can hold two data types, we would have to either replace the old data with the new data or declare it impossible to add to the current view and drop down to the next rule. My preference is to do the thing that is easier to correct.
Place the new object in an empty view frame, if available
This rule states that if the new object cannot be placed in the currently selected view, then ParaView should try to find a view frame that is empty. A view of the appropriate type is created in that view frame and the new object is placed inside of it.
This rule operates under the assumption that when a view is split into two view frames, the new view frame starts up as empty, with no view (render window or plot widget) assigned to it as shown in the image below. This is not the current behavior of ParaView, but probably will be once different view types are supported in the main window display. If for some reason this behavior is never implemented, then this rule is obsolete.
The choice of empty pane to use is not vital because if ParaView picks the wrong one, it is easy to correct. A simple drag to the appropriate view frame. However, their needs to be some logic for doing so, and it is always better to pick the most reasonable frame. Thus, there are two subrules for choosing the empty frame.
- If the current view is empty, use that. Again, this is a no-brainer.
- Do a depth first search, starting with the upper left. The splitting mechanism naturally creates a hierarchy of views. Doing the depth first search helps ensure new frames will be added in a general left-to-right, top-to-bottom manner, which will be natural to most people (at least in the western hemisphere).
Split the currently selected view and use the new view
If the currently selected view cannot hold the new data and there are no empty view panes to put a new view in, our final fallback is to split the current view and add the new object to the newly created view. The view should be split vertically. The top pane keeps the original view intact and takes up 2/3 of the space. The remaining 1/3 of the space on the bottom will be the new view.
For example, consider the running application with a single geometric view below.
Now, if the user creates a histogram filter, a new view pane is created below the currently selected (and only) view. A bar chart view is placed in the new pane and the histogram is put there. The result is shown below.
Although this example is the common use case, the same mechanism should work if a plot view is selected and a new filter providing geometric information is created.
Note that even if this rule does the wrong thing, that is the user did not want the current view split, it is easy and natural to correcty. Just click the "x" button on the newly created view.
Corner Cases
New 3D widgets on an invisible input
The example concerning an #input not visible in active window raises an interesting question about 3D widgets. What happens if a filter with an associated 3D widget is created when the active view does not have its input visible? I tried this in ParaView 2 and found that this situation is not supported. The 3D widget is not even drawn correctly.
We can probably get away with that in ParaView 2 since it is very rare to create a filter on an invisible object. With the multiview support ParaView 3, we are probably much more likely to run into this situation. At the very least we should sure the 3D widget is drawn correctly when possible. It may also be helpful if the filter input is temporarily displayed with the 3D widget. If we do the latter, we need to be careful to make sure that the input visibility is turned off no matter what when either accept is hit or the filter is deleted.
The problem gets more confusing when the current view is not of the correct type. In this case, there is no way to draw the 3D widget at all. One solution is to immediately create a view that can hold the 3D widget as per the rules given, but I do not recommend doing that, at least in the short term. That raises another bag of issues we would have to address for ParaView 3.0.
I think a simpler solution is to simply have the 3D widget appear in any render window view that gets selected. That gives the user the ability to switch to a different view where he/she can manipulate the 3D widget. This solution is pretty much already implemented. However, it raises another corner case about switching views in the middle of creating a new pipeline object. Of course, that issue needs to be addressed anyway.
Changing views between pipeline object creation and acceptance
Creating a new pipeline object is (usually) a two step object. First, the reader/source/filter is selected. An entry is added to the pipeline browser; the underlying VTK object is created; but the filter is not yet run and no data is displayed in a view. The user then has a chance to setup the parameters in the object inspector before hitting accept. At this time, the data is actually displayed and created.
The issue here is that in the time between object creation and the first hit of accept, the user may change the active view. This can be a feature in that it gives the user a chance to switch views to make 3D widget interaction easier. However, it opens the question of which view to put the resulting data in. Do you base your decision on the active view when the pipeline object was created or the active view when accept is first hit.
It is most appropriate to base the decision on the active view when the accept button is first hit. This decision is most consistent with other behaviors of ParaView during object creation (such as when the visibility of an input is turned off). It also is more natural for a user. In short order any user will know at what time data is added to a view. It is at that point when the decision should be made. Choosing the view at the time of accept also relieves some ambiguities. For example, what happens if the user destroys the current view between object creation and accept? That is not an issue if we choose the view after hitting accept.