Class: HotCocoa::LayoutView

Inherits:
NSView
  • Object
show all
Defined in:
lib/hotcocoa/layout_view.rb

Overview

TODO:

Why aren't we mixing in Behaviors?

HotCocoa layout managing class. This class is responsible for keeping track of your UI layout, including adding, removing, and updating subviews.

Direct Known Subclasses

HotCocoaView

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#frame_colorNSColor

Returns:

  • (NSColor)


238
239
240
# File 'lib/hotcocoa/layout_view.rb', line 238

def frame_color
  @frame_color
end

#marginFixnum

Returns:

  • (Fixnum)


298
299
300
# File 'lib/hotcocoa/layout_view.rb', line 298

def margin
  @margin
end

#spacingFixnum

Returns:

  • (Fixnum)


284
285
286
# File 'lib/hotcocoa/layout_view.rb', line 284

def spacing
  @spacing
end

Instance Method Details

#addSubview(view) ⇒ Object Also known as: <<

Add a new subview to the layout view.

Parameters:

  • (NSView)


315
316
317
318
319
320
321
322
# File 'lib/hotcocoa/layout_view.rb', line 315

def addSubview view
  super
  if view.respond_to? :layout
    relayout!
  else
    raise ArgumentError, "view #{view} does not support the #layout method"
  end
end

#default_layoutObject



279
280
281
# File 'lib/hotcocoa/layout_view.rb', line 279

def default_layout
  @default_layout ||= LayoutOptions.new(nil, defaults_view: self)
end

#default_layout=(options) ⇒ Object

Set the default layout options. The options should follow the format that would be given to HotCocoa::LayoutOptions.

Parameters:

  • (Hash)


273
274
275
276
277
# File 'lib/hotcocoa/layout_view.rb', line 273

def default_layout= options
  options[:defaults_view] = self
  @default_layout = LayoutOptions.new(nil, options)
  relayout!
end

#drawRect(frame) ⇒ Object

This is a callback, you don't need to worry about it.



347
348
349
350
351
352
# File 'lib/hotcocoa/layout_view.rb', line 347

def drawRect frame
  if frame_color
    frame_color.set
    NSFrameRect(frame)
  end
end

#horizontal?Boolean

Whether or not the layout mode is horizontal.

Returns:

  • (Boolean)


248
249
250
# File 'lib/hotcocoa/layout_view.rb', line 248

def horizontal?
  @mode == :horizonal
end

#initWithFrame(frame) ⇒ Object

Set some default values and call the super class initializer.

Parameters:

  • (CGRect, Array<Number, Number, Number, Number>)


229
230
231
232
233
234
235
# File 'lib/hotcocoa/layout_view.rb', line 229

def initWithFrame frame
  super
  @mode    = :vertical
  @spacing = 10
  @margin  = 10
  self
end

#mode=(new_mode) ⇒ Object

Set the layout mode. The default value is :vertical, you can change it to be :horizontal if you want.

Parameters:

  • (Symbol)


257
258
259
260
261
262
263
264
265
266
# File 'lib/hotcocoa/layout_view.rb', line 257

def mode= new_mode
  unless [:horizontal, :vertical].include?(new_mode)
    raise ArgumentError, "invalid mode value #{new_mode}"
  end

  if new_mode != @mode
    @mode = new_mode
    relayout!
  end
end

#relayout!Object

TODO:

This method could be optimized quite a bit, I think.

Figure out how to layout all the subviews. This is the meat of the class.



375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
# File 'lib/hotcocoa/layout_view.rb', line 375

def relayout!
  view_size      = frameSize
  end_dimension  = vertical? ? view_size.height : view_size.width
  end_dimension -= (@margin * 2)
  dimension      = @margin

  expandable_size = calc_expandable_size(end_dimension)

  subviews.each do |view|
    next unless can_layout? view

    options = view.layout
    subview_size = view.frameSize
    view_frame = NSMakeRect(0, 0, *subview_size)
    subview_dimension = vertical? ? subview_size.height : subview_size.width

    if vertical?
      primary_dimension   = HEIGHT
      secondary_dimension = WIDTH
      primary_axis        = X
      secondary_axis      = Y
      expand_primary      = EXPAND_HEIGHT
      expand_secondary    = EXPAND_WIDTH
      padding_first       = LEFT_PADDING
      padding_second      = RIGHT_PADDING
      padding_third       = BOTTOM_PADDING
      padding_fourth      = TOP_PADDING
    else
      primary_dimension   = WIDTH
      secondary_dimension = HEIGHT
      primary_axis        = Y
      secondary_axis      = X
      expand_primary      = EXPAND_WIDTH
      expand_secondary    = EXPAND_HEIGHT
      padding_first       = TOP_PADDING
      padding_second      = BOTTOM_PADDING
      padding_third       = LEFT_PADDING
      padding_fourth      = RIGHT_PADDING
    end

    view_frame.origin.send("#{primary_axis}=", @margin)
    view_frame.origin.send("#{secondary_axis}=", (options.start? ? dimension : (end_dimension - subview_dimension)))

    if options.send(expand_primary)
      view_frame.size.send("#{primary_dimension}=", expandable_size)
      subview_dimension = expandable_size
    end

    if options.send(expand_secondary)
      view_frame.size.send("#{secondary_dimension}=",
              view_size.send(secondary_dimension) - (2 * @margin) -
                                options.send(padding_first) - options.send(padding_second))
    else

      case options.align
      when :left, :bottom
        # Nothing to do
      when :center
        view_frame.origin.send("#{primary_axis}=", (view_size.send(secondary_dimension) / 2.0) - (subview_size.send(secondary_dimension) / 2.0))

      when :right, :top
        view_frame.origin.send("#{primary_axis}=", view_size.send(secondary_dimension) -
                                  subview_size.send(secondary_dimension) - @margin)
      end
    end

    if $DEBUG
      puts "view #{view} options #{options.inspect} " +
           "final frame [#{view_frame.origin.x}, #{view_frame.origin.y}, "+
           "#{view_frame.size.width}x#{view_frame.size.height}]"
    end

    view_frame.origin.x += options.left_padding
    view_frame.origin.y += options.bottom_padding

    if options.start?
      dimension += subview_dimension + @spacing
      dimension += options.send(padding_third) + options.send(padding_fourth)
    else
      end_dimension -= subview_dimension + @spacing
    end

    view.frame = view_frame
  end
end

#remove_all_viewsObject

Remove all the subviews from the layout view.



340
341
342
343
# File 'lib/hotcocoa/layout_view.rb', line 340

def remove_all_views
  subviews.each { |view| view.removeFromSuperview }
  relayout!
end

#remove_view(view) ⇒ Object Also known as: remove

Remove a subview from the layout.

Parameters:

  • (NSView)


329
330
331
332
333
334
335
# File 'lib/hotcocoa/layout_view.rb', line 329

def remove_view view
  unless subviews.include? view
    raise ArgumentError, "view #{view} not a subview of this LayoutView"
  end
  view.removeFromSuperview
  relayout!
end

#setFrame(frame) ⇒ Object Also known as: frame=

This is a callback, you don't need to worry about it.



356
357
358
359
# File 'lib/hotcocoa/layout_view.rb', line 356

def setFrame frame
  super(frame, &nil)
  relayout!
end

#setFrameSize(size) ⇒ Object Also known as: size=

This is a callback, you don't need to worry about it.



364
365
366
367
# File 'lib/hotcocoa/layout_view.rb', line 364

def setFrameSize size
  super(size, &nil)
  relayout!
end

#vertical?Boolean

Whether or not the layout mode is vertical.

Returns:

  • (Boolean)


242
243
244
# File 'lib/hotcocoa/layout_view.rb', line 242

def vertical?
  @mode == :vertical
end