All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scout.layout.graphics.js Maven / Gradle / Ivy

There is a newer version: 25.1.0-beta.0
Show newest version
/*******************************************************************************
 * Copyright (c) 2014-2015 BSI Business Systems Integration AG.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     BSI Business Systems Integration AG - initial API and implementation
 ******************************************************************************/
/**
 * This file contains helpers for graphical operations and JavaScript ports from java.awt classes
 */
scout.graphics = {

  /**
   * Returns the preferred size of $elem.
   * Precondition: $elem and it's parents must not be hidden (display: none. Visibility: hidden would be ok
   * because in this case the browser reserves the space the element would be using).
   *
   * @memberOf scout.graphics
   */
  prefSize: function($elem, includeMargin, options) {
    // Return 0/0 if element is not displayed (display: none).
    // We don't use isVisible by purpose because isVisible returns false for elements with visibility: hidden which is wrong here (we would like to be able to measure hidden elements)
    if ($elem.isDisplayNone()) {
      return new scout.Dimension(0, 0);
    }

    var defaults = {
      useCssSize: false,
      resetWidth: true
    };
    options = $.extend({}, defaults, options);

    var oldStyle = $elem.attr('style');
    var oldScrollLeft = $elem.scrollLeft();
    var oldScrollTop = $elem.scrollTop();

    // UseCssSize is necessary if the css rules have a fix height or width set.
    // Otherwise setting the width/height to auto could result in a different size
    var newWidth = (options.useCssSize ? '' : scout.nvl(options.widthHint, 'auto'));
    var newHeight = (options.useCssSize ? '' : 'auto');

    // modify properties which prevent reading the preferred size
    $elem.css({
      'width': newWidth,
      'height': newHeight
    });

    var prefSize;
    // measure
    if (options.useCssSize) {
      prefSize = scout.graphics.getSize($elem, includeMargin);
    } else {
      prefSize = scout.graphics.getScrollSizes($elem, includeMargin);
    }

    // reset the modified style attribute
    $elem.attrOrRemove('style', oldStyle);
    $elem.scrollLeft(oldScrollLeft);
    $elem.scrollTop(oldScrollTop);

    return prefSize;
  },

  getScrollSizes: function($comp, includeMargin) {
    var marginWidth = 0,
      marginHeight = 0,
      scrollWidth = $comp[0] ? $comp[0].scrollWidth : 0,
      scrollHeight = $comp[0] ? $comp[0].scrollHeight : 0;
    includeMargin = scout.nvl(includeMargin, false);
    if (includeMargin) {
      marginHeight += parseFloat(scout.nvl($comp.css('margin-top'), 0)) + parseFloat(scout.nvl($comp.css('margin-bottom'), 0));
      marginWidth += parseFloat(scout.nvl($comp.css('margin-left'), 0)) + parseFloat(scout.nvl($comp.css('margin-right'), 0));
    }
    return new scout.Dimension(
      scrollWidth + marginWidth + parseFloat($comp.css("border-left-width")) + parseFloat($comp.css("border-right-width")),
      scrollHeight + marginHeight + parseFloat($comp.css("border-top-width")) + parseFloat($comp.css("border-bottom-width")));
  },

  /* These functions are designed to be used with box-sizing:box-model. The only reliable
   * way to set the size of a component when working with box model is to use css('width/height'...)
   * in favor of width/height() functions.
   */
  /**
   * Returns the size of the component, insets included.
   * @param includeMargin when set to true, returned dimensions include margins of component, default is false.
   */
  getSize: function($comp, includeMargin) {
    includeMargin = scout.nvl(includeMargin, false);
    return new scout.Dimension(
      $comp.outerWidth(includeMargin),
      $comp.outerHeight(includeMargin));
  },

  setSize: function($comp, vararg, height) {
    var size = vararg instanceof scout.Dimension ?
      vararg : new scout.Dimension(vararg, height);
    $comp
      .cssWidth(size.width)
      .cssHeight(size.height);
  },

  /**
   * Returns the size of a visible component or (0,0) when component is invisible.
   */
  getVisibleSize: function($comp, includeMargin) {
    if ($comp.length === 1 && $comp.isVisible()) {
      return scout.graphics.getSize($comp, includeMargin);
    } else {
      return new scout.Dimension(0, 0);
    }
  },

  /**
   * Returns the inset-dimensions of the component (padding, margin, border).
   */
  getInsets: function($comp, options) {
    options = options || {};
    var i,
      directions = ['top', 'right', 'bottom', 'left'],
      insets = [0, 0, 0, 0],
      includeMargin = options.includeMargin !== undefined ? options.includeMargin : false,
      includePadding = options.includePadding !== undefined ? options.includePadding : true,
      includeBorder = options.includeBorder !== undefined ? options.includeBorder : true;

    for (i = 0; i < directions.length; i++) {
      if (includeMargin) {
        insets[i] += $comp.cssPxValue('margin-' + directions[i]);
      }
      if (includePadding) {
        insets[i] += $comp.cssPxValue('padding-' + directions[i]);
      }
      if (includeBorder) {
        insets[i] += $comp.cssPxValue('border-' + directions[i] + '-width');
      }
    }
    return new scout.Insets(insets[0], insets[1], insets[2], insets[3]);
  },

  getMargins: function($comp) {
    return scout.graphics.getInsets($comp, {
      includeMargin: true,
      includePadding: false,
      includeBorder: false
    });
  },

  getBounds: function($comp) {
    var parseCssPosition = function(prop) {
      var value = $comp.css(prop);
      return 'auto' === value ? 0 : parseInt(value, 10);
    };
    return new scout.Rectangle(
      parseCssPosition('left'),
      parseCssPosition('top'),
      $comp.outerWidth(true),
      $comp.outerHeight(true));
  },

  setBounds: function($comp, vararg, y, width, height) {
    var bounds = vararg instanceof scout.Rectangle ?
      vararg : new scout.Rectangle(vararg, y, width, height);
    $comp
      .cssLeft(bounds.x)
      .cssTop(bounds.y)
      .cssWidth(bounds.width)
      .cssHeight(bounds.height);
  },

  /**
   * Sets the location (CSS properties left, top) of the component.
   * @param vararg integer value for X position OR instance of scout.Point
   * @param y (optional) integer value for Y position
   * @returns
   */
  setLocation: function($comp, vararg, y) {
    var point = vararg instanceof scout.Point ?
      vararg : new scout.Point(vararg, y);
    $comp
      .cssLeft(point.x)
      .cssTop(point.y);
  },

  bounds: function($elem, includeSizeMargin, includePosMargin) {
    //FIXME cgu: merge with getBounds, ask awe why parseCssPosition is used, or rename getBounds to cssBounds
    return scout.graphics._bounds($elem, $elem.position(), includeSizeMargin, includePosMargin);
  },

  offsetBounds: function($elem, includeSizeMargin, includePosMargin) {
    return scout.graphics._bounds($elem, $elem.offset(), includeSizeMargin, includePosMargin);
  },

  _bounds: function($elem, pos, includeSizeMargin, includePosMargin) {
    if (includeSizeMargin === undefined) {
      includeSizeMargin = false;
    }
    if (includePosMargin === undefined) {
      includePosMargin = false;
    }
    if (includePosMargin) {
      pos.left += $elem.cssMarginLeft();
      pos.top += $elem.cssMarginTop();
    }
    return new scout.Rectangle(pos.left, pos.top, $elem.outerWidth(includeSizeMargin), $elem.outerHeight(includeSizeMargin));
  },

  debugOutput: function($comp) {
    if (!$comp) {
      return '$comp is undefined';
    }
    if (!($comp instanceof $)) {
      $comp = $($comp);
    }
    if ($comp.length === 0) {
      return '$comp doesn\t match any elements';
    }
    var attrs = '';
    if ($comp.attr('id')) {
      attrs += 'id=' + $comp.attr('id');
    }
    if ($comp.attr('class')) {
      attrs += ' class=' + $comp.attr('class');
    }
    if ($comp.attr('data-modelclass')) {
      attrs += ' data-modelclass=' + $comp.attr('data-modelclass');
    }
    if (attrs.length === 0) {
      var html = scout.nvl($comp.html(), '');
      if (html.length > 30) {
        html = html.substring(0, 30) + '...';
      }
      attrs = html;
    }
    return 'Element[' + attrs.trim() + ']';
  }
};

/**
 * JavaScript port from java.awt.Point.
 */
scout.Point = function(x, y) {
  this.x = x || 0;
  this.y = y || 0;
};

scout.Point.prototype.toString = function() {
  return 'Point[x=' + this.x + ' y=' + this.y + ']';
};

scout.Point.prototype.equals = function(o) {
  if (!o) {
    return false;
  }
  return (this.x === o.x && this.y === o.y);
};

scout.Point.prototype.clone = function(o) {
  return new scout.Point(this.x, this.y);
};

/**
 * JavaScript port from java.awt.Dimension.
 * @param vararg width (number) or otherDimension (scout.Dimension)
 * @param height number or undefined (when vararg is scout.Dimension)
 */
scout.Dimension = function(vararg, height) {
  if (vararg instanceof scout.Dimension) {
    this.width = vararg.width;
    this.height = vararg.height;
  } else {
    this.width = vararg || 0;
    this.height = height || 0;
  }
};

scout.Dimension.prototype.toString = function() {
  return 'Dimension[width=' + this.width + ' height=' + this.height + ']';
};

scout.Dimension.prototype.equals = function(o) {
  if (!o) {
    return false;
  }
  return (this.width === o.width && this.height === o.height);
};

scout.Dimension.prototype.clone = function() {
  return new scout.Dimension(this.width, this.height);
};

scout.Dimension.prototype.subtract = function(insets) {
  return new scout.Dimension(
    this.width - insets.horizontal(),
    this.height - insets.vertical());
};

scout.Dimension.prototype.add = function(insets) {
  return new scout.Dimension(
    this.width + insets.horizontal(),
    this.height + insets.vertical());
};

/**
 * JavaScript port from java.awt.Rectangle.
 */
scout.Rectangle = function(x, y, width, height) {
  this.x = x || 0;
  this.y = y || 0;
  this.width = width || 0;
  this.height = height || 0;
};

scout.Rectangle.prototype.equals = function(o) {
  if (!o) {
    return false;
  }
  return (this.x === o.x && this.y === o.y && this.width === o.width && this.height === o.height);
};

scout.Rectangle.prototype.toString = function() {
  return 'Rectangle[x=' + this.x + ' y=' + this.y + ' width=' + this.width + ' height=' + this.height + ']';
};

scout.Rectangle.prototype.clone = function(o) {
  return new scout.Rectangle(this.x, this.y, this.width, this.height);
};

scout.Rectangle.prototype.center = function() {
  return new scout.Point(this.x + this.width / 2, this.y + this.height / 2);
};

scout.Rectangle.prototype.contains = function(x, y) {
  return y >= this.y && y < this.y + this.height && x >= this.x && x < this.x + this.width;
};

scout.Rectangle.prototype.subtract = function(insets) {
  return new scout.Rectangle(
    this.x + insets.left,
    this.y + insets.top,
    this.width - insets.right,
    this.height - insets.bottom);
};

scout.Rectangle.prototype.union = function(r) {
  var tx2 = this.width;
  var ty2 = this.height;
  if (tx2 < 0 || ty2 < 0) {
    // This rectangle has negative dimensions...
    // If r has non-negative dimensions then it is the answer.
    // If r is non-existant (has a negative dimension), then both
    // are non-existant and we can return any non-existant rectangle
    // as an answer.  Thus, returning r meets that criterion.
    // Either way, r is our answer.
    return new scout.Rectangle(r.x, r.y, r.width, r.height);
  }
  var rx2 = r.width;
  var ry2 = r.height;
  if (rx2 < 0 || ry2 < 0) {
    return new scout.Rectangle(this.x, this.y, this.width, this.height);
  }
  var tx1 = this.x;
  var ty1 = this.y;
  tx2 += tx1;
  ty2 += ty1;
  var rx1 = r.x;
  var ry1 = r.y;
  rx2 += rx1;
  ry2 += ry1;
  if (tx1 > rx1) {
    tx1 = rx1;
  }
  if (ty1 > ry1) {
    ty1 = ry1;
  }
  if (tx2 < rx2) {
    tx2 = rx2;
  }
  if (ty2 < ry2) {
    ty2 = ry2;
  }
  tx2 -= tx1;
  ty2 -= ty1;
  // tx2,ty2 will never underflow since both original rectangles
  // were already proven to be non-empty
  // they might overflow, though...
  if (tx2 > Number.MAX_VALUE) {
    tx2 = Number.MAX_VALUE;
  }
  if (ty2 > Number.MAX_VALUE) {
    ty2 = Number.MAX_VALUE;
  }
  return new scout.Rectangle(tx1, ty1, tx2, ty2);
};

/**
 * JavaScript port from java.awt.Insets.
 */
scout.Insets = function(top, right, bottom, left) {
  this.top = top || 0;
  this.right = right || 0;
  this.bottom = bottom || 0;
  this.left = left || 0;
};

scout.Insets.prototype.equals = function(o) {
  return this.top === o.top &&
    this.right === o.right &&
    this.bottom === o.bottom &&
    this.left === o.left;
};

scout.Insets.prototype.horizontal = function() {
  return this.right + this.left;
};

scout.Insets.prototype.vertical = function() {
  return this.top + this.bottom;
};

scout.Insets.prototype.toString = function() {
  return 'Insets[top=' + this.top + ' right=' + this.right + ' bottom=' + this.bottom + ' left=' + this.left + ']';
};

scout.Insets.prototype.clone = function() {
  return new scout.Insets(this.top, this.right, this.bottom, this.left);
};

/**
 * JavaScript port from java.util.TreeSet.
 */
scout.TreeSet = function() {
  this.array = [];
  this.properties = {};
};

scout.TreeSet.prototype.add = function(value) {
  if (!this.contains(value)) {
    this.array.push(value);
    this.array.sort();
    this.properties[value] = true;
  }
};

scout.TreeSet.prototype.size = function() {
  return this.array.length;
};

scout.TreeSet.prototype.contains = function(value) {
  return (value in this.properties);
};

scout.TreeSet.prototype.last = function() {
  return this.array[this.array.length - 1];
};

/**
 * HtmlEnvironment is used in place of org.eclipse.scout.rt.ui.swing.DefaultSwingEnvironment.
 */
scout.HtmlEnvironment = {
  // -------------------------------
  // IMPORTANT:
  // Some of the following constants are also defined in sizes.css. If you change
  // them, be sure to apply them at both places. (Remember to consider margins)
  // -------------------------------
  formRowHeight: 30, // @logical-grid-height
  formRowGap: 10,
  formColumnWidth: 420,
  formColumnGap: 32, // 40 pixel actual form gap - fieldMandatoryIndicatorWidth
  smallColumnGap: 4,
  fieldLabelWidth: 140,
  fieldMandatoryIndicatorWidth: 8, // @mandatory-indicator-width
  fieldStatusWidth: 20 // @field-status-width
};




© 2015 - 2025 Weber Informatics LLC | Privacy Policy