1 /** 2 * The Render Engine 3 * FieldGroup 4 * 5 * @fileoverview A group of UI controls. 6 * 7 * @author: Brett Fattori (brettf@renderengine.com) 8 * 9 * @author: $Author: bfattori $ 10 * @version: $Revision: 1555 $ 11 * 12 * Copyright (c) 2011 Brett Fattori (brettf@renderengine.com) 13 * 14 * Permission is hereby granted, free of charge, to any person obtaining a copy 15 * of this software and associated documentation files (the "Software"), to deal 16 * in the Software without restriction, including without limitation the rights 17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 * copies of the Software, and to permit persons to whom the Software is 19 * furnished to do so, subject to the following conditions: 20 * 21 * The above copyright notice and this permission notice shall be included in 22 * all copies or substantial portions of the Software. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 * THE SOFTWARE. 31 * 32 */ 33 34 // The class this file defines and its required classes 35 R.Engine.define({ 36 "class":"R.ui.FieldGroup", 37 "requires":[ 38 "R.ui.AbstractUIControl", 39 "R.struct.Container" 40 ] 41 }); 42 43 /** 44 * @class A physical grouping of UI controls. 45 * 46 * @constructor 47 * @param label {String} The label for the field group. 48 * @extends R.ui.AbstractUIControl 49 */ 50 R.ui.FieldGroup = function () { 51 return R.ui.AbstractUIControl.extend(/** @scope R.ui.FieldGroup.prototype */{ 52 53 label:null, 54 labelPosition:0, 55 controls:null, 56 57 /** @private */ 58 constructor:function (label, textRenderer) { 59 this.base("FieldGroup", textRenderer); 60 this.addClass("fieldgroup"); 61 this.setLabel(label || ""); 62 this.labelPosition = R.ui.FieldGroup.LABEL_TOPLEFT; 63 this.controls = R.struct.Container.create("UIControls"); 64 }, 65 66 /** 67 * Destroy the text input control, releasing its event handlers. 68 */ 69 destroy:function () { 70 this.base(); 71 this.controls.cleanUp(); 72 }, 73 74 /** 75 * Releases the object back into the object pool. See {@link R.engine.PooledObject#release} 76 * for more information. 77 */ 78 release:function () { 79 this.base(); 80 this.label = null; 81 this.labelPosition = R.ui.FieldGroup.LABEL_TOPLEFT; 82 this.controls = null; 83 }, 84 85 /** 86 * Set the label for the field group, or an empty string to show no label. 87 * @param label {String} The label 88 */ 89 setLabel:function (label) { 90 this.label = label; 91 }, 92 93 /** 94 * Get the field group label. 95 * @return {String} 96 */ 97 getLabel:function () { 98 return this.label; 99 }, 100 101 /** 102 * Add a control to this field group. 103 * @param uiControl {R.ui.AbstractUIControl} The control to add 104 */ 105 addControl:function (uiControl) { 106 Assert(uiControl instanceof R.ui.AbstractUIControl, "You can only add UI controls to a field group"); 107 this.controls.add(uiControl); 108 }, 109 110 /** 111 * Remove a control from this field group. 112 * @param uiControl {R.ui.AbstractUIControl} The control to remove 113 * @return {R.ui.AbstractUIControl} The control removed 114 */ 115 removeControl:function (uiControl) { 116 return this.controls.remove(uiControl); 117 }, 118 119 /** 120 * Get the first control, within the field group, which has the specified name, 121 * or <code>null</code> if no control with the name is in the group. 122 * @param controlName {String} The name of the control to get 123 * @return {R.ui.AbstractUIControl} The control, or <code>null</code> 124 */ 125 getControlByName:function (controlName) { 126 var controls = this.controls.filter(function (c) { 127 return (c.getControlName() === controlName); 128 }); 129 if (controls.length != 0) { 130 return controls[0]; 131 } else { 132 return null; 133 } 134 }, 135 136 /** 137 * Draw the field group within the context. 138 * @param renderContext {R.rendercontexts.RenderContext2D} The render context where the control is 139 * drawn. 140 * @param worldTime {Number} The current world time, in milliseconds 141 * @param dt {Number} The time since the last frame was drawn by the engine, in milliseconds 142 */ 143 drawControl:function (renderContext, worldTime, dt) { 144 // Draw the current input text. The text baseline is the bottom of the font, 145 // so we need to move that down by the height of the control (with some padding to look right) 146 renderContext.pushTransform(); 147 148 if (this.label != "") { 149 this.getTextRenderer().setText(this.label); 150 151 // Draw the label 152 var labelPos = R.math.Point2D.create(0, 0), wBox = R.clone(this.getWorldBox()), 153 textWidth = this.getTextRenderer().getBoundingBox().w, 154 textHeight = this.getTextRenderer().getBoundingBox().h; 155 switch (this.labelPosition) { 156 case R.ui.FieldGroup.LABEL_TOPLEFT: 157 labelPos.x = wBox.x + 10; 158 labelPos.y = wBox.y + 1; 159 break; 160 case R.ui.FieldGroup.LABEL_TOPRIGHT: 161 labelPos.x = (wBox.x + wBox.w) - (textWidth + 10); 162 labelPos.y = wBox.y + 1; 163 break; 164 case R.ui.FieldGroup.LABEL_BOTTOMLEFT: 165 labelPos.x = wBox.x + 10; 166 labelPos.y = (wBox.y + wBox.h) + textHeight - 2; 167 break; 168 case R.ui.FieldGroup.LABEL_BOTTOMRIGHT: 169 labelPos.x = (wBox.x + wBox.w) - (textWidth + 10); 170 labelPos.y = (wBox.y + wBox.h) + textHeight - 2; 171 break; 172 } 173 174 renderContext.pushTransform(); 175 renderContext.setPosition(labelPos); 176 this.getTextRenderer().update(renderContext, worldTime, dt); 177 renderContext.popTransform(); 178 179 labelPos.destroy(); 180 wBox.destroy(); 181 } 182 183 // Render the controls in the group 184 var itr = this.controls.iterator(); 185 while (itr.hasNext()) { 186 var control = itr.next(); 187 if (control.getRenderContext() == null) { 188 control.setRenderContext(renderContext); 189 } 190 control.update(renderContext, worldTime, dt); 191 } 192 itr.destroy(); 193 194 renderContext.popTransform(); 195 } 196 197 }, /** @scope R.ui.FieldGroup.prototype */{ 198 199 LABEL_TOPLEFT:0, 200 201 LABEL_TOPRIGHT:1, 202 203 LABEL_BOTTOMLEFT:2, 204 205 LABEL_BOTTOMRIGHT:3, 206 207 /** 208 * Get the class name of this object 209 * @return {String} The string "R.ui.FieldGroup" 210 */ 211 getClassName:function () { 212 return "R.ui.FieldGroup"; 213 }, 214 215 /** 216 * Get a properties object with values for the given object. 217 * @param obj {R.ui.FieldGroup} The field group to query 218 * @param [defaults] {Object} Default values that don't need to be serialized unless 219 * they are different. 220 * @return {Object} 221 */ 222 serialize:function (obj, defaults) { 223 var fg = R.ui.AbstractUIControl.serialize(obj, defaults), 224 itr = obj.controls.iterator(); 225 226 fg.CONTROLS = {}; 227 while (itr.hasNext()) { 228 var control = itr.next(); 229 fg.CONTROLS[control.getControlName()] = control.constructor.serialize(control); 230 } 231 itr.destroy(); 232 return fg; 233 }, 234 235 /** 236 * Deserialize the object back into a field group. 237 * @param obj {Object} The object to deserialize 238 * @param [clazz] {Class} The object class to populate 239 * @return {R.ui.ButtonControl} The object which was deserialized 240 */ 241 deserialize:function (obj, clazz) { 242 // Get the controls for the group 243 var controls; 244 if (obj.CONTROLS) { 245 controls = obj.CONTROLS; 246 delete obj.CONTROLS; 247 } 248 249 // Now we can deserialize the class 250 clazz = clazz || R.ui.FieldGroup.create(); 251 R.ui.AbstractUIControl.deserialize(obj, clazz); 252 253 // Re-populate the controls into the form 254 for (var c in controls) { 255 // Grab the classname field so we can recreate the object 256 var control = controls[c], controlClazz = R.classForName(control.CLASSNAME), 257 uiControl = controlClazz.deserialize(control); 258 259 // Add the control which was deserialized 260 clazz.addControl(uiControl); 261 } 262 263 return clazz; 264 } 265 }); 266 267 };