Skip to content

Commit

Permalink
Preferences window uses custom color picker
Browse files Browse the repository at this point in the history
  • Loading branch information
tillvit committed Sep 19, 2024
1 parent 68bf683 commit 90328c1
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 74 deletions.
25 changes: 19 additions & 6 deletions app/src/chart/component/edit/Waveform.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import {
Color,
FXAAFilter,
ParticleContainer,
RenderTexture,
Sprite,
Texture,
} from "pixi.js"
import { colorFallback } from "../../../util/Color"
import { EventHandler } from "../../../util/EventHandler"
import { clamp } from "../../../util/Math"
import { Options } from "../../../util/Options"
Expand Down Expand Up @@ -51,6 +53,9 @@ export class Waveform extends Sprite implements ChartRendererComponent {
private drawDirty = true
private blockCache = new Map<string, number[]>()

private colorCache = new Color("black")
private filteredColorCache = new Color("black")

constructor(renderer: ChartRenderer) {
super()
this.renderer = renderer
Expand Down Expand Up @@ -95,8 +100,6 @@ export class Waveform extends Sprite implements ChartRendererComponent {
() => this.renderer.chartManager.app.renderer.screen.height,
() => this.resizeWaveform()
)
this.trackVariable(() => Options.chart.waveform.opacity)
this.trackVariable(() => Options.chart.waveform.filteredOpacity)
this.trackVariable(() => Options.chart.waveform.filteredColor)
this.trackVariable(() => Options.chart.waveform.color)
this.trackVariable(() => Options.chart.waveform.speedChanges)
Expand Down Expand Up @@ -165,6 +168,16 @@ export class Waveform extends Sprite implements ChartRendererComponent {

if (!Options.chart.waveform.enabled) return
if (this.drawDirty || this.variableChanged()) {
if (this.colorCache.toHexa() != Options.chart.waveform.color) {
this.colorCache = colorFallback(Options.chart.waveform.color)
}
if (
this.filteredColorCache.toHexa() != Options.chart.waveform.filteredColor
) {
this.filteredColorCache = colorFallback(
Options.chart.waveform.filteredColor
)
}
this.drawDirty = false
this.renderData()
this.renderer.chartManager.app.renderer.render(this.lineContainer, {
Expand Down Expand Up @@ -471,8 +484,8 @@ export class Waveform extends Sprite implements ChartRendererComponent {
16 *
Options.chart.zoom
line.y = y
line.tint = Options.chart.waveform.color
line.alpha = Options.chart.waveform.opacity
line.tint = this.colorCache
line.alpha = this.colorCache.alpha
line.x =
this.waveformTex.width / 2 +
288 * (channel + 0.5 - this.rawData.length / 2) * Options.chart.zoom
Expand All @@ -482,8 +495,8 @@ export class Waveform extends Sprite implements ChartRendererComponent {
this.getSample(this.filteredRawData[channel], second, "filter") *
16 *
Options.chart.zoom
filteredLine.tint = Options.chart.waveform.filteredColor
filteredLine.alpha = Options.chart.waveform.filteredOpacity
filteredLine.tint = this.filteredColorCache
filteredLine.alpha = this.filteredColorCache.alpha
filteredLine.y = y
filteredLine.x =
this.waveformTex.width / 2 +
Expand Down
25 changes: 2 additions & 23 deletions app/src/data/UserOptionsWindowData.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Color } from "pixi.js"
import { App } from "../App"
import { TimingWindowCollection } from "../chart/play/TimingWindowCollection"

Expand Down Expand Up @@ -94,7 +95,7 @@ interface UserOptionCheckboxInput {

interface UserOptionColorInput {
type: "color"
onChange?: (app: App, value: number) => void
onChange?: (app: App, value: Color) => void
}

type UserOptionInput<T> =
Expand Down Expand Up @@ -416,17 +417,6 @@ export const USER_OPTIONS_WINDOW_DATA: UserOption[] = [
type: "color",
},
},
{
type: "item",
label: "Opacity",
id: "chart.waveform.opacity",
input: {
type: "slider",
min: 0,
max: 1,
step: 0.01,
},
},
],
},
{
Expand All @@ -448,17 +438,6 @@ export const USER_OPTIONS_WINDOW_DATA: UserOption[] = [
type: "color",
},
},
{
type: "item",
label: "Filtered opacity",
id: "chart.waveform.filteredOpacity",
input: {
type: "slider",
min: 0,
max: 1,
step: 0.01,
},
},
],
},
{
Expand Down
47 changes: 27 additions & 20 deletions app/src/gui/element/ColorPicker.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import { Color } from "pixi.js"
import { colorToHsla, colorToHsva } from "../../util/Color"
import { colorFallback, colorToHsla, colorToHsva } from "../../util/Color"
import { clamp } from "../../util/Math"

class TransparentPreview extends HTMLDivElement {
colorElement!: HTMLDivElement
static create() {
const bg = document.createElement("div") as TransparentPreview
bg.classList.add("color-picker-transparent")
Object.setPrototypeOf(bg, TransparentPreview.prototype)
const color = document.createElement("div")
color.style.width = "100%"
color.style.height = "100%"
bg.colorElement = color
bg.appendChild(color)
return bg
}

set color(value: Color) {
this.colorElement.style.background = value.toHexa()
}
}

function createTransparent() {
const bg = document.createElement("div") as TransparentPreview
bg.classList.add("color-picker-transparent")
Object.setPrototypeOf(bg, TransparentPreview.prototype)
const color = document.createElement("div")
color.style.width = "100%"
color.style.height = "100%"
bg.colorElement = color
bg.appendChild(color)
return bg
}

interface ColorFormatInputOptions {
setValue: (color: Color) => string
isValid: (value: string) => string | null
Expand Down Expand Up @@ -158,10 +159,10 @@ export class ColorPicker extends TransparentPreview {

onColorChange?: (color: Color) => void

static createPicker(options: ColorPickerOptions): ColorPicker {
const picker = TransparentPreview.create() as ColorPicker
static create(options: ColorPickerOptions): ColorPicker {
const picker = createTransparent() as ColorPicker
Object.setPrototypeOf(picker, ColorPicker.prototype)
picker.value = new Color(options.value)
picker.value = colorFallback(options.value)
picker.classList.add("color-picker")
picker.formats = []

Expand Down Expand Up @@ -266,7 +267,10 @@ export class ColorPicker extends TransparentPreview {
const [hueSlider, hueThumb] = this.createSlider({
ondrag: () => (this.hueDragging = true),
offdrag: () => (this.hueDragging = false),
change: v => (this.hue = v),
change: v => {
this.hue = v
this.onColorChange?.(this._value)
},
})
this.hueThumb = hueThumb
hueSlider.style.background =
Expand All @@ -275,7 +279,10 @@ export class ColorPicker extends TransparentPreview {
const [alphaSlider, alphaThumb] = this.createSlider({
ondrag: () => (this.alphaDragging = true),
offdrag: () => (this.alphaDragging = false),
change: v => (this.alpha = v),
change: v => {
this.alpha = v
this.onColorChange?.(this._value)
},
})
this.alphaThumb = alphaThumb
alphaSlider.classList.add("color-picker-transparent")
Expand Down Expand Up @@ -431,8 +438,8 @@ export class ColorPicker extends TransparentPreview {
const previewContainer = document.createElement("div")
previewContainer.classList.add("color-picker-preview")

const previewNew = TransparentPreview.create()
const previewOld = TransparentPreview.create()
const previewNew = createTransparent()
const previewOld = createTransparent()
previewOld.color = this._value
previewNew.color = this._value
previewContainer.replaceChildren(previewNew, previewOld)
Expand Down Expand Up @@ -477,7 +484,7 @@ export class ColorPicker extends TransparentPreview {
updatePopup() {
if (!this.popup) return
this.matrix!.style.backgroundColor = `hsl(${this._hue * 360} 100% 50%)`
this.matrixDot!.style.backgroundColor = this._value.toRgbaString()
this.matrixDot!.style.backgroundColor = this._value.toHex()
if (!this.matrixDragging) {
this.matrixDot!.style.left = this._sat * 200 + "px"
this.matrixDot!.style.top = (1 - this._val) * 200 + "px"
Expand Down
12 changes: 3 additions & 9 deletions app/src/gui/widget/NPSGraphWidget.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BitmapText, FederatedPointerEvent, Graphics, Texture } from "pixi.js"
import { assignTint } from "../../util/Color"
import { assignTint, colorFallback } from "../../util/Color"
import { EventHandler } from "../../util/EventHandler"
import { clamp, lerp, unlerp } from "../../util/Math"
import { Options } from "../../util/Options"
Expand Down Expand Up @@ -227,14 +227,8 @@ export class NPSGraphWidget extends BaseTimelineWidget {
// use canvas2d API to create gradient
const grd = ctx.createLinearGradient(0, 0, quality, 0)

const color1 = `#${Options.chart.npsGraph.color1
.toString(16)
.padStart(6, "0")}`
const color2 = `#${Options.chart.npsGraph.color2
.toString(16)
.padStart(6, "0")}`
grd.addColorStop(0, color1)
grd.addColorStop(0.8, color2)
grd.addColorStop(0, colorFallback(Options.chart.npsGraph.color1).toHexa())
grd.addColorStop(0.8, colorFallback(Options.chart.npsGraph.color2).toHexa())

ctx.fillStyle = grd
ctx.fillRect(0, 0, quality, quality)
Expand Down
2 changes: 1 addition & 1 deletion app/src/gui/window/ThemeWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export class ThemeWindow extends Window {
const colorLabel = document.createElement("div")
colorLabel.classList.add("theme-color-detail")

const colorPicker = ColorPicker.createPicker({
const colorPicker = ColorPicker.create({
value: "white",
width: 30,
height: 30,
Expand Down
16 changes: 7 additions & 9 deletions app/src/gui/window/UserOptionsWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { clamp, roundDigit } from "../../util/Math"
import { Options } from "../../util/Options"
import { parseString } from "../../util/Util"
import { Icons } from "../Icons"
import { ColorPicker } from "../element/ColorPicker"
import { Dropdown } from "../element/Dropdown"
import { NumberSpinner } from "../element/NumberSpinner"
import { Window } from "./Window"
Expand Down Expand Up @@ -337,22 +338,19 @@ export class UserOptionsWindow extends Window {
}
case "color": {
const callback = option.input.onChange
const colorInput = document.createElement("input")
colorInput.type = "color"
colorInput.value = "#" + optionValue.toString(16).padStart(6, "0")
const colorInput = ColorPicker.create({
value: optionValue,
})
// 'change' event is fired when the user closes the color picker
colorInput.oninput = () => {
Options.applyOption([
option.id,
parseInt(colorInput.value.slice(1), 16),
])
colorInput.onColorChange = c => {
Options.applyOption([option.id, c.toHexa()])
EventHandler.emit("userOptionUpdated", option.id)
revert.style.display =
Options.getDefaultOption(option.id) ===
Options.getOption(option.id)
? "none"
: "block"
callback?.(this.app, parseInt(colorInput.value.slice(1), 16))
callback?.(this.app, c)
}
input = colorInput
}
Expand Down
11 changes: 11 additions & 0 deletions app/src/util/Color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,14 @@ export function colorToHsva(color: Color) {

return [h, s, v, a]
}

export function colorFallback(
colorString: ColorSource,
fallback?: ColorSource
) {
try {
return new Color(colorString)
} catch (e) {
return new Color(fallback ?? "black")
}
}
10 changes: 4 additions & 6 deletions app/src/util/Options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,9 @@ export class DefaultOptions {
waveform: {
enabled: true,
antialiasing: true,
color: 0x606172,
opacity: 0.5,
color: "#60617288",
allowFilter: true,
filteredColor: 0x1e523e,
filteredOpacity: 0.5,
filteredColor: "#1e523e88",
lineHeight: 1,
speedChanges: true,
},
Expand All @@ -58,8 +56,8 @@ export class DefaultOptions {
},
npsGraph: {
enabled: false,
color1: 0x4aa7bc,
color2: 0x423c7a,
color1: "#4aa7bcff",
color2: "#423c7aff",
},
timingEventOrder: {
left: [
Expand Down

0 comments on commit 90328c1

Please sign in to comment.