149 lines
5.1 KiB
JavaScript
149 lines
5.1 KiB
JavaScript
((exports) => {
|
|
|
|
/** Used by the Colors Box and by the Edit Colors dialog */
|
|
function $Swatch(color) {
|
|
const $swatch = $(E("div")).addClass("swatch");
|
|
const swatch_canvas = make_canvas();
|
|
$(swatch_canvas).css({ pointerEvents: "none" }).appendTo($swatch);
|
|
|
|
// @TODO: clean up event listener
|
|
$G.on("theme-load", () => { update_$swatch($swatch); });
|
|
$swatch.data("swatch", color);
|
|
update_$swatch($swatch, color);
|
|
|
|
return $swatch;
|
|
}
|
|
|
|
function update_$swatch($swatch, new_color) {
|
|
if (new_color instanceof CanvasPattern) {
|
|
$swatch.addClass("pattern");
|
|
$swatch[0].dataset.color = "";
|
|
} else if (typeof new_color === "string") {
|
|
$swatch.removeClass("pattern");
|
|
$swatch[0].dataset.color = new_color;
|
|
} else if (new_color !== undefined) {
|
|
throw new TypeError(`argument to update must be CanvasPattern or string (or undefined); got type ${typeof new_color}`);
|
|
}
|
|
new_color = new_color || $swatch.data("swatch");
|
|
$swatch.data("swatch", new_color);
|
|
const swatch_canvas = $swatch.find("canvas")[0];
|
|
requestAnimationFrame(() => {
|
|
swatch_canvas.width = $swatch.innerWidth();
|
|
swatch_canvas.height = $swatch.innerHeight();
|
|
if (new_color) {
|
|
swatch_canvas.ctx.fillStyle = new_color;
|
|
swatch_canvas.ctx.fillRect(0, 0, swatch_canvas.width, swatch_canvas.height);
|
|
}
|
|
});
|
|
}
|
|
|
|
function $ColorBox(vertical) {
|
|
const $cb = $(E("div")).addClass("color-box");
|
|
|
|
const $current_colors = $Swatch(selected_colors.ternary).addClass("current-colors");
|
|
const $palette = $(E("div")).addClass("palette");
|
|
|
|
$cb.append($current_colors, $palette);
|
|
|
|
const $foreground_color = $Swatch(selected_colors.foreground).addClass("color-selection foreground-color");
|
|
const $background_color = $Swatch(selected_colors.background).addClass("color-selection background-color");
|
|
$current_colors.append($background_color, $foreground_color);
|
|
|
|
$G.on("option-changed", () => {
|
|
update_$swatch($foreground_color, selected_colors.foreground);
|
|
update_$swatch($background_color, selected_colors.background);
|
|
update_$swatch($current_colors, selected_colors.ternary);
|
|
});
|
|
|
|
$current_colors.on("pointerdown", () => {
|
|
const new_bg = selected_colors.foreground;
|
|
selected_colors.foreground = selected_colors.background;
|
|
selected_colors.background = new_bg;
|
|
$G.triggerHandler("option-changed");
|
|
});
|
|
|
|
const make_color_button = (color) => {
|
|
|
|
const $b = $Swatch(color).addClass("color-button");
|
|
$b.appendTo($palette);
|
|
|
|
const double_click_period_ms = 400;
|
|
let within_double_click_period = false;
|
|
let double_click_button = null;
|
|
let double_click_tid;
|
|
// @TODO: handle left+right click at same time
|
|
// can do this with mousedown instead of pointerdown, but may need to improve eye gaze mode click simulation
|
|
$b.on("pointerdown", e => {
|
|
// @TODO: allow metaKey for ternary color, and selection cropping, on macOS?
|
|
ctrl = e.ctrlKey;
|
|
button = e.button;
|
|
if (button === 0) {
|
|
$c.data("$last_fg_color_button", $b);
|
|
}
|
|
|
|
const color_selection_slot = ctrl ? "ternary" : button === 0 ? "foreground" : button === 2 ? "background" : null;
|
|
if (color_selection_slot) {
|
|
if (within_double_click_period && button === double_click_button) {
|
|
show_edit_colors_window($b, color_selection_slot);
|
|
} else {
|
|
selected_colors[color_selection_slot] = $b.data("swatch");
|
|
$G.trigger("option-changed");
|
|
}
|
|
|
|
clearTimeout(double_click_tid);
|
|
double_click_tid = setTimeout(() => {
|
|
within_double_click_period = false;
|
|
double_click_button = null;
|
|
}, double_click_period_ms);
|
|
within_double_click_period = true;
|
|
double_click_button = button;
|
|
}
|
|
});
|
|
};
|
|
|
|
const build_palette = () => {
|
|
$palette.empty();
|
|
|
|
palette.forEach(make_color_button);
|
|
|
|
// Note: this doesn't work until the colors box is in the DOM
|
|
const $some_button = $palette.find(".color-button");
|
|
if (vertical) {
|
|
const height_per_button =
|
|
$some_button.outerHeight() +
|
|
parseFloat(getComputedStyle($some_button[0]).getPropertyValue("margin-top")) +
|
|
parseFloat(getComputedStyle($some_button[0]).getPropertyValue("margin-bottom"));
|
|
$palette.height(Math.ceil(palette.length / 2) * height_per_button);
|
|
} else {
|
|
const width_per_button =
|
|
$some_button.outerWidth() +
|
|
parseFloat(getComputedStyle($some_button[0]).getPropertyValue("margin-left")) +
|
|
parseFloat(getComputedStyle($some_button[0]).getPropertyValue("margin-right"));
|
|
$palette.width(Math.ceil(palette.length / 2) * width_per_button);
|
|
}
|
|
|
|
// the "last foreground color button" starts out as the first in the palette
|
|
$c.data("$last_fg_color_button", $palette.find(".color-button:first-child"));
|
|
};
|
|
let $c;
|
|
if (vertical) {
|
|
$c = $Component(localize("Colors"), "colors-component", "tall", $cb);
|
|
$c.appendTo(get_direction() === "rtl" ? $left : $right); // opposite ToolBox by default
|
|
} else {
|
|
$c = $Component(localize("Colors"), "colors-component", "wide", $cb);
|
|
$c.appendTo($bottom);
|
|
}
|
|
|
|
build_palette();
|
|
$(window).on("theme-change", build_palette);
|
|
|
|
$c.rebuild_palette = build_palette;
|
|
|
|
return $c;
|
|
}
|
|
|
|
exports.$ColorBox = $ColorBox;
|
|
exports.$Swatch = $Swatch;
|
|
exports.update_$swatch = update_$swatch;
|
|
|
|
})(window); |