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.
183 184 185 |
# File 'lib/ruber/pane.rb', line 183 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
308 309 310 311 312 313 314 315 316 317 318 319 |
# File 'lib/ruber/pane.rb', line 308 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.
410 411 412 413 414 415 416 417 418 419 |
# File 'lib/ruber/pane.rb', line 410 def each_view &blk return to_enum(:each_view) unless block_given? if single_view? then yield @view else 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
392 393 394 395 396 |
# File 'lib/ruber/pane.rb', line 392 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.
382 383 384 |
# File 'lib/ruber/pane.rb', line 382 def label= text set_view_label @view, text if @view end |
#orientation ⇒ Integer?
The orientation in which the pane is split
209 210 211 |
# File 'lib/ruber/pane.rb', line 209 def orientation @splitter ? @splitter.orientation : nil end |
#panes(: recursive) ⇒ Array<Pane> #panes ⇒ Array<Pane>
The panes contained in this pane
333 334 335 |
# File 'lib/ruber/pane.rb', line 333 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.
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/ruber/pane.rb', line 277 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.
359 360 361 362 363 364 365 366 367 |
# File 'lib/ruber/pane.rb', line 359 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
191 192 193 |
# File 'lib/ruber/pane.rb', line 191 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.
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/ruber/pane.rb', line 241 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
200 201 202 |
# File 'lib/ruber/pane.rb', line 200 def view @view end |
#views ⇒ Array<Qt::Widget>
Returns a list of all the views contained (directly or not) in the pane.
426 427 428 |
# File 'lib/ruber/pane.rb', line 426 def views to_a end |