Class: Ruber::Pane
- Includes:
- Enumerable
- Defined in:
- lib/ruber/pane.rb
Overview
Container used to organize multiple editor views in a tab
A pane can either contain a single non-Pane widget (usually an EditorView) or multiple Panes in a @Qt::Splitter@. In the first case, the Pane is said to be in _single view mode_, while in the second it’s said to be in _multiple view mode_.
A Pane is said to be a direct child of (or directly contained in) another Pane if it is one of the widgets contained in the second Pane‘s splitter. A non-Pane widget is said to be a direct child of (or directly contained in) a Pane if the pane is in single view mode and contains that widget or if it is in multiple view mode and one of the widgets in the splitter is in single view mode and contains that widget.
The most important method provided by this class is #split, which allows a view to be split either horizontally or vertically.
Whenever a view is closed, it is automatically removed from the pane, and panes are automatically rearranged. The only situation you should care for this is when the last view of a top-level pane is closed. In this case, the pane emits the #closing_last_view signal.
Note: the pane containing a given view (or pane) can change without warning, so never store them. To access the pane directly containing another pane, use #parent_pane on the child pane; to access the pane directly containing another widget, call the widget’s @parent@ method.
Note: this class allows to access the splitter widget. This is only meant to allow to resize it. It *must not* be used to add or remove widgets to or from it.
Instance Attribute Summary collapse
-
#splitter ⇒ Qt::Splitter?
readonly
The splitter used by the pane or nil if the pane contains a single view.
Instance Method Summary collapse
-
#contain?(widget, mode = nil) ⇒ Object
Whether the pane contains another pane or widget.
-
#each_pane(mode = :flat, &blk) ⇒ Pane, Enumerator
Iterates on child panes.
-
#each_view {|view| ... } ⇒ Pane, Enumerator
(also: #each)
Iterates on all views contained in the pane.
-
#initialize(*args) ⇒ Pane
constructor
A new instance of Pane.
-
#label ⇒ String?
The text of label associated with the pane.
-
#label=(text) ⇒ Object
Changes the label of the view in the pane.
-
#orientation ⇒ Integer?
The orientation in which the pane is split.
-
#panes(mode = :flat) ⇒ Array<Pane>
The panes contained in this pane.
-
#parent_pane ⇒ Pane
This pane’s containing pane.
-
#replace_view(old, replacement) ⇒ Boolean
Replaces a view with another.
-
#set_view_label(view, text) ⇒ Boolean
Changes the text of the label for the given view.
-
#single_view? ⇒ Boolean
Whether the pane contains a single view or not.
-
#split(view, new_view, orientation, pos = :after) ⇒ Array(Pane, Pane)?
Splits the pane in two in correspondence to the given view.
-
#view ⇒ EditorView?
The view contained in the pane.
-
#views ⇒ Array<Qt::Widget>
A list of all the views contained (directly or not) in the pane.
Methods included from Enumerable
Constructor Details
#initialize(view, parent = nil) ⇒ Pane #initialize(orientation, pane1, pane2, parent = nil) ⇒ Pane
Returns a new instance of Pane.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/ruber/pane.rb', line 75 def initialize *args case args.size when 1..2 super args[1] @view = args[0] @view.parent = self self.layout = Qt::VBoxLayout.new self layout. @view @splitter = nil connect view, SIGNAL('closing(QWidget*)'), self, SLOT('remove_view(QWidget*)') when 3..4 super args[3] self.layout = Qt::VBoxLayout.new self orientation, pane1, pane2 = args[0..3] @splitter = Qt::Splitter.new orientation, self layout. @splitter 0, pane1 1, pane2 @view = nil end margins = layout.contents_margins margins.top = margins.left = margins.bottom = margins.right = 0 layout.contents_margins = margins @label = Qt::Label.new '', self # Use the following three lines when attempting to debug issue number 10, as it # helps understanding which pane each label belongs to # color = Qt::Color.new(rand(256), rand(256), rand(256)) # @label.style_sheet = "background-color: #{color.name};" @label.hide unless parent_pane layout. @label end |
Instance Attribute Details
#splitter ⇒ Qt::Splitter? (readonly)
Returns the splitter used by the pane or nil if the pane contains a single view.
185 186 187 |
# File 'lib/ruber/pane.rb', line 185 def splitter @splitter end |
Instance Method Details
#contain?(widget) ⇒ Boolean #contain?(widget, : directly) ⇒ Boolean
Whether the pane contains another pane or widget
132 133 134 135 136 137 138 139 |
# File 'lib/ruber/pane.rb', line 132 def contain? , mode = nil if mode if @splitter then @splitter.any?{|w| w == } else @view == end else find_children(Pane).include? end end |
#each_pane {|pane| ... } ⇒ Pane, Enumerator #each_pane(: recursive) {|pane| ... } ⇒ Pane, Enumerator
Iterates on child panes
310 311 312 313 314 315 316 317 318 319 320 321 |
# File 'lib/ruber/pane.rb', line 310 def each_pane mode = :flat, &blk return to_enum(:each_pane, mode) unless block_given? return self unless @splitter if mode == :flat then @splitter.each{|w| yield w} else @splitter.each do |w| yield w w.each_pane :recursive, &blk end end self end |
#each_view {|view| ... } ⇒ Pane, Enumerator Also known as: each
Iterates on all views contained in the pane
This method always acts recursively, meaning that views indirectly contained in the pane are returned.
If the pane is in single view mode, that only view is passed to the block. If the only view has been closed, the block is not called.
413 414 415 416 417 418 419 420 421 422 |
# File 'lib/ruber/pane.rb', line 413 def each_view &blk return to_enum(:each_view) unless block_given? if single_view? and @view.parent then yield @view elsif !single_view? each_pane(:recursive) do |pn| yield pn.view if pn.single_view? end end self end |
#label ⇒ String?
The text of label associated with the pane
394 395 396 397 398 |
# File 'lib/ruber/pane.rb', line 394 def label # For some reason, Qt::Label#text returns nil if the text hasn't been set # or is set to '' @view ? (@label.text || '') : nil end |
#label=(text) ⇒ Object
Changes the label of the view in the pane
If the pane is in multiple view mode, nothing is done.
If the text is empty the label is hidden. If the text is not empty, the label is made visible, unless the pane is top-level.
This method is similar to #set_view_label, except that it doesn’t allow to specify the view to change the label for and always acts on the view contained in this pane.
384 385 386 |
# File 'lib/ruber/pane.rb', line 384 def label= text set_view_label @view, text if @view end |
#orientation ⇒ Integer?
The orientation in which the pane is split
211 212 213 |
# File 'lib/ruber/pane.rb', line 211 def orientation @splitter ? @splitter.orientation : nil end |
#panes(: recursive) ⇒ Array<Pane> #panes ⇒ Array<Pane>
The panes contained in this pane
335 336 337 |
# File 'lib/ruber/pane.rb', line 335 def panes mode = :flat single_view? ? [] : each_pane(mode).to_a end |
#parent_pane ⇒ Pane
Returns this pane’s containing pane.
110 111 112 113 114 115 |
# File 'lib/ruber/pane.rb', line 110 def parent_pane if parent.is_a?(Qt::Splitter) pane = parent.parent pane.is_a?(Pane) ? pane : nil end end |
#replace_view(old, replacement) ⇒ Boolean
Replaces a view with another
If the pane is in single view mode and its view is the same as old, the view is replaced with replacement. If the view contained in the pane is different from old, nothing is done.
If the pane is in multiple view mode, the method call will be propagated to all child panes, until one is able to carry out the replacement.
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/ruber/pane.rb', line 279 def replace_view old, replacement if @view return false unless @view == old @view = replacement replacement.parent = self layout. 0, replacement disconnect old, SIGNAL('closing(QWidget*)'), self, SLOT('remove_view(QWidget*)') connect replacement, SIGNAL('closing(QWidget*)'), self, SLOT('remove_view(QWidget*)') layout. old old.parent = nil emit view_replaced(self, old, replacement) true else each_pane.any?{|pn| pn.replace_view old, replacement} end end |
#set_view_label(view, text) ⇒ Boolean
Changes the text of the label for the given view
If the pane is in single view mode and the view given as argument is the same contained in it, the text of the label will be changed, otherwise nothing will be done. If the pane is not a toplevel pane the label will be also made visible. If the pane is a toplevel pane, the label won’t be shown. The rationale for this behaviour is that the label can be used to distinguish different widgets in the same pane. If a top-level pane is in single view mode, however, it contains no other views, so there’s no need for a label to distinguish them.
If the text is an empty string, the label will be hidden.
If the pane is in multiple view mode, the method call will be propagated recursively to child panes, until a pane containing the given view is found.
361 362 363 364 365 366 367 368 369 |
# File 'lib/ruber/pane.rb', line 361 def set_view_label view, text if single_view? return false unless @view == view @label.text = text @label.visible = !text.empty? if parent_pane true else each_pane.any? {|pn| pn.set_view_label view, text} end end |
#single_view? ⇒ Boolean
Whether the pane contains a single view or not
193 194 195 |
# File 'lib/ruber/pane.rb', line 193 def single_view? @view.to_b end |
#split(view, new_view, orientation, pos = :after) ⇒ Array(Pane, Pane)?
Splits the pane in two in correspondence to the given view
The place previously occupated by the view is divided bewtween it and another view, new_view. If needed, other panes are created to accomodate them.
The view to split must already be contained in the pane. It can be contained directly, as the only view of the pane or inserted in the splitter contained in the pane, or indirectly, contained in one of the panes contained by this pane.
If view is contained indirectly, the method call will be redirected to the correct pane (not the one associated with the view but the pane containing the latter).
If view is not contained in this pane, nothing is done.
new_view must not be associated with a pane. When this method returns, a new pane for it will have been created.
Note: after calling this method, the pane associated with view may be changed.
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/ruber/pane.rb', line 243 def split view, new_view, orientation, pos = :after idx = index_of_contained_view view return split_recursive view, new_view, orientation, pos unless idx new_pane = Pane.new(new_view) multiple_view_mode orientation old_pane = @splitter. idx keeping_focus old_pane do if @splitter.orientation == orientation idx += 1 if pos == :after idx, new_pane else pane = old_pane.multiple_view_mode orientation new_idx = pos == :after ? 1 : 0 old_pane. new_idx, new_pane old_pane = pane end end emit pane_split self, view, new_view [old_pane, new_pane] end |
#view ⇒ EditorView?
The view contained in the pane
202 203 204 |
# File 'lib/ruber/pane.rb', line 202 def view @view end |
#views ⇒ Array<Qt::Widget>
Returns a list of all the views contained (directly or not) in the pane.
429 430 431 |
# File 'lib/ruber/pane.rb', line 429 def views to_a end |