1 // ========================================================================== 2 // Project: SproutCore - JavaScript Application Framework 3 // Copyright: ©2006-2010 Sprout Systems, Inc. and contributors. 4 // Portions ©2008-2011 Apple Inc. All rights reserved. 5 // License: Licensed under MIT license (see license.js) 6 // ========================================================================== 7 8 /** @private 9 SC.SplitChild and SC.SplitThumb both share this code, but we don't want it 10 included twice if the view mixes in both SC.SplitChild and SC.SplitThumb. 11 */ 12 SC.NeedsSplitParent = { 13 14 /** 15 * The SplitView that contains the child views to be adjusted. 16 * 17 * This is computed to be the first SplitView found in a search 18 * up the view hierarchy. You can substitute your own SplitView 19 * 20 * @property SC.SplitView 21 */ 22 splitView: function () { 23 var view = this.get('parentView'); 24 while (view && !view.isSplitView) view = view.get('parentView'); 25 return view; 26 }.property('parentView').cacheable(), 27 28 /** 29 * The layoutDirection of the SplitView. This is observed so that we 30 * can update positioning if the layoutDirection changes but the position 31 * and size properties do not. 32 * 33 * @type {LayoutDirection} 34 */ 35 // NOTE: While an edge case, this is implemented because it makes it _much_ 36 // easier to write the sample in the Test Controls app. 37 splitViewLayoutDirection: null, 38 splitViewLayoutDirectionBinding: SC.Binding.oneWay('*splitView.layoutDirection') 39 40 }; 41 42 43 /** 44 @namespace 45 Child views of SplitViews should use this mixin to get their positioning 46 logic and default settings. 47 48 By default, SplitView merely sets the position and size properties on its 49 child views. This mixin observes the position and size properties and 50 calls adjust(). 51 */ 52 SC.SplitChild = 53 /** @scope SC.SplitChild.prototype */{ 54 /** 55 * Set to YES if your Split Child is a divider view. 56 * 57 * @type Boolean 58 */ 59 isSplitDivider: NO, 60 61 /** 62 * The minimum size for the SC.SplitView child. This view will 63 * be unable to be resized smaller than this size. 64 * 65 * @default 100 66 * 67 * @type {Number} 68 */ 69 minimumSize: 100, 70 71 /** 72 * The maximum size for the SC.SplitView child. This view will 73 * be unable to be resized to a size larger than this value. 74 * 75 * If undefined, there is no limit. 76 * 77 * @default 100 78 * 79 * @type {Number} 80 */ 81 maximumSize: undefined, 82 83 /** 84 * The current size of the SC.SplitView child. Use this to set the default 85 * size. 86 * 87 * If you specify a size, autoResizeStyle will default to SC.RESIZE_MANUAL; 88 * if you don't, SplitView will assume you want it to fill the available space 89 * and use SC.RESIZE_AUTOMATIC. 90 * 91 * @default undefined 92 * 93 * @type Number 94 */ 95 size: undefined, 96 97 /** 98 * [RO] The current position of the SC.SplitView. This is read-only, and is set 99 * by the SplitView as it positions the views. 100 * 101 * @type Number 102 */ 103 position: 0, 104 105 /** 106 * An amount to add to the position when adjusting layout. 107 * 108 * For example, if SC.SplitView positions this view at 100, and 109 * positionOffset is -5, the view's layout will will have a position of 95. 110 * 111 * This can be used in conjunction with sizeOffset to make dividers 112 * overlap the other views in the SplitView to have a larger grab area. 113 * 114 * TODO: Get this value from theme. 115 * 116 * @type Number 117 */ 118 positionOffset: SC.propertyFromRenderDelegate('splitPositionOffset', 0), 119 120 /** 121 * An amount to add to the assigned size when adjusting layout. 122 * 123 * For example, if SC.SplitView gives this view a size of 1, but the 124 * sizeOffset is 10, the view's layout will be given a width or height of 11. 125 * 126 * This can be used in conjunction with positionOffset to make dividers 127 * overlap the other views in the SplitView to have a larger grab area. 128 * 129 * TODO: Get this value from theme. 130 * 131 * @type Number 132 */ 133 sizeOffset: SC.propertyFromRenderDelegate('splitSizeOffset', 0), 134 135 /** 136 * If YES, the SC.SplitView can collapse this view when the user 137 * double-clicks an adjacent divider, or when the view is resized 138 * to a size smaller than the collapseAtSize. 139 * 140 * @type {Boolean} 141 */ 142 canCollapse: NO, 143 144 /** 145 * If the user attempts to resize the view to a size below this number, 146 * the view will collapse. 147 * 148 * If undefined, the view cannot be collapsed due to a resize. 149 * 150 * @type {Number} 151 */ 152 collapseAtSize: undefined, 153 154 /** 155 * When (and if) the view should automatically resize due to the SplitView changing size. 156 * 157 * - SC.RESIZE_AUTOMATIC: always resize when the SplitView changes size. 158 * - SC.RESIZE_MANUAL: resize only when the user moves a divider, or all 159 * SC.RESIZE_AUTOMATIC views have already been resized as much as possible. 160 * - SC.FIXED_SIZE: Never resize. 161 * 162 * If you specify an autoResizeStyle, it will be used. If you leave it at `undefined`, 163 * it will look at `size`: if a `size` is supplied, it will use `SC.RESIZE_MANUAL`; otherwise 164 * it will use `SC.RESIZE_AUTOMATIC`. 165 * 166 * @default based on size 167 * @type {AutoResizeStyle} 168 */ 169 autoResizeStyle: undefined, 170 171 /** 172 * If NO, moving the divider before this view will not resize the view, but 173 * instead, move it—causing further views to move as well. Most SplitView 174 * children will want this set to YES. 175 * 176 * @type Boolean 177 */ 178 compensatesForMovement: YES, 179 180 /** 181 * When NO, the view can only be adjusted when the user drags a divider 182 * immediately adjacent to it. If YES, the view can be adjusted indirectly 183 * from earlier dividers as well. 184 * 185 * For example, assume you have a 3-pane setup. Increasing the size of left pane will 186 * resize the middle one until its minimum size is reached. SplitView will then 187 * try to adjust the right pane. If the right pane has allowsIndirectAdjustments 188 * set to YES, SplitView will shrink the right pane to make way. If NO, the 189 * left pane will be unable to resize further. 190 * 191 * Default: YES. 192 * 193 * @type {Boolean} 194 */ 195 allowsIndirectAdjustments: YES, 196 197 /** @private Include SC.NeedsSplitParent if it hasn't already been included. */ 198 initMixin: function () { 199 if (!this.splitView) { 200 this.mixin(SC.NeedsSplitParent); 201 } 202 }, 203 204 // 205 // Positioning logic 206 // 207 _scsvc_positionOrSizeDidChange: function() { 208 this.invokeOnce('splitChildLayoutDidChange'); 209 }.observes('position', 'size'), 210 211 /** 212 * Called when either the position or size of the child has changed, and layout 213 * needs to be updated accordingly. You may override this method to take into 214 * account any custom layout. The default handles the position- and sizeOffset 215 * properties by adding them to the position and size, respectively. 216 * 217 * For instance, while the default implementation changes left/right/width/height 218 * to fill in one direction and fit in the allocated position in the other, you could 219 * make it only set left/width or top/height. 220 * 221 */ 222 splitChildLayoutDidChange: function() { 223 var split = this.get('splitView'); 224 if (!split) return; 225 226 var position = this.get('position') + this.get('positionOffset'), 227 size = this.get('size') + this.get('sizeOffset'); 228 229 230 if (split.get('layoutDirection') === SC.LAYOUT_HORIZONTAL) { 231 this.set('layout', { 232 left: position, 233 width: size, 234 top: 0, bottom: 0 235 }); 236 } else { 237 this.set('layout', { 238 top: position, 239 height: size, 240 right: 0, left: 0 241 }); 242 } 243 }, 244 245 splitViewLayoutDirectionDidChange: function() { 246 this.invokeOnce('splitChildLayoutDidChange'); 247 }.observes('splitViewLayoutDirection') 248 }; 249