Moves field layout constants into the renderer (#3437)

* Add field constants into renderer constants
This commit is contained in:
Sam El-Husseini
2019-11-13 16:41:35 -08:00
committed by GitHub
parent f2c477229d
commit 2dea7038d5
14 changed files with 184 additions and 127 deletions

View File

@@ -31,9 +31,10 @@ goog.require('Blockly.Gesture');
goog.require('Blockly.utils');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.Size');
goog.require('Blockly.utils.style');
goog.require('Blockly.utils.userAgent');
goog.require('Blockly.utils.style');
goog.requireType('Blockly.blockRendering.ConstantProvider');
/**
@@ -141,41 +142,6 @@ Blockly.Field = function(value, opt_validator, opt_config) {
opt_validator && this.setValidator(opt_validator);
};
/**
* The default height of the border rect on any field.
* @type {number}
* @package
*/
Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT = 16;
/**
* The default height of the text element on any field.
* @type {number}
* @package
*/
Blockly.Field.TEXT_DEFAULT_HEIGHT = 12.5;
/**
* The padding added to the width by the border rect, if it exists.
* @type {number}
* @package
*/
Blockly.Field.X_PADDING = 10;
/**
* The padding added to the height by the border rect, if it exists.
* @type {number}
* @package
*/
Blockly.Field.Y_PADDING = 10;
/**
* The default offset between the left of the text element and the left of the
* border rect, if the border rect exists.
* @type {number}
*/
Blockly.Field.DEFAULT_TEXT_OFFSET = Blockly.Field.X_PADDING / 2;
/**
* Name of field. Unique within each block.
* Static labels are usually unnamed.
@@ -354,9 +320,9 @@ Blockly.Field.prototype.initModel = function() {
*/
Blockly.Field.prototype.createBorderRect_ = function() {
this.size_.height =
Math.max(this.size_.height, Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT);
Math.max(this.size_.height, this.constants_.FIELD_BORDER_RECT_HEIGHT);
this.size_.width =
Math.max(this.size_.width, Blockly.Field.X_PADDING);
Math.max(this.size_.width, this.constants_.FIELD_BORDER_RECT_X_PADDING * 2);
this.borderRect_ = /** @type {!SVGRectElement} **/
(Blockly.utils.dom.createSvgElement('rect',
{
@@ -376,15 +342,25 @@ Blockly.Field.prototype.createBorderRect_ = function() {
* @protected
*/
Blockly.Field.prototype.createTextElement_ = function() {
var xOffset = this.borderRect_ ? Blockly.Field.DEFAULT_TEXT_OFFSET : 0;
var xOffset = this.borderRect_ ?
this.constants_.FIELD_BORDER_RECT_X_PADDING : 0;
this.size_.height = Math.max(this.size_.height,
this.constants_.FIELD_TEXT_BASELINE_CENTER ?
this.constants_.FIELD_TEXT_HEIGHT :
this.constants_.FIELD_TEXT_BASELINE_Y);
this.textElement_ = /** @type {!SVGTextElement} **/
(Blockly.utils.dom.createSvgElement('text',
{
'class': 'blocklyText',
// The y position is the baseline of the text.
'y': Blockly.Field.TEXT_DEFAULT_HEIGHT,
'y': this.size_.height / 2,
'x': xOffset
}, this.fieldGroup_));
if (this.constants_.FIELD_TEXT_BASELINE_CENTER) {
this.textElement_.setAttribute('dominant-baseline', 'central');
} else {
this.textElement_.setAttribute('dy',
this.constants_.FIELD_TEXT_BASELINE_Y - this.size_.height / 2);
}
this.textContent_ = document.createTextNode('');
this.textElement_.appendChild(this.textContent_);
};
@@ -658,7 +634,7 @@ Blockly.Field.prototype.updateSize_ = function() {
this.constants_.FIELD_TEXT_FONTFAMILY);
var totalWidth = textWidth;
if (this.borderRect_) {
totalWidth += Blockly.Field.X_PADDING;
totalWidth += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
this.borderRect_.setAttribute('width', totalWidth);
}
this.size_.width = totalWidth;

View File

@@ -91,20 +91,6 @@ Blockly.FieldCheckbox.WIDTH = 15;
*/
Blockly.FieldCheckbox.CHECK_CHAR = '\u2713';
/**
* Used to correctly position the check mark.
* @type {number}
* @const
*/
Blockly.FieldCheckbox.CHECK_X_OFFSET = Blockly.Field.DEFAULT_TEXT_OFFSET - 3;
/**
* Used to correctly position the check mark.
* @type {number}
* @const
*/
Blockly.FieldCheckbox.CHECK_Y_OFFSET = 14;
/**
* Serializable fields are saved by the XML renderer, non-serializable fields
* are not. Editable fields should also be serializable.
@@ -145,8 +131,9 @@ Blockly.FieldCheckbox.prototype.configure_ = function(config) {
Blockly.FieldCheckbox.prototype.initView = function() {
Blockly.FieldCheckbox.superClass_.initView.call(this);
this.textElement_.setAttribute('x', Blockly.FieldCheckbox.CHECK_X_OFFSET);
this.textElement_.setAttribute('y', Blockly.FieldCheckbox.CHECK_Y_OFFSET);
this.textElement_.setAttribute('x', this.constants_.FIELD_CHECKBOX_X_OFFSET);
this.textElement_.setAttribute('y', this.constants_.FIELD_CHECKBOX_Y_OFFSET);
this.textElement_.removeAttribute('dominant-baseline');
Blockly.utils.dom.addClass(this.textElement_, 'blocklyCheckbox');
this.textContent_.nodeValue =

View File

@@ -57,15 +57,6 @@ Blockly.FieldColour = function(opt_value, opt_validator, opt_config) {
this, opt_value || Blockly.FieldColour.COLOURS[0],
opt_validator, opt_config);
/**
* The size of the area rendered by the field.
* @type {Blockly.utils.Size}
* @protected
* @override
*/
this.size_ = new Blockly.utils.Size(Blockly.FieldColour.DEFAULT_WIDTH,
Blockly.FieldColour.DEFAULT_HEIGHT);
/**
* The field's colour picker element.
* @type {Element}
@@ -128,22 +119,6 @@ Blockly.FieldColour.fromJson = function(options) {
return new Blockly.FieldColour(options['colour'], undefined, options);
};
/**
* Default width of a colour field.
* @type {number}
* @private
* @const
*/
Blockly.FieldColour.DEFAULT_WIDTH = 26;
/**
* Default height of a colour field.
* @type {number}
* @private
* @const
*/
Blockly.FieldColour.DEFAULT_HEIGHT = Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT;
/**
* Serializable fields are saved by the XML renderer, non-serializable fields
* are not. Editable fields should also be serializable.
@@ -208,6 +183,9 @@ Blockly.FieldColour.prototype.configure_ = function(config) {
* @package
*/
Blockly.FieldColour.prototype.initView = function() {
this.size_ = new Blockly.utils.Size(
this.constants_.FIELD_COLOUR_DEFAULT_WIDTH,
this.constants_.FIELD_COLOUR_DEFAULT_HEIGHT);
this.createBorderRect_();
this.borderRect_.style['fillOpacity'] = '1';
this.borderRect_.style.fill = this.value_;

View File

@@ -525,19 +525,20 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) {
// Height and width include the border rect.
this.size_.height = imageHeight + Blockly.FieldDropdown.IMAGE_Y_PADDING;
this.size_.width = imageWidth + arrowWidth + Blockly.Field.X_PADDING;
var xPadding = this.constants_.FIELD_BORDER_RECT_X_PADDING;
this.size_.width = imageWidth + arrowWidth + xPadding * 2;
if (this.sourceBlock_.RTL) {
var imageX = Blockly.Field.DEFAULT_TEXT_OFFSET + arrowWidth;
var arrowX = Blockly.Field.DEFAULT_TEXT_OFFSET - 1;
var imageX = xPadding + arrowWidth;
var arrowX = xPadding - 1;
this.imageElement_.setAttribute('x', imageX);
this.textElement_.setAttribute('x', arrowX);
} else {
var arrowX =
imageWidth + arrowWidth + Blockly.Field.DEFAULT_TEXT_OFFSET + 1;
imageWidth + arrowWidth + xPadding + 1;
this.textElement_.setAttribute('text-anchor', 'end');
this.textElement_.setAttribute('x', arrowX);
this.imageElement_.setAttribute('x', Blockly.Field.DEFAULT_TEXT_OFFSET);
this.imageElement_.setAttribute('x', xPadding);
}
};
@@ -549,14 +550,24 @@ Blockly.FieldDropdown.prototype.renderSelectedText_ = function() {
// Retrieves the selected option to display through getText_.
this.textContent_.nodeValue = this.getDisplayText_();
this.textElement_.setAttribute('text-anchor', 'start');
this.textElement_.setAttribute('x', Blockly.Field.DEFAULT_TEXT_OFFSET);
this.textElement_.setAttribute('x',
this.constants_.FIELD_BORDER_RECT_X_PADDING);
// Height and width include the border rect.
this.size_.height = Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT;
this.size_.height = Math.max(
this.constants_.FIELD_DROPDOWN_BORDER_RECT_HEIGHT,
this.constants_.FIELD_TEXT_HEIGHT +
this.constants_.FIELD_BORDER_RECT_Y_PADDING * 2);
this.size_.width = Blockly.utils.dom.getFastTextWidth(this.textElement_,
this.constants_.FIELD_TEXT_FONTSIZE,
this.constants_.FIELD_TEXT_FONTWEIGHT,
this.constants_.FIELD_TEXT_FONTFAMILY) +
Blockly.Field.X_PADDING;
this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
this.textElement_.setAttribute('y', this.size_.height / 2);
if (!this.constants_.FIELD_TEXT_BASELINE_CENTER) {
this.textElement_.setAttribute('dy',
this.constants_.FIELD_TEXT_BASELINE_Y - this.size_.height / 2);
}
};
/**

View File

@@ -60,14 +60,6 @@ Blockly.FieldLabel = function(opt_value, opt_class, opt_config) {
if (!opt_config) { // If the config was not passed use old configuration.
this.class_ = opt_class || null;
}
/**
* The size of the area rendered by the field.
* @type {Blockly.utils.Size}
* @protected
* @override
*/
this.size_ = new Blockly.utils.Size(0, Blockly.Field.TEXT_DEFAULT_HEIGHT);
};
Blockly.utils.object.inherits(Blockly.FieldLabel, Blockly.Field);
@@ -105,10 +97,9 @@ Blockly.FieldLabel.prototype.configure_ = function(config) {
*/
Blockly.FieldLabel.prototype.initView = function() {
this.createTextElement_();
// The y attribute of an SVG text element is the baseline.
this.textElement_.setAttribute('y', this.size_.height);
if (this.class_) {
Blockly.utils.dom.addClass(this.textElement_, this.class_);
Blockly.utils.dom.addClass(
/** @type {!SVGTextElement} */ (this.textElement_), this.class_);
}
};

View File

@@ -152,13 +152,12 @@ Blockly.FieldMultilineInput.prototype.render_ = function() {
// Add in text elements into the group.
var lines = this.getDisplayText_().split('\n');
var yOffset = Blockly.Field.Y_PADDING / 2;
var y = 0;
for (var i = 0; i < lines.length; i++) {
var span = Blockly.utils.dom.createSvgElement('text', {
'class': 'blocklyText blocklyMultilineText',
x: Blockly.Field.DEFAULT_TEXT_OFFSET,
y: y + yOffset,
x: this.constants_.FIELD_BORDER_RECT_X_PADDING,
y: y + this.constants_.FIELD_BORDER_RECT_Y_PADDING,
dy: Blockly.FieldMultilineInput.LINE_HEIGHT / 2
}, this.textGroup_);
span.appendChild(document.createTextNode(lines[i]));
@@ -206,7 +205,7 @@ Blockly.FieldMultilineInput.prototype.updateSize_ = function() {
totalHeight += Blockly.FieldMultilineInput.LINE_HEIGHT;
}
if (this.borderRect_) {
totalWidth += Blockly.Field.X_PADDING;
totalWidth += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
this.borderRect_.setAttribute('width', totalWidth);
this.borderRect_.setAttribute('height', totalHeight);
}
@@ -250,7 +249,7 @@ Blockly.FieldMultilineInput.prototype.widgetCreate_ = function() {
htmlInput.style.fontSize = fontSize;
var borderRadius = (Blockly.FieldTextInput.BORDERRADIUS * scale) + 'px';
htmlInput.style.borderRadius = borderRadius;
var padding = Blockly.Field.DEFAULT_TEXT_OFFSET * scale;
var padding = this.constants_.FIELD_BORDER_RECT_X_PADDING * scale;
htmlInput.style.paddingLeft = padding + 'px';
htmlInput.style.width = 'calc(100% - ' + padding + 'px)';
htmlInput.style.lineHeight =

View File

@@ -85,19 +85,19 @@ Blockly.FieldTextInput = function(opt_value, opt_validator, opt_config) {
*/
this.onKeyInputWrapper_ = null;
/**
* Whether the field should consider the whole parent block to be its click
* target.
* @type {?boolean}
*/
this.fullBlockClickTarget_ = false;
/**
* Blur input event data.
* @type {?Blockly.EventData}
* @private
*/
this.onBlurInputWrapper_ = null;
/**
* Whether the field should consider the whole parent block to be its click
* target.
* @type {?boolean}
*/
this.fullBlockClickTarget_ = false;
};
Blockly.utils.object.inherits(Blockly.FieldTextInput, Blockly.Field);
@@ -146,8 +146,11 @@ Blockly.FieldTextInput.prototype.configure_ = function(config) {
* @override
*/
Blockly.FieldTextInput.prototype.initView = function() {
var renderer = this.sourceBlock_.workspace.getRenderer();
if (renderer.getConstants().FULL_BLOCK_FIELDS) {
this.size_.height = Math.max(this.constants_.FIELD_BORDER_RECT_HEIGHT,
this.constants_.FIELD_TEXT_BASELINE_CENTER ?
this.constants_.FIELD_TEXT_HEIGHT :
this.constants_.FIELD_TEXT_BASELINE_Y);
if (this.constants_.FULL_BLOCK_FIELDS) {
// Step one: figure out if this is the only field on this block.
// Rendering is quite different in that case.
var nFields = 0;
@@ -173,16 +176,14 @@ Blockly.FieldTextInput.prototype.initView = function() {
}
if (this.fullBlockClickTarget_) {
// Don't create a border rect.
this.size_.height =
Math.max(this.size_.height, Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT);
this.size_.width =
Math.max(this.size_.width, Blockly.Field.X_PADDING);
this.clickTarget_ = this.sourceBlock_.getSvgRoot();
} else {
this.createBorderRect_();
}
this.createTextElement_();
if (this.constants_.FIELD_TEXT_BASELINE_CENTER) {
this.textElement_.setAttribute('dominant-baseline', 'central');
}
};
/**
@@ -352,7 +353,7 @@ Blockly.FieldTextInput.prototype.widgetCreate_ = function() {
if (this.fullBlockClickTarget_) {
var bBox = this.getScaledBBox();
// Override border radius.
borderRadius = (bBox.bottom - bBox.top) / 2;
borderRadius = (bBox.bottom - bBox.top) / 2 + 'px';
// Pull stroke colour from the existing shadow block
var strokeColour = this.sourceBlock_.style.colourTertiary;
div.style.borderColor = strokeColour;

View File

@@ -25,6 +25,7 @@ goog.provide('Blockly.blockRendering.ConstantProvider');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.svgPaths');
goog.require('Blockly.utils.userAgent');
/**
@@ -143,6 +144,12 @@ Blockly.blockRendering.ConstantProvider = function() {
*/
this.FIELD_TEXT_FONTSIZE = 11;
/**
* Height of text.
* @type {number}
*/
this.FIELD_TEXT_HEIGHT = 13;
/**
* Text font weight. Should match blocklyText's font-weight in CSS.
* @type {string}
@@ -157,6 +164,74 @@ Blockly.blockRendering.ConstantProvider = function() {
*/
this.FIELD_TEXT_FONTFAMILY = 'sans-serif';
/**
* A field's border rect corner radius.
* @type {number}
*/
this.FIELD_BORDER_RECT_RADIUS = 4;
/**
* A field's border rect default height.
* @type {number}
*/
this.FIELD_BORDER_RECT_HEIGHT = 16;
/**
* A field's border rect X padding.
* @type {number}
*/
this.FIELD_BORDER_RECT_X_PADDING = 5;
/**
* A field's border rect Y padding.
* @type {number}
*/
this.FIELD_BORDER_RECT_Y_PADDING = 3;
/**
* Field text baseline. This is only used if `FIELD_TEXT_BASELINE_CENTER` is
* set to false.
* @type {number}
*/
this.FIELD_TEXT_BASELINE_Y = 13;
/**
* A field's text element's dominant baseline.
* @type {boolean}
*/
this.FIELD_TEXT_BASELINE_CENTER =
!Blockly.utils.userAgent.IE && !Blockly.utils.userAgent.EDGE;
/**
* A dropdown field's border rect height.
* @type {number}
*/
this.FIELD_DROPDOWN_BORDER_RECT_HEIGHT = this.FIELD_BORDER_RECT_HEIGHT;
/**
* A colour field's default width.
* @type {number}
*/
this.FIELD_COLOUR_DEFAULT_WIDTH = 26;
/**
* A colour field's default height.
* @type {number}
*/
this.FIELD_COLOUR_DEFAULT_HEIGHT = this.FIELD_BORDER_RECT_HEIGHT;
/**
* A checkbox field's X offset.
* @type {number}
*/
this.FIELD_CHECKBOX_X_OFFSET = this.FIELD_BORDER_RECT_X_PADDING - 3;
/**
* A checkbox field's Y offset.
* @type {number}
*/
this.FIELD_CHECKBOX_Y_OFFSET = 14;
/**
* The ID of the emboss filter, or the empty string if no filter is set.
* @type {string}

View File

@@ -37,6 +37,11 @@ goog.require('Blockly.utils.object');
Blockly.geras.ConstantProvider = function() {
Blockly.geras.ConstantProvider.superClass_.constructor.call(this);
/**
* @override
*/
this.FIELD_TEXT_BASELINE_CENTER = false;
// The dark/shadow path in classic rendering is the same as the normal block
// path, but translated down one and right one.
this.DARK_PATH_OFFSET = 1;

View File

@@ -127,6 +127,21 @@ Blockly.zelos.ConstantProvider = function() {
*/
this.DUMMY_INPUT_MIN_HEIGHT = 6 * this.GRID_UNIT;
/**
* @override
*/
this.FIELD_BORDER_RECT_RADIUS = this.CORNER_RADIUS;
/**
* @override
*/
this.FIELD_BORDER_RECT_X_PADDING = 2 * this.GRID_UNIT;
/**
* @override
*/
this.FIELD_DROPDOWN_BORDER_RECT_HEIGHT = 8 * this.GRID_UNIT;
/**
* The ID of the highlight glow filter, or the empty string if no filter is
* set.

View File

@@ -88,9 +88,6 @@ CustomFields.FieldTurtle.prototype.CURSOR = 'pointer';
// May change if the turtle gets fancy enough.
CustomFields.FieldTurtle.prototype.TEXT_OFFSET_X = 80;
// Padding that the border rect adds around the turtle and its name.
CustomFields.FieldTurtle.prototype.PADDING = Blockly.Field.X_PADDING;
// These are the different options for our turtle. Being declared this way
// means they are static, and not translatable. If you want to do something
// similar, but make it translatable you should set up your options like a
@@ -320,8 +317,8 @@ CustomFields.FieldTurtle.prototype.updateSize_ = function() {
var width = bbox.width;
var height = bbox.height;
if (this.borderRect_) {
width += this.PADDING;
height += this.PADDING;
width += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
height += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
this.borderRect_.setAttribute('width', width);
this.borderRect_.setAttribute('height', height);
}

View File

@@ -175,6 +175,10 @@ suite('Checkbox Fields', function() {
suite('Check Character', function() {
function assertCharacter(field, char) {
field.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null);
field.constants_ = {
FIELD_CHECKBOX_X_OFFSET: 2,
FIELD_CHECKBOX_Y_OFFSET: 2
};
field.initView();
chai.assert(field.textContent_.nodeValue, char);
}

View File

@@ -27,12 +27,18 @@ suite('Label Serializable Fields', function() {
}
function assertHasClass(labelField, cssClass) {
labelField.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null);
labelField.constants_ = {
FIELD_TEXT_BASELINE_Y: 13
};
labelField.initView();
chai.assert.isTrue(Blockly.utils.dom.hasClass(
labelField.textElement_, cssClass));
}
function assertDoesNotHaveClass(labelField, cssClass) {
labelField.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null);
labelField.constants_ = {
FIELD_TEXT_BASELINE_Y: 13
};
labelField.initView();
chai.assert.isFalse(Blockly.utils.dom.hasClass(
labelField.textElement_, cssClass));
@@ -216,6 +222,9 @@ suite('Label Serializable Fields', function() {
test('setClass', function() {
var field = new Blockly.FieldLabelSerializable();
field.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null);
field.constants_ = {
FIELD_TEXT_BASELINE_Y: 13
};
field.initView();
field.setClass('testClass');
// Don't call assertHasClass b/c we don't want to re-initialize.

View File

@@ -27,12 +27,18 @@ suite('Label Fields', function() {
}
function assertHasClass(labelField, cssClass) {
labelField.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null);
labelField.constants_ = {
FIELD_TEXT_BASELINE_Y: 13
};
labelField.initView();
chai.assert.isTrue(Blockly.utils.dom.hasClass(
labelField.textElement_, cssClass));
}
function assertDoesNotHaveClass(labelField, cssClass) {
labelField.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null);
labelField.constants_ = {
FIELD_TEXT_BASELINE_Y: 13
};
labelField.initView();
chai.assert.isFalse(Blockly.utils.dom.hasClass(
labelField.textElement_, cssClass));
@@ -205,6 +211,9 @@ suite('Label Fields', function() {
test('setClass', function() {
var field = new Blockly.FieldLabel();
field.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null);
field.constants_ = {
FIELD_TEXT_BASELINE_Y: 13
};
field.initView();
field.setClass('testClass');
// Don't call assertHasClass b/c we don't want to re-initialize.