-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix the rounded and shaded box character rendering
fixes #296
- Loading branch information
1 parent
9d18ceb
commit 54e24ec
Showing
4 changed files
with
158 additions
and
5 deletions.
There are no files selected for viewing
146 changes: 146 additions & 0 deletions
146
packages/extraterm-char-render-canvas/src/ColorUtilities.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
/* | ||
* Copyright 2020 Simon Edwards <[email protected]> | ||
* | ||
* This source code is licensed under the MIT license which is detailed in the LICENSE.txt file. | ||
*/ | ||
|
||
//------------------------------------------------------------------------- | ||
/** | ||
* Utility class for handling CSS colors | ||
*/ | ||
export class Color { | ||
|
||
_red: number; | ||
_green: number; | ||
_blue: number; | ||
_opacity: number; // 0-255 | ||
_hexString: string = null; | ||
_rgbaString: string = null; | ||
|
||
/** | ||
* Creates a color object. | ||
* | ||
* @param {string | number} redOrString [description] | ||
* @param {number} green [description] | ||
* @param {number} blue [description] | ||
* @param {number} opacity [description] | ||
* @return {[type]} [description] | ||
*/ | ||
constructor(redOrString: string | number, green?: number, blue?: number, opacity?: number) { | ||
if (typeof redOrString === "string") { | ||
const stringColor = <string> redOrString; | ||
if (stringColor.startsWith("#")) { | ||
if (stringColor.length === 4) { | ||
// Parse the 4bit colour values and expand then to 8bit. | ||
this._red = parseInt(stringColor.slice(1, 2), 16) * 17; | ||
this._green = parseInt(stringColor.slice(2, 3), 16) * 17; | ||
this._blue = parseInt(stringColor.slice(3, 4), 16) * 17; | ||
this._opacity = 255; | ||
} else if (stringColor.length === 4) { | ||
// Parse the 4bit colour values and expand then to 8bit. | ||
this._red = parseInt(stringColor.slice(1, 2), 16) * 17; | ||
this._green = parseInt(stringColor.slice(2, 3), 16) * 17; | ||
this._blue = parseInt(stringColor.slice(3, 4), 16) * 17; | ||
this._opacity = parseInt(stringColor.slice(4, 5), 16) * 17; | ||
|
||
} else if (stringColor.length === 7) { | ||
this._red = parseInt(stringColor.slice(1, 3), 16); | ||
this._green = parseInt(stringColor.slice(3, 5), 16); | ||
this._blue = parseInt(stringColor.slice(5, 7), 16); | ||
this._opacity = 255; | ||
|
||
} else if (stringColor.length === 9) { | ||
this._red = parseInt(stringColor.slice(1, 3), 16); | ||
this._green = parseInt(stringColor.slice(3, 5), 16); | ||
this._blue = parseInt(stringColor.slice(5, 7), 16); | ||
this._opacity = parseInt(stringColor.slice(7, 9), 16); | ||
} else { | ||
// Malformed hex colour. | ||
|
||
} | ||
|
||
} else { | ||
// What now?! | ||
} | ||
} else { | ||
// Assume numbers. | ||
const red = <number> redOrString; | ||
this._red = red; | ||
this._green = green !== undefined ? green : 0; | ||
this._blue = blue !== undefined ? blue : 0; | ||
this._opacity = opacity !== undefined ? opacity : 255; | ||
} | ||
} | ||
/** | ||
* Returns the color as a 6 digit hex string. | ||
* | ||
* @return the color as a CSS style hex string. | ||
*/ | ||
toHexString(): string { | ||
if (this._hexString === null) { | ||
this._hexString = "#" + to2DigitHex(this._red) + to2DigitHex(this._green) + to2DigitHex(this._blue); | ||
} | ||
return this._hexString; | ||
} | ||
|
||
/** | ||
* Returns the color as a CSS rgba() value. | ||
* | ||
* @return the color as a CSS rgba() value. | ||
*/ | ||
toRGBAString(): string { | ||
if (this._rgbaString === null) { | ||
this._rgbaString = "rgba(" + this._red + "," + this._green + "," + this._blue + "," + (this._opacity/255) + ")"; | ||
} | ||
return this._rgbaString; | ||
} | ||
|
||
toRGBA(): number { | ||
return (this._red << 24) | (this._green << 16) | (this._blue << 8) | this._opacity; | ||
} | ||
|
||
/** | ||
* Returns the color as a CSS string. | ||
* | ||
* @return the color as a CSS formatted string. | ||
*/ | ||
toString(): string { | ||
if (this._opacity === 255) { | ||
// Use a hex representation. | ||
return this.toHexString(); | ||
} else { | ||
return this.toRGBAString(); | ||
} | ||
} | ||
|
||
/** | ||
* Creates a new color with the given opacity value. | ||
* | ||
* @param newOpacity A number from 0 to 1. | ||
* @return the new color. | ||
*/ | ||
opacity(newOpacity: number): Color { | ||
return new Color(this._red, this._green, this._blue, newOpacity); | ||
} | ||
|
||
mix(otherColor: Color, fraction=0.5): Color { | ||
const rightFraction = fraction; | ||
|
||
const red = Math.min(255, Math.round(fraction * this._red + rightFraction * otherColor._red)); | ||
const green = Math.min(255, Math.round(fraction * this._green + rightFraction * otherColor._green)); | ||
const blue = Math.min(255, Math.round(fraction * this._blue + rightFraction * otherColor._blue)); | ||
const opacity = Math.min(255, Math.round(fraction* (this._opacity/255) + rightFraction * (otherColor._opacity/255))); | ||
return new Color(red, green, blue, opacity); | ||
} | ||
} | ||
|
||
/** | ||
* Converts an 8bit number to a 2 digit hexadecimal string. | ||
* | ||
* @param {number} value An integer in the range 0-255 inclusive. | ||
* @return {string} the converted number. | ||
*/ | ||
export function to2DigitHex(value: number): string { | ||
const h = value.toString(16); | ||
return h.length === 1 ? "0" + h : h; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
* Copyright 2019 Simon Edwards <[email protected]> | ||
*/ | ||
import { Logger, getLogger, log } from "extraterm-logging"; | ||
import { Color } from "../ColorUtilities"; | ||
|
||
|
||
const _log = getLogger("BoxDrawingCharacters"); | ||
|
@@ -98,7 +99,7 @@ export function drawBoxCharacter(ctx: CanvasRenderingContext2D, codePoint: numbe | |
case GlyphRenderer.ARC_DOWN_AND_LEFT: | ||
case GlyphRenderer.ARC_UP_AND_LEFT: | ||
case GlyphRenderer.ARC_UP_AND_RIGHT: | ||
drawArcDownAndRight(ctx, thisGlyphData.glyphRenderer, dx, dy, width, height); | ||
drawRoundArc(ctx, thisGlyphData.glyphRenderer, dx, dy, width, height); | ||
break; | ||
} | ||
} | ||
|
@@ -301,7 +302,10 @@ function compute8x5GlyphGrid(width: number, height: number): GlyphGridMetrics { | |
|
||
function drawShade(ctx: CanvasRenderingContext2D, dx: number, dy: number, width: number, height: number, alpha: number): void { | ||
ctx.save(); | ||
ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`; | ||
|
||
const fillColor = new Color(<string> ctx.fillStyle); | ||
ctx.fillStyle = fillColor.opacity(alpha * 255).toRGBAString(); | ||
|
||
ctx.fillRect(dx, dy, width, height); | ||
ctx.restore(); | ||
} | ||
|
@@ -343,7 +347,7 @@ interface ArcStartEndPoint { | |
endPointY: number; | ||
} | ||
|
||
const arcStartEndPoints = { | ||
const arcStartEndPoints: { [index: number]: ArcStartEndPoint } = { | ||
[GlyphRenderer.ARC_DOWN_AND_RIGHT]: { | ||
startPointX: 0.5, | ||
startPointY: 1, | ||
|
@@ -370,7 +374,7 @@ const arcStartEndPoints = { | |
}, | ||
}; | ||
|
||
function drawArcDownAndRight(ctx: CanvasRenderingContext2D, renderer: GlyphRenderer, dx: number, dy: number, | ||
function drawRoundArc(ctx: CanvasRenderingContext2D, renderer: GlyphRenderer, dx: number, dy: number, | ||
width: number, height: number): void { | ||
|
||
const metrics = compute5x5GlyphGrid(width, height); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters