mirror of
https://github.com/barsdeveloper/ueblueprint.git
synced 2026-03-05 06:57:29 +08:00
Various color picker fixes
This commit is contained in:
@@ -233,6 +233,13 @@ export default class Utility {
|
||||
.replaceAll("\\n", "\n")
|
||||
}
|
||||
|
||||
/** @param {String} value */
|
||||
static clearHTMLWhitespace(value) {
|
||||
return value
|
||||
.replaceAll(" ", "\u00A0")
|
||||
.replaceAll("<br>", "\n")
|
||||
}
|
||||
|
||||
/** @param {String} value */
|
||||
static formatStringName(value) {
|
||||
return value
|
||||
|
||||
@@ -115,8 +115,7 @@ export default class PinElement extends IElement {
|
||||
this.advancedView = entity.bAdvancedView
|
||||
this.defaultValue = entity.getDefaultValue()
|
||||
this.pinType = this.entity.getType()
|
||||
// @ts-expect-error
|
||||
this.color = this.constructor.properties.color.converter.fromAttribute(Configuration.pinColor[this.pinType]?.toString())
|
||||
this.color = PinElement.properties.color.converter.fromAttribute(Configuration.pinColor[this.pinType]?.toString())
|
||||
this.isLinked = false
|
||||
this.pinDirection = entity.isInput() ? "input" : entity.isOutput() ? "output" : "hidden"
|
||||
|
||||
|
||||
@@ -15,6 +15,30 @@ export default class LinearColorEntity extends IEntity {
|
||||
V: new TypeInitialization(RealUnitEntity, true, undefined, false, true),
|
||||
}
|
||||
|
||||
static linearToSRGB(x) {
|
||||
if (x <= 0) {
|
||||
return 0
|
||||
} else if (x >= 1) {
|
||||
return 1
|
||||
} else if (x < 0.0031308) {
|
||||
return x * 12.92
|
||||
} else {
|
||||
return Math.pow(x, 1 / 2.4) * 1.055 - 0.055
|
||||
}
|
||||
}
|
||||
|
||||
static sRGBtoLinear(x) {
|
||||
if (x <= 0) {
|
||||
return 0
|
||||
} else if (x >= 1) {
|
||||
return 1
|
||||
} else if (x < 0.04045) {
|
||||
return x / 12.92
|
||||
} else {
|
||||
return Math.pow((x + 0.055) / 1.055, 2.4)
|
||||
}
|
||||
}
|
||||
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
/** @type {RealUnitEntity} */ this.R
|
||||
@@ -109,8 +133,27 @@ export default class LinearColorEntity extends IEntity {
|
||||
]
|
||||
}
|
||||
|
||||
toSRGBA() {
|
||||
return [
|
||||
Math.round(LinearColorEntity.linearToSRGB(this.R.value) * 255),
|
||||
Math.round(LinearColorEntity.linearToSRGB(this.G.value) * 255),
|
||||
Math.round(LinearColorEntity.linearToSRGB(this.B.value) * 255),
|
||||
Math.round(this.A.value * 255),
|
||||
]
|
||||
}
|
||||
|
||||
toRGBAString() {
|
||||
return this.toRGBA().map(v => v.toString(16).padStart(2, "0")).join("")
|
||||
return this
|
||||
.toRGBA()
|
||||
.map(v => v.toString(16).toUpperCase().padStart(2, "0"))
|
||||
.join("")
|
||||
}
|
||||
|
||||
toSRGBAString() {
|
||||
return this
|
||||
.toSRGBA()
|
||||
.map(v => v.toString(16).toUpperCase().padStart(2, "0"))
|
||||
.join("")
|
||||
}
|
||||
|
||||
toHSVA() {
|
||||
@@ -130,8 +173,23 @@ export default class LinearColorEntity extends IEntity {
|
||||
return (this.R.value << 24) + (this.G.value << 16) + (this.B.value << 8) + this.A.value
|
||||
}
|
||||
|
||||
setFromRGBANumber(number) {
|
||||
this.A.value = (number & 0xFF) / 0xff
|
||||
this.B.value = ((number >> 8) & 0xFF) / 0xff
|
||||
this.G.value = ((number >> 16) & 0xFF) / 0xff
|
||||
this.R.value = ((number >> 24) & 0xFF) / 0xff
|
||||
this.#updateHSV()
|
||||
}
|
||||
|
||||
setFromSRGBANumber(number) {
|
||||
this.A.value = (number & 0xFF) / 0xff
|
||||
this.B.value = LinearColorEntity.sRGBtoLinear(((number >> 8) & 0xFF) / 0xff)
|
||||
this.G.value = LinearColorEntity.sRGBtoLinear(((number >> 16) & 0xFF) / 0xff)
|
||||
this.R.value = LinearColorEntity.sRGBtoLinear(((number >> 24) & 0xFF) / 0xff)
|
||||
this.#updateHSV()
|
||||
}
|
||||
|
||||
toString() {
|
||||
return Utility.printLinearColor(this)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -60,6 +60,32 @@ export default class ColorPickerWindowTemplate extends WindowTemplate {
|
||||
return this.#vSlider
|
||||
}
|
||||
|
||||
#hexRGBHandler =
|
||||
/** @param {FocusEvent} v */
|
||||
v => {
|
||||
// Faster than innerText which causes reflow
|
||||
const input = Utility.clearHTMLWhitespace(/** @type {HTMLElement} */(v.target).innerHTML)
|
||||
const RGBAValue = parseInt(input, 16)
|
||||
if (isNaN(RGBAValue)) {
|
||||
return
|
||||
}
|
||||
this.color.setFromRGBANumber(RGBAValue)
|
||||
this.element.requestUpdate()
|
||||
}
|
||||
|
||||
#hexSRGBHandler =
|
||||
/** @param {FocusEvent} v */
|
||||
v => {
|
||||
// Faster than innerText which causes reflow
|
||||
const input = Utility.clearHTMLWhitespace(/** @type {HTMLElement} */(v.target).innerHTML)
|
||||
const sRGBAValue = parseInt(input, 16)
|
||||
if (isNaN(sRGBAValue)) {
|
||||
return
|
||||
}
|
||||
this.color.setFromSRGBANumber(sRGBAValue)
|
||||
this.element.requestUpdate()
|
||||
}
|
||||
|
||||
#color = new LinearColorEntity()
|
||||
get color() {
|
||||
return this.#color
|
||||
@@ -211,7 +237,7 @@ export default class ColorPickerWindowTemplate extends WindowTemplate {
|
||||
break
|
||||
case 4:
|
||||
channelLetter = "h"
|
||||
channelValue = this.color.H.value
|
||||
channelValue = this.color.H.value * 360
|
||||
background = "linear-gradient(to right, #f00 0%, #ff0 16.666%, #0f0 33.333%, #0ff 50%, #00f 66.666%, #f0f 83.333%, #f00 100%)"
|
||||
break
|
||||
case 5:
|
||||
@@ -241,11 +267,11 @@ export default class ColorPickerWindowTemplate extends WindowTemplate {
|
||||
background = `background: ${background};`
|
||||
return html`
|
||||
<div class="ueb-color-picker-${channelLetter.toLowerCase()}">
|
||||
<span>${channelLetter.toUpperCase()}</span>
|
||||
<span class="ueb-color-control-label">${channelLetter.toUpperCase()}</span>
|
||||
<div>
|
||||
<div class="ueb-horizontal-slider">
|
||||
<span class="ueb-horizontal-slider-text"
|
||||
.innerText="${Utility.minDecimals(Utility.roundDecimals(channelValue))}">
|
||||
.innerText="${Utility.minDecimals(Utility.roundDecimals(channelValue, 3))}">
|
||||
</span>
|
||||
</div>
|
||||
<div class="ueb-color-picker-gradient" style="${background}"></div>
|
||||
@@ -311,12 +337,30 @@ export default class ColorPickerWindowTemplate extends WindowTemplate {
|
||||
${this.renderSlider(4)}
|
||||
${this.renderSlider(5)}
|
||||
${this.renderSlider(6)}
|
||||
<div class="ueb-color-picker-hex-linear"></div>
|
||||
<div class="ueb-color-picker-hex-srgb"></div>
|
||||
<div class="ueb-color-control">
|
||||
<span class="ueb-color-control-label">Hex Linear</span>
|
||||
<div class="ueb-color-picker-hex-linear ueb-text-input">
|
||||
<span class="ueb-pin-input-content" role="textbox" contenteditable="true"
|
||||
.innerText="${this.color.toRGBAString()}"
|
||||
@focusout="${this.#hexRGBHandler}">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ueb-color-control">
|
||||
<span class="ueb-color-control-label">Hex sRGB</span>
|
||||
<div class="ueb-color-picker-hex-srgb ueb-text-input">
|
||||
<span class="ueb-pin-input-content" role="textbox" contenteditable="true"
|
||||
.innerText="${this.color.toSRGBAString()}"
|
||||
@focusout="${this.#hexSRGBHandler}">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ueb-color-picker-ok"></div>
|
||||
<div class="ueb-color-picker-cancel"></div>
|
||||
<div class="ueb-buttons">
|
||||
<div class="ueb-color-picker-ok ueb-button" @click="${() => this.apply()}">OK</div>
|
||||
<div class="ueb-color-picker-cancel ueb-button" @click="${() => this.cancel()}">Cancel</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
@@ -6,12 +6,6 @@ import Utility from "../Utility"
|
||||
/** @extends {IDraggableControlTemplate<ColorHandlerElement>} */
|
||||
export default class ColorSliderTemplate extends IDraggableControlTemplate {
|
||||
|
||||
createInputObjects() {
|
||||
return [
|
||||
...super.createInputObjects(),
|
||||
]
|
||||
}
|
||||
|
||||
/** @param {[Number, Number]} param0 */
|
||||
adjustLocation([x, y]) {
|
||||
x = Utility.clamp(x, 0, this.movementSpaceSize[0])
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { html } from "lit"
|
||||
import MouseIgnore from "../input/mouse/MouseIgnore"
|
||||
import PinTemplate from "./PinTemplate"
|
||||
import Utility from "../Utility"
|
||||
|
||||
/**
|
||||
* @template T
|
||||
@@ -76,9 +77,7 @@ export default class IInputPinTemplate extends PinTemplate {
|
||||
getInputs() {
|
||||
return this.#inputContentElements.map(element =>
|
||||
// Faster than innerText which causes reflow
|
||||
element.innerHTML
|
||||
.replaceAll(" ", "\u00A0")
|
||||
.replaceAll("<br>", "\n")
|
||||
Utility.clearHTMLWhitespace(element.innerHTML)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import WindowElement from "../element/WindowElement"
|
||||
* @typedef {import("../entity/LinearColorEntity").default} LinearColorEntity
|
||||
*/
|
||||
|
||||
/** @extends IInputPinTemplate<LinearColorEntity> */
|
||||
export default class LinearColorPinTemplate extends IInputPinTemplate {
|
||||
|
||||
/** @type {HTMLInputElement} */
|
||||
@@ -40,7 +41,9 @@ export default class LinearColorPinTemplate extends IInputPinTemplate {
|
||||
})
|
||||
this.element.blueprint.append(this.#window)
|
||||
const windowApplyHandler = () => {
|
||||
this.element.color = /** @type {ColorPickerWindowTemplate} */(this.#window.template).color
|
||||
this.element.setDefaultValue(
|
||||
/** @type {ColorPickerWindowTemplate} */(this.#window.template).color
|
||||
)
|
||||
}
|
||||
const windowCloseHandler = () => {
|
||||
this.#window.removeEventListener(Configuration.windowApplyEventName, windowApplyHandler)
|
||||
|
||||
@@ -18,9 +18,8 @@ export default class RealPinTemplate extends INumericPinTemplate {
|
||||
return html`
|
||||
<div class="ueb-pin-input">
|
||||
<span class="ueb-pin-input-content" role="textbox" contenteditable="true"
|
||||
.innerText="${
|
||||
IInputPinTemplate.stringFromUEToInput(Utility.minDecimals(this.element.entity.DefaultValue))
|
||||
}"></span>
|
||||
.innerText="${IInputPinTemplate.stringFromUEToInput(Utility.minDecimals(this.element.entity.DefaultValue))}">
|
||||
</span>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { html } from "lit"
|
||||
import Configuration from "../Configuration"
|
||||
import IDraggablePositionedTemplate from "./IDraggablePositionedTemplate"
|
||||
import MouseClickAction from "../input/mouse/MouseClickAction"
|
||||
import MouseMoveDraggable from "../input/mouse/MouseMoveDraggable"
|
||||
|
||||
/** @typedef {import("../element/WindowElement").default} WindowElement */
|
||||
@@ -23,22 +23,12 @@ export default class WindowTemplate extends IDraggablePositionedTemplate {
|
||||
})
|
||||
}
|
||||
|
||||
createInputObjects() {
|
||||
return [
|
||||
...super.createInputObjects(),
|
||||
new MouseClickAction(this.element.querySelector(".ueb-window-close"), this.element.blueprint, {},
|
||||
undefined,
|
||||
() => this.element.remove()
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="ueb-window">
|
||||
<div class="ueb-window-top">
|
||||
<div class="ueb-window-name ueb-ellipsis-nowrap-text">${this.renderWindowName()}</div>
|
||||
<div class="ueb-window-close">
|
||||
<div class="ueb-window-close" @click="${() => this.element.remove()}">
|
||||
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="2" y1="2" x2="30" y2="30" stroke="currentColor" stroke-width="4" />
|
||||
<line x1="30" y1="2" x2="2" y2="30" stroke="currentColor" stroke-width="4" />
|
||||
@@ -59,4 +49,14 @@ export default class WindowTemplate extends IDraggablePositionedTemplate {
|
||||
renderContent() {
|
||||
return html``
|
||||
}
|
||||
|
||||
apply() {
|
||||
this.element.dispatchEvent(new CustomEvent(Configuration.windowApplyEventName))
|
||||
this.element.remove()
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.element.dispatchEvent(new CustomEvent(Configuration.windowCancelEventName))
|
||||
this.element.remove()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user