mirror of
https://github.com/google/blockly.git
synced 2026-01-07 00:50:27 +01:00
Dynamic fonts (#3698)
* Piping themes into the renderer and ensuring fields update their size information when constants change.
This commit is contained in:
@@ -310,10 +310,6 @@ Blockly.Field.prototype.initModel = function() {
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Field.prototype.createBorderRect_ = function() {
|
||||
this.size_.height =
|
||||
Math.max(this.size_.height, this.constants_.FIELD_BORDER_RECT_HEIGHT);
|
||||
this.size_.width =
|
||||
Math.max(this.size_.width, this.constants_.FIELD_BORDER_RECT_X_PADDING * 2);
|
||||
this.borderRect_ = /** @type {!SVGRectElement} **/
|
||||
(Blockly.utils.dom.createSvgElement('rect',
|
||||
{
|
||||
@@ -334,24 +330,12 @@ Blockly.Field.prototype.createBorderRect_ = function() {
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Field.prototype.createTextElement_ = function() {
|
||||
var xOffset = this.borderRect_ ?
|
||||
this.constants_.FIELD_BORDER_RECT_X_PADDING : 0;
|
||||
var baselineCenter = this.constants_.FIELD_TEXT_BASELINE_CENTER;
|
||||
var baselineY = this.constants_.FIELD_TEXT_BASELINE_Y;
|
||||
this.size_.height = Math.max(this.size_.height, baselineCenter ?
|
||||
this.constants_.FIELD_TEXT_HEIGHT : baselineY);
|
||||
if (this.size_.height > this.constants_.FIELD_TEXT_HEIGHT) {
|
||||
baselineY += (this.size_.height - baselineY) / 2;
|
||||
}
|
||||
this.textElement_ = /** @type {!SVGTextElement} **/
|
||||
(Blockly.utils.dom.createSvgElement('text',
|
||||
{
|
||||
'class': 'blocklyText',
|
||||
'y': baselineCenter ? this.size_.height / 2 : baselineY,
|
||||
'dy': this.constants_.FIELD_TEXT_Y_OFFSET,
|
||||
'x': xOffset
|
||||
}, this.fieldGroup_));
|
||||
if (baselineCenter) {
|
||||
if (this.constants_.FIELD_TEXT_BASELINE_CENTER) {
|
||||
this.textElement_.setAttribute('dominant-baseline', 'central');
|
||||
}
|
||||
this.textContent_ = document.createTextNode('');
|
||||
@@ -587,8 +571,8 @@ Blockly.Field.prototype.applyColour = function() {
|
||||
Blockly.Field.prototype.render_ = function() {
|
||||
if (this.textContent_) {
|
||||
this.textContent_.nodeValue = this.getDisplayText_();
|
||||
this.updateSize_();
|
||||
}
|
||||
this.updateSize_();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -619,22 +603,73 @@ Blockly.Field.prototype.updateWidth = function() {
|
||||
|
||||
/**
|
||||
* Updates the size of the field based on the text.
|
||||
* @param {number=} opt_margin margin to use when positioning the text element.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Field.prototype.updateSize_ = function() {
|
||||
var textWidth = Blockly.utils.dom.getFastTextWidth(
|
||||
/** @type {!SVGTextElement} */ (this.textElement_),
|
||||
this.constants_.FIELD_TEXT_FONTSIZE,
|
||||
this.constants_.FIELD_TEXT_FONTWEIGHT,
|
||||
this.constants_.FIELD_TEXT_FONTFAMILY);
|
||||
var totalWidth = textWidth;
|
||||
if (this.borderRect_) {
|
||||
totalWidth += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
|
||||
this.borderRect_.setAttribute('width', totalWidth);
|
||||
Blockly.Field.prototype.updateSize_ = function(opt_margin) {
|
||||
var constants = this.constants_;
|
||||
var xOffset = opt_margin != undefined ? opt_margin :
|
||||
(this.borderRect_ ? this.constants_.FIELD_BORDER_RECT_X_PADDING : 0);
|
||||
var totalWidth = xOffset * 2;
|
||||
var totalHeight = constants.FIELD_TEXT_HEIGHT;
|
||||
|
||||
var contentWidth = 0;
|
||||
if (this.textElement_) {
|
||||
contentWidth = Blockly.utils.dom.getFastTextWidth(this.textElement_,
|
||||
constants.FIELD_TEXT_FONTSIZE,
|
||||
constants.FIELD_TEXT_FONTWEIGHT,
|
||||
constants.FIELD_TEXT_FONTFAMILY);
|
||||
totalWidth += contentWidth;
|
||||
}
|
||||
if (this.borderRect_) {
|
||||
totalHeight = Math.max(totalHeight, constants.FIELD_BORDER_RECT_HEIGHT);
|
||||
}
|
||||
|
||||
this.size_.height = totalHeight;
|
||||
this.size_.width = totalWidth;
|
||||
|
||||
this.positionTextElement_(xOffset, contentWidth);
|
||||
this.positionBorderRect_();
|
||||
};
|
||||
|
||||
/**
|
||||
* Position a field's text element after a size change. This handles both LTR
|
||||
* and RTL positioning.
|
||||
* @param {number} xOffset x offset to use when positioning the text element.
|
||||
* @param {number} contentWidth The content width.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Field.prototype.positionTextElement_ = function(xOffset, contentWidth) {
|
||||
if (!this.textElement_) {
|
||||
return;
|
||||
}
|
||||
var constants = this.constants_;
|
||||
var halfHeight = this.size_.height / 2;
|
||||
|
||||
this.textElement_.setAttribute('x', this.sourceBlock_.RTL ?
|
||||
this.size_.width - contentWidth - xOffset : xOffset);
|
||||
this.textElement_.setAttribute('y', constants.FIELD_TEXT_BASELINE_CENTER ?
|
||||
halfHeight : halfHeight - constants.FIELD_TEXT_HEIGHT / 2 +
|
||||
constants.FIELD_TEXT_BASELINE);
|
||||
};
|
||||
|
||||
/**
|
||||
* Position a field's border rect after a size change.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Field.prototype.positionBorderRect_ = function() {
|
||||
if (!this.borderRect_) {
|
||||
return;
|
||||
}
|
||||
this.borderRect_.setAttribute('width', this.size_.width);
|
||||
this.borderRect_.setAttribute('height', this.size_.height);
|
||||
this.borderRect_.setAttribute('rx',
|
||||
this.constants_.FIELD_BORDER_RECT_RADIUS);
|
||||
this.borderRect_.setAttribute('ry',
|
||||
this.constants_.FIELD_BORDER_RECT_RADIUS);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the height and width of the field.
|
||||
*
|
||||
|
||||
@@ -82,15 +82,6 @@ Blockly.FieldCheckbox.prototype.SERIALIZABLE = true;
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.CURSOR = 'default';
|
||||
|
||||
/**
|
||||
* Used to tell if the field needs to be rendered the next time the block is
|
||||
* rendered. Checkbox fields are statically sized, and only need to be
|
||||
* rendered at initialization.
|
||||
* @type {boolean}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.isDirty_ = false;
|
||||
|
||||
/**
|
||||
* Configure the field based on the given map of options.
|
||||
* @param {!Object} config A map of options to configure the field based on.
|
||||
@@ -108,19 +99,30 @@ Blockly.FieldCheckbox.prototype.configure_ = function(config) {
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.initView = function() {
|
||||
this.size_.width = this.constants_.FIELD_CHECKBOX_DEFAULT_WIDTH;
|
||||
Blockly.FieldCheckbox.superClass_.initView.call(this);
|
||||
|
||||
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 =
|
||||
this.checkChar_ || Blockly.FieldCheckbox.CHECK_CHAR;
|
||||
Blockly.utils.dom.addClass(
|
||||
/** @type {!SVGTextElement} **/ (this.textElement_), 'blocklyCheckbox');
|
||||
this.textElement_.style.display = this.value_ ? 'block' : 'none';
|
||||
};
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.render_ = function() {
|
||||
if (this.textContent_) {
|
||||
this.textContent_.nodeValue = this.getDisplayText_();
|
||||
}
|
||||
this.updateSize_(this.constants_.FIELD_CHECKBOX_X_OFFSET);
|
||||
};
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.getDisplayText_ = function() {
|
||||
return this.checkChar_ || Blockly.FieldCheckbox.CHECK_CHAR;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the character used for the check mark.
|
||||
* @param {?string} character The character to use for the check mark, or
|
||||
|
||||
@@ -564,10 +564,8 @@ Blockly.FieldDropdown.prototype.render_ = function() {
|
||||
} else {
|
||||
this.renderSelectedText_();
|
||||
}
|
||||
if (this.borderRect_) {
|
||||
this.borderRect_.setAttribute('height', this.size_.height);
|
||||
this.borderRect_.setAttribute('width', this.size_.width);
|
||||
}
|
||||
|
||||
this.positionBorderRect_();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -588,14 +586,13 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) {
|
||||
|
||||
// Height and width include the border rect.
|
||||
var hasBorder = !!this.borderRect_;
|
||||
this.size_.height = Math.max(
|
||||
var height = Math.max(
|
||||
hasBorder ? this.constants_.FIELD_DROPDOWN_BORDER_RECT_HEIGHT : 0,
|
||||
imageHeight + Blockly.FieldDropdown.IMAGE_Y_PADDING);
|
||||
var halfHeight = this.size_.height / 2;
|
||||
var xPadding = hasBorder ? this.constants_.FIELD_BORDER_RECT_X_PADDING : 0;
|
||||
var arrowWidth = 0;
|
||||
if (this.svgArrow_) {
|
||||
arrowWidth = this.positionSVGArrow_(imageWidth + xPadding, halfHeight -
|
||||
arrowWidth = this.positionSVGArrow_(imageWidth + xPadding, height / 2 -
|
||||
this.constants_.FIELD_DROPDOWN_SVG_ARROW_SIZE / 2);
|
||||
} else {
|
||||
arrowWidth = Blockly.utils.dom.getFastTextWidth(
|
||||
@@ -605,19 +602,20 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) {
|
||||
this.constants_.FIELD_TEXT_FONTFAMILY);
|
||||
}
|
||||
this.size_.width = imageWidth + arrowWidth + xPadding * 2;
|
||||
this.size_.height = height;
|
||||
|
||||
var arrowX = 0;
|
||||
if (this.sourceBlock_.RTL) {
|
||||
var imageX = xPadding + arrowWidth;
|
||||
var arrowX = xPadding - 1;
|
||||
this.imageElement_.setAttribute('x', imageX);
|
||||
this.textElement_.setAttribute('x', arrowX);
|
||||
} else {
|
||||
var arrowX = imageWidth + arrowWidth + xPadding + 1;
|
||||
arrowX = imageWidth + arrowWidth;
|
||||
this.textElement_.setAttribute('text-anchor', 'end');
|
||||
this.textElement_.setAttribute('x', arrowX);
|
||||
this.imageElement_.setAttribute('x', xPadding);
|
||||
}
|
||||
this.imageElement_.setAttribute('y', halfHeight - imageHeight / 2);
|
||||
this.imageElement_.setAttribute('y', height / 2 - imageHeight / 2);
|
||||
|
||||
this.positionTextElement_(arrowX + xPadding, imageWidth + arrowWidth);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -633,10 +631,9 @@ Blockly.FieldDropdown.prototype.renderSelectedText_ = function() {
|
||||
|
||||
// Height and width include the border rect.
|
||||
var hasBorder = !!this.borderRect_;
|
||||
this.size_.height = Math.max(
|
||||
var height = Math.max(
|
||||
hasBorder ? this.constants_.FIELD_DROPDOWN_BORDER_RECT_HEIGHT : 0,
|
||||
this.constants_.FIELD_TEXT_HEIGHT);
|
||||
var halfHeight = this.size_.height / 2;
|
||||
var textWidth = Blockly.utils.dom.getFastTextWidth(this.textElement_,
|
||||
this.constants_.FIELD_TEXT_FONTSIZE,
|
||||
this.constants_.FIELD_TEXT_FONTWEIGHT,
|
||||
@@ -644,20 +641,13 @@ Blockly.FieldDropdown.prototype.renderSelectedText_ = function() {
|
||||
var xPadding = hasBorder ? this.constants_.FIELD_BORDER_RECT_X_PADDING : 0;
|
||||
var arrowWidth = 0;
|
||||
if (this.svgArrow_) {
|
||||
arrowWidth = this.positionSVGArrow_(textWidth + xPadding, halfHeight -
|
||||
arrowWidth = this.positionSVGArrow_(textWidth + xPadding, height / 2 -
|
||||
this.constants_.FIELD_DROPDOWN_SVG_ARROW_SIZE / 2);
|
||||
}
|
||||
this.size_.width = textWidth + arrowWidth + xPadding * 2;
|
||||
this.size_.height = height;
|
||||
|
||||
this.textElement_.setAttribute('x', this.sourceBlock_.RTL ?
|
||||
this.size_.width - textWidth - xPadding : xPadding);
|
||||
this.textElement_.setAttribute('y', halfHeight);
|
||||
if (!this.constants_.FIELD_TEXT_BASELINE_CENTER) {
|
||||
this.textElement_.setAttribute('dy',
|
||||
this.constants_.FIELD_TEXT_BASELINE_Y -
|
||||
this.constants_.FIELD_TEXT_HEIGHT / 2 +
|
||||
this.constants_.FIELD_TEXT_Y_OFFSET);
|
||||
}
|
||||
this.positionTextElement_(xPadding, textWidth);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -186,6 +186,13 @@ Blockly.FieldImage.prototype.initView = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldImage.prototype.updateSize_ = function() {
|
||||
// NOP
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensure that the input value (the source URL) is a string.
|
||||
* @param {*=} opt_newValue The input value.
|
||||
|
||||
@@ -60,13 +60,6 @@ Blockly.utils.object.inherits(Blockly.FieldMultilineInput,
|
||||
Blockly.FieldTextInput);
|
||||
|
||||
|
||||
/**
|
||||
* The default height of a single line of text.
|
||||
* @type {number}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldMultilineInput.LINE_HEIGHT = 20;
|
||||
|
||||
/**
|
||||
* Construct a FieldMultilineInput from a JSON arg object,
|
||||
* dereferencing any string table references.
|
||||
@@ -143,14 +136,16 @@ Blockly.FieldMultilineInput.prototype.render_ = function() {
|
||||
var lines = this.getDisplayText_().split('\n');
|
||||
var y = 0;
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var lineHeight = this.constants_.FIELD_TEXT_HEIGHT +
|
||||
this.constants_.FIELD_BORDER_RECT_Y_PADDING;
|
||||
var span = Blockly.utils.dom.createSvgElement('text', {
|
||||
'class': 'blocklyText blocklyMultilineText',
|
||||
x: this.constants_.FIELD_BORDER_RECT_X_PADDING,
|
||||
y: y + this.constants_.FIELD_BORDER_RECT_Y_PADDING,
|
||||
dy: Blockly.FieldMultilineInput.LINE_HEIGHT / 2
|
||||
dy: this.constants_.FIELD_TEXT_BASELINE
|
||||
}, this.textGroup_);
|
||||
span.appendChild(document.createTextNode(lines[i]));
|
||||
y += Blockly.FieldMultilineInput.LINE_HEIGHT;
|
||||
y += lineHeight;
|
||||
}
|
||||
|
||||
this.updateSize_();
|
||||
@@ -191,34 +186,19 @@ Blockly.FieldMultilineInput.prototype.updateSize_ = function() {
|
||||
if (textWidth > totalWidth) {
|
||||
totalWidth = textWidth;
|
||||
}
|
||||
totalHeight += Blockly.FieldMultilineInput.LINE_HEIGHT;
|
||||
totalHeight += this.constants_.FIELD_TEXT_HEIGHT +
|
||||
(i > 0 ? this.constants_.FIELD_BORDER_RECT_Y_PADDING : 0);
|
||||
}
|
||||
if (this.borderRect_) {
|
||||
totalHeight += this.constants_.FIELD_BORDER_RECT_Y_PADDING * 2;
|
||||
totalWidth += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
|
||||
this.borderRect_.setAttribute('width', totalWidth);
|
||||
this.borderRect_.setAttribute('height', totalHeight);
|
||||
}
|
||||
this.size_.width = totalWidth;
|
||||
this.size_.height = totalHeight;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resize the editor to fit the text.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.resizeEditor_ = function() {
|
||||
var div = Blockly.WidgetDiv.DIV;
|
||||
var bBox = this.getScaledBBox();
|
||||
div.style.width = bBox.right - bBox.left + 'px';
|
||||
div.style.height = bBox.bottom - bBox.top + 'px';
|
||||
|
||||
// In RTL mode block fields and LTR input fields the left edge moves,
|
||||
// whereas the right edge is fixed. Reposition the editor.
|
||||
var x = this.sourceBlock_.RTL ? bBox.right - div.offsetWidth : bBox.left;
|
||||
var xy = new Blockly.utils.Coordinate(x, bBox.top);
|
||||
|
||||
div.style.left = xy.x + 'px';
|
||||
div.style.top = xy.y + 'px';
|
||||
this.positionBorderRect_();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -230,7 +210,8 @@ Blockly.FieldMultilineInput.prototype.widgetCreate_ = function() {
|
||||
var div = Blockly.WidgetDiv.DIV;
|
||||
var scale = this.workspace_.scale;
|
||||
|
||||
var htmlInput = /** @type {HTMLTextAreaElement} */ (document.createElement('textarea'));
|
||||
var htmlInput =
|
||||
/** @type {HTMLTextAreaElement} */ (document.createElement('textarea'));
|
||||
htmlInput.className = 'blocklyHtmlInput blocklyHtmlTextAreaInput';
|
||||
htmlInput.setAttribute('spellcheck', this.spellcheck_);
|
||||
var fontSize = (this.constants_.FIELD_TEXT_FONTSIZE * scale) + 'pt';
|
||||
@@ -238,11 +219,13 @@ Blockly.FieldMultilineInput.prototype.widgetCreate_ = function() {
|
||||
htmlInput.style.fontSize = fontSize;
|
||||
var borderRadius = (Blockly.FieldTextInput.BORDERRADIUS * scale) + 'px';
|
||||
htmlInput.style.borderRadius = borderRadius;
|
||||
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 =
|
||||
(Blockly.FieldMultilineInput.LINE_HEIGHT * scale) + 'px';
|
||||
var paddingX = this.constants_.FIELD_BORDER_RECT_X_PADDING * scale;
|
||||
var paddingY = this.constants_.FIELD_BORDER_RECT_Y_PADDING * scale / 2;
|
||||
htmlInput.style.padding = paddingY + 'px ' + paddingX + 'px ' + paddingY +
|
||||
'px ' + paddingX + 'px';
|
||||
var lineHeight = this.constants_.FIELD_TEXT_HEIGHT +
|
||||
this.constants_.FIELD_BORDER_RECT_Y_PADDING;
|
||||
htmlInput.style.lineHeight = (lineHeight * scale) + 'px';
|
||||
|
||||
div.appendChild(htmlInput);
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ Blockly.Flyout = function(workspaceOptions) {
|
||||
*/
|
||||
this.workspace_ = new Blockly.WorkspaceSvg(workspaceOptions);
|
||||
this.workspace_.isFlyout = true;
|
||||
// Keep the workspace visibility consistent with the flyout's visibility.
|
||||
this.workspace_.setVisible(this.isVisible_);
|
||||
|
||||
/**
|
||||
* Is RTL vs LTR.
|
||||
|
||||
@@ -86,9 +86,14 @@ Blockly.FlyoutButton = function(workspace, targetWorkspace, xml, isLabel) {
|
||||
};
|
||||
|
||||
/**
|
||||
* The margin around the text in the button.
|
||||
* The horizontal margin around the text in the button.
|
||||
*/
|
||||
Blockly.FlyoutButton.MARGIN = 5;
|
||||
Blockly.FlyoutButton.MARGIN_X = 5;
|
||||
|
||||
/**
|
||||
* The vertical margin around the text in the button.
|
||||
*/
|
||||
Blockly.FlyoutButton.MARGIN_Y = 2;
|
||||
|
||||
/**
|
||||
* The width of the button's rect.
|
||||
@@ -153,11 +158,18 @@ Blockly.FlyoutButton.prototype.createDom = function() {
|
||||
'flyoutForegroundColour', 'fill');
|
||||
}
|
||||
|
||||
this.width = Blockly.utils.dom.getTextWidth(svgText);
|
||||
this.height = 20; // Can't compute it :(
|
||||
|
||||
var fontSize = Blockly.utils.style.getComputedStyle(svgText, 'fontSize');
|
||||
var fontWeight = Blockly.utils.style.getComputedStyle(svgText, 'fontWeight');
|
||||
var fontFamily = Blockly.utils.style.getComputedStyle(svgText, 'fontFamily');
|
||||
this.width = Blockly.utils.dom.getFastTextWidthWithSizeString(svgText,
|
||||
fontSize, fontWeight, fontFamily);
|
||||
var fontMetrics = Blockly.utils.dom.measureFontMetrics(text, fontSize,
|
||||
fontWeight, fontFamily);
|
||||
this.height = fontMetrics.height;
|
||||
|
||||
if (!this.isLabel_) {
|
||||
this.width += 2 * Blockly.FlyoutButton.MARGIN;
|
||||
this.width += 2 * Blockly.FlyoutButton.MARGIN_X;
|
||||
this.height += 2 * Blockly.FlyoutButton.MARGIN_Y;
|
||||
shadow.setAttribute('width', this.width);
|
||||
shadow.setAttribute('height', this.height);
|
||||
}
|
||||
@@ -165,7 +177,8 @@ Blockly.FlyoutButton.prototype.createDom = function() {
|
||||
rect.setAttribute('height', this.height);
|
||||
|
||||
svgText.setAttribute('x', this.width / 2);
|
||||
svgText.setAttribute('y', this.height - Blockly.FlyoutButton.MARGIN);
|
||||
svgText.setAttribute('y', this.height / 2 - fontMetrics.height / 2 +
|
||||
fontMetrics.baseline);
|
||||
|
||||
this.updateTransform_();
|
||||
|
||||
|
||||
@@ -79,16 +79,17 @@ Blockly.blockRendering.stopDebugger = function() {
|
||||
/**
|
||||
* Initialize anything needed for rendering (constants, etc).
|
||||
* @param {!string} name Name of the renderer to initialize.
|
||||
* @param {!Blockly.Theme} theme The workspace theme object.
|
||||
* @return {!Blockly.blockRendering.Renderer} The new instance of a renderer.
|
||||
* Already initialized.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.init = function(name) {
|
||||
Blockly.blockRendering.init = function(name, theme) {
|
||||
if (!Blockly.blockRendering.rendererMap_[name]) {
|
||||
throw Error('Renderer not registered: ', name);
|
||||
}
|
||||
var renderer = (/** @type {!Blockly.blockRendering.Renderer} */ (
|
||||
new Blockly.blockRendering.rendererMap_[name](name)));
|
||||
renderer.init();
|
||||
renderer.init(theme);
|
||||
return renderer;
|
||||
};
|
||||
|
||||
@@ -26,6 +26,20 @@ goog.require('Blockly.utils.userAgent');
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider = function() {
|
||||
|
||||
/**
|
||||
* A placeholder value for number constants that are dynamically set.
|
||||
* @type {number}
|
||||
* @protected
|
||||
*/
|
||||
this.DYNAMICALLY_SET_ = -1;
|
||||
|
||||
/**
|
||||
* A placeholder value for string constants that are dynamically set.
|
||||
* @type {string}
|
||||
* @protected
|
||||
*/
|
||||
this.DYNAMICALLY_SET_STRING_ = '';
|
||||
|
||||
/**
|
||||
* The size of an empty spacer.
|
||||
* @type {number}
|
||||
@@ -231,28 +245,39 @@ Blockly.blockRendering.ConstantProvider = function() {
|
||||
this.JAGGED_TEETH_WIDTH = 6;
|
||||
|
||||
/**
|
||||
* Point size of text.
|
||||
* Point size of text. This constant is dynamically set in
|
||||
* ``setFontConstants_`` to the size of the font used by the renderer/theme.
|
||||
* @type {number}
|
||||
*/
|
||||
this.FIELD_TEXT_FONTSIZE = 11;
|
||||
this.FIELD_TEXT_FONTSIZE = this.DYNAMICALLY_SET_;
|
||||
|
||||
/**
|
||||
* Height of text.
|
||||
* Height of text. This constant is dynamically set in ``setFontConstants_``
|
||||
* to be the height of the text based on the font used.
|
||||
* @type {number}
|
||||
*/
|
||||
this.FIELD_TEXT_HEIGHT = 16;
|
||||
this.FIELD_TEXT_HEIGHT = this.DYNAMICALLY_SET_;
|
||||
|
||||
/**
|
||||
* Text font weight.
|
||||
* @type {string}
|
||||
* Text baseline. This constant is dynamically set in ``setFontConstants_``
|
||||
* to be the baseline of the text based on the font used.
|
||||
* @type {number}
|
||||
*/
|
||||
this.FIELD_TEXT_FONTWEIGHT = 'normal';
|
||||
this.FIELD_TEXT_BASELINE = this.DYNAMICALLY_SET_;
|
||||
|
||||
/**
|
||||
* Text font family.
|
||||
* Text font weight. This constant is dynamically set in
|
||||
* ``setFontConstants_`` to the weight of the font used by the renderer/theme.
|
||||
* @type {string}
|
||||
*/
|
||||
this.FIELD_TEXT_FONTFAMILY = 'sans-serif';
|
||||
this.FIELD_TEXT_FONTWEIGHT = this.DYNAMICALLY_SET_STRING_;
|
||||
|
||||
/**
|
||||
* Text font family. This constant is dynamically set in
|
||||
* ``setFontConstants_`` to the family of the font used by the renderer/theme.
|
||||
* @type {string}
|
||||
*/
|
||||
this.FIELD_TEXT_FONTFAMILY = this.DYNAMICALLY_SET_STRING_;
|
||||
|
||||
/**
|
||||
* A field's border rect corner radius.
|
||||
@@ -285,19 +310,6 @@ Blockly.blockRendering.ConstantProvider = function() {
|
||||
*/
|
||||
this.FIELD_BORDER_RECT_COLOUR = '#fff';
|
||||
|
||||
/**
|
||||
* Field text baseline.
|
||||
* This is only used if `FIELD_TEXT_BASELINE_CENTER` is false.
|
||||
* @type {number}
|
||||
*/
|
||||
this.FIELD_TEXT_BASELINE_Y = Blockly.utils.userAgent.GECKO ? 12 : 13.09;
|
||||
|
||||
/**
|
||||
* An text offset adjusting the Y position of text after positioning.
|
||||
* @type {number}
|
||||
*/
|
||||
this.FIELD_TEXT_Y_OFFSET = 0;
|
||||
|
||||
/**
|
||||
* A field's text element's dominant baseline.
|
||||
* @type {boolean}
|
||||
@@ -392,18 +404,6 @@ Blockly.blockRendering.ConstantProvider = function() {
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* A checkbox field's default width.
|
||||
* @type {number}
|
||||
*/
|
||||
this.FIELD_CHECKBOX_DEFAULT_WIDTH = 15;
|
||||
|
||||
/**
|
||||
* A random identifier used to ensure a unique ID is used for each
|
||||
* filter/pattern for the case of multiple Blockly instances on a page.
|
||||
@@ -440,6 +440,13 @@ Blockly.blockRendering.ConstantProvider = function() {
|
||||
*/
|
||||
this.disabledPattern_ = null;
|
||||
|
||||
/**
|
||||
* The <style> element to use for injecting renderer specific CSS.
|
||||
* @type {HTMLStyleElement}
|
||||
* @private
|
||||
*/
|
||||
this.cssNode_ = null;
|
||||
|
||||
/**
|
||||
* Cursor colour.
|
||||
* @type {string}
|
||||
@@ -555,7 +562,7 @@ Blockly.blockRendering.ConstantProvider.prototype.init = function() {
|
||||
* @param {!Blockly.Theme} theme The current workspace theme.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.refreshTheme = function(
|
||||
Blockly.blockRendering.ConstantProvider.prototype.setTheme = function(
|
||||
theme) {
|
||||
|
||||
/**
|
||||
@@ -569,6 +576,62 @@ Blockly.blockRendering.ConstantProvider.prototype.refreshTheme = function(
|
||||
for (var key in blockStyles) {
|
||||
this.blockStyles[key] = this.validatedBlockStyle_(blockStyles[key]);
|
||||
}
|
||||
|
||||
this.setDynamicProperties_(theme);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets dynamic properties that depent on other values or theme properties.
|
||||
* @param {!Blockly.Theme} theme The current workspace theme.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.setDynamicProperties_ =
|
||||
function(theme) {
|
||||
/* eslint-disable indent */
|
||||
this.setFontConstants_(theme);
|
||||
}; /* eslint-enable indent */
|
||||
|
||||
/**
|
||||
* Get an object representing the default font styles specified by the renderer.
|
||||
* @return {!Blockly.Theme.FontStyle} A theme font style.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.getDefaultFontStyle_ =
|
||||
function() {
|
||||
/* eslint-disable indent */
|
||||
return {
|
||||
'weight': 'normal',
|
||||
'size': 11,
|
||||
'family': 'sans-serif'
|
||||
};
|
||||
}; /* eslint-enable indent */
|
||||
|
||||
/**
|
||||
* Set constants related to fonts.
|
||||
* @param {!Blockly.Theme} theme The current workspace theme.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.setFontConstants_ = function(
|
||||
theme) {
|
||||
var defaultFontStyle = this.getDefaultFontStyle_();
|
||||
|
||||
this.FIELD_TEXT_FONTFAMILY =
|
||||
theme.fontStyle && theme.fontStyle['family'] != undefined ?
|
||||
theme.fontStyle['family'] : defaultFontStyle['family'];
|
||||
this.FIELD_TEXT_FONTWEIGHT =
|
||||
theme.fontStyle && theme.fontStyle['weight'] != undefined ?
|
||||
theme.fontStyle['weight'] : defaultFontStyle['weight'];
|
||||
this.FIELD_TEXT_FONTSIZE =
|
||||
theme.fontStyle && theme.fontStyle['size'] != undefined ?
|
||||
theme.fontStyle['size'] : defaultFontStyle['size'];
|
||||
|
||||
var fontMetrics = Blockly.utils.dom.measureFontMetrics('Hg',
|
||||
this.FIELD_TEXT_FONTSIZE + 'pt',
|
||||
this.FIELD_TEXT_FONTWEIGHT,
|
||||
this.FIELD_TEXT_FONTFAMILY);
|
||||
|
||||
this.FIELD_TEXT_HEIGHT = fontMetrics.height;
|
||||
this.FIELD_TEXT_BASELINE = fontMetrics.baseline;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -598,7 +661,9 @@ Blockly.blockRendering.ConstantProvider.prototype.getBlockStyleForColour =
|
||||
Blockly.blockRendering.ConstantProvider.prototype.getBlockStyle = function(
|
||||
blockStyleName) {
|
||||
return this.blockStyles[blockStyleName || ''] ||
|
||||
this.createBlockStyle_('#000000');
|
||||
(blockStyleName && blockStyleName.indexOf('auto_') == 0 ?
|
||||
this.getBlockStyleForColour(blockStyleName.substring(5)).style :
|
||||
this.createBlockStyle_('#000000'));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -689,6 +754,9 @@ Blockly.blockRendering.ConstantProvider.prototype.dispose = function() {
|
||||
if (this.disabledPattern_) {
|
||||
Blockly.utils.dom.removeNode(this.disabledPattern_);
|
||||
}
|
||||
if (this.cssNode_) {
|
||||
Blockly.utils.dom.removeNode(this.cssNode_);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -915,9 +983,12 @@ Blockly.blockRendering.ConstantProvider.prototype.shapeFor = function(
|
||||
/**
|
||||
* Create any DOM elements that this renderer needs (filters, patterns, etc).
|
||||
* @param {!SVGElement} svg The root of the workspace's SVG.
|
||||
* @param {string} rendererName Name of the renderer.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg) {
|
||||
Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg,
|
||||
rendererName) {
|
||||
this.injectCSS_(rendererName);
|
||||
/*
|
||||
<defs>
|
||||
... filters go here ...
|
||||
@@ -999,9 +1070,9 @@ Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg) {
|
||||
/**
|
||||
* Inject renderer specific CSS into the page.
|
||||
* @param {string} name Name of the renderer.
|
||||
* @package
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.injectCSS = function(
|
||||
Blockly.blockRendering.ConstantProvider.prototype.injectCSS_ = function(
|
||||
name) {
|
||||
var cssArray = this.getCSS_(name);
|
||||
var cssNodeId = 'blockly-renderer-style-' + name;
|
||||
@@ -1011,11 +1082,13 @@ Blockly.blockRendering.ConstantProvider.prototype.injectCSS = function(
|
||||
}
|
||||
var text = cssArray.join('\n');
|
||||
// Inject CSS tag at start of head.
|
||||
var cssNode = document.createElement('style');
|
||||
var cssNode =
|
||||
/** @type {!HTMLStyleElement} */ (document.createElement('style'));
|
||||
cssNode.id = cssNodeId;
|
||||
var cssTextNode = document.createTextNode(text);
|
||||
cssNode.appendChild(cssTextNode);
|
||||
document.head.insertBefore(cssNode, document.head.firstChild);
|
||||
this.cssNode_ = cssNode;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,10 +24,12 @@ goog.require('Blockly.blockRendering.Types');
|
||||
|
||||
/**
|
||||
* An object that renders rectangles and dots for debugging rendering code.
|
||||
* @param {!Blockly.blockRendering.ConstantProvider} constants The renderer's
|
||||
* constants.
|
||||
* @package
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.blockRendering.Debug = function() {
|
||||
Blockly.blockRendering.Debug = function(constants) {
|
||||
/**
|
||||
* An array of SVG elements that have been created by this object.
|
||||
* @type {Array.<!SVGElement>}
|
||||
@@ -42,6 +44,13 @@ Blockly.blockRendering.Debug = function() {
|
||||
* @private
|
||||
*/
|
||||
this.svgRoot_ = null;
|
||||
|
||||
/**
|
||||
* The renderer's constant provider.
|
||||
* @type {!Blockly.blockRendering.ConstantProvider}
|
||||
* @private
|
||||
*/
|
||||
this.constants_ = constants;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -163,6 +172,23 @@ Blockly.blockRendering.Debug.prototype.drawRenderedElem = function(elem, isRtl)
|
||||
'stroke-width': '1px'
|
||||
},
|
||||
this.svgRoot_));
|
||||
|
||||
if (Blockly.blockRendering.Types.isField(elem) &&
|
||||
elem.field instanceof Blockly.FieldLabel) {
|
||||
var baseline = this.constants_.FIELD_TEXT_BASELINE;
|
||||
this.debugElements_.push(Blockly.utils.dom.createSvgElement('rect',
|
||||
{
|
||||
'class': 'rowRenderingRect blockRenderDebug',
|
||||
'x': xPos,
|
||||
'y': yPos + baseline,
|
||||
'width': elem.width,
|
||||
'height': '0.1px',
|
||||
'stroke': 'red',
|
||||
'fill': 'none',
|
||||
'stroke-width': '0.5px'
|
||||
},
|
||||
this.svgRoot_));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -48,13 +48,29 @@ Blockly.blockRendering.Renderer = function(name) {
|
||||
|
||||
/**
|
||||
* Initialize the renderer.
|
||||
* @param {!Blockly.Theme} theme The workspace theme object.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.Renderer.prototype.init = function() {
|
||||
Blockly.blockRendering.Renderer.prototype.init = function(theme) {
|
||||
this.constants_ = this.makeConstants_();
|
||||
this.constants_.setTheme(theme);
|
||||
this.constants_.init();
|
||||
};
|
||||
|
||||
/**
|
||||
* Refresh the renderer after a theme change.
|
||||
* @param {!SVGElement} svg The root of the workspace's SVG.
|
||||
* @param {!Blockly.Theme} theme The workspace theme object.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.Renderer.prototype.refresh = function(svg, theme) {
|
||||
var constants = this.getConstants();
|
||||
constants.dispose();
|
||||
constants.setTheme(theme);
|
||||
constants.init();
|
||||
constants.createDom(svg, this.name);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new instance of the renderer's constant provider.
|
||||
* @return {!Blockly.blockRendering.ConstantProvider} The constant provider.
|
||||
@@ -96,7 +112,7 @@ Blockly.blockRendering.Renderer.prototype.makeDebugger_ = function() {
|
||||
if (!Blockly.blockRendering.Debug) {
|
||||
throw Error('Missing require for Blockly.blockRendering.Debug');
|
||||
}
|
||||
return new Blockly.blockRendering.Debug();
|
||||
return new Blockly.blockRendering.Debug(this.getConstants());
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -46,6 +46,14 @@ Blockly.geras.HighlightConstantProvider = function(constants) {
|
||||
*/
|
||||
this.START_POINT = Blockly.utils.svgPaths.moveBy(this.OFFSET, this.OFFSET);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize shape objects based on the constants set in the constructor.
|
||||
* @package
|
||||
*/
|
||||
Blockly.geras.HighlightConstantProvider.prototype.init = function() {
|
||||
|
||||
/**
|
||||
* An object containing sizing and path information about inside corner
|
||||
* highlights.
|
||||
|
||||
@@ -48,9 +48,18 @@ Blockly.utils.object.inherits(Blockly.geras.Renderer,
|
||||
* @package
|
||||
* @override
|
||||
*/
|
||||
Blockly.geras.Renderer.prototype.init = function() {
|
||||
Blockly.geras.Renderer.superClass_.init.call(this);
|
||||
Blockly.geras.Renderer.prototype.init = function(theme) {
|
||||
Blockly.geras.Renderer.superClass_.init.call(this, theme);
|
||||
this.highlightConstants_ = this.makeHighlightConstants_();
|
||||
this.highlightConstants_.init();
|
||||
};
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.geras.Renderer.prototype.refresh = function(svg, theme) {
|
||||
Blockly.geras.Renderer.superClass_.refresh.call(this, svg, theme);
|
||||
this.getHighlightConstants().init();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -234,34 +234,6 @@ Blockly.zelos.ConstantProvider = function() {
|
||||
*/
|
||||
this.FULL_BLOCK_FIELDS = true;
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_TEXT_FONTSIZE = 3 * this.GRID_UNIT;
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_TEXT_FONTWEIGHT = 'bold';
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_TEXT_FONTFAMILY =
|
||||
'"Helvetica Neue", "Segoe UI", Helvetica, sans-serif';
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_TEXT_HEIGHT = 13.1;
|
||||
|
||||
/**
|
||||
* Used by positioning text on IE and Edge as they don't support
|
||||
* dominant-baseline:center.
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_TEXT_BASELINE_Y = 13.1;
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
@@ -275,7 +247,7 @@ Blockly.zelos.ConstantProvider = function() {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_BORDER_RECT_Y_PADDING = 1 * this.GRID_UNIT;
|
||||
this.FIELD_BORDER_RECT_Y_PADDING = 1.625 * this.GRID_UNIT;
|
||||
|
||||
/**
|
||||
* @override
|
||||
@@ -312,11 +284,6 @@ Blockly.zelos.ConstantProvider = function() {
|
||||
*/
|
||||
this.FIELD_TEXTINPUT_BOX_SHADOW = true;
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_TEXT_Y_OFFSET = Blockly.utils.userAgent.CHROME ? -.45 : 0;
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
@@ -335,18 +302,7 @@ Blockly.zelos.ConstantProvider = function() {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_CHECKBOX_X_OFFSET = this.FIELD_BORDER_RECT_X_PADDING - 3;
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_CHECKBOX_Y_OFFSET = 22;
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_CHECKBOX_DEFAULT_WIDTH = 6 * this.GRID_UNIT;
|
||||
|
||||
this.FIELD_CHECKBOX_X_OFFSET = 1 * this.GRID_UNIT;
|
||||
|
||||
/**
|
||||
* The maximum width of a dynamic connection shape.
|
||||
@@ -387,6 +343,30 @@ Blockly.zelos.ConstantProvider = function() {
|
||||
Blockly.utils.object.inherits(Blockly.zelos.ConstantProvider,
|
||||
Blockly.blockRendering.ConstantProvider);
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.zelos.ConstantProvider.prototype.getDefaultFontStyle_ = function() {
|
||||
var fontStyle =
|
||||
Blockly.zelos.ConstantProvider.superClass_.getDefaultFontStyle_.call(this);
|
||||
fontStyle['weight'] = 'bold';
|
||||
fontStyle['size'] = 3 * this.GRID_UNIT;
|
||||
fontStyle['family'] = '"Helvetica Neue", "Segoe UI", Helvetica, sans-serif';
|
||||
return fontStyle;
|
||||
};
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.zelos.ConstantProvider.prototype.setFontConstants_ = function(theme) {
|
||||
Blockly.zelos.ConstantProvider.superClass_.setFontConstants_.call(this,
|
||||
theme);
|
||||
|
||||
this.FIELD_BORDER_RECT_HEIGHT = this.FIELD_TEXT_HEIGHT +
|
||||
this.FIELD_BORDER_RECT_Y_PADDING * 2;
|
||||
this.FIELD_DROPDOWN_BORDER_RECT_HEIGHT = this.FIELD_BORDER_RECT_HEIGHT;
|
||||
};
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
@@ -396,7 +376,8 @@ Blockly.zelos.ConstantProvider.prototype.init = function() {
|
||||
this.ROUNDED = this.makeRounded();
|
||||
this.SQUARED = this.makeSquared();
|
||||
|
||||
this.STATEMENT_INPUT_NOTCH_OFFSET += this.INSIDE_CORNERS.rightWidth;
|
||||
this.STATEMENT_INPUT_NOTCH_OFFSET = this.NOTCH_OFFSET_LEFT +
|
||||
this.INSIDE_CORNERS.rightWidth;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -759,8 +740,10 @@ Blockly.zelos.ConstantProvider.prototype.generateTertiaryColour_ = function(
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.zelos.ConstantProvider.prototype.createDom = function(svg) {
|
||||
Blockly.zelos.ConstantProvider.superClass_.createDom.call(this, svg);
|
||||
Blockly.zelos.ConstantProvider.prototype.createDom = function(svg,
|
||||
rendererName) {
|
||||
Blockly.zelos.ConstantProvider.superClass_.createDom.call(this, svg,
|
||||
rendererName);
|
||||
/*
|
||||
<defs>
|
||||
... filters go here ...
|
||||
|
||||
@@ -57,27 +57,43 @@ Blockly.Theme = function(name, blockStyles, categoryStyles,
|
||||
* @private
|
||||
*/
|
||||
this.componentStyles_ = opt_componentStyles || Object.create(null);
|
||||
|
||||
/**
|
||||
* The font style.
|
||||
* @type {?Blockly.Theme.FontStyle}
|
||||
*/
|
||||
this.fontStyle = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* A block style.
|
||||
* @typedef {{
|
||||
* colourPrimary:string,
|
||||
* colourSecondary:string,
|
||||
* colourTertiary:string,
|
||||
* hat:string
|
||||
* }}
|
||||
*/
|
||||
* colourPrimary:string,
|
||||
* colourSecondary:string,
|
||||
* colourTertiary:string,
|
||||
* hat:string
|
||||
* }}
|
||||
*/
|
||||
Blockly.Theme.BlockStyle;
|
||||
|
||||
/**
|
||||
* A category style.
|
||||
* @typedef {{
|
||||
* colour:string
|
||||
* }}
|
||||
*/
|
||||
* colour:string
|
||||
* }}
|
||||
*/
|
||||
Blockly.Theme.CategoryStyle;
|
||||
|
||||
/**
|
||||
* A font style.
|
||||
* @typedef {{
|
||||
* family:string?,
|
||||
* weight:string?,
|
||||
* size:number?
|
||||
* }}
|
||||
*/
|
||||
Blockly.Theme.FontStyle;
|
||||
|
||||
/**
|
||||
* Overrides or adds a style to the blockStyles map.
|
||||
* @param {string} blockStyleName The name of the block style.
|
||||
@@ -97,6 +113,14 @@ Blockly.Theme.prototype.setCategoryStyle = function(categoryStyleName,
|
||||
this.categoryStyles[categoryStyleName] = categoryStyle;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure a theme's font style.
|
||||
* @param {Blockly.Theme.FontStyle} fontStyle The font style.
|
||||
*/
|
||||
Blockly.Theme.prototype.setFontStyle = function(fontStyle) {
|
||||
this.fontStyle = fontStyle;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the style for a given Blockly UI component. If the style value is a
|
||||
* string, we attempt to find the value of any named references.
|
||||
|
||||
@@ -107,3 +107,9 @@ Blockly.Themes.HighContrast =
|
||||
new Blockly.Theme('highcontrast',
|
||||
Blockly.Themes.HighContrast.defaultBlockStyles,
|
||||
Blockly.Themes.HighContrast.categoryStyles);
|
||||
|
||||
Blockly.Themes.HighContrast.setFontStyle({
|
||||
'family': null, // Use default font-family
|
||||
'weight': null, // Use default font-weight
|
||||
'size': 16
|
||||
});
|
||||
|
||||
@@ -94,6 +94,10 @@ Blockly.ThemeManager.prototype.setTheme = function(theme) {
|
||||
// Refresh all subscribed workspaces.
|
||||
for (var i = 0, workspace; (workspace = this.subscribedWorkspaces_[i]); i++) {
|
||||
workspace.refreshTheme();
|
||||
// Re-render if workspace is visible
|
||||
if (workspace.isVisible()) {
|
||||
workspace.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh all registered Blockly UI components.
|
||||
|
||||
@@ -280,6 +280,24 @@ Blockly.utils.dom.getTextWidth = function(textElement) {
|
||||
*/
|
||||
Blockly.utils.dom.getFastTextWidth = function(textElement,
|
||||
fontSize, fontWeight, fontFamily) {
|
||||
return Blockly.utils.dom.getFastTextWidthWithSizeString(textElement,
|
||||
fontSize + 'pt', fontWeight, fontFamily);
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the width of a text element using a faster method than `getTextWidth`.
|
||||
* This method requires that we know the text element's font family and size in
|
||||
* advance. Similar to `getTextWidth`, we cache the width we compute.
|
||||
* This method is similar to ``getFastTextWidth`` but expects the font size
|
||||
* parameter to be a string.
|
||||
* @param {!Element} textElement An SVG 'text' element.
|
||||
* @param {string} fontSize The font size to use.
|
||||
* @param {string} fontWeight The font weight to use.
|
||||
* @param {string} fontFamily The font family to use.
|
||||
* @return {number} Width of element.
|
||||
*/
|
||||
Blockly.utils.dom.getFastTextWidthWithSizeString = function(textElement,
|
||||
fontSize, fontWeight, fontFamily) {
|
||||
var text = textElement.textContent;
|
||||
var key = text + '\n' + textElement.className.baseVal;
|
||||
var width;
|
||||
@@ -305,7 +323,7 @@ Blockly.utils.dom.getFastTextWidth = function(textElement,
|
||||
}
|
||||
// Set the desired font size and family.
|
||||
Blockly.utils.dom.canvasContext_.font =
|
||||
fontWeight + ' ' + fontSize + 'pt ' + fontFamily;
|
||||
fontWeight + ' ' + fontSize + ' ' + fontFamily;
|
||||
|
||||
// Measure the text width using the helper canvas context.
|
||||
width = Blockly.utils.dom.canvasContext_.measureText(text).width;
|
||||
@@ -316,3 +334,41 @@ Blockly.utils.dom.getFastTextWidth = function(textElement,
|
||||
}
|
||||
return width;
|
||||
};
|
||||
|
||||
/**
|
||||
* Measure a font's metrics. The height and baseline values.
|
||||
* @param {string} text Text to measure the font dimensions of.
|
||||
* @param {string} fontSize The font size to use.
|
||||
* @param {string} fontWeight The font weight to use.
|
||||
* @param {string} fontFamily The font family to use.
|
||||
* @return {{height: number, baseline: number}} Font measurements.
|
||||
*/
|
||||
Blockly.utils.dom.measureFontMetrics = function(text, fontSize, fontWeight,
|
||||
fontFamily) {
|
||||
|
||||
var span = document.createElement('span');
|
||||
span.setAttribute('style', 'display: inline-block;');
|
||||
span.style.font = fontWeight + ' ' + fontSize + ' ' + fontFamily;
|
||||
span.textContent = text;
|
||||
|
||||
var block = document.createElement('div');
|
||||
block.setAttribute('style',
|
||||
'display: inline-block; width: 1px; height: 0px;');
|
||||
|
||||
var div = document.createElement('div');
|
||||
div.setAttribute('style', 'line-height: 0;');
|
||||
div.appendChild(span);
|
||||
div.appendChild(block);
|
||||
|
||||
document.body.appendChild(div);
|
||||
try {
|
||||
var result = {};
|
||||
block.style.verticalAlign = 'baseline';
|
||||
result.baseline = block.offsetTop - span.offsetTop;
|
||||
block.style.verticalAlign = 'bottom';
|
||||
result.height = block.offsetTop - span.offsetTop;
|
||||
} finally {
|
||||
document.body.removeChild(div);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -128,13 +128,15 @@ Blockly.WorkspaceSvg = function(options,
|
||||
this.options.parentWorkspace.getThemeManager() :
|
||||
new Blockly.ThemeManager(this,
|
||||
this.options.theme || Blockly.Themes.Classic);
|
||||
this.themeManager_.subscribeWorkspace(this);
|
||||
|
||||
/**
|
||||
* The block renderer used for rendering blocks on this workspace.
|
||||
* @type {!Blockly.blockRendering.Renderer}
|
||||
* @private
|
||||
*/
|
||||
this.renderer_ = Blockly.blockRendering.init(this.options.renderer || 'geras');
|
||||
this.renderer_ = Blockly.blockRendering.init(this.options.renderer || 'geras',
|
||||
this.getTheme());
|
||||
|
||||
/**
|
||||
* Cached parent SVG.
|
||||
@@ -143,9 +145,6 @@ Blockly.WorkspaceSvg = function(options,
|
||||
*/
|
||||
this.cachedParentSvg_ = null;
|
||||
|
||||
this.themeManager_.subscribeWorkspace(this);
|
||||
this.renderer_.getConstants().refreshTheme(this.getTheme());
|
||||
|
||||
/**
|
||||
* True if keyboard accessibility mode is on, false otherwise.
|
||||
* @type {boolean}
|
||||
@@ -516,7 +515,9 @@ Blockly.WorkspaceSvg.prototype.setTheme = function(theme) {
|
||||
* @package
|
||||
*/
|
||||
Blockly.WorkspaceSvg.prototype.refreshTheme = function() {
|
||||
this.getRenderer().getConstants().refreshTheme(this.getTheme());
|
||||
if (this.svgGroup_) {
|
||||
this.getRenderer().refresh(this.svgGroup_, this.getTheme());
|
||||
}
|
||||
|
||||
// Update all blocks in workspace that have a style name.
|
||||
this.updateBlockStyles_(this.getAllBlocks(false).filter(
|
||||
@@ -743,8 +744,7 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) {
|
||||
new Blockly.Marker());
|
||||
|
||||
var constants = this.getRenderer().getConstants();
|
||||
constants.injectCSS(this.getRenderer().name);
|
||||
constants.createDom(this.svgGroup_);
|
||||
constants.createDom(this.svgGroup_, this.getRenderer().name);
|
||||
return this.svgGroup_;
|
||||
};
|
||||
|
||||
@@ -903,6 +903,7 @@ Blockly.WorkspaceSvg.prototype.addFlyout = function(tagName) {
|
||||
this.flyout_ = new Blockly.VerticalFlyout(workspaceOptions);
|
||||
}
|
||||
this.flyout_.autoClose = false;
|
||||
this.flyout_.getWorkspace().setVisible(true);
|
||||
|
||||
// Return the element so that callers can place it in their desired
|
||||
// spot in the DOM. For example, mutator flyouts do not go in the same place
|
||||
@@ -1149,6 +1150,10 @@ Blockly.WorkspaceSvg.prototype.getWidth = function() {
|
||||
* @param {boolean} isVisible True if workspace should be visible.
|
||||
*/
|
||||
Blockly.WorkspaceSvg.prototype.setVisible = function(isVisible) {
|
||||
this.isVisible_ = isVisible;
|
||||
if (!this.svgGroup_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Tell the scrollbar whether its container is visible so it can
|
||||
// tell when to hide itself.
|
||||
@@ -1181,7 +1186,6 @@ Blockly.WorkspaceSvg.prototype.setVisible = function(isVisible) {
|
||||
} else {
|
||||
Blockly.hideChaff(true);
|
||||
}
|
||||
this.isVisible_ = isVisible;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -164,11 +164,15 @@ suite('Checkbox Fields', function() {
|
||||
suite('Check Character', function() {
|
||||
function assertCharacter(field, char) {
|
||||
field.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null);
|
||||
field.sourceBlock_ = {
|
||||
RTL: false
|
||||
};
|
||||
field.constants_ = {
|
||||
FIELD_CHECKBOX_X_OFFSET: 2,
|
||||
FIELD_CHECKBOX_Y_OFFSET: 2
|
||||
};
|
||||
field.initView();
|
||||
field.render_();
|
||||
chai.assert(field.textContent_.nodeValue, char);
|
||||
}
|
||||
test('Constant', function() {
|
||||
|
||||
@@ -347,6 +347,18 @@ function changeTheme() {
|
||||
}
|
||||
}
|
||||
|
||||
function changeRenderingConstant(value) {
|
||||
var type = document.getElementById('rendering-constant-selector').value;
|
||||
if (type == 'fontSize') {
|
||||
var fontStyle = {
|
||||
'size': value
|
||||
};
|
||||
workspace.getTheme().setFontStyle(fontStyle);
|
||||
}
|
||||
// Refresh theme.
|
||||
workspace.setTheme(workspace.getTheme());
|
||||
}
|
||||
|
||||
function setBackgroundColour() {
|
||||
// Set background colour to differentiate server vs local copy.
|
||||
if (location.protocol == 'file:') {
|
||||
@@ -563,6 +575,10 @@ var spaghettiXml = [
|
||||
.blockRenderDebug {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.zelos-renderer .blocklyFlyoutButton .blocklyText {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body onload="start()">
|
||||
@@ -631,6 +647,15 @@ var spaghettiXml = [
|
||||
<input type="button" value="Airstrike!" onclick="airstrike(100)">
|
||||
<input type="button" value="Spaghetti!" onclick="spaghetti(8)">
|
||||
</p>
|
||||
<p>
|
||||
Rendering:
|
||||
<select id="rendering-constant-selector">
|
||||
<option value="fontSize">Font Size</option>
|
||||
</select>
|
||||
<input type="range" min="3" max="50" value="4"
|
||||
oninput="changeRenderingConstant(this.value)"
|
||||
onchange="changeRenderingConstant(this.value)" />
|
||||
</p>
|
||||
<ul class="playgroundToggleOptions">
|
||||
<li>
|
||||
<label for="logCheck">Log events:</label>
|
||||
|
||||
Reference in New Issue
Block a user