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)


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

def frame_color
  @frame_color
end

#marginFixnum

Returns:

  • (Fixnum)


400
401
402
# File 'lib/hotcocoa/layout_view.rb', line 400

def margin
  @margin
end

#spacingFixnum

Returns:

  • (Fixnum)


386
387
388
# File 'lib/hotcocoa/layout_view.rb', line 386

def spacing
  @spacing
end

Instance Method Details

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

Add a new subview to the layout view.

Parameters:

  • (NSView)


417
418
419
420
421
422
423
424
# File 'lib/hotcocoa/layout_view.rb', line 417

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



381
382
383
# File 'lib/hotcocoa/layout_view.rb', line 381

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)


375
376
377
378
379
# File 'lib/hotcocoa/layout_view.rb', line 375

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.



449
450
451
452
453
454
# File 'lib/hotcocoa/layout_view.rb', line 449

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)


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

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>)


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

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)


359
360
361
362
363
364
365
366
367
368
# File 'lib/hotcocoa/layout_view.rb', line 359

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.



477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
# File 'lib/hotcocoa/layout_view.rb', line 477

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.



442
443
444
445
# File 'lib/hotcocoa/layout_view.rb', line 442

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)


431
432
433
434
435
436
437
# File 'lib/hotcocoa/layout_view.rb', line 431

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.



458
459
460
461
# File 'lib/hotcocoa/layout_view.rb', line 458

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.



466
467
468
469
# File 'lib/hotcocoa/layout_view.rb', line 466

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

#vertical?Boolean

Whether or not the layout mode is vertical.

Returns:

  • (Boolean)


344
345
346
# File 'lib/hotcocoa/layout_view.rb', line 344

def vertical?
  @mode == :vertical
end