// ========================================================================== // Project: SproutCore - JavaScript Application Framework // Copyright: ©2006-2011 Strobe Inc. and contributors. // Portions ©2008-2011 Apple Inc. All rights reserved. // License: Licensed under MIT license (see license.js) // ==========================================================================

sc_require(“views/toolbar”);

/** @class

WorkspaceView manages a content view and two optional toolbars (top and bottom).
You want to use WorkspaceView in one of two situations: iPhone apps where the toolbars
need to change size automatically based on orientation (this does that, isn't that
handy!) and iPad apps where you would like the masterIsHidden property to pass through.

@since SproutCore 1.2
@extends SC.View
@author Alex Iskander

*/ SC.WorkspaceView = SC.View.extend( /** @scope SC.WorkspaceView.prototype */ {

/**
  @type Array
  @default ['sc-workspace-view']
  @see SC.View#classNames
*/
classNames: ["sc-workspace-view"],

/**
  @type Array
  @default "hasTopToolbar hasBottomToolbar".w()
  @see SC.View#displayProperties
*/
displayProperties: ["hasTopToolbar", "hasBottomToolbar"],

/**
  @type String
  @default 'workspaceRenderDelegate'
*/
renderDelegateName: 'workspaceRenderDelegate',

/**
  @type SC.View
  @default SC.ToolbarView
*/
topToolbar: SC.ToolbarView.extend(),

/**
  @type SC.View
  @default null
*/
bottomToolbar: null,

/**
  The content. Must NOT be null.

  @type SC.View
  @default SC.View
*/
contentView: SC.View.extend(),

/**
  If you want to automatically resize the toolbars like iPhone
  apps should, set to YES.

  @type Boolean
  @default NO
*/
autoResizeToolbars: NO,

/**
  @type Number
  @default 44
*/
defaultToolbarSize: 44,

/**
  @type Number
  @default 44
*/
largeToolbarSize: 44,

/**
  @type Number
  @default 30
*/
smallToolbarSize: 30,

/**
  @field
  @type Number
*/
toolbarSize: function() {
  if (!this.get("autoResizeToolbars")) return this.get("defaultToolbarSize");
  if (this.get("orientation") === SC.HORIZONTAL_ORIENTATION) return this.get("smallToolbarSize");
  return this.get("largeToolbarSize");
}.property("autoHideMaster", "orientation"),

/**
  Tracks the orientation of the view. Possible values:

    - SC.HORIZONTAL_ORIENTATION
    - SC.PORTRAIT_ORIENTATION

  @field
  @type String
  @default SC.HORIZONTAL_ORIENTATION
*/
orientation: function() {
  var f = this.get("frame");
  if (f.width > f.height) return SC.HORIZONTAL_ORIENTATION;
  else return SC.VERTICAL_ORIENTATION;
}.property("frame").cacheable(),

/**
  @type Boolean
  @default NO
*/
masterIsHidden: NO,

/** @private */
masterIsHiddenDidChange: function() {
  var t, mih = this.get("masterIsHidden");
  if (t = this.get("topToolbar")) t.set("masterIsHidden", mih);
  if (t = this.get("bottomToolbar")) t.set("masterIsHidden", mih);
}.observes("masterIsHidden"),

/// INTERNAL CODE. HERE, THERE BE MONSTERS!

/**
  @private
  Whenever something that affects the tiling changes (for now, just toolbarSize, but if
  we allow dynamic changing of toolbars in future, this could include toolbars themselves),
  we need to update the tiling.
*/
_scmd_tilePropertyDidChange: function() {
  this.invokeOnce("_scws_tile");
}.observes("toolbarSize"),

/** @private
  Creates the child views. Specifically, instantiates master and detail views.
*/
createChildViews: function() {
  sc_super();

  var topToolbar = this.get("topToolbar");
  if (topToolbar) {
    topToolbar = this.topToolbar = this.activeTopToolbar = this.createChildView(topToolbar);
    this.appendChild(topToolbar);
  }

  var bottomToolbar = this.get("bottomToolbar");
  if (bottomToolbar) {
    bottomToolbar = this.bottomToolbar = this.activeBottomToolbar = this.createChildView(bottomToolbar);
    this.appendChild(bottomToolbar);
  }

  var content = this.get("contentView");
  content = this.contentView = this.activeContentView = this.createChildView(content);
  this.appendChild(content);

  this.invokeOnce("_scws_tile");
},

/**
  @private
  Tiles the views as necessary.
*/
_scws_tile: function() {
  var contentTop = 0, contentBottom = 0,
      topToolbar = this.get("topToolbar"),
      bottomToolbar = this.get("bottomToolbar"),
      content = this.get("contentView"),
      toolbarSize = this.get("toolbarSize");

    // basically, if there is a top toolbar, we position it and change contentTop.
  if (topToolbar) {
    topToolbar.set("layout", {
      left: 0, right: 0, top: 0, height: toolbarSize
    });
    contentTop += toolbarSize;
  }

  // same for bottom
  if (bottomToolbar) {
    bottomToolbar.set("layout", {
      left: 0, right: 0, bottom: 0, height: toolbarSize
    });
    contentBottom += toolbarSize;
  }

  // finally, position content
  this.contentView.set("layout", {
    left: 0, right: 0, top: contentTop, bottom: contentBottom
  });
},

/** @private
  Returns YES if a top toolbar is present.
*/
hasTopToolbar: function() {
  if (this.get("topToolbar")) return YES;
  return NO;
}.property("topToolbar").cacheable(),

/** @private
  Returns YES if a bottom toolbar is present.
*/
hasBottomToolbar: function() {
  if (this.get("bottomToolbar")) return YES;
  return NO;
}.property("bottomToolbar").cacheable(),

/** @private
  Called by the individual toolbar/contentView observers at runloop end when the toolbars change.
*/
childDidChange: function() {
  this._scws_tile();
},

/** @private
  For subclassing, this is the currently displaying top toolbar.
*/
activeTopToolbar: null,

/** @private
  For subclassing, this is the currently displaying bottom toolbar.
*/
activeBottomToolbar: null,

/** @private
  For subclassing, this is the currently displaying content view.
*/
activeContentView: null,

/** @private
  Called when the top toolbar changes. It appends it, removes any old ones, and calls toolbarsDidChange.

  You may want to override this if, for instance, you want to add transitions of some sort (should be trivial).
*/
topToolbarDidChange: function() {
  var active = this.activeTopToolbar, replacement = this.get("topToolbar");
  if (active) {
    if (active.createdByParent) {
      container.removeChildAndDestroy(active);
    } else {
      container.removeChild(active);
    }
  }
  if (replacement) {
    this.appendChild(replacement);
  }

  this.activeTopToolbar = replacement;
  this.invokeLast("childDidChange");
}.observes("topToolbar"),

/**
  @private
*/
bottomToolbarDidChange: function() {
  var active = this.activeBottomToolbar, replacement = this.get("bottomToolbar");
  if (active) {
    if (active.createdByParent) {
      container.removeChildAndDestroy(active);
    } else {
      container.removeChild(active);
    }
  }
  if (replacement) {
    this.appendChild(replacement);
  }

  this.activeBottomToolbar = replacement;
  this.invokeLast("childDidChange");
}.observes("bottomToolbar"),

/** @private */
contentViewDidChange: function() {
  var active = this.activeContentView, replacement = this.get("contentView");
  if (active) {
    if (active.createdByParent) {
      container.removeChildAndDestroy(active);
    } else {
      container.removeChild(active);
    }
  }
  if (replacement) {
    this.appendChild(replacement);
  }

  this.activeContentView = replacement;
  this.invokeLast("childDidChange");
}.observes("contentView")

});