1 /* 2 * JSViewFactory.js 3 * 4 * Sweet Home 3D, Copyright (c) 2024 Space Mushrooms <info@sweethome3d.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21 // Requires SweetHome3D.js 22 // Requires UserPreferences.js 23 // Requires FurnitureCatalogListPanel.js 24 // Requires PlanComponent.js 25 // Requires HomeComponent3D.js 26 // Requires HomePane.js 27 28 /** 29 * A view default factory that is use to create all the views in the application. 30 * @constructor 31 * @author Emmanuel Puybaret 32 * @author Renaud Pawlak 33 * @author Louis Grignon 34 */ 35 function JSViewFactory(application) { 36 this.application = application; 37 } 38 JSViewFactory.prototype = Object.create(JSViewFactory.prototype); 39 JSViewFactory.prototype.constructor = JSViewFactory; 40 41 JSViewFactory["__class"] = "JSViewFactory"; 42 JSViewFactory["__interfaces"] = ["com.eteks.sweethome3d.viewcontroller.ViewFactory"]; 43 44 45 JSViewFactory.dummyDialogView = { 46 displayView: function(parent) { 47 // Do nothing 48 } 49 } 50 51 JSViewFactory.prototype.createFurnitureCatalogView = function(catalog, preferences, furnitureCatalogController) { 52 return new FurnitureCatalogListPanel("furniture-catalog", catalog, preferences, furnitureCatalogController); 53 } 54 55 /** 56 * @param {Home} home 57 * @param {UserPreferences} preferences 58 * @param {FurnitureController} controller 59 * @return {FurnitureListPanel | undefined} undefined if DOM element #furniture-view is not found (feature is disabled) 60 */ 61 JSViewFactory.prototype.createFurnitureView = function(home, preferences, controller) { 62 if (document.getElementById("furniture-view") != null) { 63 return new FurnitureTablePanel("furniture-view", home, preferences, controller); 64 } else { 65 return undefined; 66 } 67 } 68 69 JSViewFactory.prototype.createPlanView = function(home, preferences, planController) { 70 return new PlanComponent("home-plan", home, preferences, planController); 71 } 72 73 JSViewFactory.prototype.createView3D = function(home, preferences, homeController3D) { 74 return new HomeComponent3D("home-3D-view", home, preferences, null, homeController3D); 75 } 76 77 JSViewFactory.prototype.createHomeView = function(home, preferences, homeController) { 78 return new HomePane("home-pane", home, preferences, homeController); 79 } 80 81 /** 82 * Returns a new view that displays a wizard. 83 * @param {UserPreferences} preferences the current user preferences 84 * @param {WizardController} controller wizard's controller 85 */ 86 JSViewFactory.prototype.createWizardView = function(preferences, controller) { 87 return new JSWizardDialog(preferences, controller, 88 controller.getTitle() || "@{WizardPane.wizard.title}", 89 { 90 }); 91 } 92 93 JSViewFactory.prototype.createBackgroundImageWizardStepsView = function(backgroundImage, preferences, controller) { 94 var LARGE_IMAGE_PIXEL_COUNT_THRESHOLD = 10000000; 95 var LARGE_IMAGE_MAX_PIXEL_COUNT = 8000000; 96 var CANVAS_TOUCHABLE_AREA_RADIUS = 10; 97 98 function BackgroundImageWizardStepsView() { 99 JSComponent.call(this, preferences, 100 "<div choiceStep>" 101 + " <div description>@{BackgroundImageWizardStepsPanel.imageChangeLabel.text}</div>" 102 + " <div class='buttons'>" 103 + " <button selectImage></button>" 104 + " <input type='file' accept='image/*' style='display: none' />" 105 + " </div>" 106 + " <div preview>" 107 + " <img />" 108 + " </div>" 109 + "</div>" 110 + "<div scaleStep>" 111 + " <div>@{BackgroundImageWizardStepsPanel.scaleLabel.text}</div>" 112 + " <br />" 113 + " <div>" 114 + " <span data-name='scale-distance-label'></span>" 115 + " <span data-name='scale-distance-input'></span>" 116 + " </div>" 117 + " <br />" 118 + " <div class='preview-panel'>" 119 + " <div preview>" 120 + " <canvas />" 121 + " </div>" 122 + " <div class='preview-controls' style='z-index:5'>" 123 + " <div previewZoomIn></div>" 124 + " <br />" 125 + " <div previewZoomOut></div>" 126 + " </div>" 127 + " </div>" 128 + "</div>" 129 + "<div originStep>" 130 + " <div>@{BackgroundImageWizardStepsPanel.originLabel.text}</div>" 131 + " <br />" 132 + " <div>" 133 + " <span data-name='x-origin-label'></span>" 134 + " <span data-name='x-origin-input'></span>" 135 + " <span data-name='y-origin-label'></span>" 136 + " <span data-name='y-origin-input'></span>" 137 + " </div>" 138 + " <br />" 139 + " <div class='preview-panel'>" 140 + " <div preview>" 141 + " <canvas />" 142 + " </div>" 143 + " <div class='preview-controls' style='z-index:5'>" 144 + " <div previewZoomIn></div>" 145 + " <br />" 146 + " <div previewZoomOut></div>" 147 + " </div>" 148 + " </div>" 149 + "</div>"); 150 151 this.controller = controller; 152 this.getHTMLElement().classList.add("background-image-wizard"); 153 154 this.initImageChoiceStep(); 155 this.initScaleStep(); 156 this.initOriginStep(); 157 158 var component = this; 159 this.registerPropertyChangeListener(controller, "STEP", function(ev) { 160 component.updateStep(); 161 component.repaintOriginCanvas(); 162 }); 163 this.registerPropertyChangeListener(controller, "IMAGE", function(ev) { 164 component.updatePreviewComponentsImage(); 165 }); 166 167 this.updateImage(backgroundImage); 168 } 169 BackgroundImageWizardStepsView.prototype = Object.create(JSComponent.prototype); 170 BackgroundImageWizardStepsView.prototype.constructor = BackgroundImageWizardStepsView; 171 172 BackgroundImageWizardStepsView.prototype.buildHtmlFromTemplate = function(templateHtml) { 173 return JSComponent.prototype.buildHtmlFromTemplate.call(this, templateHtml).replace(/\<br\>/g, " "); 174 } 175 176 /** 177 * @private 178 */ 179 BackgroundImageWizardStepsView.prototype.initImageChoiceStep = function () { 180 var component = this; 181 component.imageChoiceStep = { 182 panel: component.findElement("[choiceStep]"), 183 imageChoiceOrChangeLabel: component.findElement("[choiceStep] [description]"), 184 imageChoiceOrChangeButton: component.findElement("[choiceStep] [selectImage]"), 185 imageChooser: component.findElement("[choiceStep] input[type='file']"), 186 preview: component.findElement("[choiceStep] [preview] img"), 187 }; 188 var imageErrorListener = function(ev) { 189 console.warn("Error loading image: " + ev); 190 component.controller.setImage(null); 191 component.setImageChoiceTexts(); 192 component.updatePreviewComponentsImage(); 193 alert(ResourceAction.getLocalizedLabelText(preferences, "BackgroundImageWizardStepsPanel", 194 "imageChoiceErrorLabel.text")); 195 }; 196 component.registerEventListener(component.imageChoiceStep.imageChoiceOrChangeButton, "click", function(ev) { 197 component.imageChoiceStep.imageChooser.click(); 198 }); 199 200 var importImage = function(file) { 201 if (file) { 202 var reader = new FileReader(); 203 // Use onload and onerror rather that addEventListener for Cordova support 204 reader.onload = function(ev) { 205 var image = new Image(); 206 image.addEventListener("load", function(ev) { 207 component.updateController(image, file); 208 }); 209 image.addEventListener("error", imageErrorListener); 210 image.src = ev.target.result; 211 }; 212 reader.onerror = imageErrorListener; 213 reader.readAsDataURL(file); 214 } 215 }; 216 component.registerEventListener(component.imageChoiceStep.imageChooser, "input", function(ev) { 217 importImage(this.files[0]); 218 }); 219 component.registerEventListener(component.imageChoiceStep.preview, "drop", function(ev) { 220 ev.preventDefault(); 221 importImage(ev.dataTransfer.files[0]); 222 }); 223 component.registerEventListener(component.imageChoiceStep.preview, "dragover", function(ev) { 224 ev.preventDefault(); 225 }); 226 } 227 228 /** 229 * @private 230 */ 231 BackgroundImageWizardStepsView.prototype.initScaleStep = function () { 232 var component = this; 233 var unitName = preferences.getLengthUnit().getName(); 234 var maximumLength = preferences.getLengthUnit().getMaximumLength(); 235 236 component.scaleStep = { 237 panel: component.findElement("[scaleStep]"), 238 preview: component.findElement("[scaleStep] [preview] canvas"), 239 previewZoomIn: component.findElement("[scaleStep] [previewZoomIn]"), 240 previewZoomOut: component.findElement("[scaleStep] [previewZoomOut]"), 241 scaleDistanceLabel: component.getElement("scale-distance-label"), 242 scaleDistanceInput: new JSSpinner(preferences, component.getElement("scale-distance-input"), 243 { 244 format: preferences.getLengthUnit().getFormat(), 245 minimum: preferences.getLengthUnit().getMinimumLength(), 246 maximum: maximumLength, 247 stepSize: preferences.getLengthUnit().getStepSize() 248 }), 249 }; 250 251 component.scaleStep.scaleDistanceLabel.textContent = this.getLocalizedLabelText( 252 "BackgroundImageWizardStepsPanel", "scaleDistanceLabel.text", unitName); 253 component.registerEventListener(component.scaleStep.scaleDistanceInput, "input", function(ev) { 254 controller.setScaleDistance(component.scaleStep.scaleDistanceInput.getValue() != null 255 ? parseFloat(component.scaleStep.scaleDistanceInput.getValue()) 256 : null); 257 }); 258 var scaleDistanceChangeListener = function() { 259 var scaleDistance = controller.getScaleDistance(); 260 component.scaleStep.scaleDistanceInput.setNullable(scaleDistance === null); 261 component.scaleStep.scaleDistanceInput.setValue(scaleDistance); 262 }; 263 scaleDistanceChangeListener(); 264 this.registerPropertyChangeListener(controller, "SCALE_DISTANCE", scaleDistanceChangeListener); 265 266 var zoomInButtonAction = new ResourceAction(preferences, "BackgroundImageWizardStepsPanel", "ZOOM_IN", true); 267 var zoomOutButtonAction = new ResourceAction(preferences, "BackgroundImageWizardStepsPanel", "ZOOM_OUT", true); 268 component.scaleStep.previewZoomIn.style.backgroundImage = "url('" + zoomInButtonAction.getURL(AbstractAction.SMALL_ICON) + "')"; 269 component.registerEventListener(component.scaleStep.previewZoomIn, "click", function(ev) { 270 component.scaleStep.preview.width *= 2; 271 component.repaintScaleCanvas(); 272 }); 273 component.scaleStep.previewZoomOut.style.backgroundImage = "url('" + zoomOutButtonAction.getURL(AbstractAction.SMALL_ICON) + "')"; 274 component.registerEventListener(component.scaleStep.previewZoomOut, "click", function(ev) { 275 component.scaleStep.preview.width /= 2; 276 component.repaintScaleCanvas(); 277 }); 278 this.registerPropertyChangeListener(controller, "SCALE_DISTANCE_POINTS", function() { 279 component.repaintScaleCanvas(); 280 }); 281 282 component.repaintScaleCanvas(); 283 284 var canvas = this.scaleStep.preview; 285 canvas.style.touchAction = "none"; 286 287 var mouseUp = function(ev) { 288 if (canvas.dragging) { 289 canvas.dragging = false; 290 canvas.distanceStartPoint = canvas.distanceEndPoint = false; 291 } 292 }; 293 var mouseMove = function(ev) { 294 ev.stopImmediatePropagation(); 295 296 var canvasRect = canvas.getBoundingClientRect(); 297 var pointerCoordinatesObject = ev.touches && ev.touches.length > 0 ? ev.touches[0] : ev; 298 var x = pointerCoordinatesObject.clientX - canvasRect.left; 299 var y = pointerCoordinatesObject.clientY - canvasRect.top; 300 301 if (canvas.dragging) { 302 var scale = canvas.width / component.selectedImage.width; 303 var newX = x / scale; 304 var newY = y / scale; 305 var scaleDistancePoints = controller.getScaleDistancePoints(); 306 var updatedPoint; 307 var fixedPoint; 308 if (canvas.distanceStartPoint) { 309 updatedPoint = scaleDistancePoints [0]; 310 fixedPoint = scaleDistancePoints [1]; 311 } else { 312 updatedPoint = scaleDistancePoints [1]; 313 fixedPoint = scaleDistancePoints [0]; 314 } 315 // Accept new points only if distance is greater that 2 pixels 316 if (java.awt.geom.Point2D.distanceSq(fixedPoint [0] * scale, fixedPoint [1] * scale, 317 newX * scale, newY * scale) >= 4) { 318 // If shift is down constrain keep the line vertical or horizontal 319 if (ev.shiftKey) { 320 var angle = Math.abs(Math.atan2(fixedPoint [1] - newY, newX - fixedPoint [0])); 321 if (angle > Math.PI / 4 && angle <= 3 * Math.PI / 4) { 322 newX = fixedPoint [0]; 323 } else { 324 newY = fixedPoint [1]; 325 } 326 } 327 updatedPoint [0] = newX; 328 updatedPoint [1] = newY; 329 controller.setScaleDistancePoints( 330 scaleDistancePoints[0][0], scaleDistancePoints[0][1], 331 scaleDistancePoints[1][0], scaleDistancePoints[1][1]); 332 component.repaintScaleCanvas(); 333 } 334 } else { 335 canvas.distanceStartPoint = 336 canvas.distanceEndPoint = false; 337 338 var scaleDistancePoints = controller.getScaleDistancePoints(); 339 var scale = canvas.width / component.selectedImage.width; 340 // Check if user clicked on start or end point of distance line 341 if (Math.abs(scaleDistancePoints [0][0] * scale - x) <= CANVAS_TOUCHABLE_AREA_RADIUS 342 && Math.abs(scaleDistancePoints [0][1] * scale - y) <= CANVAS_TOUCHABLE_AREA_RADIUS) { 343 canvas.distanceStartPoint = true; 344 } else if (Math.abs(scaleDistancePoints [1][0] * scale - x) <= CANVAS_TOUCHABLE_AREA_RADIUS 345 && Math.abs(scaleDistancePoints [1][1] * scale - y) <= CANVAS_TOUCHABLE_AREA_RADIUS) { 346 canvas.distanceEndPoint = true; 347 } 348 349 if (canvas.distanceStartPoint || canvas.distanceEndPoint) { 350 canvas.style.cursor = "crosshair"; 351 } else { 352 canvas.style.cursor = "default"; 353 } 354 } 355 }; 356 var mouseDown = function(ev) { 357 ev.stopImmediatePropagation(); 358 mouseMove(ev); 359 360 if (canvas.distanceStartPoint || canvas.distanceEndPoint) { 361 canvas.dragging = true; 362 } 363 }; 364 365 this.registerEventListener(canvas, "mousedown", mouseDown, true); 366 this.registerEventListener(canvas, "touchstart", mouseDown, true); 367 this.registerEventListener(canvas, "mousemove", mouseMove, true); 368 this.registerEventListener(canvas, "touchmove", mouseMove, true); 369 this.registerEventListener(canvas, "mouseup", mouseUp, true); 370 this.registerEventListener(canvas, "touchend", mouseUp, true); 371 } 372 373 /** 374 * @private 375 */ 376 BackgroundImageWizardStepsView.prototype.repaintScaleCanvas = function () { 377 var canvas = this.scaleStep.preview; 378 var g2D = new Graphics2D(canvas); 379 g2D.fillRect(0, 0, canvas.width, canvas.height); 380 var image = this.selectedImage; 381 if (image) { 382 canvas.height = (image.height / image.width) * canvas.width; 383 g2D.drawImageWithSize(image, 0, 0, canvas.width, canvas.height); 384 g2D.setColor("blue"); 385 var oldTransform = g2D.getTransform(); 386 var scale = canvas.width / image.width; 387 g2D.scale(scale, scale); 388 // Draw a scale distance line 389 g2D.setStroke(new java.awt.BasicStroke(5 / scale, 390 java.awt.BasicStroke.CAP_BUTT, java.awt.BasicStroke.JOIN_BEVEL)); 391 var scaleDistancePoints = this.controller.getScaleDistancePoints(); 392 g2D.draw(new java.awt.geom.Line2D.Float(scaleDistancePoints [0][0], scaleDistancePoints [0][1], 393 scaleDistancePoints [1][0], scaleDistancePoints [1][1])); 394 // Draw start point line 395 g2D.setStroke(new java.awt.BasicStroke(1 / scale, 396 java.awt.BasicStroke.CAP_BUTT, java.awt.BasicStroke.JOIN_BEVEL)); 397 var angle = Math.atan2(scaleDistancePoints [1][1] - scaleDistancePoints [0][1], 398 scaleDistancePoints [1][0] - scaleDistancePoints [0][0]); 399 var oldTransform2 = g2D.getTransform(); 400 g2D.translate(scaleDistancePoints [0][0], scaleDistancePoints [0][1]); 401 g2D.rotate(angle); 402 var endLine = new java.awt.geom.Line2D.Double(0, 5 / scale, 0, -5 / scale); 403 g2D.draw(endLine); 404 g2D.setTransform(oldTransform2); 405 406 // Draw end point line 407 g2D.translate(scaleDistancePoints [1][0], scaleDistancePoints [1][1]); 408 g2D.rotate(angle); 409 g2D.draw(endLine); 410 g2D.setTransform(oldTransform); 411 } 412 } 413 414 /** 415 * @private 416 */ 417 BackgroundImageWizardStepsView.prototype.initOriginStep = function () { 418 var component = this; 419 var unitName = preferences.getLengthUnit().getName(); 420 var maximumLength = preferences.getLengthUnit().getMaximumLength(); 421 422 this.originStep = { 423 panel: this.findElement("[originStep]"), 424 preview: this.findElement("[originStep] [preview] canvas"), 425 previewZoomIn: this.findElement("[originStep] [previewZoomIn]"), 426 previewZoomOut: this.findElement("[originStep] [previewZoomOut]"), 427 xOriginLabel: this.getElement("x-origin-label"), 428 xOriginInput: new JSSpinner(preferences, this.getElement("x-origin-input"), 429 { 430 format: preferences.getLengthUnit().getFormat(), 431 value: controller.getXOrigin(), 432 minimum: -maximumLength, 433 maximum: maximumLength, 434 stepSize: preferences.getLengthUnit().getStepSize() 435 }), 436 yOriginLabel: this.getElement("y-origin-label"), 437 yOriginInput: new JSSpinner(preferences, this.getElement("y-origin-input"), 438 { 439 format: preferences.getLengthUnit().getFormat(), 440 value: controller.getYOrigin(), 441 minimum: -maximumLength, 442 maximum: maximumLength, 443 stepSize: preferences.getLengthUnit().getStepSize() 444 }), 445 }; 446 447 this.originStep.xOriginLabel.textContent = this.getLocalizedLabelText( 448 "BackgroundImageWizardStepsPanel", "xOriginLabel.text", unitName); 449 this.originStep.yOriginLabel.textContent = this.getLocalizedLabelText( 450 "BackgroundImageWizardStepsPanel", "yOriginLabel.text", unitName); 451 this.registerEventListener([this.originStep.xOriginInput, this.originStep.yOriginInput], "input", function(ev) { 452 controller.setOrigin(component.originStep.xOriginInput.getValue(), component.originStep.yOriginInput.getValue()); 453 }); 454 this.registerPropertyChangeListener(controller, "X_ORIGIN", function() { 455 component.originStep.xOriginInput.setValue(controller.getXOrigin()); 456 component.repaintOriginCanvas(); 457 }); 458 this.registerPropertyChangeListener(controller, "Y_ORIGIN", function() { 459 component.originStep.yOriginInput.setValue(controller.getYOrigin()); 460 component.repaintOriginCanvas(); 461 }); 462 463 var canvas = this.originStep.preview; 464 465 var zoomInButtonAction = new ResourceAction(preferences, "BackgroundImageWizardStepsPanel", "ZOOM_IN", true); 466 var zoomOutButtonAction = new ResourceAction(preferences, "BackgroundImageWizardStepsPanel", "ZOOM_OUT", true); 467 this.originStep.previewZoomIn.style.backgroundImage = "url('" + zoomInButtonAction.getURL(AbstractAction.SMALL_ICON) + "')"; 468 this.registerEventListener(this.originStep.previewZoomIn, "click", function(ev) { 469 component.originStep.preview.width *= 2; 470 component.repaintOriginCanvas(); 471 }); 472 this.originStep.previewZoomOut.style.backgroundImage = "url('" + zoomOutButtonAction.getURL(AbstractAction.SMALL_ICON) + "')"; 473 this.registerEventListener(this.originStep.previewZoomOut, "click", function(ev) { 474 component.originStep.preview.width /= 2; 475 component.repaintOriginCanvas(); 476 }); 477 478 var mouseUp = function(ev) { 479 component.isMovingOrigin = false; 480 canvas.style.cursor = "default"; 481 }; 482 var mouseMove = function(ev) { 483 ev.stopImmediatePropagation(); 484 if (component.isMovingOrigin) { 485 var canvasRect = canvas.getBoundingClientRect(); 486 var pointerCoordinatesObject = ev.touches && ev.touches.length > 0 ? ev.touches[0] : ev; 487 var scaleDistancePoints = controller.getScaleDistancePoints(); 488 var rescale = component.originStep.preview.width / component.selectedImage.width; 489 rescale = rescale / BackgroundImage.getScale(controller.getScaleDistance(), 490 scaleDistancePoints [0][0], scaleDistancePoints [0][1], 491 scaleDistancePoints [1][0], scaleDistancePoints [1][1]); 492 var xOrigin = Math.round((pointerCoordinatesObject.clientX - canvasRect.left) / rescale * 10) / 10; 493 var yOrigin = Math.round((pointerCoordinatesObject.clientY - canvasRect.top) / rescale * 10) / 10; 494 controller.setOrigin(xOrigin, yOrigin); 495 component.repaintOriginCanvas(); 496 } 497 }; 498 var mouseDown = function(ev) { 499 component.isMovingOrigin = true; 500 canvas.style.cursor = "crosshair"; 501 mouseMove(ev); 502 }; 503 504 this.registerEventListener(canvas, "mousedown", mouseDown, true); 505 this.registerEventListener(canvas, "touchstart", mouseDown, true); 506 this.registerEventListener(canvas, "mousemove", mouseMove, true); 507 this.registerEventListener(canvas, "touchmove", mouseMove, true); 508 this.registerEventListener(canvas, "mouseup", mouseUp, true); 509 this.registerEventListener(canvas, "touchend", mouseUp, true); 510 } 511 512 /** 513 * @private 514 */ 515 BackgroundImageWizardStepsView.prototype.repaintOriginCanvas = function () { 516 var canvas = this.originStep.preview; 517 var g2D = new Graphics2D(canvas); 518 g2D.fillRect(0, 0, canvas.width, canvas.height); 519 var image = this.selectedImage; 520 if (image) { 521 canvas.height = (image.height / image.width) * canvas.width; 522 g2D.drawImageWithSize(image, 0, 0, canvas.width, canvas.height); 523 g2D.setColor("blue"); 524 var oldTransform = g2D.getTransform(); 525 var scale = canvas.width / image.width; 526 var scaleDistancePoints = this.controller.getScaleDistancePoints(); 527 scale = scale / BackgroundImage.getScale(this.controller.getScaleDistance(), 528 scaleDistancePoints [0][0], scaleDistancePoints [0][1], 529 scaleDistancePoints [1][0], scaleDistancePoints [1][1]); 530 g2D.scale(scale, scale); 531 532 // Draw a dot at origin 533 g2D.translate(this.controller.getXOrigin(), this.controller.getYOrigin()); 534 535 var originRadius = 4 / scale; 536 g2D.fill(new java.awt.geom.Ellipse2D.Float(-originRadius, -originRadius, 537 originRadius * 2, originRadius * 2)); 538 539 // Draw a cross 540 g2D.setStroke(new java.awt.BasicStroke(1 / scale, 541 java.awt.BasicStroke.CAP_BUTT, java.awt.BasicStroke.JOIN_BEVEL)); 542 g2D.draw(new java.awt.geom.Line2D.Double(8 / scale, 0, -8 / scale, 0)); 543 g2D.draw(new java.awt.geom.Line2D.Double(0, 8 / scale, 0, -8 / scale)); 544 g2D.setTransform(oldTransform); 545 } 546 } 547 548 /** 549 * Sets the texts of label and button of image choice panel with change texts. 550 * @private 551 */ 552 BackgroundImageWizardStepsView.prototype.setImageChangeTexts = function () { 553 this.imageChoiceStep.imageChoiceOrChangeLabel.innerHTML = this.getLocalizedLabelText( 554 "BackgroundImageWizardStepsPanel", "imageChangeLabel.text").replace(/\<br\>/g, " "); 555 this.imageChoiceStep.imageChoiceOrChangeButton.innerHTML = this.getLocalizedLabelText( 556 "BackgroundImageWizardStepsPanel", "imageChangeButton.text"); 557 } 558 559 /** 560 * Sets the texts of label and button of image choice panel with choice texts. 561 * @private 562 */ 563 BackgroundImageWizardStepsView.prototype.setImageChoiceTexts = function () { 564 this.imageChoiceStep.imageChoiceOrChangeLabel.innerHTML = this.getLocalizedLabelText( 565 "BackgroundImageWizardStepsPanel", "imageChoiceLabel.text").replace(/\<br\>/g, " "); 566 this.imageChoiceStep.imageChoiceOrChangeButton.innerHTML = this.getLocalizedLabelText( 567 "BackgroundImageWizardStepsPanel", "imageChoiceButton.text"); 568 } 569 570 /** 571 * @param {BackgroundImage} backgroundImage 572 * @private 573 */ 574 BackgroundImageWizardStepsView.prototype.updateImage = function(backgroundImage) { 575 if (backgroundImage == null) { 576 this.setImageChoiceTexts(); 577 this.updatePreviewComponentsImage(); 578 } else { 579 this.setImageChangeTexts(); 580 581 // In Java's version: BackgroundImageWizardStepsPanel, image is updated in EDT (using invokeLater) when wizard view is initialized 582 // here, if we setImage right away, wizard won't be initialized yet, and next state enabled value won't be refreshed properly 583 // with this setTimeout, we ensure this code runs in next event loop 584 setTimeout(function() { 585 controller.setImage(backgroundImage.getImage()); 586 controller.setScaleDistance(backgroundImage.getScaleDistance()); 587 controller.setScaleDistancePoints(backgroundImage.getScaleDistanceXStart(), 588 backgroundImage.getScaleDistanceYStart(), backgroundImage.getScaleDistanceXEnd(), 589 backgroundImage.getScaleDistanceYEnd()); 590 controller.setOrigin(backgroundImage.getXOrigin(), backgroundImage.getYOrigin()); 591 }, 100); 592 } 593 } 594 595 /** 596 * @param {HTMLImageElement?} image 597 * @param {File} file 598 * @private 599 */ 600 BackgroundImageWizardStepsView.prototype.updateController = function(image, file) { 601 var view = this; 602 var controller = this.controller; 603 var imageType = ImageTools.isImageWithAlpha(image) ? "image/png" : "image/jpeg"; 604 this.checkImageSize(image, imageType, function(checkedImage) { 605 var contentReady = function(content) { 606 setTimeout(function() { 607 controller.setImage(content); 608 view.setImageChangeTexts(); 609 var referenceBackgroundImage = controller.getReferenceBackgroundImage(); 610 if (referenceBackgroundImage != null 611 && referenceBackgroundImage.getScaleDistanceXStart() < checkedImage.width 612 && referenceBackgroundImage.getScaleDistanceXEnd() < checkedImage.width 613 && referenceBackgroundImage.getScaleDistanceYStart() < checkedImage.height 614 && referenceBackgroundImage.getScaleDistanceYEnd() < checkedImage.height) { 615 // Initialize distance and origin with values of the reference checkedImage 616 controller.setScaleDistance(referenceBackgroundImage.getScaleDistance()); 617 controller.setScaleDistancePoints(referenceBackgroundImage.getScaleDistanceXStart(), 618 referenceBackgroundImage.getScaleDistanceYStart(), 619 referenceBackgroundImage.getScaleDistanceXEnd(), 620 referenceBackgroundImage.getScaleDistanceYEnd()); 621 controller.setOrigin(referenceBackgroundImage.getXOrigin(), referenceBackgroundImage.getYOrigin()); 622 } else { 623 // Initialize distance and origin with default values 624 controller.setScaleDistance(null); 625 var scaleDistanceXStart = checkedImage.width * 0.1; 626 var scaleDistanceYStart = checkedImage.height / 2; 627 var scaleDistanceXEnd = checkedImage.width * 0.9; 628 controller.setScaleDistancePoints(scaleDistanceXStart, scaleDistanceYStart, 629 scaleDistanceXEnd, scaleDistanceYStart); 630 controller.setOrigin(0, 0); 631 } 632 }, 100); 633 }; 634 if (image === checkedImage 635 && (file.type == "image/jpeg" 636 || file.type == "image/png")) { 637 contentReady(BlobURLContent.fromBlob(file)); 638 } else { 639 BlobURLContent.fromImage(checkedImage, imageType, contentReady); 640 } 641 }); 642 } 643 644 /** 645 * @param {HTMLImageElement} image 646 * @param {string} imageType can be "image/png" or "image/jpeg" depending on image alpha channel requirements 647 * @param {function(HTMLImageElement)} imageReady function called after resize with resized image (or with original image if resize was not necessary or declined by user) 648 * @private 649 */ 650 BackgroundImageWizardStepsView.prototype.checkImageSize = function (image, imageType, imageReady) { 651 if (image.width * image.height < LARGE_IMAGE_PIXEL_COUNT_THRESHOLD) { 652 imageReady(image); 653 } else { 654 var stepsView = this; 655 var factor = Math.sqrt(LARGE_IMAGE_MAX_PIXEL_COUNT / (image.width * image.height)); 656 var reducedWidth = Math.round(image.width * factor); 657 var reducedHeight = Math.round(image.height * factor); 658 var resizeImage = function() { 659 ImageTools.resize(image, reducedWidth, reducedHeight, imageReady, imageType); 660 }; 661 if (this.getUserPreferences().isImportedImageResizedWithoutPrompting()) { 662 resizeImage(); 663 } else { 664 var promptDialog = new JSImageResizingDialog(preferences, 665 "@{BackgroundImageWizardStepsPanel.reduceImageSize.title}", 666 stepsView.getLocalizedLabelText( 667 "BackgroundImageWizardStepsPanel", "reduceImageSize.message", [image.width, image.height, reducedWidth, reducedHeight]), 668 "@{BackgroundImageWizardStepsPanel.reduceImageSize.cancel}", 669 "@{BackgroundImageWizardStepsPanel.reduceImageSize.keepUnchanged}", 670 "@{BackgroundImageWizardStepsPanel.reduceImageSize.reduceSize}", 671 resizeImage, // Confirm image resizing 672 function() { // Original image 673 imageReady(image); 674 }); 675 promptDialog.displayView(); 676 } 677 } 678 } 679 680 /** 681 * @private 682 */ 683 BackgroundImageWizardStepsView.prototype.updatePreviewComponentsImage = function() { 684 var component = this; 685 var image = this.controller.getImage(); 686 687 delete this.imageChoiceStep.preview.src; 688 this.imageChoiceStep.preview.width = 0; 689 delete this.scaleStep.preview.src; 690 delete this.originStep.preview.src; 691 if (image != null) { 692 TextureManager.getInstance().loadTexture(image, { 693 textureUpdated: function(image) { 694 component.imageChoiceStep.preview.src = image.src; 695 component.imageChoiceStep.preview.width = image.width; 696 component.selectedImage = image; 697 if (image.width > 400) { 698 component.scaleStep.preview.width = 400; 699 component.originStep.preview.width = 400; 700 } 701 702 component.repaintScaleCanvas(); 703 component.repaintOriginCanvas(); 704 }, 705 textureError: function(error) { 706 imageErrorListener(error); 707 } 708 }); 709 } 710 } 711 712 /** 713 * Changes displayed view based on current step. 714 */ 715 BackgroundImageWizardStepsView.prototype.updateStep = function() { 716 var step = this.controller.getStep(); 717 switch (step) { 718 case BackgroundImageWizardController.Step.CHOICE: 719 this.imageChoiceStep.panel.style.display = "flex"; 720 this.scaleStep.panel.style.display = "none"; 721 this.originStep.panel.style.display = "none"; 722 break; 723 case BackgroundImageWizardController.Step.SCALE: 724 this.imageChoiceStep.panel.style.display = "none"; 725 this.scaleStep.panel.style.display = "flex"; 726 delete this.scaleStep.panel.style.display; 727 this.originStep.panel.style.display = "none"; 728 break; 729 case BackgroundImageWizardController.Step.ORIGIN: 730 this.imageChoiceStep.panel.style.display = "none"; 731 this.scaleStep.panel.style.display = "none"; 732 this.originStep.panel.style.display = "flex"; 733 break; 734 } 735 }; 736 737 return new BackgroundImageWizardStepsView(); 738 } 739 740 JSViewFactory.prototype.createImportedFurnitureWizardStepsView = function(piece, modelName, importHomePiece, preferences, importedFurnitureWizardController) { 741 return null; 742 } 743 744 /** 745 * @param {CatalogTexture} texture 746 * @param {string} textureName 747 * @param {UserPreferences} preferences 748 * @param {ImportedTextureWizardController} controller 749 * @return {JSComponent} 750 */ 751 JSViewFactory.prototype.createImportedTextureWizardStepsView = function(texture, textureName, preferences, controller) { 752 var LARGE_IMAGE_PIXEL_COUNT_THRESHOLD = 640 * 640; 753 var IMAGE_PREFERRED_MAX_SIZE = 512; 754 var LARGE_IMAGE_MAX_PIXEL_COUNT = IMAGE_PREFERRED_MAX_SIZE * IMAGE_PREFERRED_MAX_SIZE; 755 756 function ImportedTextureWizardStepsView() { 757 JSComponent.call(this, preferences, 758 "<div imageStep>" 759 + " <div description>@{ImportedTextureWizardStepsPanel.imageChangeLabel.text}</div>" 760 + " <div class='buttons'>" 761 + " <button changeImage>@{ImportedTextureWizardStepsPanel.imageChangeButton.text}</button>" 762 + " <button findImage>@{ImportedTextureWizardStepsPanel.findImagesButton.text}</button>" 763 + " <input type='file' accept='image/*' style='display: none'/>" 764 + " </div>" 765 + " <div preview>" 766 + " <img>" 767 + " </div>" 768 + "</div>" 769 + "<div attributesStep>" 770 + " <div description></div>" 771 + " <div form>" 772 + " <div preview>" 773 + " <img />" 774 + " </div>" 775 + " <div>@{ImportedTextureWizardStepsPanel.nameLabel.text}</div>" 776 + " <div>" 777 + " <input type='text' name='name' />" 778 + " </div>" 779 + " <div>@{ImportedTextureWizardStepsPanel.categoryLabel.text}</div>" 780 + " <div>" 781 + " <select name='category'></select>" 782 + " </div>" 783 + " <div>@{ImportedTextureWizardStepsPanel.creatorLabel.text}</div>" 784 + " <div>" 785 + " <input type='text' name='creator' />" 786 + " </div>" 787 + " <div data-name='width-label' class='label-cell'></div>" 788 + " <div>" 789 + " <span data-name='width-input'></span>" 790 + " </div>" 791 + " <div data-name='height-label' class='label-cell'></div>" 792 + " <div>" 793 + " <span data-name='height-input'></span>" 794 + " </div>" 795 + " </div>" 796 + "</div>"); 797 798 this.controller = controller; 799 this.userCategory = new TexturesCategory( 800 ResourceAction.getLocalizedLabelText(preferences, "ImportedTextureWizardStepsPanel", "userCategory")); 801 this.getHTMLElement().classList.add("imported-texture-wizard"); 802 803 this.initComponents(); 804 805 var component = this; 806 this.registerPropertyChangeListener(controller, "STEP", function(ev) { 807 component.updateStep(); 808 }); 809 } 810 ImportedTextureWizardStepsView.prototype = Object.create(JSComponent.prototype); 811 ImportedTextureWizardStepsView.prototype.constructor = ImportedTextureWizardStepsView; 812 813 /** 814 * @private 815 */ 816 ImportedTextureWizardStepsView.prototype.initComponents = function () { 817 this.imageStepPanel = this.findElement("[imageStep]"); 818 this.imageChoiceOrChangeLabel = this.findElement("[imageStep] [description]"); 819 this.imageChoiceOrChangeButton = this.findElement("button[changeImage]"); 820 this.imageFindImageButton = this.findElement("button[findImage]"); 821 this.imageChooserInput = this.findElement("input[type='file']"); 822 this.previewPanel = this.findElement("[preview]"); 823 824 if (texture == null) { 825 this.setImageChoiceTexts(); 826 } 827 828 this.attributesStepPanel = this.findElement("[attributesStep]"); 829 this.attributesStepPanelDescription = this.findElement("[attributesStep] [description]"); 830 831 this.attributesPreviewPanel = this.findElement("[attributesStep] [preview]"); 832 833 this.nameInput = this.findElement("input[name='name']"); 834 this.categorySelect = this.findElement("select[name='category']"); 835 this.creatorInput = this.findElement("input[name='creator']"); 836 837 var unitName = preferences.getLengthUnit().getName(); 838 var minimumLength = preferences.getLengthUnit().getMinimumLength(); 839 var maximumLength = preferences.getLengthUnit().getMaximumLength(); 840 this.widthLabel = this.getElement("width-label"), 841 this.widthLabel.textContent = this.getLocalizedLabelText( 842 "ImportedTextureWizardStepsPanel", "widthLabel.text", unitName); 843 this.widthInput = new JSSpinner(preferences, this.getElement("width-input"), 844 { 845 format: preferences.getLengthUnit().getFormat(), 846 minimum: minimumLength, 847 maximum: maximumLength, 848 stepSize: preferences.getLengthUnit().getStepSize() 849 }); 850 this.heightLabel = this.getElement("height-label"), 851 this.heightLabel.textContent = this.getLocalizedLabelText( 852 "ImportedTextureWizardStepsPanel", "heightLabel.text", unitName); 853 this.heightInput = new JSSpinner(preferences, this.getElement("height-input"), 854 { 855 format: preferences.getLengthUnit().getFormat(), 856 minimum: minimumLength, 857 maximum: maximumLength, 858 stepSize: preferences.getLengthUnit().getStepSize() 859 }); 860 861 var component = this; 862 var imageErrorListener = function(ev) { 863 console.warn("Error loading image: " + ev); 864 component.controller.setImage(null); 865 component.setImageChoiceTexts(); 866 component.updatePreviewComponentsImage(); 867 alert(ResourceAction.getLocalizedLabelText(preferences, "ImportedTextureWizardStepsPanel", 868 "imageChoiceErrorLabel.text")); 869 }; 870 this.registerEventListener(this.imageChoiceOrChangeButton, "click", function(ev) { 871 component.imageChooserInput.click(); 872 }); 873 this.registerEventListener(this.imageFindImageButton, "click", function(ev) { 874 try { 875 var url = preferences.getLocalizedString("ImportedTextureWizardStepsPanel", "findImagesButton.url"); 876 window.open(url, "_blank"); 877 } catch (e) { 878 this.imageFindImageButton.style.display = "none"; 879 } 880 }); 881 var importImage = function(file) { 882 if (file) { 883 var reader = new FileReader(); 884 // Use onload and onerror rather that addEventListener for Cordova support 885 reader.onload = function(ev) { 886 var image = new Image(); 887 image.addEventListener("load", function(ev) { 888 component.updateController(image, file); 889 }); 890 image.addEventListener("error", imageErrorListener); 891 image.src = ev.target.result; 892 }; 893 reader.onerror = imageErrorListener; 894 reader.readAsDataURL(file); 895 } 896 }; 897 this.registerEventListener(this.imageChooserInput, "input", function(ev) { 898 importImage(this.files[0]); 899 }); 900 this.registerEventListener(this.previewPanel, "drop", function(ev) { 901 ev.preventDefault(); 902 importImage(ev.dataTransfer.files[0]); 903 }); 904 this.registerEventListener(this.previewPanel, "dragover", function(ev) { 905 ev.preventDefault(); 906 }); 907 908 this.registerPropertyChangeListener(controller, "IMAGE", function(ev) { 909 component.updatePreviewComponentsImage(); 910 }); 911 this.registerPropertyChangeListener(controller, "WIDTH", function(ev) { 912 component.updatePreviewComponentsImage(); 913 }); 914 this.registerPropertyChangeListener(controller, "HEIGHT", function(ev) { 915 component.updatePreviewComponentsImage(); 916 }); 917 918 var categories = preferences.getTexturesCatalog().getCategories(); 919 if (this.findUserCategory(categories) == null) { 920 categories = categories.concat([this.userCategory]); 921 } 922 for (var i = 0; i < categories.length; i++) { 923 var option = document.createElement("option"); 924 option.value = categories[i].getName(); 925 option.textContent = categories[i].getName(); 926 option._category = categories[i]; 927 this.categorySelect.appendChild(option); 928 } 929 930 this.attributesStepPanelDescription.innerHTML = this.getLocalizedLabelText( 931 "ImportedTextureWizardStepsPanel", "attributesLabel.text").replace(/\<br\>/g, " "); 932 this.registerPropertyChangeListener(controller, "NAME", function() { 933 if (component.nameInput.value.trim() != controller.getName()) { 934 component.nameInput.value = controller.getName(); 935 } 936 }); 937 this.registerEventListener(this.nameInput, "input", function(ev) { 938 controller.setName(component.nameInput.value.trim()); 939 }); 940 941 this.registerPropertyChangeListener(controller, "CATEGORY", function(ev) { 942 var category = controller.getCategory(); 943 if (category != null) { 944 component.categorySelect.value = category.getName(); 945 } 946 }); 947 this.registerEventListener(this.categorySelect, "change", function(ev) { 948 var category = component.categorySelect.item(component.categorySelect.selectedIndex)._category; 949 controller.setCategory(category); 950 }); 951 952 this.registerPropertyChangeListener(controller, "CREATOR", function(ev) { 953 if (component.creatorInput.value.trim() != controller.getCreator()) { 954 component.creatorInput.value = controller.getCreator(); 955 } 956 }); 957 this.registerEventListener(component.creatorInput, "input", function(ev) { 958 controller.setCreator(component.creatorInput.value.trim()); 959 }); 960 961 this.registerPropertyChangeListener(controller, "WIDTH", function(ev) { 962 component.widthInput.setValue(controller.getWidth()); 963 }); 964 this.registerEventListener(this.widthInput, "input", function(ev) { 965 controller.setWidth(parseFloat(component.widthInput.value)); 966 }); 967 968 this.registerPropertyChangeListener(controller, "HEIGHT", function(ev) { 969 component.heightInput.setValue(controller.getHeight()); 970 }); 971 this.registerEventListener(this.heightInput, "input", function(ev) { 972 controller.setHeight(parseFloat(component.heightInput.value)); 973 }); 974 975 if (texture != null) { 976 TextureManager.getInstance().loadTexture(texture.getImage(), 977 { 978 textureUpdated: function(image) { 979 component.updateController(image, texture); 980 }, 981 textureError: function(error) { 982 imageErrorListener(error); 983 } 984 }); 985 } 986 } 987 988 /** 989 * @param {HTMLImageElement?} image 990 * @param {File|CatalogTexture} file 991 * @private 992 */ 993 ImportedTextureWizardStepsView.prototype.updateController = function(image, file) { 994 var component = this; 995 var controller = this.controller; 996 this.setImageChangeTexts(); 997 if (file instanceof CatalogTexture) { 998 var catalogTexture = file; 999 setTimeout(function() { 1000 controller.setImage(catalogTexture.getImage()); 1001 controller.setName(catalogTexture.getName()); 1002 controller.setCategory(catalogTexture.getCategory()); 1003 controller.setCreator(catalogTexture.getCreator()); 1004 controller.setWidth(catalogTexture.getWidth()); 1005 controller.setHeight(catalogTexture.getHeight()); 1006 }, 100); 1007 } else { 1008 // File 1009 var textureName = "Texture"; 1010 if (file.name.lastIndexOf('.') > 0) { 1011 var parts = file.name.split(/\/|\\|\./); 1012 if (parts.length > 1) { 1013 textureName = parts [parts.length - 2]; 1014 } 1015 } 1016 var imageType = ImageTools.isImageWithAlpha(image) ? "image/png" : "image/jpeg"; 1017 this.checkImageSize(image, imageType, function(checkedImage) { 1018 var contentReady = function(content) { 1019 setTimeout(function() { 1020 controller.setImage(content); 1021 controller.setName(textureName); 1022 var categories = component.preferences.getTexturesCatalog().getCategories(); 1023 var userCategory = component.findUserCategory(categories) || component.userCategory; 1024 controller.setCategory(userCategory); 1025 controller.setCreator(null); 1026 var defaultWidth = component.preferences.getLengthUnit().isMetric() 1027 ? 20 : LengthUnit.inchToCentimeter(8); 1028 controller.setWidth(defaultWidth); 1029 controller.setHeight(defaultWidth / checkedImage.width * checkedImage.height); 1030 }, 100); 1031 }; 1032 if (image === checkedImage 1033 && (file.type == "image/jpeg" 1034 || file.type == "image/png")) { 1035 contentReady(BlobURLContent.fromBlob(file)); 1036 } else { 1037 BlobURLContent.fromImage(checkedImage, imageType, contentReady); 1038 } 1039 }); 1040 } 1041 } 1042 1043 /** 1044 * Sets the texts of label and button of image choice panel with change texts. 1045 * @private 1046 */ 1047 ImportedTextureWizardStepsView.prototype.setImageChangeTexts = function() { 1048 this.imageChoiceOrChangeLabel.innerHTML = this.getLocalizedLabelText( 1049 "ImportedTextureWizardStepsPanel", "imageChangeLabel.text").replace(/\<br\>/g, " "); 1050 this.imageChoiceOrChangeButton.innerHTML = this.getLocalizedLabelText( 1051 "ImportedTextureWizardStepsPanel", "imageChangeButton.text"); 1052 } 1053 1054 /** 1055 * Sets the texts of label and button of image choice panel with choice texts. 1056 * @private 1057 */ 1058 ImportedTextureWizardStepsView.prototype.setImageChoiceTexts = function() { 1059 this.imageChoiceOrChangeLabel.innerHTML = this.getLocalizedLabelText( 1060 "ImportedTextureWizardStepsPanel", "imageChoiceLabel.text").replace(/\<br\>/g, " "); 1061 this.imageChoiceOrChangeButton.innerHTML = this.getLocalizedLabelText( 1062 "ImportedTextureWizardStepsPanel", "imageChoiceButton.text"); 1063 } 1064 1065 /** 1066 * Returns user category if it exists among existing the given <code>categories</code>. 1067 * @param {TexturesCategory[]} categories 1068 * @return {TexturesCategory | null} found user category, or null if not found 1069 * @private 1070 */ 1071 ImportedTextureWizardStepsView.prototype.findUserCategory = function(categories) { 1072 var categories = preferences.getTexturesCatalog().getCategories(); 1073 for (var i = 0; i < categories.length; i++) { 1074 if (categories[i].equals(this.userCategory)) { 1075 return categories[i]; 1076 } 1077 } 1078 return null; 1079 } 1080 1081 /** 1082 * @param {HTMLImageElement} image 1083 * @param {string} imageType can be "image/png" or "image/jpeg" depending on image alpha channel requirements 1084 * @param {function(HTMLImageElement)} imageReady function called after resize with resized image (or with original image if resize was not necessary or declined by user) 1085 * @private 1086 */ 1087 ImportedTextureWizardStepsView.prototype.checkImageSize = function (image, imageType, imageReady) { 1088 if (image.width * image.height < LARGE_IMAGE_PIXEL_COUNT_THRESHOLD) { 1089 imageReady(image); 1090 } else { 1091 var factor; 1092 var ratio = image.width / image.height; 1093 if (ratio < 0.5 || ratio > 2) { 1094 factor = Math.sqrt(LARGE_IMAGE_MAX_PIXEL_COUNT / (image.width * image.height)); 1095 } else if (ratio < 1) { 1096 factor = IMAGE_PREFERRED_MAX_SIZE / image.height; 1097 } else { 1098 factor = IMAGE_PREFERRED_MAX_SIZE / image.width; 1099 } 1100 1101 var reducedWidth = Math.round(image.width * factor); 1102 var reducedHeight = Math.round(image.height * factor); 1103 var resizeImage = function() { 1104 ImageTools.resize(image, reducedWidth, reducedHeight, imageReady, imageType); 1105 }; 1106 if (this.getUserPreferences().isImportedImageResizedWithoutPrompting()) { 1107 resizeImage(); 1108 } else { 1109 var promptDialog = new JSImageResizingDialog(preferences, 1110 "@{ImportedTextureWizardStepsPanel.reduceImageSize.title}", 1111 this.getLocalizedLabelText( 1112 "ImportedTextureWizardStepsPanel", "reduceImageSize.message", [image.width, image.height, reducedWidth, reducedHeight]), 1113 "@{ImportedTextureWizardStepsPanel.reduceImageSize.cancel}", 1114 "@{ImportedTextureWizardStepsPanel.reduceImageSize.keepUnchanged}", 1115 "@{ImportedTextureWizardStepsPanel.reduceImageSize.reduceSize}", 1116 resizeImage, // Confirm image resizing 1117 function() { // Original image 1118 imageReady(image); 1119 }); 1120 promptDialog.displayView(); 1121 } 1122 } 1123 } 1124 1125 /** 1126 * @private 1127 */ 1128 ImportedTextureWizardStepsView.prototype.updatePreviewComponentsImage = function() { 1129 this.previewPanel.innerHTML = ""; 1130 var image = new Image(); 1131 if (this.controller.getImage() !== null) { 1132 this.controller.getImage().getStreamURL({ 1133 urlReady: function(url) { 1134 image.src = url; 1135 } 1136 }); 1137 } 1138 this.previewPanel.appendChild(image); 1139 1140 this.attributesPreviewPanel.innerHTML = ""; 1141 var previewImage = document.createElement("div"); 1142 previewImage.style.backgroundImage = "url('" + image.src + "')"; 1143 previewImage.style.backgroundRepeat = "repeat"; 1144 1145 var widthFactor = this.controller.getWidth() / 250; 1146 var heightFactor = this.controller.getHeight() / 250; 1147 previewImage.style.backgroundSize = "calc(100% * " + widthFactor + ") calc(100% * " + heightFactor + ")"; 1148 previewImage.classList.add("image"); 1149 this.attributesPreviewPanel.appendChild(previewImage); 1150 } 1151 1152 /** 1153 * Changes displayed view based on current step. 1154 */ 1155 ImportedTextureWizardStepsView.prototype.updateStep = function() { 1156 var step = this.controller.getStep(); 1157 switch (step) { 1158 case ImportedTextureWizardController.Step.IMAGE: 1159 this.imageStepPanel.style.display = "block"; 1160 this.attributesStepPanel.style.display = "none"; 1161 break; 1162 case ImportedTextureWizardController.Step.ATTRIBUTES: 1163 this.imageStepPanel.style.display = "none"; 1164 this.attributesStepPanel.style.display = "block"; 1165 break; 1166 } 1167 } 1168 1169 return new ImportedTextureWizardStepsView(); 1170 } 1171 1172 /** 1173 * @param {UserPreferences} preferences 1174 * @param {UserPreferencesController} controller 1175 */ 1176 JSViewFactory.prototype.createUserPreferencesView = function(preferences, controller) { 1177 /** 1178 * @param {HTMLElement} element 1179 * @return {boolean} true if element is displayed (not hidden by css rule) 1180 * @private 1181 */ 1182 var isElementVisible = function(element) { 1183 if (element instanceof JSComponent) { 1184 element = element.getHTMLElement(); 1185 } 1186 return window.getComputedStyle(element).display !== "none"; 1187 } 1188 1189 /** 1190 * Hides a preference row from any of its input element. 1191 * @param {HTMLElement} preferenceInput 1192 */ 1193 var disablePreferenceRow = function(preferenceInput) { 1194 preferenceInput.parentElement.style.display = "none"; 1195 1196 // Search root input cell 1197 var currentElement = preferenceInput; 1198 while (currentElement.parentElement != null && !currentElement.parentElement.classList.contains("user-preferences-dialog")) { 1199 currentElement = currentElement.parentElement; 1200 } 1201 1202 // Hide input cell and its sibling label cell 1203 currentElement.style.display = "none"; 1204 currentElement.previousElementSibling.style.display = "none"; 1205 } 1206 1207 var dialog = new JSDialog(preferences, 1208 "@{UserPreferencesPanel.preferences.title}", 1209 document.getElementById("user-preferences-dialog-template"), 1210 { 1211 applier: function(dialog) { 1212 if (isElementVisible(dialog.languageSelect)) { 1213 var selectedLanguageOption = dialog.languageSelect.options[dialog.languageSelect.selectedIndex]; 1214 controller.setLanguage(selectedLanguageOption != null ? selectedLanguageOption.value : null); 1215 } 1216 if (isElementVisible(dialog.furnitureCatalogViewTreeRadioButton)) { 1217 controller.setFurnitureCatalogViewedInTree(dialog.furnitureCatalogViewTreeRadioButton.checked); 1218 } 1219 if (isElementVisible(dialog.navigationPanelCheckBox)) { 1220 controller.setNavigationPanelVisible(dialog.navigationPanelCheckBox.checked); 1221 } 1222 if (isElementVisible(dialog.editingIn3DViewCheckBox)) { 1223 controller.setEditingIn3DViewEnabled(dialog.editingIn3DViewCheckBox.checked); 1224 } 1225 if (isElementVisible(dialog.aerialViewCenteredOnSelectionCheckBox)) { 1226 controller.setAerialViewCenteredOnSelectionEnabled(dialog.aerialViewCenteredOnSelectionCheckBox.checked); 1227 } 1228 if (isElementVisible(dialog.observerCameraSelectedAtChangeCheckBox)) { 1229 controller.setObserverCameraSelectedAtChange(dialog.observerCameraSelectedAtChangeCheckBox.checked); 1230 } 1231 if (isElementVisible(dialog.magnetismCheckBox)) { 1232 controller.setMagnetismEnabled(dialog.magnetismCheckBox.checked); 1233 } 1234 if (isElementVisible(dialog.rulersCheckBox)) { 1235 controller.setRulersVisible(dialog.rulersCheckBox.checked); 1236 } 1237 if (isElementVisible(dialog.gridCheckBox)) { 1238 controller.setGridVisible(dialog.gridCheckBox.checked); 1239 } 1240 if (isElementVisible(dialog.iconTopViewRadioButton)) { 1241 controller.setFurnitureViewedFromTop(dialog.iconTopViewRadioButton.checked); 1242 } 1243 if (isElementVisible(dialog.iconSizeSelect) && !dialog.iconSizeSelect.disabled) { 1244 controller.setFurnitureModelIconSize(parseInt(dialog.iconSizeSelect.value)); 1245 } 1246 if (isElementVisible(dialog.roomRenderingFloorColorOrTextureRadioButton)) { 1247 controller.setRoomFloorColoredOrTextured(dialog.roomRenderingFloorColorOrTextureRadioButton.checked); 1248 } 1249 if (isElementVisible(dialog.newWallThicknessInput)) { 1250 controller.setNewWallThickness(parseFloat(dialog.newWallThicknessInput.getValue())); 1251 } 1252 if (isElementVisible(dialog.newWallHeightInput)) { 1253 controller.setNewWallHeight(parseFloat(dialog.newWallHeightInput.getValue())); 1254 } 1255 if (isElementVisible(dialog.newFloorThicknessInput)) { 1256 controller.setNewFloorThickness(parseFloat(dialog.newFloorThicknessInput.getValue())); 1257 } 1258 controller.modifyUserPreferences(); 1259 } 1260 }); 1261 1262 1263 // LANGUAGE 1264 dialog.languageSelect = dialog.getElement("language-select"); 1265 if (controller.isPropertyEditable("LANGUAGE")) { 1266 var supportedLanguages = preferences.getSupportedLanguages(); 1267 for (var i = 0; i < supportedLanguages.length; i++) { 1268 var languageCode = supportedLanguages[i].replace('_', '-'); 1269 var languageDisplayName = languageCode; 1270 try { 1271 languageDisplayName = new Intl.DisplayNames([languageCode, "en"], { type: "language" }).of(languageCode); 1272 if (languageDisplayName == languageCode) { 1273 throw "No support for Intl.DisplayNames"; 1274 } 1275 languageDisplayName = languageDisplayName.charAt(0).toUpperCase() + languageDisplayName.slice(1); 1276 } catch (ex) { 1277 languageDisplayName = {"bg": "Български", 1278 "cs": "Čeština", 1279 "de": "Deutsch", 1280 "el": "Ελληνικά", 1281 "en": "English", 1282 "es": "Español", 1283 "fr": "Français", 1284 "it": "Italiano", 1285 "ja": "日本語", 1286 "hu": "Magyar", 1287 "nl": "Nederlands", 1288 "pl": "Polski", 1289 "pt": "Português", 1290 "pt-BR": "Português (Brasil)", 1291 "ru": "Русский", 1292 "sv": "Svenska", 1293 "vi": "Tiếng Việt", 1294 "zh-CN": "中文(中国)", 1295 "zh-TW": "中文(台灣)"} [languageCode]; 1296 if (languageDisplayName === undefined) { 1297 languageDisplayName = languageCode; 1298 console.log("Unknown display name for " + languageCode); 1299 } 1300 } 1301 1302 var selected = supportedLanguages[i] == controller.getLanguage(); 1303 var languageOption = JSComponent.createOptionElement(supportedLanguages[i], languageDisplayName, selected); 1304 dialog.languageSelect.appendChild(languageOption); 1305 } 1306 } else { 1307 disablePreferenceRow(dialog.languageSelect); 1308 } 1309 1310 // UNIT 1311 dialog.unitSelect = dialog.getElement("unit-select"); 1312 if (controller.isPropertyEditable("UNIT")) { 1313 dialog.unitSelect.appendChild( 1314 JSComponent.createOptionElement("MILLIMETER", 1315 preferences.getLocalizedString("UserPreferencesPanel", "unitComboBox.millimeter.text"), 1316 controller.getUnit() == LengthUnit.MILLIMETER)); 1317 dialog.unitSelect.appendChild( 1318 JSComponent.createOptionElement("CENTIMETER", 1319 preferences.getLocalizedString("UserPreferencesPanel", "unitComboBox.centimeter.text"), 1320 controller.getUnit() == LengthUnit.CENTIMETER)); 1321 dialog.unitSelect.appendChild( 1322 JSComponent.createOptionElement("METER", 1323 preferences.getLocalizedString("UserPreferencesPanel", "unitComboBox.meter.text"), 1324 controller.getUnit() == LengthUnit.METER)); 1325 dialog.unitSelect.appendChild( 1326 JSComponent.createOptionElement("INCH", 1327 preferences.getLocalizedString("UserPreferencesPanel", "unitComboBox.inch.text"), 1328 controller.getUnit() == LengthUnit.INCH)); 1329 dialog.unitSelect.appendChild( 1330 JSComponent.createOptionElement("INCH_FRACTION", 1331 preferences.getLocalizedString("UserPreferencesPanel", "unitComboBox.inchFraction.text"), 1332 controller.getUnit() == LengthUnit.INCH_FRACTION)); 1333 dialog.unitSelect.appendChild( 1334 JSComponent.createOptionElement("INCH_DECIMALS", 1335 preferences.getLocalizedString("UserPreferencesPanel", "unitComboBox.inchDecimals.text"), 1336 controller.getUnit() == LengthUnit.INCH_DECIMALS)); 1337 dialog.unitSelect.appendChild( 1338 JSComponent.createOptionElement("FOOT_DECIMALS", 1339 preferences.getLocalizedString("UserPreferencesPanel", "unitComboBox.footDecimals.text"), 1340 controller.getUnit() == LengthUnit.FOOT_DECIMALS)); 1341 1342 dialog.registerEventListener(dialog.unitSelect, "change", function(ev) { 1343 var selectedUnitOption = dialog.unitSelect.options[dialog.unitSelect.selectedIndex]; 1344 controller.setUnit(selectedUnitOption != null ? LengthUnit[selectedUnitOption.value] : null); 1345 }); 1346 } else { 1347 disablePreferenceRow(dialog.unitSelect); 1348 } 1349 1350 // CURRENCY 1351 dialog.currencySelect = dialog.getElement("currency-select"); 1352 dialog.valueAddedTaxCheckBox = dialog.getElement("value-added-tax-checkbox"); 1353 var noCurrencyLabel = dialog.getLocalizedLabelText("UserPreferencesPanel", "currencyComboBox.noCurrency.text"); 1354 if (controller.isPropertyEditable("CURRENCY")) { 1355 dialog.currencySelect.appendChild(JSComponent.createOptionElement("", noCurrencyLabel, !controller.getCurrency())); 1356 var currencyDisplayNames = { 1357 EUR: "EUR €", 1358 AED: "AED AED", 1359 AFN: "AFN ؋", 1360 ALL: "ALL Lekë", 1361 AMD: "AMD ֏", 1362 ANG: "ANG NAf.", 1363 AOA: "AOA Kz", 1364 ARS: "ARS $", 1365 AUD: "AUD $", 1366 AWG: "AWG Afl.", 1367 AZN: "AZN ₼", 1368 BAM: "BAM KM", 1369 BBD: "BBD $", 1370 BDT: "BDT ৳", 1371 BGN: "BGN лв.", 1372 BHD: "BHD د.ب.", 1373 BIF: "BIF FBu", 1374 BMD: "BMD $", 1375 BND: "BND $", 1376 BOB: "BOB Bs", 1377 BRL: "BRL R$", 1378 BSD: "BSD $", 1379 BTN: "BTN Nu.", 1380 BWP: "BWP P", 1381 BYN: "BYN Br", 1382 BZD: "BZD $", 1383 CAD: "CAD $", 1384 CDF: "CDF FC", 1385 CHF: "CHF CHF", 1386 CLP: "CLP $", 1387 CNY: "CNY ¥", 1388 COP: "COP $", 1389 CRC: "CRC ₡", 1390 CSD: "CSD CSD", 1391 CUP: "CUP $", 1392 CVE: "CVE ", 1393 CZK: "CZK Kč", 1394 DJF: "DJF Fdj", 1395 DKK: "DKK kr", 1396 DOP: "DOP RD$", 1397 DZD: "DZD DA", 1398 EGP: "EGP ج.م.", 1399 ERN: "ERN Nfk", 1400 ETB: "ETB Br", 1401 EUR: "EUR €", 1402 FJD: "FJD $", 1403 FKP: "FKP £", 1404 GBP: "GBP £", 1405 GEL: "GEL ₾", 1406 GHS: "GHS GH₵", 1407 GIP: "GIP £", 1408 GMD: "GMD D", 1409 GNF: "GNF FG", 1410 GTQ: "GTQ Q", 1411 GYD: "GYD $", 1412 HKD: "HKD HK$", 1413 HNL: "HNL L", 1414 HRK: "HRK HRK", 1415 HTG: "HTG G", 1416 HUF: "HUF Ft", 1417 IDR: "IDR Rp", 1418 ILS: "ILS ₪", 1419 INR: "INR ₹", 1420 IQD: "IQD د.ع.", 1421 IRR: "IRR IRR", 1422 ISK: "ISK ISK", 1423 JMD: "JMD $", 1424 JOD: "JOD د.أ.", 1425 JPY: "JPY ¥", 1426 KES: "KES Ksh", 1427 KGS: "KGS сом", 1428 KHR: "KHR ៛", 1429 KMF: "KMF CF", 1430 KPW: "KPW KPW", 1431 KRW: "KRW ₩", 1432 KWD: "KWD د.ك.", 1433 KYD: "KYD $", 1434 KZT: "KZT ₸", 1435 LAK: "LAK ₭", 1436 LBP: "LBP ل.ل.", 1437 LKR: "LKR Rs.", 1438 LRD: "LRD $", 1439 LSL: "LSL LSL", 1440 LYD: "LYD د.ل.", 1441 MAD: "MAD MAD", 1442 MDL: "MDL L", 1443 MGA: "MGA Ar", 1444 MKD: "MKD den", 1445 MMK: "MMK K", 1446 MNT: "MNT ₮", 1447 MOP: "MOP MOP$", 1448 MRU: "MRU UM", 1449 MUR: "MUR Rs", 1450 MWK: "MWK MK", 1451 MXN: "MXN $", 1452 MYR: "MYR RM", 1453 MZN: "MZN MTn", 1454 NAD: "NAD $", 1455 NGN: "NGN ₦", 1456 NIO: "NIO C$", 1457 NOK: "NOK kr", 1458 NPR: "NPR नेरू", 1459 NZD: "NZD $", 1460 OMR: "OMR ر.ع.", 1461 PAB: "PAB B/.", 1462 PEN: "PEN S/", 1463 PGK: "PGK K", 1464 PHP: "PHP ₱", 1465 PKR: "PKR ر", 1466 PLN: "PLN zł", 1467 PYG: "PYG Gs.", 1468 QAR: "QAR ر.ق.", 1469 RON: "RON RON", 1470 RSD: "RSD RSD", 1471 RUB: "RUB ₽", 1472 RWF: "RWF RF", 1473 SAR: "SAR ر.س.", 1474 SBD: "SBD $", 1475 SCR: "SCR SR", 1476 SDG: "SDG SDG", 1477 SEK: "SEK kr", 1478 SGD: "SGD $", 1479 SHP: "SHP £", 1480 SLL: "SLL Le", 1481 SOS: "SOS S", 1482 SRD: "SRD $", 1483 SSP: "SSP £", 1484 STN: "STN Db", 1485 SVC: "SVC C", 1486 SYP: "SYP LS", 1487 SZL: "SZL E", 1488 THB: "THB ฿", 1489 TJS: "TJS сом.", 1490 TMT: "TMT TMT", 1491 TND: "TND DT", 1492 TOP: "TOP T$", 1493 TRY: "TRY ₺", 1494 TTD: "TTD $", 1495 TWD: "TWD $", 1496 TZS: "TZS TSh", 1497 UAH: "UAH ₴", 1498 UGX: "UGX USh", 1499 USD: "USD $", 1500 UYU: "UYU $", 1501 UZS: "UZS сўм", 1502 VES: "VES Bs.S", 1503 VND: "VND ₫", 1504 VUV: "VUV VT", 1505 WST: "WST WS$", 1506 XAF: "XAF FCFA", 1507 XCD: "XCD $", 1508 XOF: "XOF CFA", 1509 XPF: "XPF FCFP", 1510 YER: "YER ر.ي.", 1511 ZAR: "ZAR R", 1512 ZMW: "ZMW K", 1513 ZWL: "ZWL ZWL" 1514 }; 1515 var currencies = Object.keys(currencyDisplayNames); 1516 for (var i = 0; i < currencies.length; i++) { 1517 var currency = currencies[i]; 1518 var currencyLabel = currencyDisplayNames[currency]; 1519 dialog.currencySelect.appendChild(JSComponent.createOptionElement( 1520 currency, currencyLabel, currency == controller.getCurrency())); 1521 } 1522 1523 dialog.registerEventListener(dialog.currencySelect, "change", function(ev) { 1524 var selectedIndex = dialog.currencySelect.selectedIndex; 1525 var selectedCurrency = dialog.currencySelect.options[selectedIndex].value; 1526 controller.setCurrency(selectedCurrency ? selectedCurrency : null); 1527 }); 1528 dialog.registerPropertyChangeListener(controller, "CURRENCY", function(ev) { 1529 var option = dialog.currencySelect.querySelector("[value='" + (controller.getCurrency() ? controller.getCurrency() : "") + "']"); 1530 option.selected = true; 1531 dialog.valueAddedTaxCheckBox.disabled = controller.getCurrency() == null; 1532 }); 1533 1534 // VALUE_ADDED_TAX_ENABLED 1535 var vatEnabled = controller.isPropertyEditable("VALUE_ADDED_TAX_ENABLED"); 1536 dialog.valueAddedTaxCheckBox.parentElement.style.display = vatEnabled ? "initial" : "none"; 1537 dialog.valueAddedTaxCheckBox.disabled = controller.getCurrency() == null; 1538 dialog.valueAddedTaxCheckBox.checked = controller.isValueAddedTaxEnabled(); 1539 dialog.registerEventListener(dialog.valueAddedTaxCheckBox, "change", function(ev) { 1540 controller.setValueAddedTaxEnabled(dialog.valueAddedTaxCheckBox.checked); 1541 }); 1542 dialog.registerPropertyChangeListener(controller, "VALUE_ADDED_TAX_ENABLED", function(ev) { 1543 dialog.valueAddedTaxCheckBox.disabled = controller.getCurrency() == null; 1544 dialog.valueAddedTaxCheckBox.checked = controller.isValueAddedTaxEnabled(); 1545 }); 1546 } else { 1547 disablePreferenceRow(dialog.currencySelect); 1548 } 1549 1550 // FURNITURE_CATALOG_VIEWED_IN_TREE 1551 dialog.furnitureCatalogViewTreeRadioButton = dialog.findElement("[name='furniture-catalog-view-radio'][value='tree']"); 1552 if (controller.isPropertyEditable("FURNITURE_CATALOG_VIEWED_IN_TREE") && false) { 1553 var selectedFurnitureCatalogView = controller.isFurnitureCatalogViewedInTree() ? "tree" : "list"; 1554 dialog.findElement("[name='furniture-catalog-view-radio'][value='" + selectedFurnitureCatalogView + "']").checked = true; 1555 } else { 1556 disablePreferenceRow(dialog.furnitureCatalogViewTreeRadioButton); 1557 } 1558 1559 // NAVIGATION_PANEL_VISIBLE 1560 dialog.navigationPanelCheckBox = dialog.getElement("navigation-panel-checkbox"); 1561 if (controller.isPropertyEditable("NAVIGATION_PANEL_VISIBLE")) { 1562 dialog.navigationPanelCheckBox.checked = controller.isNavigationPanelVisible(); 1563 } else { 1564 disablePreferenceRow(dialog.navigationPanelCheckBox); 1565 } 1566 1567 // EDITING_IN_3D_VIEW_ENABLED 1568 dialog.editingIn3DViewCheckBox = dialog.getElement("editing-in-3D-view-checkbox"); 1569 if (controller.isPropertyEditable("EDITING_IN_3D_VIEW_ENABLED")) { 1570 dialog.editingIn3DViewCheckBox.checked = controller.isEditingIn3DViewEnabled(); 1571 } else { 1572 disablePreferenceRow(dialog.editingIn3DViewCheckBox); 1573 } 1574 1575 // AERIAL_VIEW_CENTERED_ON_SELECTION_ENABLED 1576 dialog.aerialViewCenteredOnSelectionCheckBox = dialog.getElement("aerial-view-centered-on-selection-checkbox"); 1577 if (controller.isPropertyEditable("AERIAL_VIEW_CENTERED_ON_SELECTION_ENABLED")) { 1578 dialog.aerialViewCenteredOnSelectionCheckBox.checked = controller.isAerialViewCenteredOnSelectionEnabled(); 1579 } else { 1580 disablePreferenceRow(dialog.aerialViewCenteredOnSelectionCheckBox); 1581 } 1582 1583 // OBSERVER_CAMERA_SELECTED_AT_CHANGE 1584 dialog.observerCameraSelectedAtChangeCheckBox = dialog.getElement("observer-camera-selected-at-change-checkbox"); 1585 if (controller.isPropertyEditable("OBSERVER_CAMERA_SELECTED_AT_CHANGE")) { 1586 dialog.observerCameraSelectedAtChangeCheckBox.checked = controller.isObserverCameraSelectedAtChange(); 1587 } else { 1588 disablePreferenceRow(dialog.observerCameraSelectedAtChangeCheckBox); 1589 } 1590 1591 // MAGNETISM 1592 dialog.magnetismCheckBox = dialog.getElement("magnetism-checkbox"); 1593 if (controller.isPropertyEditable("MAGNETISM_ENABLED")) { 1594 dialog.magnetismCheckBox.checked = controller.isMagnetismEnabled(); 1595 } else { 1596 disablePreferenceRow(dialog.magnetismCheckBox); 1597 } 1598 1599 // RULERS 1600 dialog.rulersCheckBox = dialog.getElement("rulers-checkbox"); 1601 if (controller.isPropertyEditable("RULERS_VISIBLE") && false) { 1602 dialog.rulersCheckBox.checked = controller.isRulersVisible(); 1603 } else { 1604 disablePreferenceRow(dialog.rulersCheckBox); 1605 } 1606 1607 // GRID 1608 dialog.gridCheckBox = dialog.getElement("grid-checkbox"); 1609 if (controller.isPropertyEditable("GRID_VISIBLE")) { 1610 dialog.gridCheckBox.checked = controller.isGridVisible(); 1611 } else { 1612 disablePreferenceRow(dialog.gridCheckBox); 1613 } 1614 1615 // DEFAULT_FONT_NAME 1616 dialog.defaultFontNameSelect = dialog.getElement("default-font-name-select"); 1617 if (controller.isPropertyEditable("DEFAULT_FONT_NAME")) { 1618 var DEFAULT_SYSTEM_FONT_NAME = "DEFAULT_SYSTEM_FONT_NAME"; 1619 var defaultFontChangeListener = function() { 1620 var selectedValue = controller.getDefaultFontName() == null ? DEFAULT_SYSTEM_FONT_NAME : controller.getDefaultFontName(); 1621 var selectedOption = dialog.defaultFontNameSelect.querySelector("[value='" + selectedValue + "']") 1622 if (selectedOption) { 1623 selectedOption.selected = true; 1624 } 1625 }; 1626 1627 CoreTools.loadAvailableFontNames(function(fonts) { 1628 fonts = [DEFAULT_SYSTEM_FONT_NAME].concat(fonts); 1629 for (var i = 0; i < fonts.length; i++) { 1630 var font = fonts[i]; 1631 var label = i == 0 ? dialog.getLocalizedLabelText("FontNameComboBox", "systemFontName") : font; 1632 dialog.defaultFontNameSelect.appendChild(JSComponent.createOptionElement(font, label)); 1633 } 1634 defaultFontChangeListener(); 1635 }); 1636 1637 dialog.registerPropertyChangeListener(controller, "DEFAULT_FONT_NAME", defaultFontChangeListener); 1638 1639 dialog.registerEventListener(dialog.defaultFontNameSelect, "change", function(ev) { 1640 var selectedValue = dialog.defaultFontNameSelect.querySelector("option:checked").value; 1641 controller.setDefaultFontName(selectedValue == DEFAULT_SYSTEM_FONT_NAME ? null : selectedValue); 1642 }); 1643 } else { 1644 disablePreferenceRow(dialog.defaultFontNameSelect); 1645 } 1646 1647 // FURNITURE ICON 1648 dialog.iconTopViewRadioButton = dialog.findElement("[name='furniture-icon-radio'][value='topView']"); 1649 dialog.iconSizeSelect = dialog.getElement("icon-size-select"); 1650 if (controller.isPropertyEditable("FURNITURE_VIEWED_FROM_TOP")) { 1651 var selectedIconMode = controller.isFurnitureViewedFromTop() ? "topView" : "catalog"; 1652 dialog.findElement("[name='furniture-icon-radio'][value='" + selectedIconMode + "']").checked = true; 1653 1654 var iconSizes = [128, 256, 512 ,1024]; 1655 for (var i = 0; i < iconSizes.length; i++) { 1656 var size = iconSizes[i]; 1657 dialog.iconSizeSelect.appendChild( 1658 JSComponent.createOptionElement(size, size + '×' + size, 1659 controller.getFurnitureModelIconSize() == size)); 1660 } 1661 1662 /** 1663 * Called when furniture icon mode is selected, in order to enable icon size if necessary 1664 * @private 1665 */ 1666 var iconModeSelected = function(dialog) { 1667 dialog.iconSizeSelect.disabled = !dialog.iconTopViewRadioButton.checked; 1668 } 1669 1670 iconModeSelected(dialog); 1671 dialog.registerEventListener(dialog.findElements("[name='furniture-icon-radio']"), "change", function(ev) { 1672 iconModeSelected(dialog); 1673 }); 1674 } else { 1675 disablePreferenceRow(dialog.iconTopViewRadioButton); 1676 } 1677 1678 // ROOM_FLOOR_COLORED_OR_TEXTURED 1679 dialog.roomRenderingFloorColorOrTextureRadioButton = dialog.findElement("[name='room-rendering-radio'][value='floorColorOrTexture']"); 1680 if (controller.isPropertyEditable("ROOM_FLOOR_COLORED_OR_TEXTURED")) { 1681 var roomRenderingValue = controller.isRoomFloorColoredOrTextured() ? "floorColorOrTexture" : "monochrome"; 1682 dialog.findElement("[name='room-rendering-radio'][value='" + roomRenderingValue + "']").checked = true; 1683 } else { 1684 disablePreferenceRow(dialog.roomRenderingFloorColorOrTextureRadioButton); 1685 } 1686 1687 // NEW_WALL_PATTERN 1688 var newWallPatternSelect = dialog.getElement("new-wall-pattern-select"); 1689 if (controller.isPropertyEditable("NEW_WALL_PATTERN")) { 1690 var patternsTexturesByURL = {}; 1691 var patterns = preferences.getPatternsCatalog().getPatterns(); 1692 for (var i = 0; i < patterns.length; i++) { 1693 var url = patterns[i].getImage().getURL(); 1694 patternsTexturesByURL[url] = patterns[i]; 1695 } 1696 newWallPatternSelect.classList.add("wall-pattern-combo-box"); 1697 dialog.patternComboBox = new JSComboBox(preferences, newWallPatternSelect, 1698 { 1699 availableValues: Object.keys(patternsTexturesByURL), 1700 renderCell: function(patternURL, patternItemElement) { 1701 patternItemElement.style.backgroundImage = "url('" + patternURL + "')"; 1702 }, 1703 selectionChanged: function(newValue) { 1704 controller.setNewWallPattern(patternsTexturesByURL[newValue]); 1705 } 1706 }); 1707 1708 var selectedUrl = (controller.getNewWallPattern() != null 1709 ? controller.getNewWallPattern() 1710 : controller.getWallPattern()).getImage().getURL(); 1711 dialog.patternComboBox.setSelectedItem(selectedUrl); 1712 dialog.registerPropertyChangeListener(controller, "NEW_WALL_PATTERN", function() { 1713 var selectedUrl = controller.getNewWallPattern().getImage().getURL(); 1714 dialog.patternComboBox.setSelectedItem(selectedUrl); 1715 }); 1716 } else { 1717 disablePreferenceRow(dialog.newWallPatternSelect); 1718 } 1719 1720 // NEW_WALL_THICKNESS 1721 dialog.newWallThicknessInput = new JSSpinner(preferences, dialog.getElement("new-wall-thickness-input"), 1722 { 1723 value: 1, 1724 minimum: 0, 1725 maximum: 100000 1726 }); 1727 if (controller.isPropertyEditable("NEW_WALL_THICKNESS")) { 1728 dialog.newWallThicknessInput.setValue(controller.getNewWallThickness()); 1729 } else { 1730 disablePreferenceRow(dialog.newWallThicknessInput); 1731 } 1732 1733 // NEW_WALL_HEIGHT 1734 dialog.newWallHeightInput = new JSSpinner(preferences, dialog.getElement("new-wall-height-input"), 1735 { 1736 value: 1, 1737 minimum: 0, 1738 maximum: 100000 1739 }); 1740 if (controller.isPropertyEditable("NEW_WALL_HEIGHT")) { 1741 dialog.newWallHeightInput.setValue(controller.getNewWallHeight()); 1742 } else { 1743 disablePreferenceRow(dialog.newWallHeightInput); 1744 } 1745 1746 // NEW_FLOOR_THICKNESS 1747 dialog.newFloorThicknessInput = new JSSpinner(preferences, dialog.getElement("new-floor-thickness-input"), 1748 { 1749 value: 1, 1750 minimum: 0, 1751 maximum: 100000 1752 }); 1753 if (controller.isPropertyEditable("NEW_FLOOR_THICKNESS")) { 1754 dialog.newFloorThicknessInput.setValue(controller.getNewFloorThickness()); 1755 } else { 1756 disablePreferenceRow(dialog.newFloorThicknessInput); 1757 } 1758 1759 var updateSpinnerStepsAndLength = function(spinner, centimeterStepSize, inchStepSize) { 1760 if (controller.getUnit().isMetric()) { 1761 spinner.setStepSize(centimeterStepSize); 1762 } else { 1763 spinner.setStepSize(inchStepSize); 1764 } 1765 spinner.setMinimum(controller.getUnit().getMinimumLength()); 1766 if (spinner.getMinimum() > spinner.getValue()) { 1767 spinner.setValue(spinner.getMinimum()); 1768 } 1769 spinner.setFormat(controller.getUnit().getFormat()); 1770 }; 1771 1772 var updateStepsAndLength = function() { 1773 updateSpinnerStepsAndLength(dialog.newWallThicknessInput, LengthUnit.CENTIMETER.getStepSize(), LengthUnit.INCH.getStepSize()); 1774 updateSpinnerStepsAndLength(dialog.newWallHeightInput, LengthUnit.CENTIMETER.getStepSize() * 20, LengthUnit.INCH.getStepSize() * 16); 1775 updateSpinnerStepsAndLength(dialog.newFloorThicknessInput, LengthUnit.CENTIMETER.getStepSize(), LengthUnit.INCH.getStepSize()); 1776 }; 1777 1778 updateStepsAndLength(); 1779 dialog.registerPropertyChangeListener(controller, "UNIT", function(ev) { 1780 updateStepsAndLength(); 1781 }); 1782 return dialog; 1783 } 1784 1785 JSViewFactory.prototype.createLevelView = function(preferences, controller) { 1786 var dialog = new JSDialog(preferences, 1787 "@{LevelPanel.level.title}", 1788 document.getElementById("level-dialog-template"), 1789 { 1790 size: "medium", 1791 applier: function() { 1792 controller.modifyLevels(); 1793 } 1794 }); 1795 1796 var unitName = preferences.getLengthUnit().getName(); 1797 1798 // Viewable check box bound to VIEWABLE controller property 1799 var viewableCheckBox = dialog.getElement("viewable-checkbox"); 1800 var viewableCheckBoxDisplay = controller.isPropertyEditable("VIEWABLE") ? "initial" : "none"; 1801 viewableCheckBox.parentElement.style.display = viewableCheckBoxDisplay; 1802 viewableCheckBox.checked = controller.getViewable(); 1803 dialog.registerEventListener(viewableCheckBox, "change", function(ev) { 1804 controller.setViewable(viewableCheckBox.checked); 1805 }); 1806 dialog.registerPropertyChangeListener(controller, "VIEWABLE", function(ev) { 1807 viewableCheckBox.checked = controller.getViewable(); 1808 }); 1809 1810 // Name text field bound to NAME controller property 1811 var nameInput = dialog.getElement("name-input"); 1812 var nameDisplay = controller.isPropertyEditable("NAME") ? "initial" : "none"; 1813 nameInput.parentElement.style.display = nameDisplay; 1814 nameInput.parentElement.previousElementSibling.style.display = nameDisplay; 1815 nameInput.value = controller.getName() != null ? controller.getName() : ""; 1816 dialog.registerEventListener(nameInput, "input", function(ev) { 1817 var name = nameInput.value; 1818 if (name.trim().length == 0) { 1819 controller.setName(null); 1820 } else { 1821 controller.setName(name); 1822 } 1823 }); 1824 dialog.registerPropertyChangeListener(controller, "NAME", function(ev) { 1825 nameInput.value = controller.getName() != null ? controller.getName() : ""; 1826 }); 1827 1828 // Elevation spinner bound to ELEVATION controller property 1829 var minimumLength = preferences.getLengthUnit().getMinimumLength(); 1830 var maximumLength = preferences.getLengthUnit().getMaximumLength(); 1831 var setFloorThicknessEnabled = function() { 1832 var selectedLevelIndex = controller.getSelectedLevelIndex(); 1833 if (selectedLevelIndex != null) { 1834 var levels = controller.getLevels(); 1835 dialog.floorThicknessInput.setEnabled(levels[selectedLevelIndex].getElevation() != levels[0].getElevation()); 1836 } 1837 }; 1838 var setElevationIndexButtonsEnabled = function() { 1839 var selectedLevelIndex = controller.getSelectedLevelIndex(); 1840 if (selectedLevelIndex != null) { 1841 var levels = controller.getLevels(); 1842 dialog.increaseElevationButton.disabled = !(selectedLevelIndex < levels.length - 1 1843 && levels [selectedLevelIndex].getElevation() == levels [selectedLevelIndex + 1].getElevation()); 1844 dialog.decreaseElevationButton.disabled = !(selectedLevelIndex > 0 1845 && levels [selectedLevelIndex].getElevation() == levels [selectedLevelIndex - 1].getElevation()); 1846 } else { 1847 dialog.increaseElevationButton.setEnabled(false); 1848 dialog.decreaseElevationButton.setEnabled(false); 1849 } 1850 }; 1851 1852 var elevationDisplay = controller.isPropertyEditable("ELEVATION") ? "initial" : "none"; 1853 dialog.getElement("elevation-label").textContent = dialog.getLocalizedLabelText("LevelPanel", "elevationLabel.text", unitName); 1854 var elevationInput = new JSSpinner(preferences, dialog.getElement("elevation-input"), 1855 { 1856 nullable: controller.getElevation() == null, 1857 format: preferences.getLengthUnit().getFormat(), 1858 value: controller.getElevation(), 1859 minimum: -1000, 1860 maximum: preferences.getLengthUnit().getMaximumElevation(), 1861 stepSize: preferences.getLengthUnit().getStepSize() 1862 }); 1863 elevationInput.parentElement.style.display = elevationDisplay; 1864 elevationInput.parentElement.previousElementSibling.style.display = elevationDisplay; 1865 dialog.registerEventListener(elevationInput, "input", function(ev) { 1866 controller.setElevation(elevationInput.getValue()); 1867 setFloorThicknessEnabled(); 1868 setElevationIndexButtonsEnabled(); 1869 }); 1870 dialog.registerPropertyChangeListener(controller, "ELEVATION", function(ev) { 1871 elevationInput.setValue(ev.getNewValue()); 1872 }); 1873 1874 var floorThicknessDisplay = controller.isPropertyEditable("FLOOR_THICKNESS") ? "initial" : "none"; 1875 dialog.getElement("floor-thickness-label").textContent = dialog.getLocalizedLabelText("LevelPanel", "floorThicknessLabel.text", unitName); 1876 var floorThicknessInput = new JSSpinner(preferences, dialog.getElement("floor-thickness-input"), 1877 { 1878 nullable: controller.getFloorThickness() == null, 1879 format: preferences.getLengthUnit().getFormat(), 1880 value: controller.getFloorThickness(), 1881 minimum: minimumLength, 1882 maximum: maximumLength / 10, 1883 stepSize: preferences.getLengthUnit().getStepSize(), 1884 }); 1885 floorThicknessInput.parentElement.style.display = floorThicknessDisplay; 1886 floorThicknessInput.parentElement.previousElementSibling.style.display = floorThicknessDisplay; 1887 dialog.registerEventListener(floorThicknessInput, "input", function(ev) { 1888 controller.setFloorThickness(floorThicknessInput.getValue()); 1889 }); 1890 dialog.registerPropertyChangeListener(controller, "FLOOR_THICKNESS", function(ev) { 1891 floorThicknessInput.setValue(ev.getNewValue()); 1892 }); 1893 dialog.floorThicknessInput = floorThicknessInput; 1894 setFloorThicknessEnabled(controller); 1895 1896 var heightDisplay = controller.isPropertyEditable("HEIGHT") ? "initial" : "none"; 1897 dialog.getElement("height-label").textContent = dialog.getLocalizedLabelText("LevelPanel", "heightLabel.text", unitName); 1898 var heightInput = new JSSpinner(preferences, dialog.getElement("height-input"), 1899 { 1900 nullable: controller.getHeight() == null, 1901 format: preferences.getLengthUnit().getFormat(), 1902 value: controller.getHeight(), 1903 minimum: minimumLength, 1904 maximum: maximumLength, 1905 stepSize: preferences.getLengthUnit().getStepSize() 1906 }); 1907 heightInput.parentElement.style.display = heightDisplay; 1908 heightInput.parentElement.previousElementSibling.style.display = heightDisplay; 1909 dialog.registerEventListener(heightInput, "input", function(ev) { 1910 controller.setHeight(heightInput.getValue()); 1911 }); 1912 dialog.registerPropertyChangeListener(controller, "HEIGHT", function(ev) { 1913 heightInput.setValue(ev.getNewValue()); 1914 }); 1915 1916 var elevationButtonsDisplay = controller.isPropertyEditable("ELEVATION_INDEX") ? "initial" : "none"; 1917 var increaseElevationButtonAction = new ResourceAction(preferences, "LevelPanel", "INCREASE_ELEVATION_INDEX", true); 1918 var decreaseElevationButtonAction = new ResourceAction(preferences, "LevelPanel", "DECREASE_ELEVATION_INDEX", true); 1919 dialog.increaseElevationButton = dialog.getElement("increase-elevation-index-button"); 1920 dialog.increaseElevationButton.style.backgroundImage = "url('" + increaseElevationButtonAction.getURL(AbstractAction.SMALL_ICON) + "')"; 1921 dialog.increaseElevationButton.style.display = elevationButtonsDisplay; 1922 dialog.registerEventListener(dialog.increaseElevationButton, "click", function(ev) { 1923 controller.setElevationIndex(controller.getElevationIndex() + 1); 1924 setElevationIndexButtonsEnabled(); 1925 }); 1926 1927 dialog.decreaseElevationButton = dialog.getElement("decrease-elevation-index-button"); 1928 dialog.decreaseElevationButton.style.backgroundImage = "url('" + decreaseElevationButtonAction.getURL(AbstractAction.SMALL_ICON) + "')"; 1929 dialog.decreaseElevationButton.style.display = elevationButtonsDisplay; 1930 dialog.registerEventListener(dialog.decreaseElevationButton, "click", function(ev) { 1931 controller.setElevationIndex(controller.getElevationIndex() - 1); 1932 setElevationIndexButtonsEnabled(); 1933 }); 1934 1935 setElevationIndexButtonsEnabled(); 1936 1937 var levelsTableBody = dialog.getElement("levels-table").querySelector("tbody"); 1938 1939 var updateSelectedLevel = function() { 1940 var selectedLevelIndex = controller.getSelectedLevelIndex(); 1941 1942 var selectedLevelRow = levelsTableBody.querySelector(".selected"); 1943 if (selectedLevelRow != null) { 1944 selectedLevelRow.classList.remove("selected"); 1945 } 1946 1947 if (selectedLevelIndex != null) { 1948 // Levels are listed in the table in reverse order 1949 var rowIndex = levelsTableBody.childElementCount - selectedLevelIndex - 1; 1950 levelsTableBody.children[rowIndex].classList.add("selected"); 1951 } 1952 }; 1953 1954 var generateTableBody = function() { 1955 var levels = controller.getLevels(); 1956 var bodyHtml = ""; 1957 1958 var lengthFormat = preferences.getLengthUnit().getFormat(); 1959 for (var i = levels.length - 1; i >= 0; i--) { 1960 var level = levels[i]; 1961 var disabledAttribute = level.isViewable() ? "" : "disabled"; 1962 bodyHtml += 1963 "<tr " + disabledAttribute + ">" 1964 + " <td>" + level.getName() + "</td>" 1965 + " <td>" + lengthFormat.format(level.getElevation()) + "</td>" 1966 + " <td>" + (level.getElevation() == levels [0].getElevation() ? "" : lengthFormat.format(level.getFloorThickness())) + "</td>" 1967 + " <td>" + lengthFormat.format(level.getHeight()) + "</td>" 1968 + "</tr>"; 1969 } 1970 1971 levelsTableBody.innerHTML = bodyHtml; 1972 updateSelectedLevel(); 1973 }; 1974 1975 generateTableBody(); 1976 1977 dialog.registerPropertyChangeListener(controller, "SELECT_LEVEL_INDEX", updateSelectedLevel); 1978 dialog.registerPropertyChangeListener(controller, "LEVELS", generateTableBody); 1979 return dialog; 1980 } 1981 1982 /** 1983 * 1984 * @param {UserPreferences} preferences 1985 * @param {HomeFurnitureController} controller 1986 */ 1987 JSViewFactory.prototype.createHomeFurnitureView = function(preferences, controller) { 1988 function HomeFurnitureDialog() { 1989 this.controller = controller; 1990 1991 JSDialog.call(this, preferences, 1992 "@{HomeFurniturePanel.homeFurniture.title}", 1993 document.getElementById("home-furniture-dialog-template"), 1994 { 1995 applier: function() { 1996 controller.modifyFurniture(); 1997 }, 1998 disposer: function(dialog) { 1999 dialog.paintPanel.colorButton.dispose(); 2000 dialog.paintPanel.textureComponent.dispose(); 2001 } 2002 }); 2003 2004 this.initNameAndPricePanel(); 2005 this.initLocationPanel(); 2006 this.initPaintPanel(); 2007 this.initOrientationPanel(); 2008 this.initSizePanel(); 2009 this.initShininessPanel(); 2010 2011 var dialog = this; 2012 if (this.controller.isPropertyEditable("VISIBLE")) { 2013 // Create visible check box bound to VISIBLE controller property 2014 var visibleCheckBox = this.getElement("visible-checkbox"); 2015 visibleCheckBox.checked = this.controller.getVisible(); 2016 this.registerPropertyChangeListener(this.controller, "VISIBLE", function(ev) { 2017 visibleCheckBox.checked = ev.getNewValue(); 2018 }); 2019 2020 this.registerEventListener(visibleCheckBox, "change", function(ev) { 2021 dialog.controller.setVisible(visibleCheckBox.checked); 2022 }); 2023 } 2024 2025 // must be done at last, needs multiple components to be initialized 2026 if (this.controller.isPropertyEditable("PAINT")) { 2027 this.updatePaintRadioButtons(); 2028 } 2029 } 2030 HomeFurnitureDialog.prototype = Object.create(JSDialog.prototype); 2031 HomeFurnitureDialog.prototype.constructor = HomeFurnitureDialog; 2032 2033 /** 2034 * @private 2035 */ 2036 HomeFurnitureDialog.prototype.initNameAndPricePanel = function() { 2037 var title = this.getElement("name-and-price-title"); 2038 title.textContent = this.getLocalizedLabelText( 2039 "HomeFurniturePanel", controller.isPropertyEditable("PRICE") ? "nameAndPricePanel.title" : "namePanel.title"); 2040 2041 var nameLabel = this.getElement("name-label"); 2042 var nameInput = this.getElement("name-input"); 2043 var nameVisibleCheckBox = this.getElement("name-visible-checkbox"); 2044 var descriptionLabel = this.getElement("description-label"); 2045 var descriptionInput = this.getElement("description-input"); 2046 var priceLabel = this.getElement("price-label"); 2047 var priceInput = new JSSpinner(this.preferences, this.getElement("price-input"), 2048 { 2049 nullable: this.controller.getPrice() == null, 2050 value: 0, 2051 minimum: 0, 2052 maximum: 1000000000 2053 }); 2054 var valueAddedTaxPercentageInput = new JSSpinner(this.preferences, this.getElement("value-added-tax-percentage-input"), 2055 { 2056 nullable: this.controller.getValueAddedTaxPercentage() == null, 2057 value: 0, 2058 minimum: 0, 2059 maximum: 100, 2060 stepSize: 0.5 2061 }); 2062 2063 // 1) Adjust visibility 2064 var nameDisplay = this.controller.isPropertyEditable("NAME") ? "initial" : "none"; 2065 var nameVisibleDisplay = this.controller.isPropertyEditable("NAME_VISIBLE") ? "initial" : "none"; 2066 var descriptionDisplay = this.controller.isPropertyEditable("DESCRIPTION") ? "initial" : "none"; 2067 var priceDisplay = this.controller.isPropertyEditable("PRICE") ? "inline-block" : "none"; 2068 var vatDisplay = this.controller.isPropertyEditable("VALUE_ADDED_TAX_PERCENTAGE") ? "inline-block" : "none"; 2069 2070 nameLabel.style.display = nameDisplay; 2071 nameInput.style.display = nameDisplay; 2072 2073 nameVisibleCheckBox.parentElement.style.display = nameVisibleDisplay; 2074 2075 descriptionLabel.style.display = descriptionDisplay; 2076 descriptionInput.style.display = descriptionDisplay; 2077 descriptionLabel.parentElement.style.display = descriptionDisplay; 2078 descriptionInput.parentElement.style.display = descriptionDisplay; 2079 2080 priceLabel.style.display = priceDisplay; 2081 priceInput.style.display = priceDisplay; 2082 priceLabel.parentElement.style.display = priceDisplay; 2083 priceInput.parentElement.style.display = priceDisplay; 2084 2085 valueAddedTaxPercentageInput.getHTMLElement().previousElementSibling.style.display = vatDisplay; 2086 valueAddedTaxPercentageInput.style.display = vatDisplay; 2087 2088 // 2) Set values 2089 nameInput.value = controller.getName() != null ? controller.getName() : ""; 2090 nameVisibleCheckBox.checked = this.controller.getNameVisible(); 2091 descriptionInput.value = controller.getDescription() != null ? controller.getDescription() : ""; 2092 priceInput.setValue(this.controller.getPrice()); 2093 if (this.controller.getValueAddedTaxPercentage()) { 2094 valueAddedTaxPercentageInput.setValue(this.controller.getValueAddedTaxPercentage() * 100); 2095 } 2096 2097 // 3) Add property listeners 2098 this.registerPropertyChangeListener(this.controller, "NAME", function(ev) { 2099 nameInput.value = controller.getName() != null ? controller.getName() : ""; 2100 }); 2101 this.registerPropertyChangeListener(this.controller, "NAME_VISIBLE", function(ev) { 2102 nameVisibleCheckBox.checked = controller.getNameVisible(); 2103 }); 2104 this.registerPropertyChangeListener(this.controller, "DESCRIPTION", function(ev) { 2105 descriptionInput.value = controller.getDescription() != null ? controller.getDescription() : ""; 2106 }); 2107 this.registerPropertyChangeListener(this.controller, "PRICE", function(ev) { 2108 priceInput.setValue(controller.getPrice()); 2109 }); 2110 this.registerPropertyChangeListener(this.controller, "VALUE_ADDED_TAX_PERCENTAGE", function(ev) { 2111 if (controller.getValueAddedTaxPercentage()) { 2112 valueAddedTaxPercentageInput.setValue(controller.getValueAddedTaxPercentage() * 100); 2113 } else { 2114 valueAddedTaxPercentageInput.setValue(null); 2115 } 2116 }); 2117 2118 // 4) Add change listeners 2119 this.registerEventListener(nameInput, "input", function(ev) { 2120 var name = nameInput.value; 2121 if (name.trim().length == 0) { 2122 controller.setName(null); 2123 } else { 2124 controller.setName(name); 2125 } 2126 }); 2127 this.registerEventListener(nameVisibleCheckBox, "change", function(ev) { 2128 controller.setNameVisible(nameVisibleCheckBox.checked); 2129 }); 2130 this.registerEventListener(descriptionInput, "input", function(ev) { 2131 var description = descriptionInput.value; 2132 if (description.trim().length == 0) { 2133 controller.setDescription(null); 2134 } else { 2135 controller.setDescription(description); 2136 } 2137 }); 2138 this.registerEventListener(priceInput, "input", function(ev) { 2139 controller.setPrice(priceInput.getValue() != null 2140 ? new Big(priceInput.getValue()) 2141 : null); 2142 }); 2143 this.registerEventListener(valueAddedTaxPercentageInput, "input", function(ev) { 2144 var vat = valueAddedTaxPercentageInput.getValue(); 2145 controller.setValueAddedTaxPercentage(vat != null 2146 ? new Big(vat / 100) 2147 : null); 2148 }); 2149 } 2150 2151 /** 2152 * @private 2153 */ 2154 HomeFurnitureDialog.prototype.initLocationPanel = function() { 2155 var xLabel = this.getElement("x-label"); 2156 var xInput = new JSSpinner(this.preferences, this.getElement("x-input"), 2157 { 2158 nullable: this.controller.getX() == null, 2159 format: this.preferences.getLengthUnit().getFormat(), 2160 stepSize: this.preferences.getLengthUnit().getStepSize() 2161 }); 2162 var yLabel = this.getElement("y-label"); 2163 var yInput = new JSSpinner(this.preferences, this.getElement("y-input"), 2164 { 2165 nullable: this.controller.getY() == null, 2166 format: this.preferences.getLengthUnit().getFormat(), 2167 stepSize: this.preferences.getLengthUnit().getStepSize() 2168 }); 2169 var elevationLabel = this.getElement("elevation-label"); 2170 var elevationInput = new JSSpinner(this.preferences, this.getElement("elevation-input"), 2171 { 2172 nullable: this.controller.getElevation() == null, 2173 format: this.preferences.getLengthUnit().getFormat(), 2174 stepSize: this.preferences.getLengthUnit().getStepSize() 2175 }); 2176 2177 var mirroredModelCheckBox = this.getElement("mirrored-model-checkbox"); 2178 var basePlanItemCheckBox = this.getElement("base-plan-item-checkbox"); 2179 2180 // 1) Adjust visibility 2181 var xDisplay = this.controller.isPropertyEditable("X") ? "initial" : "none"; 2182 var yDisplay = this.controller.isPropertyEditable("Y") ? "initial" : "none"; 2183 var elevationDisplay = this.controller.isPropertyEditable("ELEVATION") ? "initial" : "none"; 2184 var modelMirroredDisplay = this.controller.isPropertyEditable("MODEL_MIRRORED") ? "initial" : "none"; 2185 var basePlanItemDisplay = this.controller.isPropertyEditable("BASE_PLAN_ITEM") ? "initial" : "none"; 2186 2187 xLabel.style.display = xDisplay; 2188 xInput.getHTMLElement().parentElement.style.display = xDisplay; 2189 yLabel.style.display = yDisplay; 2190 yInput.getHTMLElement().parentElement.style.display = yDisplay; 2191 elevationLabel.style.display = elevationDisplay; 2192 elevationInput.getHTMLElement().parentElement.style.display = elevationDisplay; 2193 2194 mirroredModelCheckBox.parentElement.style.display = modelMirroredDisplay; 2195 basePlanItemCheckBox.parentElement.style.display = basePlanItemDisplay; 2196 2197 // 2) Set values 2198 xInput.setValue(this.controller.getX()); 2199 yInput.setValue(this.controller.getY()); 2200 elevationInput.setValue(this.controller.getElevation()); 2201 mirroredModelCheckBox.checked = this.controller.getModelMirrored(); 2202 basePlanItemCheckBox.checked = this.controller.getBasePlanItem(); 2203 2204 // 3) Set labels 2205 var unitName = this.preferences.getLengthUnit().getName(); 2206 xLabel.textContent = this.getLocalizedLabelText("HomeFurniturePanel", "xLabel.text", unitName); 2207 yLabel.textContent = this.getLocalizedLabelText("HomeFurniturePanel", "yLabel.text", unitName); 2208 elevationLabel.textContent = this.getLocalizedLabelText("HomeFurniturePanel", "elevationLabel.text", unitName); 2209 2210 // 4) Set custom attributes 2211 var maximumLength = this.preferences.getLengthUnit().getMaximumLength(); 2212 var maximumElevation = this.preferences.getLengthUnit().getMaximumElevation(); 2213 xInput.setMinimum(-maximumLength); 2214 yInput.setMinimum(-maximumLength); 2215 xInput.setMaximum(maximumLength); 2216 yInput.setMaximum(maximumLength); 2217 elevationInput.setMinimum(0); 2218 elevationInput.setMaximum(maximumElevation); 2219 2220 // 5) add property listeners 2221 var controller = this.controller; 2222 this.registerPropertyChangeListener(this.controller, "X", function(ev) { 2223 xInput.setValue(controller.getX()); 2224 }); 2225 this.registerPropertyChangeListener(this.controller, "Y", function(ev) { 2226 yInput.setValue(controller.getY()); 2227 }); 2228 this.registerPropertyChangeListener(this.controller, "ELEVATION", function(ev) { 2229 elevationInput.setValue(controller.getElevation()); 2230 }); 2231 this.registerPropertyChangeListener(this.controller, "MODEL_MIRRORED", function(ev) { 2232 mirroredModelCheckBox.checked = controller.getModelMirrored(); 2233 }); 2234 this.registerPropertyChangeListener(this.controller, "BASE_PLAN_ITEM", function(ev) { 2235 basePlanItemCheckBox.checked = controller.getBasePlanItem(); 2236 }); 2237 2238 // 6) Add change listeners 2239 this.registerEventListener(xInput, "input", function(ev) { 2240 controller.setX(xInput.getValue()); 2241 }); 2242 this.registerEventListener(yInput, "input", function(ev) { 2243 controller.setY(yInput.getValue()); 2244 }); 2245 this.registerEventListener(elevationInput, "input", function(ev) { 2246 controller.setElevation(elevationInput.getValue()); 2247 }); 2248 this.registerEventListener(mirroredModelCheckBox, "change", function(ev) { 2249 controller.setModelMirrored(mirroredModelCheckBox.checked); 2250 }); 2251 this.registerEventListener(basePlanItemCheckBox, "change", function(ev) { 2252 controller.setBasePlanItem(basePlanItemCheckBox.checked); 2253 }); 2254 2255 this.locationPanel = { 2256 element: this.findElement('.location-panel'), 2257 elevationInput: elevationInput 2258 }; 2259 } 2260 2261 /** 2262 * @private 2263 */ 2264 HomeFurnitureDialog.prototype.initOrientationPanel = function() { 2265 var controller = this.controller; 2266 2267 var angleLabel = this.getElement("angle-label"); 2268 var angleDecimalFormat = new DecimalFormat("0.#"); 2269 var angleInput = new JSSpinner(this.preferences, this.getElement("angle-input"), 2270 { 2271 nullable: this.controller.getAngle() == null, 2272 format: angleDecimalFormat, 2273 minimum: 0, 2274 maximum: 360 2275 }); 2276 var rollRadioButton = this.findElement("[name='horizontal-rotation-radio'][value='ROLL']"); 2277 var pitchRadioButton = this.findElement("[name='horizontal-rotation-radio'][value='PITCH']"); 2278 var rollInput = new JSSpinner(this.preferences, this.getElement("roll-input"), 2279 { 2280 nullable: this.controller.getRoll() == null, 2281 format: angleDecimalFormat, 2282 minimum: 0, 2283 maximum: 360 2284 }); 2285 var pitchInput = new JSSpinner(this.preferences, this.getElement("pitch-input"), 2286 { 2287 nullable: this.controller.getPitch() == null, 2288 format: angleDecimalFormat, 2289 minimum: 0, 2290 maximum: 360 2291 }); 2292 2293 var verticalRotationLabel = this.getElement("vertical-rotation-label"); 2294 var horizontalRotationLabel = this.getElement("horizontal-rotation-label"); 2295 var furnitureOrientationImage = this.getElement("furniture-orientation-image"); 2296 furnitureOrientationImage.innerHTML = "<img src='" + ZIPTools.getScriptFolder() + "resources/furnitureOrientation.png' />"; 2297 2298 // 1) Adjust visibility 2299 var angleDisplay = this.controller.isPropertyEditable("ANGLE_IN_DEGREES") || this.controller.isPropertyEditable("ANGLE") ? "initial" : "none"; 2300 var rollDisplay = this.controller.isPropertyEditable("ROLL") ? "initial" : "none"; 2301 var pitchDisplay = this.controller.isPropertyEditable("PITCH") ? "initial" : "none"; 2302 2303 var rollAndPitchDisplayed = this.controller.isPropertyEditable("ROLL") && this.controller.isPropertyEditable("PITCH"); 2304 var verticalRotationLabelDisplay = rollAndPitchDisplayed ? "initial" : "none"; 2305 var horizontalRotationLabelDisplay = verticalRotationLabelDisplay; 2306 var furnitureOrientationImageDisplay = this.controller.isTexturable() && rollAndPitchDisplayed ? "initial" : "none"; 2307 2308 angleLabel.style.display = angleDisplay; 2309 angleInput.getHTMLElement().parentElement.style.display = angleDisplay; 2310 2311 rollRadioButton.parentElement.style.display = rollDisplay; 2312 rollInput.getHTMLElement().parentElement.style.display = rollDisplay; 2313 2314 pitchRadioButton.parentElement.style.display = pitchDisplay; 2315 pitchInput.getHTMLElement().parentElement.style.display = pitchDisplay; 2316 2317 horizontalRotationLabel.style.display = horizontalRotationLabelDisplay; 2318 verticalRotationLabel.style.display = verticalRotationLabelDisplay; 2319 furnitureOrientationImage.style.display = furnitureOrientationImageDisplay; 2320 2321 // 2) Set values 2322 if (this.controller.getAngle() != null) { 2323 angleInput.setValue(Math.toDegrees(this.controller.getAngle())); 2324 } else { 2325 angleInput.setValue(null); 2326 } 2327 if (this.controller.getRoll() != null) { 2328 rollInput.setValue(Math.toDegrees(this.controller.getRoll())); 2329 } else { 2330 rollInput.setValue(null); 2331 } 2332 if (this.controller.getPitch() != null) { 2333 pitchInput.setValue(Math.toDegrees(this.controller.getPitch())); 2334 } else { 2335 pitchInput.setValue(null); 2336 } 2337 2338 var updateHorizontalAxisRadioButtons = function() { 2339 rollRadioButton.checked = controller.getHorizontalAxis() == HomeFurnitureController.FurnitureHorizontalAxis.ROLL; 2340 pitchRadioButton.checked = controller.getHorizontalAxis() == HomeFurnitureController.FurnitureHorizontalAxis.PITCH; 2341 }; 2342 updateHorizontalAxisRadioButtons(); 2343 2344 // 3) Add property listeners 2345 this.registerPropertyChangeListener(this.controller, "ANGLE", function(ev) { 2346 if (controller.getAngle() != null) { 2347 angleInput.setValue(Math.toDegrees(controller.getAngle())); 2348 } else { 2349 angleInput.setValue(null); 2350 } 2351 }); 2352 this.registerPropertyChangeListener(this.controller, "ROLL", function(ev) { 2353 if (controller.getRoll() != null) { 2354 rollInput.setValue(Math.toDegrees(controller.getRoll())); 2355 } else { 2356 rollInput.setValue(null); 2357 } 2358 }); 2359 this.registerPropertyChangeListener(this.controller, "PITCH", function(ev) { 2360 if (controller.getPitch() != null) { 2361 pitchInput.setValue(Math.toDegrees(controller.getPitch())); 2362 } else { 2363 pitchInput.setValue(null); 2364 } 2365 }); 2366 this.registerPropertyChangeListener(this.controller, "HORIZONTAL_AXIS", function(ev) { 2367 updateHorizontalAxisRadioButtons(); 2368 }); 2369 2370 // 4) Add change listeners 2371 this.registerEventListener(angleInput, "input", function(ev) { 2372 if (angleInput.getValue() == null) { 2373 controller.setAngle(null); 2374 } else { 2375 controller.setAngle(Math.toRadians(angleInput.getValue())); 2376 } 2377 }); 2378 this.registerEventListener(rollInput, "input", function(ev) { 2379 if (rollInput.getValue() == null) { 2380 controller.setRoll(null); 2381 } else { 2382 controller.setRoll(Math.toRadians(rollInput.getValue())); 2383 controller.setHorizontalAxis(HomeFurnitureController.FurnitureHorizontalAxis.ROLL); 2384 } 2385 }); 2386 this.registerEventListener(pitchInput, "input", function(ev) { 2387 if (pitchInput.getValue() == null) { 2388 controller.setPitch(null); 2389 } else { 2390 controller.setPitch(Math.toRadians(pitchInput.getValue())); 2391 controller.setHorizontalAxis(HomeFurnitureController.FurnitureHorizontalAxis.PITCH); 2392 } 2393 }); 2394 this.registerEventListener([rollRadioButton, pitchRadioButton], "change", function(ev) { 2395 if (rollRadioButton.checked) { 2396 controller.setHorizontalAxis(HomeFurnitureController.FurnitureHorizontalAxis.ROLL); 2397 } else { 2398 controller.setHorizontalAxis(HomeFurnitureController.FurnitureHorizontalAxis.PITCH); 2399 } 2400 }); 2401 2402 if (!rollAndPitchDisplayed) { 2403 this.findElement('.orientation-column').style.display = 'none'; 2404 this.locationPanel.elevationInput.parentElement.insertAdjacentElement('afterend', angleLabel); 2405 angleLabel.insertAdjacentElement('afterend', angleInput.parentElement); 2406 } 2407 } 2408 2409 /** 2410 * @private 2411 */ 2412 HomeFurnitureDialog.prototype.initPaintPanel = function() { 2413 var dialog = this; 2414 var controller = this.controller; 2415 var preferences = this.preferences; 2416 2417 var colorButton = new ColorButton(preferences, 2418 { 2419 colorChanged: function(color) { 2420 colorAndTextureRadioButtons[HomeFurnitureController.FurniturePaint.COLORED].checked = true; 2421 controller.setPaint(HomeFurnitureController.FurniturePaint.COLORED); 2422 controller.setColor(color); 2423 } 2424 }); 2425 this.attachChildComponent("color-button", colorButton); 2426 colorButton.setColor(controller.getColor()); 2427 colorButton.setColorDialogTitle(preferences.getLocalizedString("HomeFurniturePanel", "colorDialog.title")); 2428 2429 var textureComponent = controller.getTextureController().getView(); 2430 this.attachChildComponent("texture-component", textureComponent); 2431 2432 var selectedPaint = controller.getPaint(); 2433 2434 var colorAndTextureRadioButtons = []; 2435 colorAndTextureRadioButtons[HomeFurnitureController.FurniturePaint.DEFAULT] = dialog.findElement("[name='paint-checkbox'][value='default']"); 2436 colorAndTextureRadioButtons[HomeFurnitureController.FurniturePaint.COLORED] = dialog.findElement("[name='paint-checkbox'][value='color']"); 2437 colorAndTextureRadioButtons[HomeFurnitureController.FurniturePaint.TEXTURED] = dialog.findElement("[name='paint-checkbox'][value='texture']"); 2438 colorAndTextureRadioButtons[HomeFurnitureController.FurniturePaint.MODEL_MATERIALS] = dialog.findElement("[name='paint-checkbox'][value='MODEL_MATERIALS']"); 2439 2440 for (var paint = 0; paint < colorAndTextureRadioButtons.length; paint++) { 2441 var radioButton = colorAndTextureRadioButtons[paint]; 2442 radioButton.checked = paint == selectedPaint 2443 || (paint == HomeFurnitureController.FurniturePaint.DEFAULT && !colorAndTextureRadioButtons[selectedPaint]); 2444 } 2445 2446 // Material 2447 var modelMaterialsComponent = controller.getModelMaterialsController().getView(); 2448 this.attachChildComponent("material-component", modelMaterialsComponent); 2449 2450 var uniqueModel = controller.getModelMaterialsController().getModel() != null; 2451 colorAndTextureRadioButtons[HomeFurnitureController.FurniturePaint.MODEL_MATERIALS].disabled = !uniqueModel; 2452 modelMaterialsComponent.setEnabled(uniqueModel); 2453 2454 this.paintPanel = { 2455 colorAndTextureRadioButtons: colorAndTextureRadioButtons, 2456 colorButton: colorButton, 2457 textureComponent: textureComponent}; 2458 2459 var panelDisplay = controller.isPropertyEditable("PAINT") && controller.isTexturable() ? undefined : "none"; 2460 this.getElement("paint-panel").style.display = panelDisplay; 2461 this.getElement("paint-panel").previousElementSibling.style.display = panelDisplay; 2462 2463 this.registerPropertyChangeListener(controller, "PAINT", function(ev) { 2464 dialog.updatePaintRadioButtons(); 2465 }); 2466 2467 this.registerEventListener(colorAndTextureRadioButtons, "change", function(ev) { 2468 var paint = colorAndTextureRadioButtons.indexOf(ev.target); 2469 controller.setPaint(paint); 2470 }); 2471 } 2472 2473 /** 2474 * @private 2475 */ 2476 HomeFurnitureDialog.prototype.updatePaintRadioButtons = function() { 2477 var dialog = this; 2478 var controller = this.controller; 2479 var colorAndTextureRadioButtons = dialog.paintPanel.colorAndTextureRadioButtons; 2480 if (controller.getPaint() == null) { 2481 for (var i = 0; i < colorAndTextureRadioButtons.length; i++) { 2482 colorAndTextureRadioButtons[i].checked = false; 2483 } 2484 } else { 2485 var selectedRadioButton = colorAndTextureRadioButtons[controller.getPaint()]; 2486 if (selectedRadioButton) { 2487 selectedRadioButton.checked = true; 2488 } 2489 this.updateShininessRadioButtons(controller); 2490 } 2491 }; 2492 2493 /** 2494 * @private 2495 */ 2496 HomeFurnitureDialog.prototype.initSizePanel = function() { 2497 var dialog = this; 2498 var controller = this.controller; 2499 2500 var widthLabel = this.getElement("width-label"); 2501 var widthInput = new JSSpinner(this.preferences, this.getElement("width-input"), 2502 { 2503 nullable: controller.getWidth() == null, 2504 format: this.preferences.getLengthUnit().getFormat(), 2505 stepSize: this.preferences.getLengthUnit().getStepSize() 2506 }); 2507 var depthLabel = this.getElement("depth-label"); 2508 var depthInput = new JSSpinner(this.preferences, this.getElement("depth-input"), 2509 { 2510 nullable: controller.getDepth() == null, 2511 format: this.preferences.getLengthUnit().getFormat(), 2512 stepSize: this.preferences.getLengthUnit().getStepSize() 2513 }); 2514 var heightLabel = this.getElement("height-label"); 2515 var heightInput = this.getElement("height-input"); 2516 var heightInput = new JSSpinner(this.preferences, this.getElement("height-input"), 2517 { 2518 nullable: controller.getHeight() == null, 2519 format: this.preferences.getLengthUnit().getFormat(), 2520 stepSize: this.preferences.getLengthUnit().getStepSize() 2521 }); 2522 var keepProportionsCheckBox = this.getElement("keep-proportions-checkbox"); 2523 var modelTransformationsButton = this.getElement("model-transformations-button"); 2524 2525 // 1) Adjust visibility 2526 var widthDisplay = this.controller.isPropertyEditable("WIDTH") ? "initial" : "none"; 2527 var depthDisplay = this.controller.isPropertyEditable("DEPTH") ? "initial" : "none"; 2528 var heightDisplay = this.controller.isPropertyEditable("HEIGHT") ? "initial" : "none"; 2529 var keepProportionsDisplay = this.controller.isPropertyEditable("PROPORTIONAL") ? "initial" : "none"; 2530 2531 widthLabel.style.display = widthDisplay; 2532 widthInput.parentElement.style.display = widthDisplay; 2533 depthLabel.style.display = depthDisplay; 2534 depthInput.parentElement.style.display = depthDisplay; 2535 heightLabel.style.display = heightDisplay; 2536 heightInput.parentElement.style.display = heightDisplay; 2537 keepProportionsCheckBox.parentElement.style.display = keepProportionsDisplay; 2538 modelTransformationsButton.parentElement.style.display = "none"; 2539 2540 if (this.controller.isPropertyEditable("MODEL_TRANSFORMATIONS") 2541 && modelTransformationsButton != null) { 2542 var modelMaterialsController = controller.getModelMaterialsController(); 2543 if (modelMaterialsController !== null && modelMaterialsController.getModel() !== null) { 2544 ModelManager.getInstance().loadModel(modelMaterialsController.getModel(), 2545 { 2546 modelUpdated : function(modelRoot) { 2547 var modelManager = ModelManager.getInstance(); 2548 if (modelManager.containsDeformableNode(modelRoot)) { 2549 // Make button visible only if model contains some deformable nodes 2550 modelTransformationsButton.innerHTML = dialog.getLocalizedLabelText("HomeFurniturePanel", 2551 modelManager.containsNode(modelRoot, ModelManager.MANNEQUIN_ABDOMEN_PREFIX) 2552 ? "mannequinTransformationsButton.text" 2553 : "modelTransformationsButton.text"); 2554 modelTransformationsButton.parentElement.style.display = "block"; 2555 dialog.registerEventListener(modelTransformationsButton, "click", function(ev) { 2556 dialog.displayModelTransformationsView(dialog.getUserPreferences(), dialog.controller); 2557 }); 2558 } 2559 }, 2560 modelError : function(ex) { 2561 // Ignore missing models 2562 } 2563 }); 2564 } 2565 } 2566 2567 // 2) Set values 2568 widthInput.setValue(this.controller.getWidth()); 2569 depthInput.setValue(this.controller.getDepth()); 2570 heightInput.setValue(this.controller.getHeight()); 2571 keepProportionsCheckBox.checked = this.controller.isProportional(); 2572 2573 // 3) Set labels 2574 var unitName = this.preferences.getLengthUnit().getName(); 2575 widthLabel.textContent = this.getLocalizedLabelText("HomeFurniturePanel", "widthLabel.text", unitName); 2576 depthLabel.textContent = this.getLocalizedLabelText("HomeFurniturePanel", "depthLabel.text", unitName); 2577 heightLabel.textContent = this.getLocalizedLabelText("HomeFurniturePanel", "heightLabel.text", unitName); 2578 2579 // 4) Set custom attributes 2580 var minimumLength = this.preferences.getLengthUnit().getMinimumLength(); 2581 var maximumLength = this.preferences.getLengthUnit().getMaximumLength(); 2582 widthInput.setMinimum(minimumLength); 2583 widthInput.setMaximum(maximumLength); 2584 depthInput.setMinimum(minimumLength); 2585 depthInput.setMaximum(maximumLength); 2586 heightInput.setMinimum(minimumLength); 2587 heightInput.setMaximum(maximumLength); 2588 2589 // 5) Add property listeners 2590 var controller = this.controller; 2591 this.registerPropertyChangeListener(this.controller, "WIDTH", function(ev) { 2592 widthInput.setValue(controller.getWidth()); 2593 }); 2594 this.registerPropertyChangeListener(this.controller, "DEPTH", function(ev) { 2595 depthInput.setValue(controller.getDepth()); 2596 }); 2597 this.registerPropertyChangeListener(this.controller, "HEIGHT", function(ev) { 2598 heightInput.setValue(controller.getHeight()); 2599 }); 2600 this.registerPropertyChangeListener(this.controller, "PROPORTIONAL", function(ev) { 2601 keepProportionsCheckBox.checked = controller.isProportional(); 2602 }); 2603 2604 // 6) Add change listeners 2605 this.registerEventListener(widthInput, "input", function(ev) { 2606 controller.setWidth(widthInput.getValue()); 2607 }); 2608 this.registerEventListener(depthInput, "input", function(ev) { 2609 controller.setDepth(depthInput.getValue()); 2610 }); 2611 this.registerEventListener(heightInput, "input", function(ev) { 2612 controller.setHeight(heightInput.getValue()); 2613 }); 2614 this.registerEventListener(keepProportionsCheckBox, "change", function(ev) { 2615 controller.setProportional(keepProportionsCheckBox.checked); 2616 }); 2617 2618 // 7) Assign panel's components 2619 this.sizePanel = { 2620 widthLabel: widthLabel, 2621 widthInput: widthInput, 2622 depthLabel: depthLabel, 2623 depthInput: depthInput, 2624 heightLabel: heightLabel, 2625 heightInput: heightInput, 2626 keepProportionsCheckBox: keepProportionsCheckBox 2627 }; 2628 2629 // 8) Handle components activation 2630 this.updateSizeComponents(); 2631 // Add a listener that enables / disables size fields depending on furniture 2632 // resizable and deformable 2633 this.registerPropertyChangeListener(this.controller, "RESIZABLE", function(ev) { 2634 dialog.updateSizeComponents(); 2635 }); 2636 this.registerPropertyChangeListener(this.controller, "DEFORMABLE", function(ev) { 2637 dialog.updateSizeComponents(); 2638 }); 2639 }; 2640 2641 /** 2642 * @private 2643 */ 2644 HomeFurnitureDialog.prototype.updateSizeComponents = function() { 2645 var editableSize = this.controller.isResizable(); 2646 this.sizePanel.widthLabel.disabled = !editableSize; 2647 this.sizePanel.widthInput.disabled = !editableSize; 2648 this.sizePanel.depthLabel.disabled = !editableSize; 2649 this.sizePanel.depthInput.disabled = !editableSize; 2650 this.sizePanel.heightLabel.disabled = !editableSize; 2651 this.sizePanel.heightInput.disabled = !editableSize; 2652 this.sizePanel.keepProportionsCheckBox.disabled = !editableSize || !this.controller.isDeformable(); 2653 }; 2654 2655 /** 2656 * @private 2657 */ 2658 HomeFurnitureDialog.prototype.initShininessPanel = function() { 2659 var controller = this.controller; 2660 var dialog = this; 2661 2662 var defaultShininessRadioButton = this.findElement("[name='shininess-radio'][value='DEFAULT']"); 2663 var mattRadioButton = this.findElement("[name='shininess-radio'][value='MATT']"); 2664 var shinyRadioButton = this.findElement("[name='shininess-radio'][value='SHINY']"); 2665 this.shininessPanel = { 2666 defaultShininessRadioButton: defaultShininessRadioButton, 2667 mattRadioButton: mattRadioButton, 2668 shinyRadioButton: shinyRadioButton}; 2669 2670 var panelDisplay = controller.isPropertyEditable("SHININESS") && controller.isTexturable() ? undefined : "none"; 2671 this.getElement("shininess-panel").style.display = panelDisplay; 2672 this.getElement("shininess-panel").previousElementSibling.style.display = panelDisplay; 2673 2674 if (controller.isPropertyEditable("SHININESS")) { 2675 // Create radio buttons bound to SHININESS controller properties 2676 this.registerEventListener([defaultShininessRadioButton, mattRadioButton, shinyRadioButton], "change", 2677 function(ev) { 2678 var selectedRadioButton = dialog.findElement("[name='shininess-radio']:checked"); 2679 controller.setShininess(HomeFurnitureController.FurnitureShininess[selectedRadioButton.value]); 2680 }); 2681 this.registerPropertyChangeListener(controller, "SHININESS", function(ev) { 2682 dialog.updateShininessRadioButtons(controller); 2683 }); 2684 2685 this.updateShininessRadioButtons(controller); 2686 } 2687 }; 2688 2689 /** 2690 * @private 2691 */ 2692 HomeFurnitureDialog.prototype.updateShininessRadioButtons = function() { 2693 var controller = this.controller; 2694 2695 if (controller.isPropertyEditable("SHININESS")) { 2696 if (controller.getShininess() == HomeFurnitureController.FurnitureShininess.DEFAULT) { 2697 this.shininessPanel.defaultShininessRadioButton.checked = true; 2698 } else if (controller.getShininess() == HomeFurnitureController.FurnitureShininess.MATT) { 2699 this.shininessPanel.mattRadioButton.checked = true; 2700 } else if (controller.getShininess() == HomeFurnitureController.FurnitureShininess.SHINY) { 2701 this.shininessPanel.shinyRadioButton.checked = true; 2702 } else { // null 2703 this.shininessPanel.defaultShininessRadioButton.checked = false; 2704 this.shininessPanel.mattRadioButton.checked = false; 2705 this.shininessPanel.shinyRadioButton.checked = false; 2706 } 2707 var shininessEnabled = controller.getPaint() != HomeFurnitureController.FurniturePaint.MODEL_MATERIALS; 2708 this.shininessPanel.defaultShininessRadioButton.disabled = !shininessEnabled; 2709 this.shininessPanel.mattRadioButton.disabled = !shininessEnabled; 2710 this.shininessPanel.shinyRadioButton.disabled = !shininessEnabled; 2711 if (!shininessEnabled) { 2712 this.shininessPanel.defaultShininessRadioButton.checked = false; 2713 this.shininessPanel.mattRadioButton.checked = false; 2714 this.shininessPanel.shinyRadioButton.checked = false; 2715 } 2716 } 2717 }; 2718 2719 /** 2720 * @private 2721 */ 2722 HomeFurnitureDialog.prototype.displayModelTransformationsView = function(preferences, controller) { 2723 var html = 2724 "<div data-name='label-panel'>" 2725 + " <span>@{ModelTransformationsPanel.transformationsLabel.text}</span><br/>" 2726 + "</div>" 2727 + "<div data-name='preview-panel'>" 2728 + " <canvas id='model-preview-canvas'></canvas>" 2729 + "</div>" 2730 + "<div data-name='edit-panel'>" 2731 + " <div>" 2732 + " <button name='reset-transformations-button'>@{ModelTransformationsPanel.resetTransformationsButton.text}</button>" 2733 + " <div name='presetTransformationsLabel'>@{ModelTransformationsPanel.presetTransformationsLabel.text}</div> " 2734 + " <div>" 2735 + " <select name='presetTransformations'></select>" 2736 + " </div>" 2737 + " <button name='view-from-front-button'>@{ModelTransformationsPanel.viewFromFrontButton.text}</button>" 2738 + " <button name='view-from-side-button'>@{ModelTransformationsPanel.viewFromSideButton.text}</button>" 2739 + " <button name='view-from-top-button'>@{ModelTransformationsPanel.viewFromTopButton.text}</button>" 2740 + " </div>" 2741 + "</div>"; 2742 var dialog = new JSDialog(preferences, 2743 preferences.getLocalizedString("ModelTransformationsPanel", "modelTransformations.title"), 2744 html, 2745 { 2746 size: "medium", 2747 applier: function() { 2748 var modelX = controller.getModelMirrored() 2749 ? -dialog.previewComponent.getModelX() 2750 : dialog.previewComponent.getModelX(); 2751 var modelY = dialog.previewComponent.getModelY(); 2752 var pieceX = (controller.getX() 2753 + modelX * Math.cos(controller.getAngle()) - modelY * Math.sin(controller.getAngle())); 2754 var pieceY = (controller.getY() 2755 + modelX * Math.sin(controller.getAngle()) + modelY * Math.cos(controller.getAngle())); 2756 var pieceElevation = controller.getElevation() 2757 + dialog.previewComponent.getModelElevation() + controller.getHeight() / 2; 2758 var modelTransformations = dialog.previewComponent.getModelTransformations(); 2759 controller.setModelTransformations(modelTransformations !== null ? modelTransformations : [], 2760 pieceX, pieceY, pieceElevation, 2761 dialog.previewComponent.getModelWidth(), 2762 dialog.previewComponent.getModelDepth(), 2763 dialog.previewComponent.getModelHeight()); 2764 }, 2765 disposer: function() { 2766 } 2767 }); 2768 2769 dialog.getHTMLElement().classList.add("model-transformations-chooser-dialog"); 2770 2771 var previewCanvas = dialog.findElement("#model-preview-canvas"); 2772 previewCanvas.width = 350; 2773 previewCanvas.height = 350; 2774 2775 var modelMaterialsController = controller.getModelMaterialsController(); 2776 dialog.previewComponent = new ModelPreviewComponent(previewCanvas, true, true); 2777 dialog.previewComponent.setModel(modelMaterialsController.getModel(), modelMaterialsController.getModelFlags(), modelMaterialsController.getModelRotation(), 2778 modelMaterialsController.getModelWidth(), modelMaterialsController.getModelDepth(), modelMaterialsController.getModelHeight()); 2779 dialog.previewComponent.setModelMaterials(modelMaterialsController.getMaterials()); 2780 dialog.previewComponent.setModelTransformations(controller.getModelTransformations()); 2781 2782 var resetTransformationsButton = dialog.getElement("reset-transformations-button"); 2783 dialog.registerEventListener(resetTransformationsButton, "click", function(ev) { 2784 dialog.previewComponent.resetModelTransformations(); 2785 }); 2786 var presetTransformationsSelect = dialog.getElement("presetTransformations"); 2787 var modelPresetTransformationsNames = controller.getModelPresetTransformationsNames(); 2788 if (modelPresetTransformationsNames.length > 0) { 2789 var option = document.createElement("option"); 2790 option.value = -1; 2791 option.textContent = preferences.getLocalizedString("ModelTransformationsPanel", "presetTransformationsComboBox.chooseTransformations.text"); 2792 presetTransformationsSelect.appendChild(option); 2793 for (var i = 0; i < modelPresetTransformationsNames.length; i++) { 2794 var option = document.createElement("option"); 2795 option.value = i; 2796 option.textContent = modelPresetTransformationsNames[i]; 2797 presetTransformationsSelect.appendChild(option); 2798 } 2799 dialog.registerEventListener(presetTransformationsSelect, "change", function(ev) { 2800 if (presetTransformationsSelect.value >= 0) 2801 dialog.previewComponent.setPresetModelTransformations( 2802 controller.getModelPresetTransformations(presetTransformationsSelect.value)); 2803 }); 2804 } else { 2805 dialog.getElement("presetTransformationsLabel").style.display = "none"; 2806 presetTransformationsSelect.style.display = "none"; 2807 } 2808 var viewFromFrontButton = dialog.getElement("view-from-front-button"); 2809 dialog.registerEventListener(viewFromFrontButton, "click", function(ev) { 2810 dialog.previewComponent.setViewYaw(0); 2811 dialog.previewComponent.setViewPitch(0); 2812 }); 2813 var viewFromSideButton = dialog.getElement("view-from-side-button"); 2814 dialog.registerEventListener(viewFromSideButton, "click", function(ev) { 2815 dialog.previewComponent.setViewYaw(Math.PI / 2); 2816 dialog.previewComponent.setViewPitch(0); 2817 }); 2818 var viewFromTopButton = dialog.getElement("view-from-top-button"); 2819 dialog.registerEventListener(viewFromTopButton, "click", function(ev) { 2820 dialog.previewComponent.setViewYaw(0); 2821 dialog.previewComponent.setViewPitch(-Math.PI / 2); 2822 }); 2823 2824 dialog.displayView(); 2825 }; 2826 2827 return new HomeFurnitureDialog(); 2828 } 2829 2830 JSViewFactory.prototype.createWallView = function(preferences, controller) { 2831 var initStartAndEndPointsPanel = function(dialog) { 2832 var maximumLength = preferences.getLengthUnit().getMaximumLength(); 2833 2834 var xStartLabel = dialog.getElement("x-start-label"); 2835 var yStartLabel = dialog.getElement("y-start-label"); 2836 var xStartInput = new JSSpinner(preferences, dialog.getElement("x-start-input"), 2837 { 2838 nullable: controller.getXStart() == null, 2839 format: preferences.getLengthUnit().getFormat(), 2840 value: controller.getXStart(), 2841 minimum: -maximumLength, 2842 maximum: maximumLength, 2843 stepSize: preferences.getLengthUnit().getStepSize() 2844 }); 2845 var yStartInput = new JSSpinner(preferences, dialog.getElement("y-start-input"), 2846 { 2847 nullable: controller.getYStart() == null, 2848 format: preferences.getLengthUnit().getFormat(), 2849 value: controller.getYStart(), 2850 minimum: -maximumLength, 2851 maximum: maximumLength, 2852 stepSize: preferences.getLengthUnit().getStepSize() 2853 }); 2854 var xEndLabel = dialog.getElement("x-end-label"); 2855 var yEndLabel = dialog.getElement("y-end-label"); 2856 var distanceToEndPointLabel = dialog.getElement("distance-to-end-point-label"); 2857 var xEndInput = new JSSpinner(preferences, dialog.getElement("x-end-input"), 2858 { 2859 nullable: controller.getXEnd() == null, 2860 format: preferences.getLengthUnit().getFormat(), 2861 value: controller.getXEnd(), 2862 minimum: -maximumLength, 2863 maximum: maximumLength, 2864 stepSize: preferences.getLengthUnit().getStepSize() 2865 }); 2866 var yEndInput = new JSSpinner(preferences, dialog.getElement("y-end-input"), 2867 { 2868 nullable: controller.getYEnd() == null, 2869 format: preferences.getLengthUnit().getFormat(), 2870 value: controller.getYEnd(), 2871 minimum: -maximumLength, 2872 maximum: maximumLength, 2873 stepSize: preferences.getLengthUnit().getStepSize() 2874 }); 2875 var distanceToEndPointInput = new JSSpinner(preferences, dialog.getElement("distance-to-end-point-input"), 2876 { 2877 nullable: controller.getDistanceToEndPoint() == null, 2878 format: preferences.getLengthUnit().getFormat(), 2879 value: controller.getDistanceToEndPoint(), 2880 minimum: preferences.getLengthUnit().getMinimumLength(), 2881 maximum: 2 * maximumLength * Math.sqrt(2), 2882 stepSize: preferences.getLengthUnit().getStepSize() 2883 }); 2884 2885 var unitName = preferences.getLengthUnit().getName(); 2886 xStartLabel.textContent = dialog.getLocalizedLabelText("WallPanel", "xLabel.text", unitName); 2887 xEndLabel.textContent = dialog.getLocalizedLabelText("WallPanel", "xLabel.text", unitName); 2888 yStartLabel.textContent = dialog.getLocalizedLabelText("WallPanel", "yLabel.text", unitName); 2889 yEndLabel.textContent = dialog.getLocalizedLabelText("WallPanel", "yLabel.text", unitName); 2890 distanceToEndPointLabel.textContent = dialog.getLocalizedLabelText("WallPanel", "distanceToEndPointLabel.text", unitName); 2891 2892 dialog.registerPropertyChangeListener(controller, "X_START", function(ev) { 2893 xStartInput.setValue(ev.getNewValue()); 2894 }); 2895 dialog.registerPropertyChangeListener(controller, "Y_START", function(ev) { 2896 yStartInput.setValue(ev.getNewValue()); 2897 }); 2898 dialog.registerPropertyChangeListener(controller, "X_END", function(ev) { 2899 xEndInput.setValue(ev.getNewValue()); 2900 }); 2901 dialog.registerPropertyChangeListener(controller, "Y_END", function(ev) { 2902 yEndInput.setValue(ev.getNewValue()); 2903 }); 2904 dialog.registerPropertyChangeListener(controller, "DISTANCE_TO_END_POINT", function(ev) { 2905 distanceToEndPointInput.setValue(ev.getNewValue()); 2906 }); 2907 2908 dialog.registerEventListener(xStartInput, "input", function(ev) { 2909 controller.setXStart(xStartInput.getValue()); 2910 }); 2911 dialog.registerEventListener(yStartInput, "input", function(ev) { 2912 controller.setYStart(yStartInput.getValue()); 2913 }); 2914 dialog.registerEventListener(xEndInput, "input", function(ev) { 2915 controller.setXEnd(xEndInput.getValue()); 2916 }); 2917 dialog.registerEventListener(yEndInput, "input", function(ev) { 2918 controller.setYEnd(yEndInput.getValue()); 2919 }); 2920 dialog.registerEventListener(distanceToEndPointInput, "input", function(ev) { 2921 controller.setDistanceToEndPoint(distanceToEndPointInput.getValue()); 2922 }); 2923 } 2924 2925 var editBaseboard = function(dialogTitle, controller) { 2926 var view = controller.getView(); 2927 var dialog = new JSDialog(preferences, dialogTitle, 2928 "<div data-name='content'></div>", 2929 { 2930 size: "small", 2931 applier: function() { 2932 // Do not remove - applier must be defined so OK button shows 2933 }, 2934 disposer: function() { 2935 view.dispose(); 2936 } 2937 }); 2938 dialog.attachChildComponent("content", view); 2939 2940 var visible = controller.getVisible(); 2941 var color = controller.getColor(); 2942 var texture = controller.getTextureController().getTexture(); 2943 var paint = controller.getPaint(); 2944 var thickness = controller.getThickness(); 2945 var height = controller.getHeight(); 2946 2947 dialog.cancel = function() { 2948 controller.setVisible(visible); 2949 controller.setColor(color); 2950 controller.getTextureController().setTexture(texture); 2951 controller.setPaint(paint); 2952 controller.setThickness(thickness); 2953 controller.setHeight(height); 2954 dialog.close(); 2955 }; 2956 dialog.displayView(); 2957 }; 2958 2959 var initLeftAndRightSidesPanels = function(dialog) { 2960 var leftSideColorRadioButton = dialog.findElement("[name='left-side-color-and-texture-choice'][value='COLORED']"); 2961 var leftSideTextureRadioButton = dialog.findElement("[name='left-side-color-and-texture-choice'][value='TEXTURED']"); 2962 var rightSideColorRadioButton = dialog.findElement("[name='right-side-color-and-texture-choice'][value='COLORED']"); 2963 var rightSideTextureRadioButton = dialog.findElement("[name='right-side-color-and-texture-choice'][value='TEXTURED']"); 2964 2965 var updateLeftSidePaint = function() { 2966 leftSideColorRadioButton.checked = controller.getLeftSidePaint() == WallController.WallPaint.COLORED; 2967 leftSideTextureRadioButton.checked = controller.getLeftSidePaint() == WallController.WallPaint.TEXTURED; 2968 } 2969 var updateRightSidePaint = function() { 2970 rightSideColorRadioButton.checked = controller.getRightSidePaint() == WallController.WallPaint.COLORED; 2971 rightSideTextureRadioButton.checked = controller.getRightSidePaint() == WallController.WallPaint.TEXTURED; 2972 } 2973 2974 updateLeftSidePaint(); 2975 updateRightSidePaint(); 2976 dialog.registerPropertyChangeListener(controller, "LEFT_SIDE_PAINT", function() { 2977 updateLeftSidePaint(); 2978 }); 2979 dialog.registerPropertyChangeListener(controller, "RIGHT_SIDE_PAINT", function() { 2980 updateRightSidePaint(); 2981 }); 2982 2983 // Colors 2984 dialog.leftSideColorButton = new ColorButton(preferences, 2985 { 2986 colorChanged: function(selectedColor) { 2987 dialog.findElement("[name='left-side-color-and-texture-choice'][value='COLORED']").checked = true; 2988 controller.setLeftSidePaint(WallController.WallPaint.COLORED); 2989 controller.setLeftSideColor(selectedColor); 2990 } 2991 }); 2992 dialog.rightSideColorButton = new ColorButton(preferences, 2993 { 2994 colorChanged: function(selectedColor) { 2995 dialog.findElement("[name='right-side-color-and-texture-choice'][value='COLORED']").checked = true; 2996 controller.setRightSidePaint(WallController.WallPaint.COLORED); 2997 controller.setRightSideColor(selectedColor); 2998 } 2999 }); 3000 dialog.attachChildComponent("left-side-color-button", dialog.leftSideColorButton); 3001 dialog.attachChildComponent("right-side-color-button", dialog.rightSideColorButton); 3002 3003 dialog.leftSideColorButton.setColor(controller.getLeftSideColor()); 3004 dialog.leftSideColorButton.setColorDialogTitle(preferences.getLocalizedString( 3005 "WallPanel", "leftSideColorDialog.title")); 3006 dialog.rightSideColorButton.setColor(controller.getRightSideColor()); 3007 dialog.rightSideColorButton.setColorDialogTitle(preferences.getLocalizedString( 3008 "WallPanel", "rightSideColorDialog.title")); 3009 dialog.registerPropertyChangeListener(controller, "LEFT_SIDE_COLOR", function() { 3010 dialog.leftSideColorButton.setColor(controller.getLeftSideColor()); 3011 }); 3012 dialog.registerPropertyChangeListener(controller, "RIGHT_SIDE_COLOR", function() { 3013 dialog.rightSideColorButton.setColor(controller.getRightSideColor()); 3014 }); 3015 3016 // Textures 3017 dialog.leftSideTextureComponent = controller.getLeftSideTextureController().getView(); 3018 dialog.attachChildComponent('left-side-texture-component', dialog.leftSideTextureComponent); 3019 3020 dialog.rightSideTextureComponent = controller.getRightSideTextureController().getView(); 3021 dialog.attachChildComponent("right-side-texture-component", dialog.rightSideTextureComponent); 3022 3023 // Shininess 3024 var leftSideMattRadioButton = dialog.findElement("[name='left-side-shininess-choice'][value='0']"); 3025 var leftSideShinyRadioButton = dialog.findElement("[name='left-side-shininess-choice'][value='0.25']"); 3026 var rightSideMattRadioButton = dialog.findElement("[name='right-side-shininess-choice'][value='0']"); 3027 var rightSideShinyRadioButton = dialog.findElement("[name='right-side-shininess-choice'][value='0.25']"); 3028 3029 var updateLeftSideShininess = function() { 3030 leftSideMattRadioButton.checked = controller.getLeftSideShininess() == 0; 3031 leftSideShinyRadioButton.checked = controller.getLeftSideShininess() == 0.25; 3032 } 3033 var updateRightSideShininess = function() { 3034 rightSideMattRadioButton.checked = controller.getRightSideShininess() == 0; 3035 rightSideShinyRadioButton.checked = controller.getRightSideShininess() == 0.25 3036 } 3037 3038 updateLeftSideShininess(); 3039 updateRightSideShininess(); 3040 dialog.registerPropertyChangeListener(controller, "LEFT_SIDE_SHININESS", function(ev) { 3041 updateLeftSideShininess(); 3042 }); 3043 dialog.registerPropertyChangeListener(controller, "RIGHT_SIDE_SHININESS", function(ev) { 3044 updateRightSideShininess(); 3045 }); 3046 dialog.registerEventListener([leftSideMattRadioButton, leftSideShinyRadioButton], "change", 3047 function(ev) { 3048 controller.setLeftSideShininess(parseFloat(this.value)); 3049 }); 3050 dialog.registerEventListener([rightSideMattRadioButton, rightSideShinyRadioButton], "change", 3051 function(ev) { 3052 controller.setRightSideShininess(parseFloat(this.value)); 3053 }); 3054 3055 // Baseboards 3056 var leftSideBaseboardButton = dialog.getElement("left-side-modify-baseboard-button"); 3057 var rightSideBaseboardButton = dialog.getElement("right-side-modify-baseboard-button"); 3058 var leftSideBaseboardButtonAction = new ResourceAction(preferences, "WallPanel", "MODIFY_LEFT_SIDE_BASEBOARD", true); 3059 var rightSideBaseboardButtonAction = new ResourceAction(preferences, "WallPanel", "MODIFY_RIGHT_SIDE_BASEBOARD", true); 3060 leftSideBaseboardButton.textContent = leftSideBaseboardButtonAction.getValue(AbstractAction.NAME); 3061 rightSideBaseboardButton.textContent = rightSideBaseboardButtonAction.getValue(AbstractAction.NAME); 3062 3063 dialog.registerEventListener(leftSideBaseboardButton, "click", function(ev) { 3064 editBaseboard(dialog.getLocalizedLabelText("WallPanel", "leftSideBaseboardDialog.title"), 3065 controller.getLeftSideBaseboardController()); 3066 }); 3067 dialog.registerEventListener(rightSideBaseboardButton, "click", function(ev) { 3068 editBaseboard(dialog.getLocalizedLabelText("WallPanel", "rightSideBaseboardDialog.title"), 3069 controller.getRightSideBaseboardController()); 3070 }); 3071 }; 3072 3073 var initTopPanel = function(dialog) { 3074 var patternsTexturesByURL = {}; 3075 var patterns = preferences.getPatternsCatalog().getPatterns(); 3076 for (var i = 0; i < patterns.length; i++) { 3077 var url = patterns[i].getImage().getURL(); 3078 patternsTexturesByURL[url] = patterns[i]; 3079 } 3080 var patternSelect = dialog.getElement("pattern-select"); 3081 patternSelect.classList.add("wall-pattern-combo-box"); 3082 var patternComboBox = new JSComboBox(this.preferences, patternSelect, 3083 { 3084 nullable: controller.getPattern() != null, 3085 availableValues: Object.keys(patternsTexturesByURL), 3086 renderCell: function(patternURL, patternItemElement) { 3087 patternItemElement.style.backgroundImage = "url('" + patternURL + "')"; 3088 }, 3089 selectionChanged: function(newValue) { 3090 controller.setPattern(patternsTexturesByURL[newValue]); 3091 } 3092 }); 3093 3094 var patternChangeListener = function() { 3095 var pattern = controller.getPattern(); 3096 patternComboBox.setSelectedItem(controller.getPattern() != null 3097 ? pattern.getImage().getURL() 3098 : null); 3099 }; 3100 patternChangeListener(); 3101 dialog.registerPropertyChangeListener(controller, "PATTERN", function(ev) { 3102 patternChangeListener(); 3103 }); 3104 3105 var topDefaultColorRadioButton = dialog.findElement("[name='top-color-choice'][value='DEFAULT']"); 3106 var topColorRadioButton = dialog.findElement("[name='top-color-choice'][value='COLORED']"); 3107 var topPaintRadioButtons = [topDefaultColorRadioButton, topColorRadioButton]; 3108 var topPaintChangeListener = function() { 3109 topDefaultColorRadioButton.checked = controller.getTopPaint() == WallController.WallPaint.DEFAULT; 3110 topColorRadioButton.checked = controller.getTopPaint() == WallController.WallPaint.COLORED; 3111 }; 3112 3113 dialog.registerEventListener(topPaintRadioButtons, "click", function(ev) { 3114 controller.setTopPaint(WallController.WallPaint[this.value]); 3115 }); 3116 topPaintChangeListener(); 3117 dialog.registerPropertyChangeListener(controller, "TOP_PAINT", function(ev) { 3118 topPaintChangeListener(); 3119 }); 3120 3121 dialog.topColorButton = new ColorButton(preferences, 3122 { 3123 colorChanged: function(selectedColor) { 3124 topColorRadioButton.checked = true; 3125 controller.setTopPaint(WallController.WallPaint.COLORED); 3126 controller.setTopColor(selectedColor); 3127 } 3128 }); 3129 dialog.attachChildComponent("top-color-button", dialog.topColorButton); 3130 dialog.topColorButton.setColor(controller.getTopColor()); 3131 dialog.topColorButton.setColorDialogTitle(preferences.getLocalizedString( 3132 "WallPanel", "topColorDialog.title")); 3133 dialog.registerPropertyChangeListener(controller, "TOP_COLOR", function() { 3134 dialog.topColorButton.setColor(controller.getTopColor()); 3135 }); 3136 }; 3137 3138 var initHeightPanel = function(dialog) { 3139 var unitName = preferences.getLengthUnit().getName(); 3140 dialog.getElement("rectangular-wall-height-label").textContent = dialog.getLocalizedLabelText("WallPanel", "rectangularWallHeightLabel.text", unitName); 3141 3142 var rectangularWallRadioButton = dialog.findElement("[name='wall-shape-choice'][value='RECTANGULAR_WALL']"); 3143 var slopingWallRadioButton = dialog.findElement("[name='wall-shape-choice'][value='SLOPING_WALL']"); 3144 3145 dialog.registerEventListener([rectangularWallRadioButton, slopingWallRadioButton], "change", function(ev) { 3146 controller.setShape(WallController.WallShape[this.value]); 3147 }); 3148 var wallShapeChangeListener = function() { 3149 rectangularWallRadioButton.checked = controller.getShape() == WallController.WallShape.RECTANGULAR_WALL; 3150 slopingWallRadioButton.checked = controller.getShape() == WallController.WallShape.SLOPING_WALL; 3151 }; 3152 wallShapeChangeListener(); 3153 dialog.registerPropertyChangeListener(controller, "SHAPE", function(ev) { 3154 wallShapeChangeListener(); 3155 }); 3156 3157 var minimumLength = preferences.getLengthUnit().getMinimumLength(); 3158 var maximumLength = preferences.getLengthUnit().getMaximumLength(); 3159 var rectangularWallHeightInput = new JSSpinner(preferences, dialog.getElement("rectangular-wall-height-input"), 3160 { 3161 nullable: controller.getRectangularWallHeight() == null, 3162 format: preferences.getLengthUnit().getFormat(), 3163 value: controller.getRectangularWallHeight(), 3164 minimum: minimumLength, 3165 maximum: maximumLength, 3166 stepSize: preferences.getLengthUnit().getStepSize() 3167 }); 3168 dialog.registerPropertyChangeListener(controller, "RECTANGULAR_WALL_HEIGHT", function(ev) { 3169 rectangularWallHeightInput.setValue(ev.getNewValue()); 3170 }); 3171 dialog.registerEventListener(rectangularWallHeightInput, "input", function(ev) { 3172 controller.setRectangularWallHeight(rectangularWallHeightInput.getValue()); 3173 }); 3174 3175 var minimumHeight = controller.getSlopingWallHeightAtStart() != null && controller.getSlopingWallHeightAtEnd() != null 3176 ? 0 3177 : minimumLength; 3178 var slopingWallHeightAtStartInput = new JSSpinner(preferences, dialog.getElement("sloping-wall-height-at-start-input"), 3179 { 3180 nullable: controller.getSlopingWallHeightAtStart() == null, 3181 format: preferences.getLengthUnit().getFormat(), 3182 value: controller.getSlopingWallHeightAtStart(), 3183 minimum: minimumHeight, 3184 maximum: maximumLength, 3185 stepSize: preferences.getLengthUnit().getStepSize() 3186 }); 3187 dialog.registerPropertyChangeListener(controller, "SLOPING_WALL_HEIGHT_AT_START", function(ev) { 3188 slopingWallHeightAtStartInput.setValue(ev.getNewValue()); 3189 }); 3190 dialog.registerEventListener(slopingWallHeightAtStartInput, "input", function(ev) { 3191 controller.setSlopingWallHeightAtStart(slopingWallHeightAtStartInput.getValue()); 3192 if (minimumHeight == 0 3193 && controller.getSlopingWallHeightAtStart() == 0 3194 && controller.getSlopingWallHeightAtEnd() == 0) { 3195 // Ensure wall height is never 0 3196 controller.setSlopingWallHeightAtEnd(minimumLength); 3197 } 3198 }); 3199 3200 var slopingWallHeightAtEndInput = new JSSpinner(preferences, dialog.getElement("sloping-wall-height-at-end-input"), 3201 { 3202 nullable: controller.getSlopingWallHeightAtEnd() == null, 3203 format: preferences.getLengthUnit().getFormat(), 3204 value: controller.getSlopingWallHeightAtEnd(), 3205 minimum: minimumHeight, 3206 maximum: maximumLength, 3207 stepSize: preferences.getLengthUnit().getStepSize() 3208 }); 3209 dialog.registerPropertyChangeListener(controller, "SLOPING_WALL_HEIGHT_AT_END", function(ev) { 3210 slopingWallHeightAtEndInput.setValue(ev.getNewValue()); 3211 }); 3212 dialog.registerEventListener(slopingWallHeightAtEndInput, "input", function(ev) { 3213 controller.setSlopingWallHeightAtEnd(slopingWallHeightAtEndInput.getValue()); 3214 if (minimumHeight == 0 3215 && controller.getSlopingWallHeightAtStart() == 0 3216 && controller.getSlopingWallHeightAtEnd() == 0) { 3217 // Ensure wall height is never 0 3218 controller.setSlopingWallHeightAtStart(minimumLength); 3219 } 3220 }); 3221 3222 dialog.getElement("thickness-label").textContent = dialog.getLocalizedLabelText("WallPanel", "thicknessLabel.text", unitName); 3223 var thicknessInput = new JSSpinner(preferences, dialog.getElement("thickness-input"), 3224 { 3225 nullable: controller.getThickness() == null, 3226 format: preferences.getLengthUnit().getFormat(), 3227 value: controller.getThickness(), 3228 minimum: minimumLength, 3229 maximum: maximumLength / 10, 3230 stepSize: preferences.getLengthUnit().getStepSize() 3231 }); 3232 dialog.registerPropertyChangeListener(controller, "THICKNESS", function(ev) { 3233 thicknessInput.setValue(ev.getNewValue()); 3234 }); 3235 dialog.registerEventListener(thicknessInput, "input", function(ev) { 3236 controller.setThickness(thicknessInput.getValue()); 3237 }); 3238 3239 dialog.getElement("arc-extent-label").textContent = dialog.getLocalizedLabelText("WallPanel", "arcExtentLabel.text", unitName); 3240 var angleDecimalFormat = new DecimalFormat("0.#"); 3241 var arcExtentInput = new JSSpinner(this.preferences, dialog.getElement("arc-extent-input"), 3242 { 3243 nullable: controller.getArcExtentInDegrees() == null, 3244 format: angleDecimalFormat, 3245 value: 0, 3246 minimum: -270, 3247 maximum: 270, 3248 stepSize: 5 3249 }); 3250 var arcExtentChangeListener = function() { 3251 arcExtentInput.setValue(controller.getArcExtentInDegrees()); 3252 }; 3253 arcExtentChangeListener(); 3254 dialog.registerPropertyChangeListener(controller, "ARC_EXTENT_IN_DEGREES", function(ev) { 3255 arcExtentChangeListener(); 3256 }); 3257 3258 dialog.registerEventListener(arcExtentInput, "input", function(ev) { 3259 controller.setArcExtentInDegrees(arcExtentInput.getValue()); 3260 }); 3261 }; 3262 3263 var dialog = new JSDialog(preferences, 3264 "@{WallPanel.wall.title}", 3265 document.getElementById("wall-dialog-template"), 3266 { 3267 applier: function(dialog) { 3268 controller.modifyWalls(); 3269 }, 3270 disposer: function(dialog) { 3271 dialog.leftSideColorButton.dispose(); 3272 dialog.rightSideColorButton.dispose(); 3273 dialog.leftSideTextureComponent.dispose(); 3274 dialog.rightSideTextureComponent.dispose(); 3275 dialog.topColorButton.dispose(); 3276 }, 3277 size: "medium" 3278 }); 3279 3280 initStartAndEndPointsPanel(dialog); 3281 initLeftAndRightSidesPanels(dialog); 3282 initTopPanel(dialog); 3283 initHeightPanel(dialog); 3284 3285 dialog.getElement("wall-orientation-label").innerHTML = dialog.getLocalizedLabelText( 3286 "WallPanel", "wallOrientationLabel.text", ZIPTools.getScriptFolder() + "resources/wallOrientation.png"); 3287 3288 var setVisible = function(element, visible, parent) { 3289 if (element != null) { 3290 if (parent) { 3291 element = element.parentElement; 3292 } 3293 element.style.display = visible ? "" : "none"; 3294 element.previousElementSibling.style.display = visible ? "" : "none"; 3295 if (parent) { 3296 element.nextElementSibling.style.display = visible ? "" : "none"; 3297 } 3298 } 3299 }; 3300 3301 var editablePointsListener = function() { 3302 setVisible(dialog.getElement("x-start-input"), controller.isEditablePoints(), true); 3303 setVisible(dialog.getElement("x-end-input"), controller.isEditablePoints(), true); 3304 setVisible(dialog.getElement("distance-to-end-point-input"), controller.isEditablePoints()); 3305 setVisible(dialog.getElement("arc-extent-input"), controller.isEditablePoints()); 3306 }; 3307 dialog.registerPropertyChangeListener(controller, "EDITABLE_POINTS", editablePointsListener); 3308 editablePointsListener(controller.isEditablePoints()); 3309 3310 return dialog; 3311 } 3312 3313 /** 3314 * @param {UserPreferences} preferences 3315 * @param {RoomController} controller 3316 * @return {JSDialog} 3317 */ 3318 JSViewFactory.prototype.createRoomView = function(preferences, controller) { 3319 var initFloorPanel = function(dialog) { 3320 // FLOOR_VISIBLE 3321 var floorVisibleDisplay = controller.isPropertyEditable("FLOOR_VISIBLE") ? "initial" : "none"; 3322 dialog.floorVisibleCheckBox = dialog.getElement("floor-visible-checkbox"); 3323 dialog.floorVisibleCheckBox.checked = controller.getFloorVisible(); 3324 dialog.floorVisibleCheckBox.parentElement.style.display = floorVisibleDisplay; 3325 dialog.registerEventListener(dialog.floorVisibleCheckBox, "change", function(ev) { 3326 controller.setFloorVisible(dialog.floorVisibleCheckBox.checked); 3327 }); 3328 dialog.registerPropertyChangeListener(controller, "FLOOR_VISIBLE", function(ev) { 3329 dialog.floorVisibleCheckBox.checked = controller.getFloorVisible(ev); 3330 }); 3331 3332 // FLOOR_PAINT 3333 var floorColorRadioButton = dialog.findElement("[name='floor-color-and-texture-choice'][value='COLORED']"); 3334 dialog.floorColorButton = new ColorButton(preferences, 3335 { 3336 colorChanged: function(selectedColor) { 3337 floorColorRadioButton.checked = true; 3338 controller.setFloorPaint(RoomController.RoomPaint.COLORED); 3339 controller.setFloorColor(selectedColor); 3340 } 3341 }); 3342 dialog.attachChildComponent("floor-color-button", dialog.floorColorButton); 3343 dialog.floorColorButton.setColor(controller.getFloorColor()); 3344 dialog.floorColorButton.setColorDialogTitle(preferences.getLocalizedString( 3345 "RoomPanel", "floorColorDialog.title")); 3346 3347 var floorTextureRadioButton = dialog.findElement("[name='floor-color-and-texture-choice'][value='TEXTURED']"); 3348 dialog.floorTextureComponent = controller.getFloorTextureController().getView(); 3349 dialog.attachChildComponent("floor-texture-component", dialog.floorTextureComponent); 3350 3351 dialog.registerEventListener([floorColorRadioButton, floorTextureRadioButton], "change", function(ev) { 3352 controller.setFloorPaint(RoomController.RoomPaint[this.value]); 3353 }); 3354 3355 var paintChangeListener = function() { 3356 floorColorRadioButton.checked = controller.getFloorPaint() == RoomController.RoomPaint.COLORED; 3357 floorTextureRadioButton.checked = controller.getFloorPaint() == RoomController.RoomPaint.TEXTURED; 3358 }; 3359 dialog.registerPropertyChangeListener(controller, "FLOOR_PAINT", paintChangeListener); 3360 3361 var floorPaintDisplay = controller.isPropertyEditable("FLOOR_PAINT") ? "initial" : "none"; 3362 floorColorRadioButton.parentElement.parentElement.style.display = floorPaintDisplay; 3363 floorTextureRadioButton.parentElement.parentElement.style.display = floorPaintDisplay; 3364 dialog.getElement("floor-color-button").style.display = floorPaintDisplay; 3365 dialog.getElement("floor-texture-component").style.display = floorPaintDisplay; 3366 3367 paintChangeListener(); 3368 3369 // FLOOR_SHININESS 3370 var shininessRadioButtons = dialog.findElements("[name='floor-shininess-choice']"); 3371 dialog.registerEventListener(shininessRadioButtons, "change", function() { 3372 controller.setFloorShininess(parseFloat(this.value)); 3373 }); 3374 3375 var shininessChangeListener = function() { 3376 for (var i = 0; i < shininessRadioButtons.length; i++) { 3377 shininessRadioButtons[i].checked = controller.getFloorShininess() == parseFloat(shininessRadioButtons[i].value); 3378 } 3379 }; 3380 shininessChangeListener(); 3381 dialog.registerPropertyChangeListener(controller, "FLOOR_SHININESS", shininessChangeListener); 3382 3383 var floorShininessDisplay = controller.isPropertyEditable("FLOOR_SHININESS") ? "initial" : "none"; 3384 shininessRadioButtons[0].parentElement.parentElement = floorShininessDisplay; 3385 }; 3386 3387 var initCeilingPanel = function(dialog) { 3388 // CEILING_VISIBLE 3389 var ceilingVisibleDisplay = controller.isPropertyEditable("CEILING_VISIBLE") ? "initial" : "none"; 3390 dialog.ceilingVisibleCheckBox = dialog.getElement("ceiling-visible-checkbox"); 3391 dialog.ceilingVisibleCheckBox.checked = controller.getCeilingVisible(); 3392 dialog.ceilingVisibleCheckBox.parentElement.style.display = ceilingVisibleDisplay; 3393 dialog.registerEventListener(dialog.ceilingVisibleCheckBox, "change", function(ev) { 3394 controller.setCeilingVisible(dialog.ceilingVisibleCheckBox.checked); 3395 }); 3396 dialog.registerPropertyChangeListener(controller, "CEILING_VISIBLE", function(ev) { 3397 dialog.ceilingVisibleCheckBox.checked = controller.getCeilingVisible(); 3398 }); 3399 3400 // CEILING_PAINT 3401 var ceilingColorRadioButton = dialog.findElement("[name='ceiling-color-and-texture-choice'][value='COLORED']"); 3402 dialog.ceilingColorButton = new ColorButton(preferences, 3403 { 3404 colorChanged: function(selectedColor) { 3405 ceilingColorRadioButton.checked = true; 3406 controller.setCeilingPaint(RoomController.RoomPaint.COLORED); 3407 controller.setCeilingColor(selectedColor); 3408 } 3409 }); 3410 dialog.attachChildComponent("ceiling-color-button", dialog.ceilingColorButton); 3411 dialog.ceilingColorButton.setColor(controller.getCeilingColor()); 3412 dialog.ceilingColorButton.setColorDialogTitle(preferences.getLocalizedString( 3413 "RoomPanel", "ceilingColorDialog.title")); 3414 3415 var ceilingTextureRadioButton = dialog.findElement("[name='ceiling-color-and-texture-choice'][value='TEXTURED']"); 3416 dialog.ceilingTextureComponent = controller.getCeilingTextureController().getView(); 3417 dialog.attachChildComponent("ceiling-texture-component", dialog.ceilingTextureComponent); 3418 3419 dialog.registerEventListener([ceilingColorRadioButton, ceilingTextureRadioButton], "change", function(ev) { 3420 controller.setCeilingPaint(RoomController.RoomPaint[this.value]); 3421 }); 3422 3423 var paintChangeListener = function() { 3424 ceilingColorRadioButton.checked = controller.getCeilingPaint() == RoomController.RoomPaint.COLORED; 3425 ceilingTextureRadioButton.checked = controller.getCeilingPaint() == RoomController.RoomPaint.TEXTURED; 3426 }; 3427 paintChangeListener(); 3428 dialog.registerPropertyChangeListener(controller, "CEILING_PAINT", paintChangeListener); 3429 3430 var ceilingPaintDisplay = controller.isPropertyEditable("CEILING_PAINT") ? "initial" : "none"; 3431 ceilingColorRadioButton.parentElement.parentElement.style.display = ceilingPaintDisplay; 3432 ceilingTextureRadioButton.parentElement.parentElement.style.display = ceilingPaintDisplay; 3433 dialog.getElement("ceiling-color-button").style.display = ceilingPaintDisplay; 3434 dialog.getElement("ceiling-texture-component").style.display = ceilingPaintDisplay; 3435 3436 // CEILING_SHININESS 3437 var shininessRadioButtons = dialog.findElements("[name='ceiling-shininess-choice']"); 3438 dialog.registerEventListener(shininessRadioButtons, "change", function() { 3439 controller.setCeilingShininess(parseFloat(this.value)); 3440 }); 3441 3442 var shininessChangeListener = function() { 3443 for (var i = 0; i < shininessRadioButtons.length; i++) { 3444 shininessRadioButtons[i].checked = controller.getCeilingShininess() == parseFloat(shininessRadioButtons[i].value); 3445 } 3446 } 3447 shininessChangeListener(); 3448 dialog.registerPropertyChangeListener(controller, "CEILING_SHININESS", shininessChangeListener); 3449 3450 var ceilingShininessDisplay = controller.isPropertyEditable("CEILING_SHININESS") ? "initial" : "none"; 3451 shininessRadioButtons[0].parentElement.parentElement = ceilingShininessDisplay; 3452 3453 // CEILING_FLAT 3454 dialog.ceilingFlatCheckBox = dialog.getElement("ceiling-flat-checkbox"); 3455 dialog.ceilingFlatCheckBox.checked = controller.getCeilingFlat(); 3456 dialog.ceilingFlatCheckBox.parentElement.style.display = 3457 controller.isPropertyEditable("CEILING_FLAT") ? "initial" : "none"; 3458 dialog.registerEventListener(dialog.ceilingFlatCheckBox, "change", function(ev) { 3459 controller.setCeilingFlat(dialog.ceilingFlatCheckBox.checked); 3460 }); 3461 dialog.registerPropertyChangeListener(controller, "CEILING_FLAT", function(ev) { 3462 dialog.ceilingFlatCheckBox.checked = controller.getCeilingFlat(ev); 3463 }); 3464 }; 3465 3466 var selectSplitSurroundingWallsAtFirstChange = function(dialog) { 3467 if (dialog.firstWallChange 3468 && dialog.splitSurroundingWallsCheckBox != null 3469 && !dialog.splitSurroundingWallsCheckBox.disabled) { 3470 dialog.splitSurroundingWallsCheckBox.checked = true; 3471 var ev = document.createEvent("Event"); 3472 ev.initEvent("change", true, true); 3473 dialog.splitSurroundingWallsCheckBox.dispatchEvent(ev); 3474 dialog.firstWallChange = false; 3475 } 3476 }; 3477 3478 var initWallSidesPanel = function (dialog) { 3479 // SPLIT_SURROUNDING_WALLS 3480 var splitSurroundingWallsPropertyChanged = function() { 3481 dialog.splitSurroundingWallsCheckBox.disabled = !controller.isSplitSurroundingWallsNeeded(); 3482 dialog.splitSurroundingWallsCheckBox.checked = controller.isSplitSurroundingWalls(); 3483 } 3484 3485 var splitSurroundingWallsDisplay = controller.isPropertyEditable("SPLIT_SURROUNDING_WALLS") ? "initial" : "none"; 3486 dialog.splitSurroundingWallsCheckBox = dialog.getElement("split-surrounding-walls-checkbox"); 3487 dialog.splitSurroundingWallsCheckBox.parentElement.style.display = splitSurroundingWallsDisplay; 3488 dialog.registerEventListener(dialog.splitSurroundingWallsCheckBox, "change", function(ev) { 3489 controller.setSplitSurroundingWalls(dialog.splitSurroundingWallsCheckBox.checked); 3490 dialog.firstWallChange = false; 3491 }); 3492 splitSurroundingWallsPropertyChanged(); 3493 dialog.registerPropertyChangeListener(controller, "SPLIT_SURROUNDING_WALLS", function(ev) { 3494 splitSurroundingWallsPropertyChanged(); 3495 }); 3496 3497 // WALL_SIDES_PAINT 3498 var wallSidesColorRadioButton = dialog.findElement("[name='wall-sides-color-and-texture-choice'][value='COLORED']"); 3499 dialog.wallSidesColorButton = new ColorButton(preferences, 3500 { 3501 colorChanged: function(selectedColor) { 3502 wallSidesColorRadioButton.checked = true; 3503 controller.setWallSidesPaint(RoomController.RoomPaint.COLORED); 3504 controller.setWallSidesColor(selectedColor); 3505 selectSplitSurroundingWallsAtFirstChange(dialog); 3506 } 3507 }); 3508 dialog.attachChildComponent("wall-sides-color-button", dialog.wallSidesColorButton); 3509 dialog.wallSidesColorButton.setColor(controller.getWallSidesColor()); 3510 dialog.wallSidesColorButton.setColorDialogTitle(preferences.getLocalizedString( 3511 "RoomPanel", "wallSidesColorDialog.title")); 3512 3513 var wallSidesTextureRadioButton = dialog.findElement("[name='wall-sides-color-and-texture-choice'][value='TEXTURED']"); 3514 dialog.wallSidesTextureComponent = controller.getWallSidesTextureController().getView(); 3515 dialog.registerPropertyChangeListener(controller.getWallSidesTextureController(), "TEXTURE", function(ev) { 3516 selectSplitSurroundingWallsAtFirstChange(dialog); 3517 }); 3518 dialog.attachChildComponent("wall-sides-texture-component", dialog.wallSidesTextureComponent); 3519 3520 dialog.registerEventListener([wallSidesColorRadioButton, wallSidesTextureRadioButton], "change", function(ev) { 3521 controller.setWallSidesPaint(RoomController.RoomPaint[this.value]); 3522 }); 3523 3524 var paintChangeListener = function() { 3525 wallSidesColorRadioButton.checked = controller.getWallSidesPaint() == RoomController.RoomPaint.COLORED; 3526 wallSidesTextureRadioButton.checked = controller.getWallSidesPaint() == RoomController.RoomPaint.TEXTURED; 3527 }; 3528 paintChangeListener(); 3529 dialog.registerPropertyChangeListener(controller, "WALL_SIDES_PAINT", paintChangeListener); 3530 3531 var wallSidesPaintDisplay = controller.isPropertyEditable("WALL_SIDES_PAINT") ? "initial" : "none"; 3532 wallSidesColorRadioButton.parentElement.parentElement.style.display = wallSidesPaintDisplay; 3533 wallSidesTextureRadioButton.parentElement.parentElement.style.display = wallSidesPaintDisplay; 3534 dialog.getElement("wall-sides-color-button").style.display = wallSidesPaintDisplay; 3535 dialog.getElement("wall-sides-texture-component").style.display = wallSidesPaintDisplay; 3536 3537 // WALL_SIDES_SHININESS 3538 var shininessRadioButtons = dialog.findElements("[name='wall-sides-shininess-choice']"); 3539 dialog.registerEventListener(shininessRadioButtons, "change", function(ev) { 3540 controller.setWallSidesShininess(parseFloat(this.value)); 3541 }); 3542 3543 var shininessChangeListener = function() { 3544 for (var i = 0; i < shininessRadioButtons.length; i++) { 3545 shininessRadioButtons[i].checked = controller.getWallSidesShininess() == parseFloat(shininessRadioButtons[i].value); 3546 } 3547 } 3548 shininessChangeListener(); 3549 dialog.registerPropertyChangeListener(controller, "WALL_SIDES_SHININESS", shininessChangeListener); 3550 3551 var wallSidesShininessDisplay = controller.isPropertyEditable("WALL_SIDES_SHININESS") ? "initial" : "none"; 3552 shininessRadioButtons[0].parentElement.parentElement.style.display = wallSidesShininessDisplay; 3553 3554 if (wallSidesPaintDisplay == "none" && wallSidesShininessDisplay == "none") { 3555 dialog.getElement("wall-sides-panel").parentElement.style.display = "none"; 3556 } 3557 }; 3558 3559 var initWallSidesBaseboardPanel = function(dialog) { 3560 if (!controller.isPropertyEditable("WALL_SIDES_BASEBOARD")) { 3561 dialog.getElement("wall-sides-baseboard-panel").parentElement.style.display = "none"; 3562 return; 3563 } 3564 3565 var baseboardComponentView = controller.getWallSidesBaseboardController().getView(); 3566 dialog.attachChildComponent("wall-sides-baseboard-panel", baseboardComponentView); 3567 dialog.registerPropertyChangeListener(controller.getWallSidesBaseboardController(), "VISIBLE", function() { 3568 selectSplitSurroundingWallsAtFirstChange(dialog); 3569 }); 3570 }; 3571 3572 var dialog = new JSDialog(preferences, 3573 "@{RoomPanel.room.title}", 3574 document.getElementById("room-dialog-template"), 3575 { 3576 applier: function(dialog) { 3577 controller.modifyRooms(); 3578 }, 3579 disposer: function(dialog) { 3580 dialog.floorColorButton.dispose(); 3581 dialog.floorTextureComponent.dispose(); 3582 dialog.ceilingColorButton.dispose(); 3583 dialog.ceilingTextureComponent.dispose(); 3584 controller.getWallSidesBaseboardController().getView().dispose(); 3585 }, 3586 }); 3587 3588 var nameDisplay = controller.isPropertyEditable("NAME") ? "initial" : "none"; 3589 dialog.nameInput = dialog.getElement("name-input"); 3590 dialog.nameInput.value = controller.getName() != null ? controller.getName() : ""; 3591 dialog.nameInput.parentElement.style.display = nameDisplay; 3592 dialog.registerEventListener(dialog.nameInput, "input", function(ev) { 3593 controller.setName(dialog.nameInput.value.trim()); 3594 }); 3595 dialog.registerPropertyChangeListener(controller, "NAME", function(ev) { 3596 dialog.nameInput.value = controller.getName() != null ? controller.getName() : ""; 3597 }); 3598 3599 var areaVisiblePanelDisplay = controller.isPropertyEditable("AREA_VISIBLE") ? "initial" : "none"; 3600 dialog.areaVisibleCheckBox = dialog.getElement("area-visible-checkbox"); 3601 dialog.areaVisibleCheckBox.checked = controller.getAreaVisible(); 3602 dialog.areaVisibleCheckBox.parentElement.style.display = areaVisiblePanelDisplay; 3603 dialog.registerEventListener(dialog.areaVisibleCheckBox, "change", function(ev) { 3604 controller.setAreaVisible(dialog.areaVisibleCheckBox.checked); 3605 }); 3606 dialog.registerPropertyChangeListener(controller, "AREA_VISIBLE", function(ev) { 3607 dialog.areaVisibleCheckBox.checked = controller.getAreaVisible(); 3608 }); 3609 3610 initFloorPanel(dialog); 3611 initCeilingPanel(dialog); 3612 initWallSidesPanel(dialog); 3613 initWallSidesBaseboardPanel(dialog); 3614 3615 dialog.firstWallChange = true; 3616 return dialog; 3617 } 3618 3619 /** 3620 * Creates a polyline editor dialog 3621 * @param {UserPreferences} preferences 3622 * @param {PolylineController} controller 3623 */ 3624 JSViewFactory.prototype.createPolylineView = function(preferences, controller) { 3625 var initArrowsStyleComboBox = function(dialog) { 3626 var arrowsStyles = []; 3627 var arrowsStyleEnumValues = Object.keys(Polyline.ArrowStyle); 3628 for (var i = 0; i < arrowsStyleEnumValues.length; i++) { 3629 var arrowStyle = parseInt(arrowsStyleEnumValues[i]); 3630 if (!isNaN(arrowStyle)) { 3631 arrowsStyles.push(arrowStyle); 3632 } 3633 } 3634 3635 /** @var {{ startStyle: number, endStyle: number }[]} */ 3636 var arrowsStylesCombinations = []; 3637 for (var i = 0; i < arrowsStyles.length; i++) { 3638 for (var j = 0; j < arrowsStyles.length; j++) { 3639 arrowsStylesCombinations.push({ startStyle: arrowsStyles[i], endStyle: arrowsStyles[j] }); 3640 } 3641 } 3642 3643 var openStyleAtStart = new java.awt.geom.GeneralPath(); 3644 openStyleAtStart.moveTo(15, 4); 3645 openStyleAtStart.lineTo(5, 8); 3646 openStyleAtStart.lineTo(15, 12); 3647 var deltaStyleAtStart = new java.awt.geom.GeneralPath(); 3648 deltaStyleAtStart.moveTo(3, 8); 3649 deltaStyleAtStart.lineTo(15, 3); 3650 deltaStyleAtStart.lineTo(15, 13); 3651 deltaStyleAtStart.closePath(); 3652 var iconWidth = 64; 3653 var openStyleAtEnd = new java.awt.geom.GeneralPath(); 3654 openStyleAtEnd.moveTo(iconWidth - 14, 4); 3655 openStyleAtEnd.lineTo(iconWidth - 4, 8); 3656 openStyleAtEnd.lineTo(iconWidth - 14, 12); 3657 var deltaStyleAtEnd = new java.awt.geom.GeneralPath(); 3658 deltaStyleAtEnd.moveTo(iconWidth - 2, 8); 3659 deltaStyleAtEnd.lineTo(iconWidth - 14, 3); 3660 deltaStyleAtEnd.lineTo(iconWidth - 14, 13); 3661 deltaStyleAtEnd.closePath(); 3662 var comboBox = new JSComboBox(this.preferences, dialog.getElement("arrows-style-select"), 3663 { 3664 nullable: controller.getCapStyle() == null, 3665 availableValues: arrowsStylesCombinations, 3666 renderCell: function(arrowStyle, itemElement) { 3667 itemElement.style.border = "none"; 3668 itemElement.style.maxWidth = "6em"; 3669 itemElement.style.margin = "auto"; 3670 itemElement.style.textAlign = "center"; 3671 3672 var canvas = document.createElement("canvas"); 3673 canvas.width = 200; 3674 canvas.height = 50; 3675 canvas.style.maxWidth = "100%"; 3676 canvas.style.height = "1em"; 3677 if (arrowStyle != null) { 3678 var g2D = new Graphics2D(canvas); 3679 g2D.scale(canvas.width / iconWidth, canvas.width / iconWidth); 3680 g2D.setStroke(new java.awt.BasicStroke(2)); 3681 g2D.draw(new java.awt.geom.Line2D.Float(6, 8, iconWidth - 6, 8)); 3682 switch (arrowStyle.startStyle) { 3683 case Polyline.ArrowStyle.DISC : 3684 g2D.fill(new java.awt.geom.Ellipse2D.Float(4, 4, 9, 9)); 3685 break; 3686 case Polyline.ArrowStyle.OPEN : 3687 g2D.draw(openStyleAtStart); 3688 break; 3689 case Polyline.ArrowStyle.DELTA : 3690 g2D.fill(deltaStyleAtStart); 3691 break; 3692 } 3693 switch (arrowStyle.endStyle) { 3694 case Polyline.ArrowStyle.DISC : 3695 g2D.fill(new java.awt.geom.Ellipse2D.Float(iconWidth - 12, 4, 9, 9)); 3696 break; 3697 case Polyline.ArrowStyle.OPEN : 3698 g2D.draw(openStyleAtEnd); 3699 break; 3700 case Polyline.ArrowStyle.DELTA : 3701 g2D.fill(deltaStyleAtEnd); 3702 break; 3703 } 3704 3705 itemElement.appendChild(canvas); 3706 } 3707 }, 3708 selectionChanged: function(newValue) { 3709 controller.setStartArrowStyle(newValue.startStyle); 3710 controller.setEndArrowStyle(newValue.endStyle); 3711 } 3712 }); 3713 3714 var arrowStyleChangeListener = function() { 3715 var startArrowStyle = controller.getStartArrowStyle(); 3716 var endArrowStyle = controller.getEndArrowStyle(); 3717 comboBox.setEnabled(controller.isArrowsStyleEditable()); 3718 comboBox.setSelectedItem( 3719 { 3720 startStyle: startArrowStyle, 3721 endStyle: endArrowStyle 3722 }); 3723 }; 3724 arrowStyleChangeListener(); 3725 dialog.registerPropertyChangeListener(controller, "START_ARROW_STYLE", arrowStyleChangeListener); 3726 dialog.registerPropertyChangeListener(controller, "END_ARROW_STYLE", arrowStyleChangeListener); 3727 }; 3728 3729 var initJoinStyleComboBox = function(dialog) { 3730 var joinStyles = []; 3731 var joinStyleEnumValues = Object.keys(Polyline.JoinStyle); 3732 for (var i = 0; i < joinStyleEnumValues.length; i++) { 3733 var joinStyle = parseInt(joinStyleEnumValues[i]); 3734 if (!isNaN(joinStyle)) { 3735 joinStyles.push(joinStyle); 3736 } 3737 } 3738 3739 var joinPath = new java.awt.geom.GeneralPath(); 3740 joinPath.moveTo(10, 10); 3741 joinPath.lineTo(80, 10); 3742 joinPath.lineTo(50, 35); 3743 var curvedPath = new java.awt.geom.Arc2D.Float(10, 20, 80, 20, 0, 180, java.awt.geom.Arc2D.OPEN); 3744 var comboBox = new JSComboBox(this.preferences, dialog.getElement("join-style-select"), 3745 { 3746 nullable: controller.getJoinStyle() == null, 3747 availableValues: joinStyles, 3748 renderCell: function(joinStyle, itemElement) { 3749 itemElement.style.border = "none"; 3750 itemElement.style.textAlign = "center"; 3751 3752 var canvas = document.createElement("canvas"); 3753 canvas.width = 100; 3754 canvas.height = 40; 3755 canvas.style.maxWidth = "100%"; 3756 canvas.style.height = "1em"; 3757 if (joinStyle != null) { 3758 var g2D = new Graphics2D(canvas); 3759 g2D.setStroke(ShapeTools.getStroke(8, Polyline.CapStyle.BUTT, joinStyle, null, 0)); 3760 if (joinStyle == Polyline.JoinStyle.CURVED) { 3761 g2D.draw(curvedPath); 3762 } else { 3763 g2D.draw(joinPath); 3764 } 3765 } 3766 3767 itemElement.appendChild(canvas); 3768 }, 3769 selectionChanged: function(newValue) { 3770 controller.setJoinStyle(newValue); 3771 } 3772 }); 3773 3774 var joinStyleChangeListener = function() { 3775 comboBox.setEnabled(controller.isJoinStyleEditable()); 3776 comboBox.setSelectedItem(controller.getJoinStyle()); 3777 }; 3778 joinStyleChangeListener(); 3779 dialog.registerPropertyChangeListener(controller, "JOIN_STYLE", joinStyleChangeListener); 3780 }; 3781 3782 var initDashStyleComboBox = function(dialog) { 3783 var dashStyles = []; 3784 var dashStyleEnumValues = Object.keys(Polyline.DashStyle); 3785 for (var i = 0; i < dashStyleEnumValues.length; i++) { 3786 var dashStyle = parseInt(dashStyleEnumValues[i]); 3787 if (!isNaN(dashStyle) 3788 && (dashStyle != Polyline.DashStyle.CUSTOMIZED || controller.getDashStyle() == Polyline.DashStyle.CUSTOMIZED)) { 3789 dashStyles.push(dashStyle); 3790 } 3791 } 3792 3793 var comboBox = new JSComboBox(this.preferences, dialog.getElement("dash-style-select"), 3794 { 3795 nullable: controller.getDashStyle() == null, 3796 availableValues: dashStyles, 3797 renderCell: function(dashStyle, itemElement) { 3798 itemElement.style.border = "none"; 3799 itemElement.style.textAlign = "center"; 3800 itemElement.style.maxHeight = "2em"; 3801 itemElement.style.minWidth = "4em"; 3802 3803 var canvas = document.createElement("canvas"); 3804 canvas.width = 500; 3805 canvas.height = 100; 3806 canvas.style.maxWidth = "100%"; 3807 canvas.style.height = "1em"; 3808 var dashPattern = dashStyle != null && dashStyle != Polyline.DashStyle.CUSTOMIZED 3809 ? Polyline.DashStyle._$wrappers[dashStyle].getDashPattern() 3810 : controller.getDashPattern(); 3811 if (dashPattern != null) { 3812 var g2D = new Graphics2D(canvas); 3813 var dashOffset = controller.getDashOffset() != null ? controller.getDashOffset() : 0; 3814 g2D.setStroke(ShapeTools.getStroke(12, Polyline.CapStyle.BUTT, Polyline.JoinStyle.MITER, 3815 dashPattern, dashOffset)); 3816 g2D.draw(new java.awt.geom.Line2D.Float(20, canvas.height / 2, canvas.width - 60, canvas.height / 2)); 3817 } 3818 3819 itemElement.appendChild(canvas); 3820 }, 3821 selectionChanged: function(newValue) { 3822 controller.setDashStyle(newValue); 3823 } 3824 }); 3825 3826 var dashOffsetInput = new JSSpinner(preferences, dialog.getElement("dash-offset-input"), 3827 { 3828 nullable: controller.getDashOffset() == null, 3829 value: controller.getDashOffset() == null ? null : controller.getDashOffset() * 100, 3830 minimum: 0, 3831 maximum: 100, 3832 stepSize: 5 3833 }); 3834 dialog.registerEventListener(dashOffsetInput, "input", function(ev) { 3835 controller.setDashOffset(dashOffsetInput.getValue() != null 3836 ? dashOffsetInput.getValue() / 100 3837 : null); 3838 }); 3839 dialog.registerPropertyChangeListener(controller, "DASH_OFFSET", function() { 3840 dashOffsetInput.setValue(controller.getDashOffset() == null ? null : controller.getDashOffset() * 100); 3841 comboBox.updateUI(); 3842 }); 3843 3844 var dashStyleChangeListener = function() { 3845 dashOffsetInput.setEnabled(controller.getDashStyle() != Polyline.DashStyle.SOLID); 3846 comboBox.setSelectedItem(controller.getDashStyle()); 3847 }; 3848 dashStyleChangeListener(); 3849 dialog.registerPropertyChangeListener(controller, "DASH_STYLE", dashStyleChangeListener); 3850 }; 3851 3852 var dialog = new JSDialog(preferences, 3853 "@{PolylinePanel.polyline.title}", 3854 document.getElementById("polyline-dialog-template"), 3855 { 3856 size: "small", 3857 applier: function(dialog) { 3858 controller.modifyPolylines(); 3859 }, 3860 disposer: function(dialog) { 3861 dialog.colorButton.dispose(); 3862 } 3863 }); 3864 3865 dialog.colorButton = new ColorButton(preferences, 3866 { 3867 colorChanged: function(selectedColor) { 3868 controller.setColor(selectedColor); 3869 } 3870 }); 3871 dialog.attachChildComponent("color-button", dialog.colorButton); 3872 dialog.colorButton.setColor(controller.getColor()); 3873 dialog.colorButton.setColorDialogTitle(preferences.getLocalizedString( 3874 "PolylinePanel", "colorDialog.title")); 3875 3876 dialog.thicknessLabelElement = dialog.getElement("thickness-label"); 3877 dialog.thicknessLabelElement.textContent = dialog.getLocalizedLabelText( 3878 "PolylinePanel", "thicknessLabel.text", dialog.preferences.getLengthUnit().getName()); 3879 3880 dialog.thicknessInput = new JSSpinner(preferences, dialog.getElement("thickness-input"), 3881 { 3882 nullable: controller.getThickness() == null, 3883 format: preferences.getLengthUnit().getFormat(), 3884 value: controller.getThickness(), 3885 minimum: preferences.getLengthUnit().getMinimumLength(), 3886 maximum: 50, 3887 stepSize: preferences.getLengthUnit().getStepSize() 3888 }); 3889 dialog.registerPropertyChangeListener(controller, "THICKNESS", function(ev) { 3890 dialog.thicknessInput.setValue(controller.getThickness()); 3891 }); 3892 dialog.registerEventListener(dialog.thicknessInput, "input", function(ev) { 3893 controller.setThickness(dialog.thicknessInput.getValue()); 3894 }); 3895 3896 initArrowsStyleComboBox(dialog); 3897 initJoinStyleComboBox(dialog); 3898 initDashStyleComboBox(dialog); 3899 3900 dialog.visibleIn3DCheckBox = dialog.getElement("visible-in-3D-checkbox"); 3901 dialog.visibleIn3DCheckBox.checked = controller.isElevationEnabled() && controller.getElevation() != null; 3902 dialog.registerEventListener(dialog.visibleIn3DCheckBox, "change", function(ev) { 3903 if (dialog.visibleIn3DCheckBox.checked) { 3904 controller.setElevation(0); 3905 } else { 3906 controller.setElevation(null); 3907 } 3908 }); 3909 return dialog; 3910 } 3911 3912 JSViewFactory.prototype.createDimensionLineView = function(modification, preferences, controller) { 3913 var dialog = new JSDialog(preferences, 3914 modification ? "@{DimensionLinePanel.dimensionLineModification.title}" : "@{DimensionLinePanel.dimensionLineCreation.title}", 3915 document.getElementById("dimension-line-dialog-template"), 3916 { 3917 applier: function(dialog) { 3918 if (modification) { 3919 controller.modifyDimensionLines(); 3920 } else { 3921 controller.createDimensionLine(); 3922 } 3923 }, 3924 disposer: function(dialog) { 3925 dialog.colorButton.dispose(); 3926 }, 3927 size: "small" 3928 }); 3929 3930 var maximumLength = preferences.getLengthUnit().getMaximumLength(); 3931 var unitName = preferences.getLengthUnit().getName(); 3932 3933 // Spinner bound to X_START controller property 3934 dialog.xStartLabel = dialog.getElement("x-start-label"); 3935 dialog.xStartLabel.textContent = dialog.getLocalizedLabelText("DimensionLinePanel", "xLabel.text", unitName); 3936 dialog.xStartInput = new JSSpinner(preferences, dialog.getElement("x-start-input"), 3937 { 3938 nullable: controller.getXStart() == null, 3939 format: preferences.getLengthUnit().getFormat(), 3940 value: controller.getXStart(), 3941 minimum: -maximumLength, 3942 maximum: maximumLength, 3943 stepSize: preferences.getLengthUnit().getStepSize() 3944 }); 3945 dialog.registerPropertyChangeListener(controller, "X_START", function(ev) { 3946 dialog.xStartInput.setValue(ev.getNewValue()); 3947 }); 3948 dialog.registerEventListener(dialog.xStartInput, "input", function(ev) { 3949 controller.setXStart(dialog.xStartInput.getValue()); 3950 }); 3951 3952 // Spinner bound to Y_START controller property 3953 dialog.yStartLabel = dialog.getElement("y-start-label"); 3954 dialog.yStartLabel.textContent = dialog.getLocalizedLabelText("DimensionLinePanel", "yLabel.text", unitName); 3955 dialog.yStartInput = new JSSpinner(preferences, dialog.getElement("y-start-input"), 3956 { 3957 nullable: controller.getYStart() == null, 3958 format: preferences.getLengthUnit().getFormat(), 3959 value: controller.getYStart(), 3960 minimum: -maximumLength, 3961 maximum: maximumLength, 3962 stepSize: preferences.getLengthUnit().getStepSize() 3963 }); 3964 dialog.registerPropertyChangeListener(controller, "Y_START", function(ev) { 3965 dialog.yStartInput.setValue(ev.getNewValue()); 3966 }); 3967 dialog.registerEventListener(dialog.yStartInput, "input", function(ev) { 3968 controller.setYStart(dialog.yStartInput.getValue()); 3969 }); 3970 3971 // Spinner bound to ELEVATION_START controller property 3972 dialog.elevationStartLabel = dialog.getElement("elevation-start-label"); 3973 dialog.elevationStartLabel.textContent = dialog.getLocalizedLabelText("DimensionLinePanel", "elevationLabel.text", unitName); 3974 dialog.elevationStartInput = new JSSpinner(preferences, dialog.getElement("elevation-start-input"), 3975 { 3976 nullable: controller.getElevationStart() == null, 3977 format: preferences.getLengthUnit().getFormat(), 3978 value: controller.getElevationStart(), 3979 minimum: 0, 3980 maximum: maximumLength, 3981 stepSize: preferences.getLengthUnit().getStepSize() 3982 }); 3983 dialog.registerPropertyChangeListener(controller, "ELEVATION_START", function(ev) { 3984 dialog.elevationStartInput.setValue(ev.getNewValue()); 3985 }); 3986 dialog.registerEventListener(dialog.elevationStartInput, "input", function(ev) { 3987 controller.setElevationStart(dialog.elevationStartInput.getValue()); 3988 }); 3989 3990 // Spinner bound to X_END controller property 3991 dialog.xEndLabel = dialog.getElement("x-end-label"); 3992 dialog.xEndLabel.textContent = dialog.getLocalizedLabelText("DimensionLinePanel", "xLabel.text", unitName); 3993 dialog.xEndInput = new JSSpinner(preferences, dialog.getElement("x-end-input"), 3994 { 3995 nullable: controller.getXEnd() == null, 3996 format: preferences.getLengthUnit().getFormat(), 3997 value: controller.getXEnd(), 3998 minimum: -maximumLength, 3999 maximum: maximumLength, 4000 stepSize: preferences.getLengthUnit().getStepSize() 4001 }); 4002 dialog.registerPropertyChangeListener(controller, "X_END", function(ev) { 4003 dialog.xEndInput.setValue(ev.getNewValue()); 4004 }); 4005 dialog.registerEventListener(dialog.xEndInput, "input", function(ev) { 4006 controller.setXEnd(dialog.xEndInput.getValue()); 4007 }); 4008 4009 // Spinner bound to Y_END controller property 4010 dialog.yEndLabel = dialog.getElement("y-end-label"); 4011 dialog.yEndLabel.textContent = dialog.getLocalizedLabelText("DimensionLinePanel", "yLabel.text", unitName); 4012 dialog.yEndInput = new JSSpinner(preferences, dialog.getElement("y-end-input"), 4013 { 4014 nullable: controller.getYEnd() == null, 4015 format: preferences.getLengthUnit().getFormat(), 4016 value: controller.getYEnd(), 4017 minimum: -maximumLength, 4018 maximum: maximumLength, 4019 stepSize: preferences.getLengthUnit().getStepSize() 4020 }); 4021 dialog.registerPropertyChangeListener(controller, "Y_END", function(ev) { 4022 dialog.yEndInput.setValue(ev.getNewValue()); 4023 }); 4024 dialog.registerEventListener(dialog.yEndInput, "input", function(ev) { 4025 controller.setYEnd(dialog.yEndInput.getValue()); 4026 }); 4027 4028 // Spinner bound to DISTANCE_TO_END_POINT controller property 4029 dialog.distanceToEndPointLabel = dialog.getElement("distance-to-end-point-label"); 4030 dialog.distanceToEndPointLabel.textContent = dialog.getLocalizedLabelText("DimensionLinePanel", "distanceToEndPointLabel.text", unitName); 4031 dialog.distanceToEndPointInput = new JSSpinner(preferences, dialog.getElement("distance-to-end-point-input"), 4032 { 4033 nullable: controller.getDistanceToEndPoint() == null, 4034 format: preferences.getLengthUnit().getFormat(), 4035 value: controller.getDistanceToEndPoint(), 4036 minimum: preferences.getLengthUnit().getMinimumLength(), 4037 maximum: 2 * maximumLength * Math.sqrt(2), 4038 stepSize: preferences.getLengthUnit().getStepSize() 4039 }); 4040 dialog.registerPropertyChangeListener(controller, "DISTANCE_TO_END_POINT", function(ev) { 4041 dialog.distanceToEndPointInput.setValue(ev.getNewValue()); 4042 }); 4043 dialog.registerEventListener(dialog.distanceToEndPointInput, "input", function(ev) { 4044 controller.setDistanceToEndPoint(dialog.distanceToEndPointInput.getValue()); 4045 }); 4046 4047 // Spinner bound to OFFSET controller property 4048 dialog.offsetLabel = dialog.getElement("offset-label"); 4049 dialog.offsetLabel.textContent = dialog.getLocalizedLabelText("DimensionLinePanel", "offsetLabel.text", unitName); 4050 dialog.offsetInput = new JSSpinner(preferences, dialog.getElement("offset-input"), 4051 { 4052 nullable: controller.getOffset() == null, 4053 format: preferences.getLengthUnit().getFormat(), 4054 value: controller.getOffset(), 4055 minimum: -10000, 4056 maximum: 10000, 4057 stepSize: preferences.getLengthUnit().getStepSize() 4058 }); 4059 dialog.registerPropertyChangeListener(controller, "OFFSET", function(ev) { 4060 dialog.offsetInput.setValue(ev.getNewValue()); 4061 }); 4062 dialog.registerEventListener(dialog.offsetInput, "input", function(ev) { 4063 controller.setOffset(dialog.offsetInput.getValue()); 4064 }); 4065 4066 // Radio buttons bound to ORIENTATION controller property 4067 dialog.planDimensionLineRadioButton = dialog.findElement("[name='orientation-choice'][value='PLAN']"); 4068 dialog.registerEventListener(dialog.planDimensionLineRadioButton, "change", function(ev) { 4069 if (dialog.planDimensionLineRadioButton.checked) { 4070 controller.setOrientation(DimensionLineController.DimensionLineOrientation.PLAN); 4071 } 4072 }); 4073 dialog.elevationDimensionLineRadioButton = dialog.findElement("[name='orientation-choice'][value='ELEVATION']"); 4074 dialog.registerEventListener(dialog.elevationDimensionLineRadioButton, "change", function(ev) { 4075 if (dialog.elevationDimensionLineRadioButton.checked) { 4076 controller.setOrientation(DimensionLineController.DimensionLineOrientation.ELEVATION); 4077 } 4078 }); 4079 4080 dialog.registerPropertyChangeListener(controller, "ORIENTATION", function(ev) { 4081 updateOrientationRadioButtons(); 4082 }); 4083 4084 // Font size label and spinner bound to FONT_SIZE controller property 4085 dialog.lengthFontSizeLabel = dialog.getElement("length-font-size-label"); 4086 dialog.lengthFontSizeLabel.textContent = dialog.getLocalizedLabelText( 4087 "DimensionLinePanel", "lengthFontSizeLabel.text", dialog.preferences.getLengthUnit().getName()); 4088 dialog.lengthFontSizeInput = new JSSpinner(preferences, dialog.getElement("length-font-size-input"), 4089 { 4090 format: preferences.getLengthUnit().getFormat(), 4091 value: controller.getLengthFontSize(), 4092 minimum: 5, 4093 maximum: 999, 4094 stepSize: preferences.getLengthUnit().getStepSize() 4095 }); 4096 var lengthFontSizeChangeListener = function() { 4097 var fontSize = controller.getLengthFontSize(); 4098 dialog.lengthFontSizeInput.setNullable(fontSize == null); 4099 dialog.lengthFontSizeInput.setValue(fontSize); 4100 }; 4101 lengthFontSizeChangeListener(); 4102 dialog.registerPropertyChangeListener(controller, "LENGTH_FONT_SIZE", lengthFontSizeChangeListener); 4103 dialog.registerEventListener(dialog.lengthFontSizeInput, "input", function(ev) { 4104 controller.setLengthFontSize(dialog.lengthFontSizeInput.getValue()); 4105 }); 4106 4107 // Color button bound to controller COLOR controller property 4108 dialog.colorButton = new ColorButton(preferences, 4109 { 4110 colorChanged: function(selectedColor) { 4111 controller.setColor(dialog.colorButton.getColor()); 4112 } 4113 }); 4114 dialog.attachChildComponent("color-button", dialog.colorButton); 4115 dialog.colorButton.setColor(controller.getColor()); 4116 dialog.colorButton.setColorDialogTitle(preferences.getLocalizedString("DimensionLinePanel", "colorDialog.title")); 4117 dialog.registerPropertyChangeListener(controller, "COLOR", function() { 4118 dialog.colorButton.setColor(controller.getColor()); 4119 }); 4120 4121 // Pitch components bound to PITCH controller property 4122 var updateOrientationRadioButtons = function() { 4123 if (controller.getOrientation() == DimensionLineController.DimensionLineOrientation.PLAN) { 4124 dialog.planDimensionLineRadioButton.checked = true; 4125 } else if (controller.getOrientation() == DimensionLineController.DimensionLineOrientation.ELEVATION) { 4126 dialog.elevationDimensionLineRadioButton.checked = true; 4127 } 4128 orientable = controller.isEditableDistance(); 4129 dialog.planDimensionLineRadioButton.disabled = !orientable; 4130 dialog.elevationDimensionLineRadioButton.disabled = !orientable; 4131 4132 if (controller.getPitch() != null 4133 && controller.getOrientation() != DimensionLineController.DimensionLineOrientation.ELEVATION) { 4134 if (controller.getPitch() === 0) { 4135 dialog.pitch0DegreeRadioButton.checked = true; 4136 } else if (Math.abs(controller.getPitch()) === Math.PI / 2) { 4137 dialog.pitch90DegreeRadioButton.checked = true; 4138 } 4139 } 4140 4141 var planOrientation = controller.getOrientation() == DimensionLineController.DimensionLineOrientation.PLAN; 4142 var visibleIn3D = controller.isVisibleIn3D() === true; 4143 dialog.pitch0DegreeRadioButton.disabled = !(visibleIn3D && planOrientation); 4144 dialog.pitch90DegreeRadioButton.disabled = !(visibleIn3D && planOrientation); 4145 4146 dialog.elevationStartInput.setEnabled(visibleIn3D 4147 || controller.getOrientation() == DimensionLineController.DimensionLineOrientation.ELEVATION); 4148 dialog.xEndInput.setEnabled(planOrientation); 4149 dialog.yEndInput.setEnabled(planOrientation); 4150 }; 4151 4152 dialog.visibleIn3DViewCheckBox = dialog.getElement("visible-in-3D-checkbox"); 4153 dialog.visibleIn3DViewCheckBox.checked = controller.isVisibleIn3D(); 4154 dialog.registerPropertyChangeListener(controller, "VISIBLE_IN_3D", function(ev) { 4155 dialog.visibleIn3DViewCheckBox.checked = controller.isVisibleIn3D(); 4156 }); 4157 dialog.registerEventListener(dialog.visibleIn3DViewCheckBox, "change", function(ev) { 4158 controller.setVisibleIn3D(dialog.visibleIn3DViewCheckBox.checked); 4159 updateOrientationRadioButtons(); 4160 }); 4161 4162 dialog.pitch0DegreeRadioButton = dialog.findElement("[name='label-pitch-radio'][value='0']"); 4163 dialog.pitch90DegreeRadioButton = dialog.findElement("[name='label-pitch-radio'][value='90']"); 4164 var pitchRadioButtonsChangeListener = function() { 4165 if (dialog.pitch0DegreeRadioButton.checked) { 4166 controller.setPitch(0); 4167 } else if (dialog.pitch90DegreeRadioButton.checked) { 4168 controller.setPitch(-Math.PI / 2); 4169 } 4170 }; 4171 dialog.registerEventListener([dialog.pitch0DegreeRadioButton, dialog.pitch90DegreeRadioButton], "change", 4172 pitchRadioButtonsChangeListener); 4173 dialog.registerPropertyChangeListener(controller, "PITCH", updateOrientationRadioButtons); 4174 4175 updateOrientationRadioButtons(); 4176 return dialog; 4177 } 4178 4179 JSViewFactory.prototype.createLabelView = function(modification, preferences, controller) { 4180 var dialog = new JSDialog(preferences, 4181 modification ? "@{LabelPanel.labelModification.title}": "@{LabelPanel.labelCreation.title}", 4182 document.getElementById("label-dialog-template"), 4183 { 4184 applier: function(dialog) { 4185 if (modification) { 4186 controller.modifyLabels(); 4187 } else { 4188 controller.createLabel(); 4189 } 4190 }, 4191 disposer: function(dialog) { 4192 dialog.colorButton.dispose(); 4193 }, 4194 size: "small" 4195 }); 4196 4197 // Text field bound to NAME controller property 4198 dialog.textInput = dialog.getElement("text"); 4199 dialog.textInput.value = controller.getText() != null ? controller.getText() : ""; 4200 dialog.registerEventListener(dialog.textInput, "input", function(ev) { 4201 controller.setText(dialog.textInput.value); 4202 }); 4203 dialog.registerPropertyChangeListener(controller, "TEXT", function(ev) { 4204 dialog.textInput.value = controller.getText() != null ? controller.getText() : ""; 4205 }); 4206 4207 // Radio buttons bound to controller ALIGNMENT property 4208 dialog.alignmentRadioButtons = dialog.getHTMLElement().querySelectorAll("[name='label-alignment-radio']"); 4209 dialog.registerEventListener(dialog.alignmentRadioButtons, "change", function(ev) { 4210 for (var i = 0; i < dialog.alignmentRadioButtons.length; i++) { 4211 if (dialog.alignmentRadioButtons[i].checked) { 4212 controller.setAlignment(TextStyle.Alignment[dialog.alignmentRadioButtons[i].value]); 4213 } 4214 } 4215 }); 4216 var alignmentChangeListener = function() { 4217 var selectedAlignmentRadioButton = dialog.findElement("[name='label-alignment-radio'][value='" + TextStyle.Alignment[controller.getAlignment()] + "']"); 4218 if (selectedAlignmentRadioButton != null) { 4219 selectedAlignmentRadioButton.checked = true; 4220 } 4221 }; 4222 dialog.registerPropertyChangeListener(controller, "ALIGNMENT", alignmentChangeListener); 4223 alignmentChangeListener(); 4224 4225 // Font select bound to controller FONT_NAME property 4226 dialog.fontSelect = dialog.getElement("font-select"); 4227 var DEFAULT_SYSTEM_FONT_NAME = "DEFAULT_SYSTEM_FONT_NAME"; 4228 dialog.registerEventListener(dialog.fontSelect, "change", function(ev) { 4229 var selectedValue = dialog.fontSelect.querySelector("option:checked").value; 4230 controller.setFontName(selectedValue == DEFAULT_SYSTEM_FONT_NAME ? null : selectedValue); 4231 }); 4232 var fontNameChangeListener = function() { 4233 if (controller.isFontNameSet()) { 4234 var selectedValue = controller.getFontName() == null 4235 ? DEFAULT_SYSTEM_FONT_NAME 4236 : controller.getFontName(); 4237 var selectedOption = dialog.fontSelect.querySelector("[value='" + selectedValue + "']"); 4238 if (selectedOption) { 4239 selectedOption.selected = true; 4240 } 4241 } else { 4242 dialog.fontSelect.selectedIndex = undefined; 4243 } 4244 }; 4245 dialog.registerPropertyChangeListener(controller, "FONT_NAME", fontNameChangeListener); 4246 CoreTools.loadAvailableFontNames(function(fonts) { 4247 fonts = [DEFAULT_SYSTEM_FONT_NAME].concat(fonts); 4248 for (var i = 0; i < fonts.length; i++) { 4249 var font = fonts[i]; 4250 var label = i == 0 ? dialog.getLocalizedLabelText("FontNameComboBox", "systemFontName") : font; 4251 dialog.fontSelect.appendChild(JSComponent.createOptionElement(font, label)); 4252 } 4253 fontNameChangeListener(); 4254 }); 4255 4256 // Font size label and spinner bound to FONT_SIZE controller property 4257 dialog.fontSizeLabel = dialog.getElement("font-size-label"); 4258 dialog.fontSizeLabel.textContent = dialog.getLocalizedLabelText( 4259 "LabelPanel", "fontSizeLabel.text", dialog.preferences.getLengthUnit().getName()); 4260 dialog.fontSizeInput = new JSSpinner(preferences, dialog.getElement("font-size-input"), 4261 { 4262 format: preferences.getLengthUnit().getFormat(), 4263 value: controller.getFontSize(), 4264 minimum: 5, 4265 maximum: 999, 4266 stepSize: preferences.getLengthUnit().getStepSize() 4267 }); 4268 var fontSizeChangeListener = function() { 4269 var fontSize = controller.getFontSize(); 4270 dialog.fontSizeInput.setNullable(fontSize == null); 4271 dialog.fontSizeInput.setValue(fontSize); 4272 }; 4273 fontSizeChangeListener(); 4274 dialog.registerPropertyChangeListener(controller, "FONT_SIZE", fontSizeChangeListener); 4275 dialog.registerEventListener(dialog.fontSizeInput, "input", function(ev) { 4276 controller.setFontSize(dialog.fontSizeInput.getValue()); 4277 }); 4278 4279 // Color button bound to controller COLOR controller property 4280 dialog.colorButton = new ColorButton(preferences, 4281 { 4282 colorChanged: function(selectedColor) { 4283 controller.setColor(dialog.colorButton.getColor()); 4284 } 4285 }); 4286 dialog.attachChildComponent("color-button", dialog.colorButton); 4287 dialog.colorButton.setColor(controller.getColor()); 4288 dialog.colorButton.setColorDialogTitle(preferences 4289 .getLocalizedString("LabelPanel", "colorDialog.title")); 4290 dialog.registerPropertyChangeListener(controller, "COLOR", function() { 4291 dialog.colorButton.setColor(controller.getColor()); 4292 }); 4293 4294 // Pitch components bound to PITCH controller property 4295 var update3DViewComponents = function() { 4296 var visibleIn3D = controller.isPitchEnabled() === true; 4297 dialog.pitch0DegreeRadioButton.disabled = !visibleIn3D; 4298 dialog.pitch90DegreeRadioButton.disabled = !visibleIn3D; 4299 dialog.elevationInput.setEnabled(visibleIn3D); 4300 if (controller.getPitch() !== null) { 4301 if (controller.getPitch() === 0) { 4302 dialog.pitch0DegreeRadioButton.checked = true; 4303 } else if (controller.getPitch() === Math.PI / 2) { 4304 dialog.pitch90DegreeRadioButton.checked = true; 4305 } 4306 } 4307 }; 4308 dialog.registerPropertyChangeListener(controller, "PITCH", update3DViewComponents); 4309 4310 dialog.visibleIn3DCheckBox = dialog.getElement("visible-in-3D-checkbox"); 4311 dialog.visibleIn3DCheckBox.checked = 4312 controller.isPitchEnabled() !== null && controller.getPitch() !== null; 4313 dialog.registerEventListener(dialog.visibleIn3DCheckBox, "change", function(ev) { 4314 if (!dialog.visibleIn3DCheckBox.checked) { 4315 controller.setPitch(null); 4316 } else if (dialog.pitch90DegreeRadioButton.checked) { 4317 controller.setPitch(Math.PI / 2); 4318 } else { 4319 controller.setPitch(0); 4320 } 4321 update3DViewComponents(); 4322 }); 4323 4324 dialog.pitch0DegreeRadioButton = dialog.findElement("[name='label-pitch-radio'][value='0']"); 4325 dialog.pitch90DegreeRadioButton = dialog.findElement("[name='label-pitch-radio'][value='90']"); 4326 var pitchRadioButtonsChangeListener = function() { 4327 if (dialog.pitch0DegreeRadioButton.checked) { 4328 controller.setPitch(0); 4329 } else if (dialog.pitch90DegreeRadioButton.checked) { 4330 controller.setPitch(Math.PI / 2); 4331 } 4332 }; 4333 dialog.registerEventListener([dialog.pitch0DegreeRadioButton, dialog.pitch90DegreeRadioButton], "change", 4334 pitchRadioButtonsChangeListener); 4335 4336 // Elevation label and spinner bound to ELEVATION controller property 4337 dialog.elevationLabel = dialog.getElement("elevation-label"); 4338 dialog.elevationLabel.textContent = dialog.getLocalizedLabelText( 4339 "LabelPanel", "elevationLabel.text", dialog.preferences.getLengthUnit().getName()); 4340 dialog.elevationInput = new JSSpinner(preferences, dialog.getElement("elevation-input"), 4341 { 4342 nullable: controller.getElevation() == null, 4343 format: preferences.getLengthUnit().getFormat(), 4344 value: controller.getElevation(), 4345 minimum: 0, 4346 maximum: preferences.getLengthUnit().getMaximumElevation(), 4347 stepSize: preferences.getLengthUnit().getStepSize() 4348 }); 4349 var elevationChangeListener = function(ev) { 4350 dialog.elevationInput.setNullable(ev.getNewValue() === null); 4351 dialog.elevationInput.setValue(ev.getNewValue()); 4352 }; 4353 dialog.registerPropertyChangeListener(controller, "ELEVATION", elevationChangeListener); 4354 dialog.registerEventListener(dialog.elevationInput, "input", function(ev) { 4355 controller.setElevation(dialog.elevationInput.getValue()); 4356 }); 4357 4358 update3DViewComponents(); 4359 4360 return dialog; 4361 } 4362 4363 /** 4364 * @param {UserPreferences} preferences 4365 * @param {CompassController} controller 4366 * @return {JSCompassDialogView} 4367 */ 4368 JSViewFactory.prototype.createCompassView = function(preferences, controller) { 4369 function CompassDialog() { 4370 this.controller = controller; 4371 4372 JSDialog.call(this, preferences, 4373 "@{CompassPanel.compass.title}", 4374 document.getElementById("compass-dialog-template"), 4375 { 4376 size: "medium", 4377 applier: function(dialog) { 4378 dialog.controller.modifyCompass(); 4379 } 4380 }); 4381 4382 this.initRosePanel(); 4383 this.initGeographicLocationPanel(); 4384 } 4385 CompassDialog.prototype = Object.create(JSDialog.prototype); 4386 CompassDialog.prototype.constructor = CompassDialog; 4387 4388 /** 4389 * @private 4390 */ 4391 CompassDialog.prototype.initRosePanel = function() { 4392 var preferences = this.preferences; 4393 var controller = this.controller; 4394 4395 var maximumLength = preferences.getLengthUnit().getMaximumLength(); 4396 4397 var xLabel = this.getElement("x-label"); 4398 var xInput = new JSSpinner(this.preferences, this.getElement("x-input"), 4399 { 4400 format: preferences.getLengthUnit().getFormat(), 4401 minimum: -maximumLength, 4402 maximum: maximumLength, 4403 stepSize: preferences.getLengthUnit().getStepSize() 4404 }); 4405 var yLabel = this.getElement("y-label"); 4406 var yInput = new JSSpinner(this.preferences, this.getElement("y-input"), 4407 { 4408 format: preferences.getLengthUnit().getFormat(), 4409 minimum: -maximumLength, 4410 maximum: maximumLength, 4411 stepSize: preferences.getLengthUnit().getStepSize() 4412 }); 4413 var diameterLabel = this.getElement("diameter-label"); 4414 var diameterInput = new JSSpinner(this.preferences, this.getElement("diameter-input"), 4415 { 4416 format: preferences.getLengthUnit().getFormat(), 4417 minimum: preferences.getLengthUnit().getMinimumLength(), 4418 maximum: preferences.getLengthUnit().getMaximumLength() / 10, 4419 stepSize: preferences.getLengthUnit().getStepSize() 4420 }); 4421 4422 // Set values 4423 xInput.setValue(controller.getX()); 4424 yInput.setValue(controller.getY()); 4425 diameterInput.setValue(controller.getDiameter()); 4426 4427 // Set labels 4428 var unitName = this.preferences.getLengthUnit().getName(); 4429 xLabel.textContent = this.getLocalizedLabelText("CompassPanel", "xLabel.text", unitName); 4430 yLabel.textContent = this.getLocalizedLabelText("CompassPanel", "yLabel.text", unitName); 4431 diameterLabel.textContent = this.getLocalizedLabelText("CompassPanel", "diameterLabel.text", unitName); 4432 4433 // Add property listeners 4434 var controller = this.controller; 4435 this.registerPropertyChangeListener(this.controller, "X", function (ev) { 4436 xInput.setValue(controller.getX()); 4437 }); 4438 this.registerPropertyChangeListener(this.controller, "Y", function (ev) { 4439 yInput.setValue(controller.getY()); 4440 }); 4441 this.registerPropertyChangeListener(this.controller, "DIAMETER", function (ev) { 4442 diameterInput.setValue(controller.getDiameter()); 4443 }); 4444 4445 // Add change listeners 4446 this.registerEventListener(xInput, "input", function (ev) { 4447 controller.setX(xInput.getValue()); 4448 }); 4449 this.registerEventListener(yInput, "input", function (ev) { 4450 controller.setY(yInput.getValue()); 4451 }); 4452 this.registerEventListener(diameterInput, "input", function (ev) { 4453 controller.setDiameter(diameterInput.getValue()); 4454 }); 4455 4456 var visibleCheckBox = this.getElement("visible-checkbox"); 4457 visibleCheckBox.checked = controller.isVisible(); 4458 this.registerEventListener(visibleCheckBox, "change", function(ev) { 4459 controller.setVisible(visibleCheckBox.checked); 4460 }); 4461 this.registerPropertyChangeListener(controller, "VISIBLE", function(ev) { 4462 visibleCheckBox.checked = controller.isVisible(); 4463 }); 4464 }; 4465 4466 /** 4467 * @private 4468 */ 4469 CompassDialog.prototype.initGeographicLocationPanel = function() { 4470 var preferences = this.preferences; 4471 var controller = this.controller; 4472 4473 var latitudeInput = new JSSpinner(this.preferences, this.getElement("latitude-input"), 4474 { 4475 format: new DecimalFormat("N ##0.000;S ##0.000"), 4476 minimum: -90, 4477 maximum: 90, 4478 stepSize: 5 4479 }); 4480 var longitudeInput = new JSSpinner(this.preferences, this.getElement("longitude-input"), 4481 { 4482 format: new DecimalFormat("E ##0.000;W ##0.000"), 4483 minimum: -180, 4484 maximum: 180, 4485 stepSize: 5 4486 }); 4487 var northDirectionInput = new JSSpinner(this.preferences, this.getElement("north-direction-input"), 4488 { 4489 format: new IntegerFormat(), 4490 minimum: 0, 4491 maximum: 360, 4492 stepSize: 5 4493 }); 4494 northDirectionInput.getHTMLElement().style.width = "3em"; 4495 northDirectionInput.style.verticalAlign = "super"; 4496 4497 // Set values 4498 latitudeInput.setValue(controller.getLatitudeInDegrees()); 4499 longitudeInput.setValue(controller.getLongitudeInDegrees()); 4500 northDirectionInput.setValue(controller.getNorthDirectionInDegrees()); 4501 4502 // Add property listeners 4503 this.registerPropertyChangeListener(controller, "LATITUDE_IN_DEGREES", function(ev) { 4504 latitudeInput.setValue(controller.getLatitudeInDegrees()); 4505 }); 4506 this.registerPropertyChangeListener(controller, "LONGITUDE_IN_DEGREES", function(ev) { 4507 longitudeInput.setValue(controller.getLongitudeInDegrees()); 4508 }); 4509 this.registerPropertyChangeListener(controller, "NORTH_DIRECTION_IN_DEGREES", function(ev) { 4510 northDirectionInput.setValue(controller.getNorthDirectionInDegrees()); 4511 }); 4512 4513 // Add change listeners 4514 this.registerEventListener(latitudeInput, "input", function(ev) { 4515 controller.setLatitudeInDegrees(latitudeInput.getValue()); 4516 }); 4517 this.registerEventListener(longitudeInput, "input", function(ev) { 4518 controller.setLongitudeInDegrees(longitudeInput.getValue()); 4519 }); 4520 this.registerEventListener(northDirectionInput, "input", function(ev) { 4521 controller.setNorthDirectionInDegrees(northDirectionInput.getValue()); 4522 updatePreview(); 4523 }); 4524 4525 var compassPreviewCanvas = this.getElement("compass-preview"); 4526 compassPreviewCanvas.width = 140; 4527 compassPreviewCanvas.height = 140; 4528 compassPreviewCanvas.style.verticalAlign = "middle"; 4529 4530 compassPreviewCanvas.style.width = "35px"; 4531 4532 var compassPreviewCanvasContext = compassPreviewCanvas.getContext("2d"); 4533 var canvasGraphics = new Graphics2D(compassPreviewCanvas); 4534 4535 var updatePreview = function () { 4536 canvasGraphics.clear(); 4537 var previousTransform = canvasGraphics.getTransform(); 4538 canvasGraphics.translate(70, 70); 4539 canvasGraphics.scale(100, 100); 4540 4541 canvasGraphics.setColor("#000000"); 4542 canvasGraphics.fill(PlanComponent.COMPASS); 4543 canvasGraphics.setTransform(previousTransform); 4544 4545 if (controller.getNorthDirectionInDegrees() == 0 || controller.getNorthDirectionInDegrees() == null) { 4546 compassPreviewCanvas.style.transform = ""; 4547 } else { 4548 compassPreviewCanvas.style.transform = "rotate(" + controller.getNorthDirectionInDegrees() + "deg)"; 4549 } 4550 }; 4551 updatePreview(); 4552 }; 4553 4554 return new CompassDialog(); 4555 } 4556 4557 JSViewFactory.prototype.createObserverCameraView = function(preferences, controller) { 4558 function ObserverCameraDialog() { 4559 this.controller = controller; 4560 4561 JSDialog.call(this, preferences, 4562 "@{ObserverCameraPanel.observerCamera.title}", 4563 document.getElementById("observer-camera-dialog-template"), 4564 { 4565 applier: function(dialog) { 4566 dialog.controller.modifyObserverCamera(); 4567 } 4568 }); 4569 4570 this.initLocationPanel(); 4571 this.initAnglesPanel(); 4572 4573 var adjustObserverCameraElevationCheckBox = this.getElement("adjust-observer-camera-elevation-checkbox"); 4574 adjustObserverCameraElevationCheckBox.checked = controller.isElevationAdjusted(); 4575 var adjustObserverCameraElevationCheckBoxDisplay = controller.isObserverCameraElevationAdjustedEditable() ? "initial" : "none"; 4576 adjustObserverCameraElevationCheckBox.parentElement.style.display = adjustObserverCameraElevationCheckBoxDisplay; 4577 this.registerEventListener(adjustObserverCameraElevationCheckBox, "change", function(ev) { 4578 controller.setElevationAdjusted(adjustObserverCameraElevationCheckBox.checked); 4579 }); 4580 this.registerPropertyChangeListener(controller, "OBSERVER_CAMERA_ELEVATION_ADJUSTED", function(ev) { 4581 adjustObserverCameraElevationCheckBox.checked = controller.isElevationAdjusted(); 4582 }); 4583 } 4584 ObserverCameraDialog.prototype = Object.create(JSDialog.prototype); 4585 ObserverCameraDialog.prototype.constructor = ObserverCameraDialog; 4586 4587 /** 4588 * @private 4589 */ 4590 ObserverCameraDialog.prototype.initLocationPanel = function() { 4591 var maximumLength = 5E5; 4592 var xLabel = this.getElement("x-label"); 4593 var xInput = new JSSpinner(this.preferences, this.getElement("x-input"), 4594 { 4595 nullable: this.controller.getX() == null, 4596 format: this.preferences.getLengthUnit().getFormat(), 4597 minimum: -maximumLength, 4598 maximum: maximumLength, 4599 stepSize: this.preferences.getLengthUnit().getStepSize() 4600 }); 4601 var yLabel = this.getElement("y-label"); 4602 var yInput = new JSSpinner(this.preferences, this.getElement("y-input"), 4603 { 4604 nullable: this.controller.getY() == null, 4605 format: this.preferences.getLengthUnit().getFormat(), 4606 minimum: -maximumLength, 4607 maximum: maximumLength, 4608 stepSize: this.preferences.getLengthUnit().getStepSize() 4609 }); 4610 var elevationLabel = this.getElement("elevation-label"); 4611 var elevationInput = new JSSpinner(this.preferences, this.getElement("elevation-input"), 4612 { 4613 nullable: this.controller.getElevation() == null, 4614 format: this.preferences.getLengthUnit().getFormat(), 4615 minimum: this.controller.getMinimumElevation(), 4616 maximum: this.preferences.getLengthUnit().getMaximumElevation(), 4617 stepSize: this.preferences.getLengthUnit().getStepSize() 4618 }); 4619 4620 // Set values 4621 xInput.setValue(this.controller.getX()); 4622 yInput.setValue(this.controller.getY()); 4623 elevationInput.setValue(this.controller.getElevation()); 4624 4625 // Set labels 4626 var unitName = this.preferences.getLengthUnit().getName(); 4627 xLabel.textContent = this.getLocalizedLabelText("HomeFurniturePanel", "xLabel.text", unitName); 4628 yLabel.textContent = this.getLocalizedLabelText("HomeFurniturePanel", "yLabel.text", unitName); 4629 elevationLabel.textContent = this.getLocalizedLabelText("ObserverCameraPanel", "elevationLabel.text", unitName); 4630 4631 // Add property listeners 4632 var controller = this.controller; 4633 this.registerPropertyChangeListener(this.controller, "X", function (ev) { 4634 xInput.setValue(controller.getX()); 4635 }); 4636 this.registerPropertyChangeListener(this.controller, "Y", function (ev) { 4637 yInput.setValue(controller.getY()); 4638 }); 4639 this.registerPropertyChangeListener(this.controller, "ELEVATION", function (ev) { 4640 elevationInput.setValue(controller.getElevation()); 4641 }); 4642 4643 // Add change listeners 4644 this.registerEventListener(xInput, "input", function (ev) { 4645 controller.setX(xInput.getValue()); 4646 }); 4647 this.registerEventListener(yInput, "input", function (ev) { 4648 controller.setY(yInput.getValue()); 4649 }); 4650 this.registerEventListener(elevationInput, "input", function (ev) { 4651 controller.setElevation(elevationInput.getValue()); 4652 }); 4653 }; 4654 4655 /** 4656 * @private 4657 */ 4658 ObserverCameraDialog.prototype.initAnglesPanel = function() { 4659 var angleDecimalFormat = new DecimalFormat("0.#"); 4660 var yawInput = new JSSpinner(this.preferences, this.getElement("yaw-input"), 4661 { 4662 format: angleDecimalFormat, 4663 value: Math.toDegrees(this.controller.getYaw()), 4664 minimum: -10000, 4665 maximum: 10000, 4666 stepSize: 5 4667 }); 4668 var pitchInput = new JSSpinner(this.preferences, this.getElement("pitch-input"), 4669 { 4670 format: angleDecimalFormat, 4671 value: Math.toDegrees(this.controller.getPitch()), 4672 minimum: -90, 4673 maximum: 90, 4674 stepSize: 5 4675 }); 4676 var fieldOfViewInput = new JSSpinner(this.preferences, this.getElement("field-of-view-input"), 4677 { 4678 nullable: this.controller.getFieldOfView() == null, 4679 format: angleDecimalFormat, 4680 value: Math.toDegrees(this.controller.getFieldOfView()), 4681 minimum: 2, 4682 maximum: 120, 4683 stepSize: 1 4684 }); 4685 4686 // add property listeners 4687 var controller = this.controller; 4688 this.registerPropertyChangeListener(this.controller, "YAW", function (ev) { 4689 yawInput.setValue(Math.toDegrees(this.controller.getYaw())); 4690 }); 4691 this.registerPropertyChangeListener(this.controller, "PITCH", function (ev) { 4692 pitchInput.setValue(Math.toDegrees(this.controller.getPitch())); 4693 }); 4694 this.registerPropertyChangeListener(this.controller, "FIELD_OF_VIEW", function (ev) { 4695 fieldOfViewInput.setValue(Math.toDegrees(this.controller.getFieldOfView())); 4696 }); 4697 4698 // add change listeners 4699 this.registerEventListener(yawInput, "input", function (ev) { 4700 controller.setYaw(yawInput.getValue() != null ? Math.toRadians(yawInput.getValue()) : null); 4701 }); 4702 this.registerEventListener(pitchInput, "input", function (ev) { 4703 controller.setPitch(pitchInput.getValue() != null ? Math.toRadians(pitchInput.getValue()) : null); 4704 }); 4705 this.registerEventListener(fieldOfViewInput, "input", function (ev) { 4706 controller.setFieldOfView(fieldOfViewInput.getValue() != null ? Math.toRadians(fieldOfViewInput.getValue()) : null); 4707 }); 4708 }; 4709 4710 return new ObserverCameraDialog(); 4711 } 4712 4713 JSViewFactory.prototype.createHome3DAttributesView = function(preferences, controller) { 4714 function Home3DAttributesDialog() { 4715 this.controller = controller; 4716 4717 JSDialog.call(this, preferences, 4718 "@{Home3DAttributesPanel.home3DAttributes.title}", 4719 document.getElementById("home-3Dattributes-dialog-template"), 4720 { 4721 size: "small", 4722 applier: function(dialog) { 4723 dialog.controller.modify3DAttributes(); 4724 }, 4725 disposer: function(dialog) { 4726 dialog.groundPanel.colorButton.dispose(); 4727 dialog.groundPanel.textureComponent.dispose(); 4728 dialog.skyPanel.colorButton.dispose(); 4729 dialog.skyPanel.textureComponent.dispose(); 4730 } 4731 }); 4732 4733 4734 this.initGroundPanel(); 4735 this.initSkyPanel(); 4736 this.initRenderingPanel(); 4737 } 4738 Home3DAttributesDialog.prototype = Object.create(JSDialog.prototype); 4739 Home3DAttributesDialog.prototype.constructor = Home3DAttributesDialog; 4740 4741 /** 4742 * @private 4743 */ 4744 Home3DAttributesDialog.prototype.initGroundPanel = function() { 4745 var controller = this.controller; 4746 var dialog = this; 4747 4748 var groundColorRadioButton = dialog.findElement("[name='ground-color-and-texture-choice'][value='COLORED']"); 4749 var groundColorButton = new ColorButton(preferences, 4750 { 4751 colorChanged: function(selectedColor) { 4752 groundColorRadioButton.checked = true; 4753 controller.setGroundPaint(Home3DAttributesController.EnvironmentPaint.COLORED); 4754 controller.setGroundColor(selectedColor); 4755 } 4756 }); 4757 dialog.attachChildComponent("ground-color-button", groundColorButton); 4758 groundColorButton.setColor(controller.getGroundColor()); 4759 groundColorButton.setColorDialogTitle(preferences.getLocalizedString( 4760 "Home3DAttributesPanel", "groundColorDialog.title")); 4761 4762 var groundTextureRadioButton = dialog.findElement("[name='ground-color-and-texture-choice'][value='TEXTURED']"); 4763 var textureComponent = controller.getGroundTextureController().getView(); 4764 dialog.attachChildComponent("ground-texture-component", textureComponent); 4765 4766 var radioButtons = [groundColorRadioButton, groundTextureRadioButton]; 4767 dialog.registerEventListener(radioButtons, "change", function(ev) { 4768 if (ev.target.checked) { 4769 controller.setGroundPaint(Home3DAttributesController.EnvironmentPaint[ev.target.value]); 4770 } 4771 }); 4772 4773 var paintChangeListener = function() { 4774 groundColorRadioButton.checked = controller.getGroundPaint() == Home3DAttributesController.EnvironmentPaint.COLORED; 4775 groundTextureRadioButton.checked = controller.getGroundPaint() == Home3DAttributesController.EnvironmentPaint.TEXTURED; 4776 }; 4777 paintChangeListener(); 4778 this.registerPropertyChangeListener(controller, "GROUND_PAINT", paintChangeListener); 4779 this.registerPropertyChangeListener(controller, "GROUND_COLOR", function(ev) { 4780 groundColorButton.setColor(controller.getGroundColor()); 4781 }); 4782 4783 var backgroundImageVisibleOnGround3DCheckBox = this.getElement("background-image-visible-on-ground-3D-checkbox"); 4784 backgroundImageVisibleOnGround3DCheckBox.checked = controller.isBackgroundImageVisibleOnGround3D(); 4785 this.registerEventListener(backgroundImageVisibleOnGround3DCheckBox, "change", function(ev) { 4786 controller.setBackgroundImageVisibleOnGround3D(backgroundImageVisibleOnGround3DCheckBox.checked); 4787 }); 4788 this.registerPropertyChangeListener(controller, "BACKGROUND_IMAGE_VISIBLE_ON_GROUND_3D", function(ev) { 4789 backgroundImageVisibleOnGround3DCheckBox.checked = controller.isBackgroundImageVisibleOnGround3D(); 4790 }); 4791 4792 this.groundPanel = { 4793 colorButton: groundColorButton, 4794 textureComponent: textureComponent, 4795 }; 4796 }; 4797 4798 /** 4799 * @private 4800 */ 4801 Home3DAttributesDialog.prototype.initSkyPanel = function() { 4802 var controller = this.controller; 4803 var dialog = this; 4804 4805 var skyColorRadioButton = dialog.findElement("[name='sky-color-and-texture-choice'][value='COLORED']"); 4806 var skyColorButton = new ColorButton(preferences, 4807 { 4808 colorChanged: function(selectedColor) { 4809 skyColorRadioButton.checked = true; 4810 controller.setSkyPaint(Home3DAttributesController.EnvironmentPaint.COLORED); 4811 controller.setSkyColor(selectedColor); 4812 } 4813 }); 4814 dialog.attachChildComponent("sky-color-button", skyColorButton); 4815 skyColorButton.setColor(controller.getSkyColor()); 4816 skyColorButton.setColorDialogTitle(preferences.getLocalizedString( 4817 "Home3DAttributesPanel", "skyColorDialog.title")); 4818 4819 var skyTextureRadioButton = dialog.findElement("[name='sky-color-and-texture-choice'][value='TEXTURED']"); 4820 var textureComponent = controller.getSkyTextureController().getView(); 4821 dialog.attachChildComponent("sky-texture-component", textureComponent); 4822 4823 var radioButtons = [skyColorRadioButton, skyTextureRadioButton]; 4824 dialog.registerEventListener(radioButtons, "change", function(ev) { 4825 if (ev.target.checked) { 4826 controller.setSkyPaint(Home3DAttributesController.EnvironmentPaint[ev.target.value]); 4827 } 4828 }); 4829 4830 var paintChangeListener = function() { 4831 skyColorRadioButton.checked = controller.getSkyPaint() == Home3DAttributesController.EnvironmentPaint.COLORED; 4832 skyTextureRadioButton.checked = controller.getSkyPaint() == Home3DAttributesController.EnvironmentPaint.TEXTURED; 4833 }; 4834 paintChangeListener(); 4835 this.registerPropertyChangeListener(controller, "SKY_PAINT", paintChangeListener); 4836 this.registerPropertyChangeListener(controller, "SKY_COLOR", function() { 4837 skyColorButton.setColor(controller.getSkyColor()); 4838 }); 4839 4840 this.skyPanel = { 4841 colorButton: skyColorButton, 4842 textureComponent: textureComponent, 4843 }; 4844 }; 4845 4846 /** 4847 * @private 4848 */ 4849 Home3DAttributesDialog.prototype.initRenderingPanel = function() { 4850 var controller = this.controller; 4851 4852 var brightnessSlider = this.getElement("brightness-slider"); 4853 var brightnessList = this.findElement("#home-3Dattributes-brightness-list"); 4854 4855 var wallsTransparencySlider = this.getElement("walls-transparency-slider"); 4856 var wallsTransparencyList = this.findElement("#home-3Dattributes-walls-transparency-list"); 4857 4858 for (var i = 0; i <= 255; i+= 17) { 4859 var option = document.createElement("option"); 4860 option.value = i; 4861 brightnessList.appendChild(option); 4862 wallsTransparencyList.appendChild(option.cloneNode()); 4863 } 4864 4865 brightnessSlider.value = controller.getLightColor() & 0xFF; 4866 wallsTransparencySlider.value = controller.getWallsAlpha() * 255; 4867 4868 this.registerEventListener(brightnessSlider, "input", function(ev) { 4869 var brightness = ev.target.value; 4870 controller.setLightColor((brightness << 16) | (brightness << 8) | brightness); 4871 }); 4872 this.registerEventListener(wallsTransparencySlider, "input", function(ev) { 4873 controller.setWallsAlpha(this.value / 255); 4874 }); 4875 4876 this.registerPropertyChangeListener(controller, "LIGHT_COLOR", function(ev) { 4877 brightnessSlider.value = controller.getLightColor() & 0xFF; 4878 }); 4879 this.registerPropertyChangeListener(controller, "WALLS_ALPHA", function(ev) { 4880 wallsTransparencySlider.value = controller.getWallsAlpha() * 255; 4881 }); 4882 }; 4883 4884 return new Home3DAttributesDialog(); 4885 } 4886 4887 /** 4888 * Creates a texture selection component 4889 * @param {UserPreferences} preferences current user's preferences 4890 * @param {TextureChoiceController} textureChoiceController texture choice controller 4891 * @return {JSComponent} 4892 */ 4893 JSViewFactory.prototype.createTextureChoiceView = function(preferences, textureChoiceController) { 4894 return new TextureChoiceComponent(preferences, textureChoiceController); 4895 } 4896 4897 JSViewFactory.prototype.createBaseboardChoiceView = function(preferences, controller) { 4898 function BaseboardChoiceComponent() { 4899 JSComponent.call(this, preferences, 4900 " <div class='whole-line'>" 4901 + " <label>" 4902 + " <input name='baseboard-visible-checkbox' type='checkbox'/>" 4903 + " @{BaseboardChoiceComponent.visibleCheckBox.text}" 4904 + " </label>" 4905 + " </div>" 4906 + "" 4907 + " <div class='whole-line'>" 4908 + " <label>" 4909 + " <input type='radio' name='baseboard-color-and-texture-choice' value='sameColorAsWall'/>" 4910 + " @{BaseboardChoiceComponent.sameColorAsWallRadioButton.text}" 4911 + " </label>" 4912 + " </div>" 4913 + " <div>" 4914 + " <label>" 4915 + " <input type='radio' name='baseboard-color-and-texture-choice' value='COLORED'>" 4916 + " @{BaseboardChoiceComponent.colorRadioButton.text}" 4917 + " </label>" 4918 + " </div>" 4919 + " <div data-name='baseboard-color-button'></div>" 4920 + " <div>" 4921 + " <label>" 4922 + " <input type='radio' name='baseboard-color-and-texture-choice' value='TEXTURED'>" 4923 + " @{BaseboardChoiceComponent.textureRadioButton.text}" 4924 + " </label>" 4925 + " </div>" 4926 + " <div data-name='baseboard-texture-component'></div>" 4927 + " <div class='whole-line'>" 4928 + " <hr/>" 4929 + " </div>" 4930 + " <div data-name='height-label' class='label-cell'></div>" 4931 + " <div><span data-name='height-input'></span></div>" 4932 + " <div data-name='thickness-label' class='label-cell'></div>" 4933 + " <div><span data-name='thickness-input'></span></div>"); 4934 4935 this.initComponents(controller); 4936 } 4937 BaseboardChoiceComponent.prototype = Object.create(JSComponent.prototype); 4938 BaseboardChoiceComponent.prototype.constructor = BaseboardChoiceComponent; 4939 4940 BaseboardChoiceComponent.prototype.dispose = function () { 4941 this.colorButton.dispose(); 4942 this.textureComponent.dispose(); 4943 JSComponent.prototype.dispose.call(this); 4944 } 4945 4946 /** 4947 * @private 4948 */ 4949 BaseboardChoiceComponent.prototype.initComponents = function (controller) { 4950 var component = this; 4951 this.getHTMLElement().dataset["name"] = "baseboard-panel"; 4952 this.getHTMLElement().classList.add("label-input-grid"); 4953 4954 // VISIBLE 4955 this.visibleCheckBox = this.getElement("baseboard-visible-checkbox"); 4956 this.visibleCheckBox.checked = controller.getVisible(); 4957 this.registerEventListener(this.visibleCheckBox, "change", function(ev) { 4958 controller.setVisible(component.visibleCheckBox.checked); 4959 }); 4960 4961 var visibleChanged = function() { 4962 var visible = controller.getVisible(); 4963 component.visibleCheckBox.checked = visible; 4964 var componentsEnabled = visible !== false; 4965 for (var i = 0; i < component.colorAndTextureRadioButtons.length; i++) { 4966 component.colorAndTextureRadioButtons[i].disabled = !componentsEnabled; 4967 } 4968 component.colorButton.setEnabled(componentsEnabled); 4969 component.textureComponent.setEnabled(componentsEnabled); 4970 component.heightInput.setEnabled(componentsEnabled); 4971 component.thicknessInput.setEnabled(componentsEnabled); 4972 }; 4973 this.registerPropertyChangeListener(controller, "VISIBLE", function(ev) { 4974 visibleChanged(); 4975 }); 4976 4977 // PAINT 4978 var sameColorAsWallRadioButton = this.findElement("[name='baseboard-color-and-texture-choice'][value='sameColorAsWall']"); 4979 4980 var colorRadioButton = this.findElement("[name='baseboard-color-and-texture-choice'][value='COLORED']"); 4981 this.colorButton = new ColorButton(preferences, 4982 { 4983 colorChanged: function(selectedColor) { 4984 colorRadioButton.checked = true; 4985 controller.setPaint(BaseboardChoiceController.BaseboardPaint.COLORED); 4986 controller.setColor(selectedColor); 4987 } 4988 }); 4989 this.attachChildComponent("baseboard-color-button", this.colorButton); 4990 this.colorButton.setColor(controller.getColor()); 4991 this.colorButton.setColorDialogTitle(preferences.getLocalizedString( 4992 "BaseboardChoiceComponent", "colorDialog.title")); 4993 4994 var textureRadioButton = this.findElement("[name='baseboard-color-and-texture-choice'][value='TEXTURED']"); 4995 this.textureComponent = controller.getTextureController().getView(); 4996 this.attachChildComponent("baseboard-texture-component", this.textureComponent); 4997 4998 this.colorAndTextureRadioButtons = [sameColorAsWallRadioButton, colorRadioButton, textureRadioButton]; 4999 this.registerEventListener(this.colorAndTextureRadioButtons, "change", function(ev) { 5000 if (ev.target.checked) { 5001 var selectedPaint = ev.target.value == "sameColorAsWall" 5002 ? BaseboardChoiceController.BaseboardPaint.DEFAULT 5003 : BaseboardChoiceController.BaseboardPaint[ev.target.value]; 5004 controller.setPaint(selectedPaint); 5005 } 5006 }); 5007 5008 var paintChangeListener = function() { 5009 sameColorAsWallRadioButton.checked = controller.getPaint() == BaseboardChoiceController.BaseboardPaint.DEFAULT; 5010 colorRadioButton.checked = controller.getPaint() == BaseboardChoiceController.BaseboardPaint.COLORED; 5011 textureRadioButton.checked = controller.getPaint() == BaseboardChoiceController.BaseboardPaint.TEXTURED; 5012 }; 5013 paintChangeListener(); 5014 this.registerPropertyChangeListener(controller, "PAINT", paintChangeListener); 5015 5016 // Height & thickness 5017 var unitName = preferences.getLengthUnit().getName(); 5018 this.getElement("height-label").textContent = this.getLocalizedLabelText("BaseboardChoiceComponent", "heightLabel.text", unitName); 5019 this.getElement("thickness-label").textContent = this.getLocalizedLabelText("BaseboardChoiceComponent", "thicknessLabel.text", unitName); 5020 5021 var minimumLength = preferences.getLengthUnit().getMinimumLength(); 5022 this.heightInput = new JSSpinner(preferences, this.getElement("height-input"), 5023 { 5024 nullable: controller.getHeight() == null, 5025 format: preferences.getLengthUnit().getFormat(), 5026 value: controller.getHeight() != null && controller.getMaxHeight() != null 5027 ? Math.min(controller.getHeight(), controller.getMaxHeight()) 5028 : controller.getHeight(), 5029 minimum: minimumLength, 5030 maximum: controller.getMaxHeight() == null 5031 ? preferences.getLengthUnit().getMaximumLength() / 10 5032 : controller.getMaxHeight(), 5033 stepSize: preferences.getLengthUnit().getStepSize() 5034 }); 5035 this.thicknessInput = new JSSpinner(preferences, this.getElement("thickness-input"), 5036 { 5037 nullable: controller.getThickness() == null, 5038 format: preferences.getLengthUnit().getFormat(), 5039 value: controller.getThickness(), 5040 minimum: minimumLength, 5041 maximum: 2, 5042 stepSize: preferences.getLengthUnit().getStepSize() 5043 }); 5044 5045 this.registerPropertyChangeListener(controller, "HEIGHT", function(ev) { 5046 component.heightInput.setValue(ev.getNewValue()); 5047 }); 5048 this.registerPropertyChangeListener(controller, "MAX_HEIGHT", function(ev) { 5049 if (ev.getOldValue() == null 5050 || controller.getMaxHeight() != null 5051 && component.heightInput.max < controller.getMaxHeight()) { 5052 // Change max only if larger value to avoid taking into account intermediate max values 5053 // that may be fired by auto commit spinners while entering a value 5054 component.heightInput.max = controller.getMaxHeight(); 5055 } 5056 }); 5057 this.registerPropertyChangeListener(controller, "THICKNESS", function(ev) { 5058 component.thicknessInput.setValue(ev.getNewValue()); 5059 }); 5060 5061 this.registerEventListener(this.heightInput, "input", function(ev) { 5062 controller.setHeight(component.heightInput.getValue()); 5063 }); 5064 this.registerEventListener(this.thicknessInput, "input", function(ev) { 5065 controller.setThickness(component.thicknessInput.getValue()); 5066 }); 5067 5068 visibleChanged(); 5069 } 5070 5071 return new BaseboardChoiceComponent(); 5072 } 5073 5074 JSViewFactory.prototype.createModelMaterialsView = function(preferences, controller) { 5075 return new ModelMaterialsComponent(preferences, controller); 5076 } 5077 5078 JSViewFactory.prototype.createPageSetupView = function(preferences, pageSetupController) { 5079 return this.dummyDialogView; 5080 } 5081 5082 JSViewFactory.prototype.createPrintPreviewView = function(home, preferences, homeController, printPreviewController) { 5083 return this.dummyDialogView; 5084 } 5085 5086 JSViewFactory.prototype.createPhotoView = function(home, preferences, photoController) { 5087 return this.dummyDialogView; 5088 } 5089 5090 JSViewFactory.prototype.createPhotosView = function(home, preferences, photosController) { 5091 return this.dummyDialogView; 5092 } 5093 5094 JSViewFactory.prototype.createVideoView = function(home, preferences, videoController) { 5095 return this.dummyDialogView; 5096 } 5097