init the awkward code

This commit is contained in:
Bao Nguyen
2023-02-13 19:32:10 +07:00
commit 27170afcac
5426 changed files with 1244579 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,996 @@
((exports) => {
function E(nodeName, attrs) {
const el = document.createElement(nodeName);
if (attrs) {
for (const key in attrs) {
if (key === "class") {
el.className = attrs[key];
} else {
el.setAttribute(key, attrs[key]);
}
}
}
return el;
}
let uid_counter = 0;
function uid() {
// make id from counter (guaranteeing page-local uniqueness)
// and random base 36 number (making it look random, so there's no temptation to use it as a sequence)
// Note: Math.random().toString(36).slice(2) can give empty string
return (uid_counter++).toString(36) + Math.random().toString(36).slice(2);
}
// @TODO: export hotkey helpers; also include one for escaping &'s (useful for dynamic menus like a list of history entries)
// also @TODO: support dynamic menus (e.g. a list of history entries, contextually shown options, or a contextually named "Undo <action>" label; Explorer has all these things)
// & defines accelerators (hotkeys) in menus and buttons and things, which get underlined in the UI.
// & can be escaped by doubling it, e.g. "&Taskbar && Start Menu"
function index_of_hotkey(text) {
// Returns the index of the ampersand that defines a hotkey, or -1 if not present.
// return english_text.search(/(?<!&)&(?!&|\s)/); // not enough browser support for negative lookbehind assertions
// The space here handles beginning-of-string matching and counteracts the offset for the [^&] so it acts like a negative lookbehind
return ` ${text}`.search(/[^&]&[^&\s]/);
}
// function has_hotkey(text) {
// return index_of_hotkey(text) !== -1;
// }
function remove_hotkey(text) {
return text.replace(/\s?\(&.\)/, "").replace(/([^&]|^)&([^&\s])/, "$1$2");
}
function display_hotkey(text) {
// TODO: use a more general term like .hotkey or .accelerator?
return text.replace(/([^&]|^)&([^&\s])/, "$1<span class='menu-hotkey'>$2</span>").replace(/&&/g, "&");
}
function get_hotkey(text) {
return text[index_of_hotkey(text) + 1].toUpperCase();
}
// TODO: support copy/pasting text in the text tool textarea from the menus
// probably by recording document.activeElement on pointer down,
// and restoring focus before executing menu item actions.
const MENU_DIVIDER = "MENU_DIVIDER";
const MAX_MENU_NESTING = 1000;
let internal_z_counter = 1;
function get_new_menu_z_index() {
// integrate with the OS window z-indexes, if applicable
// but don't depend on $Window existing, the modules should be independent
if (typeof $Window !== "undefined") {
return ($Window.Z_INDEX++) + MAX_MENU_NESTING; // MAX_MENU_NESTING is needed because the window gets brought to the top
}
return (++internal_z_counter) + MAX_MENU_NESTING;
}
function MenuBar(menus) {
if (!(this instanceof MenuBar)) {
return new MenuBar(menus);
}
const menus_el = E("div", {
class: "menus",
role: "menubar",
"aria-label": "Application Menu",
});
menus_el.style.touchAction = "none";
menus_el.style.pointerEvents = "none";
// returns writing/layout direction, "ltr" or "rtl"
function get_direction() {
return window.get_direction ? window.get_direction() : getComputedStyle(menus_el).direction;
}
let selecting_menus = false; // state where you can glide between menus without clicking
const top_level_menus = [];
let top_level_menu_index = -1; // index of the top level menu that's most recently open, or highlighted
let active_menu_popup; // most nested open MenuPopup
const menu_popup_by_el = new WeakMap(); // maps DOM elements to MenuPopup instances
// There can be multiple menu bars instantiated from the same menu definitions,
// so this can't be a map of menu item to submenu, it has to be of menu item ELEMENTS to submenu.
// (or you know, it could work totally differently, this is just one way to do it)
// This is for entering submenus.
const submenu_popup_by_menu_item_el = new WeakMap();
// This is for exiting submenus.
const parent_item_el_by_popup_el = new WeakMap();
const close_menus = () => {
for (const { menu_button_el } of top_level_menus) {
if (menu_button_el.getAttribute("aria-expanded") === "true") {
menu_button_el.dispatchEvent(new CustomEvent("release"), {});
}
}
};
const refocus_window = () => {
const window_el = menus_el.closest(".window");
if (window_el) {
window_el.dispatchEvent(new CustomEvent("refocus-window"));
}
};
const top_level_highlight = (new_index_or_menu_key) => {
const new_index = typeof new_index_or_menu_key === "string" ?
Object.keys(menus).indexOf(new_index_or_menu_key) :
new_index_or_menu_key;
if (top_level_menu_index !== -1 && top_level_menu_index !== new_index) {
top_level_menus[top_level_menu_index].menu_button_el.classList.remove("highlight");
// could close the menu here, but it's handled externally right now
}
if (new_index !== -1) {
top_level_menus[new_index].menu_button_el.classList.add("highlight");
}
top_level_menu_index = new_index;
};
menus_el.addEventListener("pointerleave", () => {
// unhighlight unless a menu is open
if (
top_level_menu_index !== -1 &&
top_level_menus[top_level_menu_index].menu_popup_el.style.display === "none"
) {
top_level_highlight(-1);
}
});
const is_disabled = item => {
if (typeof item.enabled === "function") {
return !item.enabled();
} else if (typeof item.enabled === "boolean") {
return !item.enabled;
} else {
return false;
}
};
function send_info_event(item) {
// @TODO: in a future version, give the whole menu item definition (or null)
const description = item?.description || "";
if (window.jQuery) {
// old API (using jQuery's "extraParameters"), made forwards compatible with new API (event.detail)
const event = new window.jQuery.Event("info", { detail: { description } });
const extraParam = {
toString() {
console.warn("jQuery extra parameter for info event is deprecated, use event.detail instead");
return description;
},
};
window.jQuery(menus_el).trigger(event, extraParam);
} else {
menus_el.dispatchEvent(new CustomEvent("info", { detail: { description } }));
}
}
// attached to menu bar and floating popups (which are not descendants of the menu bar)
function handleKeyDown(e) {
if (e.defaultPrevented) {
return;
}
const active_menu_popup_el = active_menu_popup?.element;
const top_level_menu = top_level_menus[top_level_menu_index];
const { menu_button_el, open_top_level_menu } = top_level_menu || {};
const menu_popup_el = active_menu_popup_el || top_level_menu?.menu_popup_el;
const parent_item_el = parent_item_el_by_popup_el.get(active_menu_popup_el);
const highlighted_item_el = menu_popup_el?.querySelector(".menu-item.highlight");
// console.log("keydown", e.key, { target: e.target, active_menu_popup_el, top_level_menu, menu_popup_el, parent_item_el, highlighted_item_el });
switch (e.key) {
case "ArrowLeft":
case "ArrowRight":
const right = e.key === "ArrowRight";
if (
highlighted_item_el?.matches(".has-submenu:not([aria-disabled='true'])") &&
(get_direction() === "ltr") === right
) {
// enter submenu
highlighted_item_el.click();
e.preventDefault();
} else if (
active_menu_popup &&
active_menu_popup.parentMenuPopup && // left/right doesn't make sense to close the top level menu
(get_direction() === "ltr") !== right
) {
// exit submenu
active_menu_popup.close(true); // This changes the active_menu_popup_el to the parent menu!
parent_item_el.setAttribute("aria-expanded", "false");
send_info_event(active_menu_popup.menuItems[active_menu_popup.itemElements.indexOf(parent_item_el)]);
e.preventDefault();
} else if (
// basically any case except if you hover to open a submenu and then press right/left
// in which case the menu is already open/focused
// This is mimicking the behavior of Explorer's menus; most Windows 98 apps work differently; @TODO: make this configurable
highlighted_item_el ||
!active_menu_popup ||
!active_menu_popup.parentMenuPopup
) {
// go to next/previous top level menu, wrapping around
// and open a new menu only if a menu was already open
const menu_was_open = menu_popup_el && menu_popup_el.style.display !== "none";
const cycle_dir = ((get_direction() === "ltr") === right) ? 1 : -1;
let new_index;
if (top_level_menu_index === -1) {
new_index = cycle_dir === 1 ? 0 : top_level_menus.length - 1;
} else {
new_index = (top_level_menu_index + cycle_dir + top_level_menus.length) % top_level_menus.length;
}
const new_top_level_menu = top_level_menus[new_index];
const target_button_el = new_top_level_menu.menu_button_el;
if (menu_was_open) {
new_top_level_menu.open_top_level_menu("keydown");
} else {
menu_button_el?.dispatchEvent(new CustomEvent("release"), {});
target_button_el.focus({ preventScroll: true });
// Note case where menu is closed, menu button is hovered, then menu bar is unhovered,
// rehovered (outside any buttons), and unhovered, and THEN you try to go to the next menu.
top_level_highlight(new_index);
}
e.preventDefault();
} // else:
// if there's no highlighted item, the user may be expecting to enter the menu even though it's already open,
// so it makes sense to do nothing (as Windows 98 does) and not go to the next/previous menu
// (although highlighting the first item might be nicer...)
break;
case "ArrowUp":
case "ArrowDown":
const down = e.key === "ArrowDown";
// if (menu_popup_el && menu_popup_el.style.display !== "none") && highlighted_item_el) {
if (active_menu_popup) {
const cycle_dir = down ? 1 : -1;
const item_els = [...menu_popup_el.querySelectorAll(".menu-item")];
const from_index = item_els.indexOf(highlighted_item_el);
let to_index = (from_index + cycle_dir + item_els.length) % item_els.length;
if (from_index === -1) {
if (down) {
to_index = 0;
} else {
to_index = item_els.length - 1;
}
}
// more fun way to do it:
// const to_index = (Math.max(from_index, -down) + cycle_dir + item_els.length) % item_els.length;
const to_item_el = item_els[to_index];
// active_menu_popup.highlight(to_index); // wouldn't work because to_index doesn't count separators
active_menu_popup.highlight(to_item_el);
send_info_event(active_menu_popup.menuItems[active_menu_popup.itemElements.indexOf(to_item_el)]);
e.preventDefault();
} else {
open_top_level_menu?.("keydown");
}
e.preventDefault();
break;
case "Escape":
if (active_menu_popup) {
// (@TODO: doesn't parent_item_el always exist?)
if (parent_item_el && parent_item_el !== menu_button_el) {
// exit submenu (@TODO: DRY further by moving more logic into close()?)
active_menu_popup.close(true); // This changes the active_menu_popup to the parent menu!
parent_item_el.setAttribute("aria-expanded", "false");
send_info_event(active_menu_popup.menuItems[active_menu_popup.itemElements.indexOf(parent_item_el)]);
} else {
// close_menus takes care of releasing the pressed state of the button as well
close_menus();
menu_button_el.focus({ preventScroll: true });
}
e.preventDefault();
} else {
const window_el = menus_el.closest(".window");
if (window_el) {
// refocus last focused control in window
// refocus-window should never focus the menu bar
// it stores the last focused control in the window and specifically not in the menus
window_el.dispatchEvent(new CustomEvent("refocus-window"));
e.preventDefault();
}
}
break;
case "Alt":
// close all menus and refocus the last focused control in the window
close_menus();
refocus_window();
e.preventDefault();
break;
case "Space":
// opens system menu in Windows 98
// (at top level)
break;
case "Enter":
if (menu_button_el === document.activeElement) {
open_top_level_menu("keydown");
e.preventDefault();
} else {
highlighted_item_el?.click();
e.preventDefault();
}
break;
default:
if (e.ctrlKey || e.metaKey) {
break;
}
// handle accelerators and first-letter navigation
const key = e.key.toLowerCase();
const item_els = active_menu_popup ?
[...menu_popup_el.querySelectorAll(".menu-item")] :
top_level_menus.map(top_level_menu => top_level_menu.menu_button_el);
const item_els_by_accelerator = {};
for (const item_el of item_els) {
const accelerator = item_el.querySelector(".menu-hotkey");
const accelerator_key = (accelerator ?
accelerator.textContent :
(item_el.querySelector(".menu-item-label") ?? item_el).textContent[0]
).toLowerCase();
item_els_by_accelerator[accelerator_key] = item_els_by_accelerator[accelerator_key] || [];
item_els_by_accelerator[accelerator_key].push(item_el);
}
const matching_item_els = item_els_by_accelerator[key] || [];
// console.log({ key, item_els, item_els_by_accelerator, matching_item_els });
if (matching_item_els.length) {
if (matching_item_els.length === 1) {
// it's unambiguous, go ahead and activate it
const menu_item_el = matching_item_els[0];
// click() doesn't work for menu buttons at the moment,
// and also we want to highlight the first item in the menu
// in that case, which doesn't happen with the mouse
const top_level_menu = top_level_menus.find(top_level_menu => top_level_menu.menu_button_el === menu_item_el);
if (top_level_menu) {
top_level_menu.open_top_level_menu("keydown");
} else {
menu_item_el.click();
}
e.preventDefault();
} else {
// cycle the menu items that match the key
let index = matching_item_els.indexOf(highlighted_item_el);
if (index === -1) {
index = 0;
} else {
index = (index + 1) % matching_item_els.length;
}
const menu_item_el = matching_item_els[index];
// active_menu_popup.highlight(index); // would very much not work
active_menu_popup.highlight(menu_item_el);
e.preventDefault();
}
}
break;
}
}
menus_el.addEventListener("keydown", handleKeyDown);
// TODO: API for context menus (i.e. floating menu popups)
function MenuPopup(menu_items, { parentMenuPopup } = {}) {
this.parentMenuPopup = parentMenuPopup;
this.menuItems = menu_items;
this.itemElements = []; // one-to-one with menuItems (note: not all itemElements have class .menu-item) (@TODO: unify terminology)
const menu_popup_el = E("div", {
class: "menu-popup",
id: `menu-popup-${uid()}`,
tabIndex: "-1",
role: "menu",
});
menu_popup_el.style.touchAction = "pan-y"; // will allow for scrolling overflowing menus in the future, but prevent event delay and double tap to zoom
menu_popup_el.style.outline = "none";
const menu_popup_table_el = E("table", { class: "menu-popup-table", role: "presentation" });
menu_popup_el.appendChild(menu_popup_table_el);
this.element = menu_popup_el;
menu_popup_by_el.set(menu_popup_el, this);
let submenus = [];
menu_popup_el.addEventListener("keydown", handleKeyDown);
menu_popup_el.addEventListener("pointerleave", () => {
// if there's a submenu popup, highlight the item for that, otherwise nothing
// could use aria-expanded for selecting this, alternatively
for (const submenu of submenus) {
if (submenu.submenu_popup_el.style.display !== "none") {
this.highlight(submenu.item_el);
return;
}
}
this.highlight(-1);
});
menu_popup_el.addEventListener("focusin", (e) => {
// prevent focus going to menu items; as designed, it works with aria-activedescendant and focus on the menu popup itself
// (on desktop when clicking (and dragging out) then pressing a key, or on mobile when tapping, a focus ring was visible, and it wouldn't go away with keyboard navigation either)
menu_popup_el.focus({ preventScroll: true });
});
let last_item_el;
this.highlight = (index_or_element) => { // index includes separators
let item_el = index_or_element;
if (typeof index_or_element === "number") {
item_el = this.itemElements[index_or_element];
}
if (last_item_el && last_item_el !== item_el) {
last_item_el.classList.remove("highlight");
}
if (item_el) {
item_el.classList.add("highlight");
menu_popup_el.setAttribute("aria-activedescendant", item_el.id);
last_item_el = item_el;
} else {
menu_popup_el.removeAttribute("aria-activedescendant");
last_item_el = null;
}
};
this.close = (focus_parent_menu_popup = true) => { // Note: won't focus menu bar buttons.
// idempotent
for (const submenu of submenus) {
submenu.submenu_popup.close(false);
}
if (focus_parent_menu_popup) {
this.parentMenuPopup?.element.focus({ preventScroll: true });
}
menu_popup_el.style.display = "none";
this.highlight(-1);
// after closing submenus, which should move the active_menu_popup to this level, move it up to the parent level
if (active_menu_popup === this) {
active_menu_popup = this.parentMenuPopup;
}
};
const add_menu_item = (parent_element, item, item_index) => {
const row_el = E("tr", { class: "menu-row" });
this.itemElements.push(row_el);
parent_element.appendChild(row_el);
if (item === MENU_DIVIDER) {
const td_el = E("td", { colspan: 4 });
const hr_el = E("hr", { class: "menu-hr" });
// hr_el.setAttribute("role", "separator"); // this is the implicit ARIA role for <hr>
// and setting it on the <tr> might cause problems due to multiple elements with the role
// hopefully it's fine that the semantic <hr> is nested?
td_el.appendChild(hr_el);
row_el.appendChild(td_el);
// Favorites menu behavior:
// hr_el.addEventListener("click", () => {
// this.highlight(-1);
// });
// Normal menu behavior:
hr_el.addEventListener("pointerenter", () => {
this.highlight(-1);
});
} else {
const item_el = row_el;
item_el.classList.add("menu-item");
item_el.id = `menu-item-${uid()}`;
item_el.tabIndex = -1; // may be needed for aria-activedescendant in some browsers?
item_el.setAttribute("role", item.checkbox ? item.checkbox.type === "radio" ? "menuitemradio" : "menuitemcheckbox" : "menuitem");
// prevent announcing the SHORTCUT (distinct from the hotkey, which would already not be announced unless it's e.g. a translated string like "새로 만들기 (&N)")
// remove_hotkey so it doesn't announce an ampersand
item_el.setAttribute("aria-label", remove_hotkey(item.label || item.item));
// include the shortcut semantically; if you want to display the shortcut differently than aria-keyshortcuts syntax,
// provide both ariaKeyShortcuts and shortcutLabel (old API: shortcut)
item_el.setAttribute("aria-keyshortcuts", item.ariaKeyShortcuts || item.shortcut || item.shortcutLabel);
if (item.description) {
item_el.setAttribute("aria-description", item.description);
}
const checkbox_area_el = E("td", { class: "menu-item-checkbox-area" });
const label_el = E("td", { class: "menu-item-label" });
const shortcut_el = E("td", { class: "menu-item-shortcut" });
const submenu_area_el = E("td", { class: "menu-item-submenu-area" });
item_el.appendChild(checkbox_area_el);
item_el.appendChild(label_el);
item_el.appendChild(shortcut_el);
item_el.appendChild(submenu_area_el);
label_el.innerHTML = display_hotkey(item.label || item.item);
shortcut_el.textContent = item.shortcut;
menu_popup_el.addEventListener("update", () => {
// item_el.disabled = is_disabled(item); // doesn't work, probably because it's a <tr>
if (is_disabled(item)) {
item_el.setAttribute("disabled", "");
item_el.setAttribute("aria-disabled", "true");
} else {
item_el.removeAttribute("disabled");
item_el.removeAttribute("aria-disabled");
}
if (item.checkbox && item.checkbox.check) {
const checked = item.checkbox.check();
item_el.setAttribute("aria-checked", checked ? "true" : "false");
}
});
// You may ask, why not call `send_info_event` in `highlight`?
// Consider the case where you hover to open a menu, and it sets highlight to none,
// it shouldn't reset the status bar. It needs to be more based on the pointer and keyboard interactions directly.
// *Maybe* it could be a parameter (to `highlight`) if that's really helpful, but it's probably not.
// *Maybe* it could look at more of the overall state within `highlight`,
// but could it distinguish hovering an outer vs an inner item if two are highlighted?
item_el.addEventListener("pointerenter", () => {
this.highlight(item_index);
send_info_event(item);
});
item_el.addEventListener("pointerleave", (event) => {
if (
menu_popup_el.style.display !== "none" && // not "left" due to closing
event.pointerType !== "touch" // not "left" as in finger lifting off
) {
send_info_event();
}
});
if (item.checkbox?.type === "radio") {
checkbox_area_el.classList.add("radio");
} else if (item.checkbox) {
checkbox_area_el.classList.add("checkbox");
}
let open_submenu, submenu_popup_el;
if (item.submenu) {
item_el.classList.add("has-submenu"); // @TODO: remove this, and use [aria-haspopup] instead (note true = menu)
submenu_area_el.classList.toggle("point-right", get_direction() === "rtl");
const submenu_popup = new MenuPopup(item.submenu, { parentMenuPopup: this });
submenu_popup_el = submenu_popup.element;
document.body?.appendChild(submenu_popup_el);
submenu_popup_el.style.display = "none";
item_el.setAttribute("aria-haspopup", "true");
item_el.setAttribute("aria-expanded", "false");
item_el.setAttribute("aria-controls", submenu_popup_el.id);
submenu_popup_by_menu_item_el.set(item_el, submenu_popup);
parent_item_el_by_popup_el.set(submenu_popup_el, item_el);
submenu_popup_el.dataset.semanticParent = menu_popup_el.id; // for $Window to understand the popup belongs to its window
menu_popup_el.setAttribute("aria-owns", `${menu_popup_el.getAttribute("aria-owns") || ""} ${submenu_popup_el.id}`);
submenu_popup_el.setAttribute("aria-labelledby", item_el.id);
open_submenu = (highlight_first = true) => {
if (submenu_popup_el.style.display !== "none") {
return;
}
if (item_el.getAttribute("aria-disabled") === "true") {
return;
}
close_submenus_at_this_level();
item_el.setAttribute("aria-expanded", "true");
submenu_popup_el.style.display = "";
submenu_popup_el.style.zIndex = get_new_menu_z_index();
submenu_popup_el.setAttribute("dir", get_direction());
if (window.inheritTheme) {
window.inheritTheme(submenu_popup_el, menu_popup_el);
}
if (!submenu_popup_el.parentElement) {
document.body.appendChild(submenu_popup_el);
}
// console.log("open_submenu — submenu_popup_el.style.zIndex", submenu_popup_el.style.zIndex, "$Window.Z_INDEX", $Window.Z_INDEX, "menus_el.closest('.window').style.zIndex", menus_el.closest(".window").style.zIndex);
// setTimeout(() => { console.log("after timeout, menus_el.closest('.window').style.zIndex", menus_el.closest(".window").style.zIndex); }, 0);
submenu_popup_el.dispatchEvent(new CustomEvent("update"), {});
if (highlight_first) {
submenu_popup.highlight(0);
send_info_event(submenu_popup.menuItems[0]);
} else {
submenu_popup.highlight(-1);
// send_info_event(); // no, keep the status bar text!
}
const rect = item_el.getBoundingClientRect();
let submenu_popup_rect = submenu_popup_el.getBoundingClientRect();
submenu_popup_el.style.position = "absolute";
submenu_popup_el.style.left = `${(get_direction() === "rtl" ? rect.left - submenu_popup_rect.width : rect.right) + window.scrollX}px`;
submenu_popup_el.style.top = `${rect.top + window.scrollY}px`;
submenu_popup_rect = submenu_popup_el.getBoundingClientRect();
// This is surely not the cleanest way of doing this,
// and the logic is not very robust in the first place,
// but I want to get RTL support done and so I'm mirroring this in the simplest way possible.
if (get_direction() === "rtl") {
if (submenu_popup_rect.left < 0) {
submenu_popup_el.style.left = `${rect.right}px`;
submenu_popup_rect = submenu_popup_el.getBoundingClientRect();
if (submenu_popup_rect.right > innerWidth) {
submenu_popup_el.style.left = `${innerWidth - submenu_popup_rect.width}px`;
}
}
} else {
if (submenu_popup_rect.right > innerWidth) {
submenu_popup_el.style.left = `${rect.left - submenu_popup_rect.width}px`;
submenu_popup_rect = submenu_popup_el.getBoundingClientRect();
if (submenu_popup_rect.left < 0) {
submenu_popup_el.style.left = "0";
}
}
}
submenu_popup_el.focus({ preventScroll: true });
active_menu_popup = submenu_popup;
};
submenus.push({
item_el,
submenu_popup_el,
submenu_popup,
});
function close_submenus_at_this_level() {
for (const { submenu_popup, item_el } of submenus) {
submenu_popup.close(false);
item_el.setAttribute("aria-expanded", "false");
}
menu_popup_el.focus({ preventScroll: true });
}
// It should close when hovering a different higher level menu
// after a delay, unless the mouse returns to the submenu.
// If you return the mouse from a submenu into its parent
// *directly onto the parent menu item*, it stays open, but if you cross other menu items
// in the parent menu, (@TODO:) it'll close after the delay even if you land on the parent menu item.
// Once a submenu opens (completing its animation if it has one),
// - up/down should navigate the submenu (although it should not show as focused right away)
// (i.e. up/down always navigate the most-nested open submenu, as long as it's not animating, in which case nothing happens)
// - @TODO: the submenu cancels its closing timeout (if you've moved outside all menus, say)
// (but if you move outside menus AFTER the submenu has opened, it should start the closing timeout)
// @TODO: make this more robust in general! Make some automated tests.
let open_tid, close_tid;
submenu_popup_el.addEventListener("pointerenter", () => {
if (open_tid) { clearTimeout(open_tid); open_tid = null; }
if (close_tid) { clearTimeout(close_tid); close_tid = null; }
});
item_el.addEventListener("pointerenter", () => {
// @TODO: don't cancel close timer? in Windows 98 it'll still close after a delay if you hover the submenu's parent item
if (open_tid) { clearTimeout(open_tid); open_tid = null; }
if (close_tid) { clearTimeout(close_tid); close_tid = null; }
open_tid = setTimeout(() => {
open_submenu(false);
}, 501); // @HACK: slightly longer than close timer so it doesn't close immediately
});
item_el.addEventListener("pointerleave", () => {
if (open_tid) { clearTimeout(open_tid); open_tid = null; }
});
menu_popup_el.addEventListener("pointerenter", (event) => {
// console.log(event.target.closest(".menu-item"));
if (event.target.closest(".menu-item") === item_el) {
return;
}
if (!close_tid) {
// This is a little confusing, with timers per-item...
// @TODO: try doing this with just one or two timers.
// if (submenus.some(submenu => submenu.submenu_popup_el.style.display !== "none")) {
if (submenu_popup_el.style.display !== "none") {
close_tid = setTimeout(() => {
if (!window.debugKeepMenusOpen) {
// close_submenu();
close_submenus_at_this_level();
}
}, 500);
}
}
});
// keep submenu open while mouse is outside any parent menus
// (@TODO: what if it goes to another parent menu though?)
menu_popup_el.addEventListener("pointerleave", () => {
if (close_tid) { clearTimeout(close_tid); close_tid = null; }
});
item_el.addEventListener("pointerdown", () => { open_submenu(false); });
}
let just_activated = false; // to prevent double-activation from pointerup + click
const item_action = () => {
if (just_activated) {
return;
}
just_activated = true;
setTimeout(() => { just_activated = false; }, 10);
if (item.checkbox) {
if (item.checkbox.toggle) {
item.checkbox.toggle();
}
menu_popup_el.dispatchEvent(new CustomEvent("update"), {});
} else if (item.action) {
close_menus();
refocus_window(); // before action, so things like copy/paste have a better chance of working
item.action();
}
};
// pointerup is for gliding to menu items to activate
item_el.addEventListener("pointerup", e => {
if (e.pointerType === "mouse" && e.button !== 0) {
return;
}
if (e.pointerType === "touch") {
// Will use click instead; otherwise focus is lost on a delay: if it opens a dialog for example,
// you have to hold down on the menu item for a bit otherwise it'll blur the dialog after opening.
// I think this is caused by the pointer falling through to elements without touch-action defined.
// RIGHT NOW, gliding to menu items isn't supported for touch anyways,
// although I'd like to support it in the future.
// Well, it might have accessibility problems, so maybe not. I think this is fine.
return;
}
item_el.click();
});
item_el.addEventListener("click", e => {
if (item.submenu) {
open_submenu(true);
} else {
item_action();
}
});
}
};
if (menu_items.length === 0) {
menu_items = [{
label: "(Empty)",
enabled: false,
}];
}
let init_index = 0;
for (const item of menu_items) {
if (item.radioItems) {
const tbody = E("tbody", { role: "group" }); // multiple tbody elements are allowed, can be used for grouping rows,
// and in this case providing an ARIA role for the radio group.
if (item.ariaLabel) {
tbody.setAttribute("aria-label", item.ariaLabel);
}
for (const radio_item of item.radioItems) {
radio_item.checkbox = {
type: "radio",
check: () => radio_item.value === item.getValue(),
toggle: () => {
item.setValue(radio_item.value);
},
};
add_menu_item(tbody, radio_item, init_index++);
}
menu_popup_table_el.appendChild(tbody);
} else {
add_menu_item(menu_popup_table_el, item, init_index++);
}
}
}
// let this_click_opened_the_menu = false;
const make_menu_button = (menus_key, menu_items) => {
const menu_button_el = E("div", {
class: "menu-button",
"aria-expanded": "false",
"aria-haspopup": "true",
role: "menuitem",
});
menus_el.appendChild(menu_button_el);
const menu_popup = new MenuPopup(menu_items);
const menu_popup_el = menu_popup.element;
document.body?.appendChild(menu_popup_el);
submenu_popup_by_menu_item_el.set(menu_button_el, menu_popup);
parent_item_el_by_popup_el.set(menu_popup_el, menu_button_el);
menu_button_el.id = `menu-button-${menus_key}-${uid()}`;
menu_popup_el.dataset.semanticParent = menu_button_el.id; // for $Window to understand the popup belongs to its window
menu_button_el.setAttribute("aria-controls", menu_popup_el.id);
menu_popup_el.setAttribute("aria-labelledby", menu_button_el.id);
menus_el.setAttribute("aria-owns", `${menus_el.getAttribute("aria-owns") || ""} ${menu_popup_el.id}`);
const update_position_from_containing_bounds = () => {
const rect = menu_button_el.getBoundingClientRect();
let popup_rect = menu_popup_el.getBoundingClientRect();
menu_popup_el.style.position = "absolute";
menu_popup_el.style.left = `${(get_direction() === "rtl" ? rect.right - popup_rect.width : rect.left) + window.scrollX}px`;
menu_popup_el.style.top = `${rect.bottom + window.scrollY}px`;
const uncorrected_rect = menu_popup_el.getBoundingClientRect();
// rounding down is needed for RTL layout for the rightmost menu, to prevent a scrollbar
if (Math.floor(uncorrected_rect.right) > innerWidth) {
menu_popup_el.style.left = `${innerWidth - uncorrected_rect.width}px`;
}
if (Math.ceil(uncorrected_rect.left) < 0) {
menu_popup_el.style.left = "0px";
}
};
window.addEventListener("resize", update_position_from_containing_bounds);
menu_popup_el.addEventListener("update", update_position_from_containing_bounds);
// update_position_from_containing_bounds(); // will be called when the menu is opened
const menu_id = menus_key.replace("&", "").replace(/ /g, "-").toLowerCase();
menu_button_el.classList.add(`${menu_id}-menu-button`);
// menu_popup_el.id = `${menu_id}-menu-popup-${uid()}`; // id is created by MenuPopup and changing it breaks the data-semantic-parent relationship
menu_popup_el.style.display = "none";
menu_button_el.innerHTML = display_hotkey(menus_key);
menu_button_el.tabIndex = -1;
menu_button_el.setAttribute("aria-haspopup", "true");
menu_button_el.setAttribute("aria-controls", menu_popup_el.id);
menu_button_el.addEventListener("focus", () => {
top_level_highlight(menus_key);
});
menu_button_el.addEventListener("pointerdown", e => {
if (menu_button_el.classList.contains("active")) {
menu_button_el.dispatchEvent(new CustomEvent("release", {}));
refocus_window();
e.preventDefault(); // needed for refocus_window() to work
} else {
open_top_level_menu(e.type);
}
});
menu_button_el.addEventListener("pointermove", e => {
top_level_highlight(menus_key);
if (e.pointerType === "touch") {
return;
}
if (selecting_menus) {
open_top_level_menu(e.type);
}
});
function open_top_level_menu(type = "other") {
const new_index = Object.keys(menus).indexOf(menus_key);
if (new_index === top_level_menu_index && menu_button_el.getAttribute("aria-expanded") === "true") {
return; // already open
}
close_menus();
menu_button_el.classList.add("active");
menu_button_el.setAttribute("aria-expanded", "true");
menu_popup_el.style.display = "";
menu_popup_el.style.zIndex = get_new_menu_z_index();
menu_popup_el.setAttribute("dir", get_direction());
if (window.inheritTheme) {
window.inheritTheme(menu_popup_el, menus_el);
}
if (!menu_popup_el.parentElement) {
document.body.appendChild(menu_popup_el);
}
// console.log("pointerdown (possibly simulated) — menu_popup_el.style.zIndex", menu_popup_el.style.zIndex, "$Window.Z_INDEX", $Window.Z_INDEX, "menus_el.closest('.window').style.zIndex", menus_el.closest(".window").style.zIndex);
// setTimeout(() => { console.log("after timeout, menus_el.closest('.window').style.zIndex", menus_el.closest(".window").style.zIndex); }, 0);
top_level_highlight(menus_key);
menu_popup_el.dispatchEvent(new CustomEvent("update"), {});
selecting_menus = true;
menu_popup_el.focus({ preventScroll: true });
active_menu_popup = menu_popup;
if (type === "keydown") {
menu_popup.highlight(0);
send_info_event(menu_popup.menuItems[0]);
} else {
send_info_event(); // @TODO: allow descriptions on top level menus
}
};
menu_button_el.addEventListener("release", () => {
selecting_menus = false;
menu_button_el.classList.remove("active");
if (!window.debugKeepMenusOpen) {
menu_popup.close(true);
menu_button_el.setAttribute("aria-expanded", "false");
}
menus_el.dispatchEvent(new CustomEvent("default-info", {}));
});
top_level_menus.push({
menu_button_el,
menu_popup_el,
menus_key,
hotkey: get_hotkey(menus_key),
open_top_level_menu,
});
};
for (const menu_key in menus) {
make_menu_button(menu_key, menus[menu_key]);
}
window.addEventListener("keydown", e => {
// close any errant menus
// taking care not to interfere with regular Escape key behavior
// @TODO: listen for menus_el removed from DOM, and close menus there
if (
!document.activeElement ||
!document.activeElement.closest || // window or document
!document.activeElement.closest(".menus, .menu-popup")
) {
if (e.key === "Escape") {
if (active_menu_popup) {
close_menus();
e.preventDefault();
}
}
}
});
// window.addEventListener("blur", close_menus);
window.addEventListener("blur", (event) => {
// hack for Pinball (in 98.js.org) where it triggers fake blur events
// in order to pause the game
if (!event.isTrusted) {
return;
}
close_menus();
});
function close_menus_on_click_outside(event) {
if (event.target?.closest?.(".menus") === menus_el || event.target?.closest?.(".menu-popup")) {
return;
}
// window.console && console.log(event.type, "occurred outside of menus (on ", event.target, ") so...");
close_menus();
top_level_highlight(-1);
}
window.addEventListener("pointerdown", close_menus_on_click_outside);
window.addEventListener("pointerup", close_menus_on_click_outside);
window.addEventListener("focusout", (event) => {
// if not still in menus, unhighlight (e.g. if you hit Escape to unfocus the menus)
if (event.relatedTarget?.closest?.(".menus") === menus_el || event.relatedTarget?.closest?.(".menu-popup")) {
return;
}
close_menus();
// Top level buttons should no longer be highlighted due to focus, but still may be highlighted due to hover.
top_level_highlight(top_level_menus.findIndex(({ menu_button_el }) => menu_button_el.matches(":hover")));
});
let keyboard_scope_elements = [];
function set_keyboard_scope(...elements) {
for (const el of keyboard_scope_elements) {
el.removeEventListener("keydown", keyboard_scope_keydown);
}
keyboard_scope_elements = elements;
for (const el of keyboard_scope_elements) {
el.addEventListener("keydown", keyboard_scope_keydown);
}
}
function keyboard_scope_keydown(e) {
// Close menus if the user presses almost any key combination
// e.g. if you look in the menu to remember a shortcut,
// and then use the shortcut.
if (
(e.ctrlKey || e.metaKey) && // Ctrl or Command held down
// and anything then pressed other than Ctrl or Command
e.key !== "Control" &&
e.key !== "Meta"
) {
close_menus();
return;
}
if (e.defaultPrevented) {
return; // closing menus above is meant to be done when activating unrelated shortcuts
// but stuff after this is should not be handled at the same time as something else
}
if (e.altKey && !e.shiftKey && !e.ctrlKey && !e.metaKey) { // Alt held
const menu = top_level_menus.find((menu) =>
menu.hotkey.toLowerCase() === e.key.toLowerCase()
);
if (menu) {
e.preventDefault();
menu.open_top_level_menu("keydown");
}
}
}
set_keyboard_scope(window);
this.element = menus_el;
this.closeMenus = close_menus;
this.setKeyboardScope = set_keyboard_scope;
}
exports.MenuBar = MenuBar;
exports.MENU_DIVIDER = MENU_DIVIDER;
})(window);

View File

@@ -0,0 +1,49 @@
/* Source: https://www.deviantart.com/tpenguinltg/art/Blue-525167751 */
/* License: https://creativecommons.org/licenses/by-sa/3.0/ */
/* This is a generated file. */
:root {
--checker: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAG0lEQVQYV2O8/OTH/8vPfjAwLjv14b+uFAcDAG90ChC/AKc5AAAAAElFTkSuQmCC");
--button-active-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h192v192h-192v-192z%22%20fill%3D%22rgb(49%2C%20131%2C%20221)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22rgb(166%2C%20202%2C%20240)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--button-normal-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22rgb(211%2C%20228%2C%20248)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22rgb(166%2C%20202%2C%20240)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22rgb(49%2C%20131%2C%20221)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22rgb(166%2C%20202%2C%20240)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--inset-deep-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22rgb(211%2C%20228%2C%20248)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22rgb(49%2C%20131%2C%20221)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22rgb(166%2C%20202%2C%20240)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22rgb(166%2C%20202%2C%20240)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--button-default-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22rgb(211%2C%20228%2C%20248)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h96v32h-64v64h-32v-96z%22%20fill%3D%22rgb(166%2C%20202%2C%20240)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M160%2064h32v128h-128v-32h96v-96z%22%20fill%3D%22rgb(49%2C%20131%2C%20221)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M96%2096h64v64h-64v-64z%22%20fill%3D%22rgb(166%2C%20202%2C%20240)%22%2F%3E%0A%09%09%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22256%22%20height%3D%22256%22%20stroke-width%3D%2264%22%20stroke%3D%22rgb(0%2C%200%2C%200)%22%20fill%3D%22none%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 96 / 3px;
--button-default-active-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h192v192h-192v-192z%22%20fill%3D%22rgb(49%2C%20131%2C%20221)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22rgb(166%2C%20202%2C%20240)%22%2F%3E%0A%09%09%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22256%22%20height%3D%22256%22%20stroke-width%3D%2264%22%20stroke%3D%22rgb(0%2C%200%2C%200)%22%20fill%3D%22none%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--scrollbar-arrows-ButtonText: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAW0lEQVQ4T2NkGGSAcZC5h4FWDvrPwEC02ShqkR0EkkAHuBxMyEKYWYQ8jKEOXQOyo/A5BuZwqqvBZiA+3xMbilQLIWqlcUJRimwPzjRELcdQZA6hREeR4eRoBgBoXhAK6oiMhwAAAABJRU5ErkJggg==");
--scrollbar-arrows-GrayText: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAYElEQVQ4T2NkGGSAcZC5h4EmDjJsvvv/fK0yUWajq4VrAkmghxYuQwlZCDOLkKOwqUPxBbKj8DkG5nBaqMEIVny+JzYUqRZC1ErghKIU2R6caYhajqHUHKJyAqWWkKIfANj2QArAsbtdAAAAAElFTkSuQmCC");
--scrollbar-arrows-ButtonHilight: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAYElEQVQ4T2NkGGSAcZC5h4EmDrr85Md/XRkOosxGVwvXBJJADy1chhKyEGYWIUdhU4fiC2RH4XMMzOG0UIMRrPh8T2woUi2EqJXACUUpsj040xC1HEOpOUTlBEotIUU/AHnlQApCJ0jDAAAAAElFTkSuQmCC");
--scrollbar-size: 13px;
--scrollbar-button-inner-size: 9px;
--ActiveTitle: rgb(0, 0, 128);
--Background: rgb(58, 110, 165);
--Hilight: rgb(51, 153, 255);
--HilightText: rgb(255, 255, 255);
--TitleText: rgb(255, 255, 255);
--Window: rgb(255, 255, 255);
--WindowText: rgb(0, 0, 0);
--Scrollbar: rgb(211, 228, 248);
--InactiveTitle: rgb(49, 131, 221);
--Menu: rgb(166, 202, 240);
--WindowFrame: rgb(0, 0, 0);
--MenuText: rgb(0, 0, 0);
--ActiveBorder: rgb(166, 202, 240);
--InactiveBorder: rgb(166, 202, 240);
--AppWorkspace: rgb(49, 131, 221);
--ButtonFace: rgb(166, 202, 240);
--ButtonShadow: rgb(49, 131, 221);
--GrayText: rgb(49, 131, 221);
--ButtonText: rgb(0, 0, 0);
--InactiveTitleText: rgb(0, 0, 128);
--ButtonHilight: rgb(211, 228, 248);
--ButtonDkShadow: rgb(0, 0, 0);
--ButtonLight: rgb(166, 202, 240);
--InfoText: rgb(0, 0, 0);
--InfoWindow: rgb(225, 225, 255);
--GradientActiveTitle: rgb(16, 132, 208);
--GradientInactiveTitle: rgb(49, 131, 221);
--ButtonAlternateFace: rgb(192, 192, 192);
--HotTrackingColor: rgb(0, 0, 128);
--MenuHilight: rgb(0, 0, 128);
--MenuBar: rgb(166, 202, 240);
}
/*# sourceMappingURL=blue.css.map */

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,108 @@
.menus,
.menu-popup,
.os-window,
.os-window .window-titlebar,
.os-window .window-title {
cursor: default;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.os-window {
contain: layout; /* contain: paint; seems to clip children to the padding-box, including for interaction, not just painting; it breaks being able to grab resize handles over the border */
/* overflow: hidden; is also not usable for the same reason */
/* I might be able to do either with overflow-clip-margin however (@TODO) */
display: flex;
flex-direction: column;
/* will-change: width height left top; */
}
.window-content {
flex: 1;
min-height: 0px;
/* Text overflowing the window frame is really ugly!
overflow: hidden; would make it harder to enable scrollbars (overflow: auto !important)
We want to allow scrollbars to be enabled easily (but not enable them),
and we want to clip to the border of the window, without contents overlapping the border at all. */
contain: layout paint;
}
.os-window .window-titlebar,
body > .window-titlebar {
display: flex;
flex-direction: row;
align-items: center;
white-space: nowrap;
overflow: hidden;
flex-shrink: 0;
}
.os-window .window-title-area {
position: relative;
flex: 1;
}
.os-window .window-titlebar .icon {
vertical-align: bottom;
}
.os-window.maximized .handle,
.os-window.minimized-without-taskbar .handle {
display: none; /* prevent resizing when window is minimized */
}
/* Fix dragging things (like windows) over iframes */
.dragging iframe {
pointer-events: none;
}
.menus {
display: flex;
flex: 0 0 auto;
flex-wrap: wrap;
}
.menu-popup {
position: absolute;
box-sizing: border-box;
}
.menu-popup-table {
border-collapse: collapse;
}
.menu-button,
.menu-item {
white-space: nowrap;
max-width: 100%;
overflow: hidden;
/* text-overflow: ellipsis; might imply a dialog */
}
.menu-hr {
display: block !important;
height: 0;
width: auto;
}
.menu-hotkey {
display: inline !important;
}
.menu-item-checkbox-area,
.menu-item-submenu-area {
min-width: 16px;
}
.menu-item-checkbox-area,
.menu-item-submenu-area {
text-align: center;
}
/* .window-content .button-group {
width: 85px;
}
.window-content .button-group > button {
width: 95%;
padding: 3px 5px;
} */
::before,
::after {
pointer-events: none;
}
/*# sourceMappingURL=layout.css.map */

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/layout.css"],"names":[],"mappings":"AAAA;;;;;CAKC,eAAe;CACf,yBAAiB;IAAjB,sBAAiB;KAAjB,qBAAiB;SAAjB,iBAAiB;AAClB;;AAEA;CACC,eAAe,EAAE,yKAAyK;CAC1L,6DAA6D;CAC7D,2EAA2E;CAC3E,aAAa;CACb,sBAAsB;CACtB,wCAAwC;AACzC;AACA;CACC,OAAO;CACP,eAAe;CACf;;;mGAGkG;IAC/F,qBAAqB;AACzB;;AAEA;;CAEC,aAAa;CACb,mBAAmB;CACnB,mBAAmB;CACnB,mBAAmB;CACnB,gBAAgB;CAChB,cAAc;AACf;AACA;CACC,kBAAkB;CAClB,OAAO;AACR;;AAEA;CACC,sBAAsB;AACvB;;AAEA;;CAEC,aAAa,EAAE,8CAA8C;AAC9D;;AAEA,oDAAoD;AACpD;CACC,oBAAoB;AACrB;;AAEA;CACC,aAAa;CACb,cAAc;CACd,eAAe;AAChB;AACA;CACC,kBAAkB;CAClB,sBAAsB;AACvB;AACA;CACC,yBAAyB;AAC1B;AACA;;CAEC,mBAAmB;IAChB,eAAe;IACf,gBAAgB;IAChB,kDAAkD;AACtD;AACA;CACC,yBAAyB;CACzB,SAAS;CACT,WAAW;AACZ;AACA;CACC,0BAA0B;AAC3B;AACA;;CAEC,eAAe;AAChB;AACA;;CAEC,kBAAkB;AACnB;;AAEA;;;;;;GAMG;;AAEH;;CAEC,oBAAoB;AACrB","file":"layout.css","sourcesContent":[".menus,\n.menu-popup,\n.os-window,\n.os-window .window-titlebar,\n.os-window .window-title {\n\tcursor: default;\n\tuser-select: none;\n}\n\n.os-window {\n\tcontain: layout; /* contain: paint; seems to clip children to the padding-box, including for interaction, not just painting; it breaks being able to grab resize handles over the border */\n\t/* overflow: hidden; is also not usable for the same reason */\n\t/* I might be able to do either with overflow-clip-margin however (@TODO) */\n\tdisplay: flex;\n\tflex-direction: column;\n\t/* will-change: width height left top; */\n}\n.window-content {\n\tflex: 1;\n\tmin-height: 0px;\n\t/* Text overflowing the window frame is really ugly!\n\toverflow: hidden; would make it harder to enable scrollbars (overflow: auto !important)\n\tWe want to allow scrollbars to be enabled easily (but not enable them),\n\tand we want to clip to the border of the window, without contents overlapping the border at all. */\n contain: layout paint;\n}\n\n.os-window .window-titlebar,\nbody > .window-titlebar {\n\tdisplay: flex;\n\tflex-direction: row;\n\talign-items: center;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\tflex-shrink: 0;\n}\n.os-window .window-title-area {\n\tposition: relative;\n\tflex: 1;\n}\n\n.os-window .window-titlebar .icon {\n\tvertical-align: bottom;\n}\n\n.os-window.maximized .handle,\n.os-window.minimized-without-taskbar .handle {\n\tdisplay: none; /* prevent resizing when window is minimized */\n}\n\n/* Fix dragging things (like windows) over iframes */\n.dragging iframe {\n\tpointer-events: none;\n}\n\n.menus {\n\tdisplay: flex;\n\tflex: 0 0 auto;\n\tflex-wrap: wrap;\n}\n.menu-popup {\n\tposition: absolute;\n\tbox-sizing: border-box;\n}\n.menu-popup-table {\n\tborder-collapse: collapse;\n}\n.menu-button,\n.menu-item {\n\twhite-space: nowrap;\n max-width: 100%;\n overflow: hidden;\n /* text-overflow: ellipsis; might imply a dialog */\n}\n.menu-hr {\n\tdisplay: block !important;\n\theight: 0;\n\twidth: auto;\n}\n.menu-hotkey {\n\tdisplay: inline !important;\n}\n.menu-item-checkbox-area,\n.menu-item-submenu-area {\n\tmin-width: 16px;\n}\n.menu-item-checkbox-area,\n.menu-item-submenu-area {\n\ttext-align: center;\n}\n\n/* .window-content .button-group {\n\twidth: 85px;\n}\n.window-content .button-group > button {\n\twidth: 95%;\n\tpadding: 3px 5px;\n} */\n\n::before,\n::after {\n\tpointer-events: none;\n}\n"]}

View File

@@ -0,0 +1,106 @@
.menus,
.menu-popup,
.os-window,
.os-window .window-titlebar,
.os-window .window-title {
cursor: default;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.os-window {
contain: layout; /* contain: paint; seems to clip children to the padding-box, including for interaction, not just painting; it breaks being able to grab resize handles over the border */
/* overflow: hidden; is also not usable for the same reason */
/* I might be able to do either with overflow-clip-margin however (@TODO) */
display: flex;
flex-direction: column;
/* will-change: width height left top; */
}
.window-content {
flex: 1;
min-height: 0px;
/* Text overflowing the window frame is really ugly!
overflow: hidden; would make it harder to enable scrollbars (overflow: auto !important)
We want to allow scrollbars to be enabled easily (but not enable them),
and we want to clip to the border of the window, without contents overlapping the border at all. */
contain: layout paint;
}
.os-window .window-titlebar,
body > .window-titlebar {
display: flex;
flex-direction: row;
align-items: center;
white-space: nowrap;
overflow: hidden;
flex-shrink: 0;
}
.os-window .window-title-area {
position: relative;
flex: 1;
}
.os-window .window-titlebar .icon {
vertical-align: bottom;
}
.os-window.maximized .handle,
.os-window.minimized-without-taskbar .handle {
display: none; /* prevent resizing when window is minimized */
}
/* Fix dragging things (like windows) over iframes */
.dragging iframe {
pointer-events: none;
}
.menus {
display: flex;
flex: 0 0 auto;
flex-wrap: wrap;
}
.menu-popup {
position: absolute;
box-sizing: border-box;
}
.menu-popup-table {
border-collapse: collapse;
}
.menu-button,
.menu-item {
white-space: nowrap;
max-width: 100%;
overflow: hidden;
/* text-overflow: ellipsis; might imply a dialog */
}
.menu-hr {
display: block !important;
height: 0;
width: auto;
}
.menu-hotkey {
display: inline !important;
}
.menu-item-checkbox-area,
.menu-item-submenu-area {
min-width: 16px;
}
.menu-item-checkbox-area,
.menu-item-submenu-area {
text-align: center;
}
/* .window-content .button-group {
width: 85px;
}
.window-content .button-group > button {
width: 95%;
padding: 3px 5px;
} */
::before,
::after {
pointer-events: none;
}

View File

@@ -0,0 +1,372 @@
function parseINIString(data) {
var regex = {
section: /^\s*\[\s*([^\]]*)\s*\]\s*$/,
param: /^\s*([^=]+?)\s*=\s*(.*?)\s*$/,
comment: /^\s*;.*$/
};
var value = {};
var lines = data.split(/[\r\n]+/);
var section = null;
lines.forEach(function (line) {
if (regex.comment.test(line)) {
return;
} else if (regex.param.test(line)) {
var match = line.match(regex.param);
if (section) {
value[section][match[1]] = match[2];
} else {
value[match[1]] = match[2];
}
} else if (regex.section.test(line)) {
var match = line.match(regex.section);
value[match[1]] = {};
section = match[1];
} else if (line.length == 0 && section) {
section = null;
};
});
return value;
}
// takes a CSSStyleDeclaration or simple object of CSS properties
function renderThemeGraphics(cssProperties) {
var getProp = (propName) => cssProperties.getPropertyValue ? cssProperties.getPropertyValue(propName) : cssProperties[propName];
var canvas = document.createElement("canvas");
canvas.width = canvas.height = 2;
var ctx = canvas.getContext("2d");
ctx.fillStyle = getProp("--ButtonFace");
ctx.fillRect(0, 1, 1, 1);
ctx.fillRect(1, 0, 1, 1);
ctx.fillStyle = getProp("--ButtonHilight");
ctx.fillRect(0, 0, 1, 1);
ctx.fillRect(1, 1, 1, 1);
var checker = `url("${canvas.toDataURL()}")`;
var scrollbar_size = parseInt(getProp("--scrollbar-size"));
if (!isFinite(scrollbar_size)) {
scrollbar_size = 13;
}
var scrollbar_button_inner_size = scrollbar_size - 4;
// I don't know the exact formula, so approximate and special-case it for now
// (It may very well *be* special cased, tho)
var arrow_size = Math.floor(0.3 * scrollbar_size);
if (scrollbar_size < 16 && scrollbar_size > 13) arrow_size -= 1;
var arrow_width = arrow_size * 2 - 1;
var arrow_canvas = document.createElement("canvas");
var arrow_ctx = arrow_canvas.getContext("2d");
arrow_canvas.width = arrow_width;
arrow_canvas.height = arrow_size;
arrow_ctx.fillStyle = "white";
for (let y = 0; y < arrow_size; y += 1) {
for (let x = y; x < arrow_width - y; x += 1) {
arrow_ctx.fillRect(x, y, 1, 1);
}
}
canvas.width = scrollbar_button_inner_size * 4;
canvas.height = scrollbar_button_inner_size;
let i = 0;
for (let horizontal = 0; horizontal < 2; horizontal += 1) {
for (let decrement = 0; decrement < 2; decrement += 1) {
ctx.save();
ctx.translate(i * scrollbar_button_inner_size, 0);
ctx.translate(scrollbar_button_inner_size / 2, scrollbar_button_inner_size / 2);
// ctx.rotate(i * Math.PI / 2);
if (horizontal) {
ctx.rotate(-Math.PI / 2);
}
if (decrement) {
ctx.scale(1, -1);
}
ctx.translate(-scrollbar_button_inner_size / 2, -scrollbar_button_inner_size / 2);
ctx.drawImage(arrow_canvas, ~~(scrollbar_button_inner_size / 2 - arrow_width / 2), ~~(scrollbar_button_inner_size / 2 - arrow_size / 2));
ctx.restore();
i += 1;
}
}
ctx.save();
ctx.globalCompositeOperation = "source-in";
ctx.fillStyle = getProp("--ButtonText");
ctx.fillRect(0, 0, canvas.width, canvas.height);
var scrollbar_arrows_ButtonText = `url("${canvas.toDataURL()}")`;
ctx.fillStyle = getProp("--GrayText");
ctx.fillRect(0, 0, canvas.width, canvas.height);
var scrollbar_arrows_GrayText = `url("${canvas.toDataURL()}")`;
ctx.fillStyle = getProp("--ButtonHilight");
ctx.fillRect(0, 0, canvas.width, canvas.height);
var scrollbar_arrows_ButtonHilight = `url("${canvas.toDataURL()}")`;
// ctx.fillStyle = "red";
// ctx.fillRect(0, 0, canvas.width, canvas.height);
// canvas.style.background = "rgba(0, 0, 0, 0.2)";
// $("h1").append(arrow_canvas).append(canvas);
ctx.restore();
function border_image(border_size, svg_contents) {
var base_size = 8;
var border_size = border_size;
var scale = 32;
var slice_size = border_size * scale;
var view_size = base_size * scale;
// transform causes janky buggy garbage
// var svg = `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="${view_size}px" height="${view_size}px" viewBox="0 0 ${view_size} ${view_size}">
// <g transform="scale(${scale})">
// ${svg_contents}
// </g>
// </svg>`;
var svg = `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="${view_size}px" height="${view_size}px" viewBox="0 0 ${view_size} ${view_size}">
${svg_contents.replace(/(d|x|y|width|height|stroke-width)="[^"]*"/g, (attr) => attr.replace(/\d+/g, (n) => n * scale))}
</svg>`;
var url = `data:image/svg+xml,${encodeURIComponent(svg)}`;
return `url("${url}") ${slice_size} / ${border_size}px`;
}
var button_active_border_image = border_image(2, `
<path d="M0 0h8v8h-8v-8z" fill="${getProp("--ButtonDkShadow")}"/>
<path d="M1 1h6v6h-6v-6z" fill="${getProp("--ButtonShadow")}"/>
<path d="M2 2h4v4h-4v-4z" fill="${getProp("--ButtonFace")}"/>
`);
var button_default_active_border_image = border_image(2, `
<path d="M0 0h8v8h-8v-8z" fill="${getProp("--ButtonDkShadow")}"/>
<path d="M1 1h6v6h-6v-6z" fill="${getProp("--ButtonShadow")}"/>
<path d="M2 2h4v4h-4v-4z" fill="${getProp("--ButtonFace")}"/>
<rect x="0" y="0" width="8" height="8" stroke-width="2" stroke="${getProp("--WindowFrame")}" fill="none"/>
`);
// TODO: rename
var button_normal_border_image = border_image(2, `
<path d="M0 0h7v1h-6v6h-1v-7z" fill="${getProp("--ButtonHilight")}"/>
<path d="M7 0h1v8h-8v-1h7v-7z" fill="${getProp("--ButtonDkShadow")}"/>
<path d="M1 1h5v1h-4v4h-1v-5z" fill="${getProp("--ButtonLight")}"/>
<path d="M6 1h1v6h-6v-1h5v-5z" fill="${getProp("--ButtonShadow")}"/>
<path d="M2 2h4v4h-4v-4z" fill="${getProp("--ButtonFace")}"/>
`);
var inset_deep_border_image = border_image(2, `
<path d="M0 0h7v1h-6v6h-1v-7z" fill="${getProp("--ButtonDkShadow")}"/>
<path d="M7 0h1v8h-8v-1h7v-7z" fill="${getProp("--ButtonHilight")}"/>
<path d="M1 1h5v1h-4v4h-1v-5z" fill="${getProp("--ButtonShadow")}"/>
<path d="M6 1h1v6h-6v-1h5v-5z" fill="${getProp("--ButtonLight")}"/>
<path d="M2 2h4v4h-4v-4z" fill="${getProp("--ButtonFace")}"/>
`);
var button_default_border_image = border_image(3, `
<path d="M0 0h8v8h-8v-8z" fill="${getProp("--ButtonDkShadow")}"/>
<path d="M1 1h5v1h-4v4h-1v-5z" fill="${getProp("--ButtonHilight")}"/>
<path d="M2 2h3v1h-2v2h-1v-3z" fill="${getProp("--ButtonLight")}"/>
<path d="M5 2h1v4h-4v-1h3v-3z" fill="${getProp("--ButtonShadow")}"/>
<path d="M3 3h2v2h-2v-2z" fill="${getProp("--ButtonFace")}"/>
<rect x="0" y="0" width="8" height="8" stroke-width="2" stroke="${getProp("--WindowFrame")}" fill="none"/>
`);
return {
"--checker": checker,
"--button-active-border-image": button_active_border_image,
"--button-normal-border-image": button_normal_border_image,
"--inset-deep-border-image": inset_deep_border_image,
"--button-default-border-image": button_default_border_image,
"--button-default-active-border-image": button_default_active_border_image,
"--scrollbar-arrows-ButtonText": scrollbar_arrows_ButtonText,
"--scrollbar-arrows-GrayText": scrollbar_arrows_GrayText,
"--scrollbar-arrows-ButtonHilight": scrollbar_arrows_ButtonHilight,
"--scrollbar-size": `${scrollbar_size}px`,
"--scrollbar-button-inner-size": `${scrollbar_button_inner_size}px`,
};
}
function getThemeCSSProperties(element) {
const keys = [
"--checker",
"--button-active-border-image",
"--button-normal-border-image",
"--inset-deep-border-image",
"--button-default-border-image",
"--button-default-active-border-image",
"--scrollbar-arrows-ButtonText",
"--scrollbar-arrows-GrayText",
"--scrollbar-arrows-ButtonHilight",
"--scrollbar-size",
"--scrollbar-button-inner-size",
"--ActiveBorder",
"--ActiveTitle",
"--AppWorkspace",
"--Background",
"--ButtonAlternateFace",
"--ButtonDkShadow",
"--ButtonFace",
"--ButtonHilight",
"--ButtonLight",
"--ButtonShadow",
"--ButtonText",
"--GradientActiveTitle",
"--GradientInactiveTitle",
"--GrayText",
"--Hilight",
"--HilightText",
"--HotTrackingColor",
"--InactiveBorder",
"--InactiveTitle",
"--InactiveTitleText",
"--InfoText",
"--InfoWindow",
"--Menu",
"--MenuText",
"--Scrollbar",
"--TitleText",
"--Window",
"--WindowFrame",
"--WindowText",
];
const style = window.getComputedStyle(element);
const result = {};
for (const key of keys) {
result[key] = style.getPropertyValue(key);
}
return result;
}
function inheritTheme(target, source) {
applyCSSProperties(getThemeCSSProperties(source), { element: target, recurseIntoIframes: true });
}
// Parse NonClientMetrics
// https://docs.microsoft.com/en-us/windows/win32/controls/themesfileformat-overview?redirectedfrom=MSDN#metrics-section
// https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types
// using https://github.com/toji/js-struct
// var NonClientMetricsStruct = Struct.create(
// Struct.uint32("cbSize"),
// Struct.int32("iBorderWidth"),
// Struct.int32("iScrollWidth"),
// Struct.int32("iScrollHeight"),
// Struct.int32("iCaptionWidth"),
// Struct.int32("iCaptionHeight"),
// // after that, it may be W or A
// // LOGFONTW lfCaptionFont;
// // int iSmCaptionWidth;
// // int iSmCaptionHeight;
// // LOGFONTW lfSmCaptionFont;
// // int iMenuWidth;
// // int iMenuHeight;
// // LOGFONTW lfMenuFont;
// // LOGFONTW lfStatusFont;
// // LOGFONTW lfMessageFont;
// // int iPaddedBorderWidth;
// );
// var NonClientMetrics_buffer = new Uint8Array(NonClientMetrics_string.split(" ").map((str)=> parseInt(str))).buffer;
// NonClientMetricsStruct.readStructs(NonClientMetrics_buffer, 0, 1)[0];
function parseThemeFileString(themeIni) {
// .theme is a renamed .ini text file
// .themepack is a renamed .cab file, and parsing it as .ini seems to work well enough for the most part, as the .ini data appears in plain,
// but it may not if compression is enabled for the .cab file
var theme = parseINIString(themeIni);
var colors = theme["Control Panel\\Colors"];
if (!colors) {
alert("Invalid theme file, no [Control Panel\\Colors] section");
console.log(theme);
return;
}
for (var k in colors) {
// for .themepack file support, just ignore bad keys that were parsed
if (k.match(/\W/)) {
delete colors[k];
} else {
colors[k] = `rgb(${colors[k].split(" ").join(", ")})`;
}
}
var cssProperties = {};
for (var k in colors) {
cssProperties[`--${k}`] = colors[k];
}
cssProperties = Object.assign(renderThemeGraphics(cssProperties), cssProperties);
return cssProperties;
}
function applyCSSProperties(cssProperties, options = {}) {
// @TODO: clean up deprecated argument handling
let element, recurseIntoIframes;
if ("tagName" in options) {
console.warn("deprecated: use options argument to applyCSSProperties, e.g. applyCSSProperties(cssProperties, { element: document.documentElement, recurseIntoIframes: true })");
element = options;
recurseIntoIframes = false;
} else {
({ element = document.documentElement, recurseIntoIframes = false } = options);
}
var getProp = (propName) => cssProperties.getPropertyValue ? cssProperties.getPropertyValue(propName) : cssProperties[propName];
for (var k in cssProperties) {
element.style.setProperty(k, getProp(k));
}
// iframe theme propagation
if (recurseIntoIframes) {
var iframes = element.querySelectorAll("iframe");
for (var i = 0; i < iframes.length; i++) {
try {
applyCSSProperties(cssProperties, { element: iframes[i].contentDocument.documentElement, recurseIntoIframes: true });
} catch (error) {
// ignore
// @TODO: share warning with $Window's iframe handling
}
}
}
}
function makeThemeCSSFile(cssProperties) {
var css = `
/* This is a generated file. */
:root {
`;
for (var k in cssProperties) {
css += `\t${k}: ${cssProperties[k]};\n`;
}
css += `}
`;
return css;
}
// @TODO: should this be part of theme graphics generation?
// I want to figure out a better way to do dynamic theme features,
// where it works with the CSS cascade as much as possible
function makeBlackToInsetFilter() {
if (document.getElementById("os-gui-black-to-inset-filter")) {
return;
}
const svg_xml = `
<svg style="position: absolute; pointer-events: none; bottom: 100%;">
<defs>
<filter id="os-gui-black-to-inset-filter" x="0" y="0" width="1px" height="1px">
<feColorMatrix
in="SourceGraphic"
type="matrix"
values="
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
-1000 -1000 -1000 1 0
"
result="black-parts-isolated"
/>
<feFlood result="shadow-color" flood-color="var(--ButtonShadow)"/>
<feFlood result="hilight-color" flood-color="var(--ButtonHilight)"/>
<feOffset in="black-parts-isolated" dx="1" dy="1" result="offset"/>
<feComposite in="hilight-color" in2="offset" operator="in" result="hilight-colored-offset"/>
<feComposite in="shadow-color" in2="black-parts-isolated" operator="in" result="shadow-colored"/>
<feMerge>
<feMergeNode in="hilight-colored-offset"/>
<feMergeNode in="shadow-colored"/>
</feMerge>
</filter>
</defs>
</svg>
`;
const $svg = $(svg_xml);
$svg.appendTo("body");
}

View File

@@ -0,0 +1,49 @@
/* Source: https://www.deviantart.com/tpenguinltg/art/Peggy-s-Pastels-505540096 */
/* License: https://creativecommons.org/licenses/by-sa/3.0/ */
/* This is a generated file. */
:root {
--checker: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAG0lEQVQYV2P89eDJ/18PnzEwfjl46j+bvBQDAHJ8Cj5el2f8AAAAAElFTkSuQmCC");
--button-active-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22rgb(64%2C%2064%2C%2064)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h192v192h-192v-192z%22%20fill%3D%22rgb(222%2C%2069%2C%2096)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22rgb(244%2C%20193%2C%20202)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--button-normal-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22rgb(250%2C%20224%2C%20228)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22rgb(64%2C%2064%2C%2064)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22rgb(247%2C%20219%2C%20215)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22rgb(222%2C%2069%2C%2096)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22rgb(244%2C%20193%2C%20202)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--inset-deep-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22rgb(64%2C%2064%2C%2064)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22rgb(250%2C%20224%2C%20228)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22rgb(222%2C%2069%2C%2096)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22rgb(247%2C%20219%2C%20215)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22rgb(244%2C%20193%2C%20202)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--button-default-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22rgb(64%2C%2064%2C%2064)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22rgb(250%2C%20224%2C%20228)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h96v32h-64v64h-32v-96z%22%20fill%3D%22rgb(247%2C%20219%2C%20215)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M160%2064h32v128h-128v-32h96v-96z%22%20fill%3D%22rgb(222%2C%2069%2C%2096)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M96%2096h64v64h-64v-64z%22%20fill%3D%22rgb(244%2C%20193%2C%20202)%22%2F%3E%0A%09%09%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22256%22%20height%3D%22256%22%20stroke-width%3D%2264%22%20stroke%3D%22rgb(0%2C%200%2C%200)%22%20fill%3D%22none%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 96 / 3px;
--button-default-active-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22rgb(64%2C%2064%2C%2064)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h192v192h-192v-192z%22%20fill%3D%22rgb(222%2C%2069%2C%2096)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22rgb(244%2C%20193%2C%20202)%22%2F%3E%0A%09%09%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22256%22%20height%3D%22256%22%20stroke-width%3D%2264%22%20stroke%3D%22rgb(0%2C%200%2C%200)%22%20fill%3D%22none%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--scrollbar-arrows-ButtonText: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAW0lEQVQ4T2NkGGSAcZC5h4FWDvrPwEC02ShqkR0EkkAHuBxMyEKYWYQ8jKEOXQOyo/A5BuZwqqvBZiA+3xMbilQLIWqlcUJRimwPzjRELcdQZA6hREeR4eRoBgBoXhAK6oiMhwAAAABJRU5ErkJggg==");
--scrollbar-arrows-GrayText: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAYElEQVQ4T2NkGGSAcZC5h4EmDrrnmvBfafcCosxGVwvXBJJADy1chhKyEGYWIUdhU4fiC2RH4XMMzOG0UIMRrPh8T2woUi2EqJXACUUpsj040xC1HEOpOUTlBEotIUU/ANEWQAoG78U6AAAAAElFTkSuQmCC");
--scrollbar-arrows-ButtonHilight: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAYElEQVQ4T2NkGGSAcZC5h4EmDvr14Ml/NgUZosxGVwvXBJJADy1chhKyEGYWIUdhU4fiC2RH4XMMzOG0UIMRrPh8T2woUi2EqJXACUUpsj040xC1HEOpOUTlBEotIUU/AIJVQAqPLmKjAAAAAElFTkSuQmCC");
--scrollbar-size: 13px;
--scrollbar-button-inner-size: 9px;
--Scrollbar: rgb(250, 224, 228);
--Background: rgb(162, 219, 210);
--ActiveTitle: rgb(0, 191, 188);
--InactiveTitle: rgb(0, 187, 169);
--Menu: rgb(244, 193, 202);
--Window: rgb(244, 255, 255);
--WindowFrame: rgb(0, 0, 0);
--MenuText: rgb(0, 0, 0);
--WindowText: rgb(0, 0, 0);
--TitleText: rgb(255, 255, 255);
--ActiveBorder: rgb(244, 193, 202);
--InactiveBorder: rgb(244, 193, 202);
--AppWorkspace: rgb(255, 184, 182);
--Hilight: rgb(162, 219, 210);
--HilightText: rgb(0, 0, 0);
--ButtonFace: rgb(244, 193, 202);
--ButtonShadow: rgb(222, 69, 96);
--GrayText: rgb(222, 69, 96);
--ButtonText: rgb(0, 0, 0);
--InactiveTitleText: rgb(0, 85, 77);
--ButtonHilight: rgb(250, 224, 228);
--ButtonDkShadow: rgb(64, 64, 64);
--ButtonLight: rgb(247, 219, 215);
--InfoText: rgb(0, 0, 0);
--InfoWindow: rgb(204, 255, 255);
--ButtonAlternateFace: rgb(181, 181, 181);
--HotTrackingColor: rgb(0, 128, 128);
--GradientActiveTitle: rgb(202, 156, 185);
--GradientInactiveTitle: rgb(236, 145, 162);
--MenuHilight: rgb(162, 219, 210);
--MenuBar: rgb(244, 193, 202);
}
/*# sourceMappingURL=peggys-pastels.css.map */

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,993 @@
:root {
/* These resources are generated. */
/* JS: makeThemeCSSFile(renderThemeGraphics(getComputedStyle(document.documentElement))) */
--checker: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAG0lEQVQYV2P8/////4MHDzIwHjhw4L+9vT0DAHAFCj6esq3FAAAAAElFTkSuQmCC");
--button-active-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h192v192h-192v-192z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--button-normal-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--inset-deep-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--button-default-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h96v32h-64v64h-32v-96z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M160%2064h32v128h-128v-32h96v-96z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M96%2096h64v64h-64v-64z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%09%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22256%22%20height%3D%22256%22%20stroke-width%3D%2264%22%20stroke%3D%22%20rgb(0%2C%200%2C%200)%22%20fill%3D%22none%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 96 / 3px;
--button-default-active-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h192v192h-192v-192z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%09%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22256%22%20height%3D%22256%22%20stroke-width%3D%2264%22%20stroke%3D%22%20rgb(0%2C%200%2C%200)%22%20fill%3D%22none%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--scrollbar-arrows-ButtonText: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAW0lEQVQ4T2NkGGSAcZC5h4FWDvrPwEC02ShqkR0EkkAHuBxMyEKYWYQ8jKEOXQOyo/A5BuZwqqvBZiA+3xMbilQLIWqlcUJRimwPzjRELcdQZA6hREeR4eRoBgBoXhAK6oiMhwAAAABJRU5ErkJggg==");
--scrollbar-arrows-GrayText: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAYElEQVQ4T2NkGGSAcZC5h4EmDmpoaPjf0NBAlNnoauGaQBLooYXLUEIWwswi5Chs6lB8gewofI6BOZwWajCCFZ/viQ1FqoUQtRI4oShFtgdnGqKWYyg1h6icQKklpOgHAM9mQArEvm5+AAAAAElFTkSuQmCC");
--scrollbar-arrows-ButtonHilight: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAYElEQVQ4T2NkGGSAcZC5h4EmDvr///9/RkZGosxGVwvXBJJADy1chhKyEGYWIUdhU4fiC2RH4XMMzOG0UIMRrPh8T2woUi2EqJXACUUpsj040xC1HEOpOUTlBEotIUU/AKXFQAqyTJ6DAAAAAElFTkSuQmCC");
--scrollbar-size: 13px;
--scrollbar-button-inner-size: 9px;
/* Colors */
--ActiveBorder: rgb(192, 192, 192);
--ActiveTitle: rgb(0, 0, 128);
--AppWorkspace: rgb(128, 128, 128);
--Background: rgb(0, 128, 128);
--ButtonAlternateFace: rgb(180, 180, 180);
--ButtonDkShadow: rgb(0, 0, 0);
--ButtonFace: rgb(192, 192, 192);
--ButtonHilight: rgb(255, 255, 255);
--ButtonLight: rgb(223, 223, 223);
--ButtonShadow: rgb(128, 128, 128);
--ButtonText: rgb(0, 0, 0);
--GradientActiveTitle: rgb(16, 132, 208);
--GradientInactiveTitle: rgb(181, 181, 181);
--GrayText: rgb(128, 128, 128);
--Hilight: rgb(0, 0, 128);
--HilightText: rgb(255, 255, 255);
--HotTrackingColor: rgb(0, 0, 255);
--InactiveBorder: rgb(192, 192, 192);
--InactiveTitle: rgb(128, 128, 128);
--InactiveTitleText: rgb(192, 192, 192);
--InfoText: rgb(0, 0, 0);
--InfoWindow: rgb(255, 255, 225);
--Menu: rgb(192, 192, 192);
--MenuText: rgb(0, 0, 0);
--Scrollbar: rgb(192, 192, 192);
--TitleText: rgb(255, 255, 255);
--Window: rgb(255, 255, 255);
--WindowFrame: rgb(0, 0, 0);
--WindowText: rgb(0, 0, 0);
}
.inset-deep {
border-style: solid;
border-width: 1px;
border-color: rgb(128, 128, 128) rgb(255, 255, 255) rgb(255, 255, 255) rgb(128, 128, 128);
border-color: var(--ButtonShadow) var(--ButtonHilight) var(--ButtonHilight) var(--ButtonShadow);
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
color: rgb(0, 0, 0);
color: var(--ButtonText);
/* as fallback */
position: relative;
/* for pseudo element(s) */
-o-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
-o-border-image: var(--inset-deep-border-image);
border-image: var(--inset-deep-border-image);
border-color: rgb(128, 128, 128);
border-color: var(--ButtonShadow);
border-style: solid;
border-width: 2px 2px;
}
.outset-deep {
border-style: solid;
border-width: 1px;
border-color: rgb(255, 255, 255) rgb(128, 128, 128) rgb(128, 128, 128) rgb(255, 255, 255);
border-color: var(--ButtonHilight) var(--ButtonShadow) var(--ButtonShadow) var(--ButtonHilight);
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
color: rgb(0, 0, 0);
color: var(--ButtonText);
/* as fallback */
position: relative;
/* for pseudo element(s) */
-o-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
-o-border-image: var(--button-normal-border-image);
border-image: var(--button-normal-border-image);
border-color: rgb(223, 223, 223) rgb(128, 128, 128) rgb(128, 128, 128) rgb(223, 223, 223);
border-color: var(--ButtonLight) var(--ButtonShadow) var(--ButtonShadow) var(--ButtonLight);
border-style: solid;
border-width: 2px 2px;
}
.inset-shallow {
border-style: solid;
border-width: 1px;
border-color: rgb(128, 128, 128) rgb(255, 255, 255) rgb(255, 255, 255) rgb(128, 128, 128);
border-color: var(--ButtonShadow) var(--ButtonHilight) var(--ButtonHilight) var(--ButtonShadow);
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
color: rgb(0, 0, 0);
color: var(--ButtonText);
}
.outset-shallow {
border-style: solid;
border-width: 1px;
border-color: rgb(255, 255, 255) rgb(128, 128, 128) rgb(128, 128, 128) rgb(255, 255, 255);
border-color: var(--ButtonHilight) var(--ButtonShadow) var(--ButtonShadow) var(--ButtonHilight);
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
color: rgb(0, 0, 0);
color: var(--ButtonText);
}
button {
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
color: rgb(0, 0, 0);
color: var(--ButtonText);
}
button:not(.lightweight) {
outline: none; /* replaced with inner dotted focus ring (which is admittedly not so prominent...) */ border-style: solid; border-width: 1px; border-color: rgb(255, 255, 255) rgb(128, 128, 128) rgb(128, 128, 128) rgb(255, 255, 255); border-color: var(--ButtonHilight) var(--ButtonShadow) var(--ButtonShadow) var(--ButtonHilight); background-color: rgb(192, 192, 192); background-color: var(--ButtonFace); color: rgb(0, 0, 0); color: var(--ButtonText); /* as fallback */ position: relative; /* for pseudo element(s) */ -o-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px; border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px; -o-border-image: var(--button-normal-border-image); border-image: var(--button-normal-border-image); border-color: rgb(223, 223, 223) rgb(128, 128, 128) rgb(128, 128, 128) rgb(223, 223, 223); border-color: var(--ButtonLight) var(--ButtonShadow) var(--ButtonShadow) var(--ButtonLight); border-style: solid; border-width: 2px 2px; border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px; border-image: var(--button-normal-border-image);
}
button:not(.lightweight).default {
-o-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h96v32h-64v64h-32v-96z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M160%2064h32v128h-128v-32h96v-96z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M96%2096h64v64h-64v-64z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%09%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22256%22%20height%3D%22256%22%20stroke-width%3D%2264%22%20stroke%3D%22%20rgb(0%2C%200%2C%200)%22%20fill%3D%22none%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 96 / 3px;
border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h96v32h-64v64h-32v-96z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M160%2064h32v128h-128v-32h96v-96z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M96%2096h64v64h-64v-64z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%09%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22256%22%20height%3D%22256%22%20stroke-width%3D%2264%22%20stroke%3D%22%20rgb(0%2C%200%2C%200)%22%20fill%3D%22none%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 96 / 3px;
-o-border-image: var(--button-default-border-image);
border-image: var(--button-default-border-image);
}
button:not(.lightweight):enabled:hover:active {
-o-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h192v192h-192v-192z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h192v192h-192v-192z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
-o-border-image: var(--button-active-border-image);
border-image: var(--button-active-border-image);
}
button:not(.lightweight).default:enabled:hover:active {
-o-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h192v192h-192v-192z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%09%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22256%22%20height%3D%22256%22%20stroke-width%3D%2264%22%20stroke%3D%22%20rgb(0%2C%200%2C%200)%22%20fill%3D%22none%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h192v192h-192v-192z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%09%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22256%22%20height%3D%22256%22%20stroke-width%3D%2264%22%20stroke%3D%22%20rgb(0%2C%200%2C%200)%22%20fill%3D%22none%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
-o-border-image: var(--button-default-active-border-image);
border-image: var(--button-default-active-border-image);
}
/* TODO: offset content on press! */
/* (this would need a child ELEMENT, wouldn't work with text nodes as direct descendants:) */
/*button:active > * {
position: relative;
left: 1px;
top: 1px;
}
*/
/* also, this is more complicated; see Paint; the tool buttons translate when being pushed and when depressed, and these add together */
/* omg, a thought... what if I used feDisplacementMap SVG filter... */
button:not(.lightweight):focus::before {
content: "";
display: block;
position: absolute;
left: 2px;
top: 2px;
right: 2px;
bottom: 2px;
border: 1px dotted rgb(0, 0, 0);
border: 1px dotted var(--ButtonDkShadow); /* ?? */
/* TODO: get exact inset dimensions, and have corners without dots ideally */
/* (could use outline instead of ::before at this point) */
}
button.lightweight {
outline: none; /* these buttons are not usually keyboard accessible, or the focus it shown just by inset (menu buttons) */
border-style: solid;
border-width: 1px;
border-color: transparent;
}
/* TODO: recommend preventing focus on click for lightweight buttons */
button.lightweight:enabled:hover {
border-style: solid;
border-width: 1px;
border-color: rgb(255, 255, 255) rgb(128, 128, 128) rgb(128, 128, 128) rgb(255, 255, 255);
border-color: var(--ButtonHilight) var(--ButtonShadow) var(--ButtonShadow) var(--ButtonHilight);
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
color: rgb(0, 0, 0);
color: var(--ButtonText);
}
button.lightweight:enabled:hover:active, button.lightweight.pressing, button.lightweight.pressed {
border-style: solid;
border-width: 1px;
border-color: rgb(128, 128, 128) rgb(255, 255, 255) rgb(255, 255, 255) rgb(128, 128, 128);
border-color: var(--ButtonShadow) var(--ButtonHilight) var(--ButtonHilight) var(--ButtonShadow);
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
color: rgb(0, 0, 0);
color: var(--ButtonText);
}
button:disabled {
color: rgb(128, 128, 128);
color: var(--GrayText);
text-shadow: 1px 1px 0px rgb(255, 255, 255);
text-shadow: 1px 1px 0px var(--ButtonHilight);
}
button:not(.lightweight).toggle:enabled:hover:active, button:not(.lightweight).pressing {
border-style: solid;
border-width: 1px;
border-color: rgb(128, 128, 128) rgb(255, 255, 255) rgb(255, 255, 255) rgb(128, 128, 128);
border-color: var(--ButtonShadow) var(--ButtonHilight) var(--ButtonHilight) var(--ButtonShadow);
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
color: rgb(0, 0, 0);
color: var(--ButtonText);
/* as fallback */
position: relative;
/* for pseudo element(s) */
-o-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
-o-border-image: var(--inset-deep-border-image);
border-image: var(--inset-deep-border-image);
}
button:not(.lightweight).toggle:enabled:hover:active, button:not(.lightweight).pressing {
border-color: rgb(128, 128, 128);
border-color: var(--ButtonShadow);
border-style: solid;
border-width: 2px 2px;
}
button:not(.lightweight).toggle.selected, button:not(.lightweight).pressed {
border-style: solid;
border-width: 1px;
border-color: rgb(128, 128, 128) rgb(255, 255, 255) rgb(255, 255, 255) rgb(128, 128, 128);
border-color: var(--ButtonShadow) var(--ButtonHilight) var(--ButtonHilight) var(--ButtonShadow);
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
color: rgb(0, 0, 0);
color: var(--ButtonText);
/* as fallback */
position: relative;
/* for pseudo element(s) */
-o-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
-o-border-image: var(--inset-deep-border-image);
border-image: var(--inset-deep-border-image);
}
button:not(.lightweight).toggle.selected, button:not(.lightweight).pressed {
border-color: rgb(128, 128, 128);
border-color: var(--ButtonShadow);
border-style: solid;
border-width: 2px 2px;
}
button:not(.lightweight).toggle.selected, button:not(.lightweight).pressed {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAG0lEQVQYV2P8/////4MHDzIwHjhw4L+9vT0DAHAFCj6esq3FAAAAAElFTkSuQmCC") repeat;
background: var(--checker) repeat;
-ms-interpolation-mode: nearest-neighbor;
image-rendering: -moz-crisp-edges;
image-rendering: pixelated;
}
.os-window .window-titlebar,
body > .window-titlebar {
background: rgb(0, 0, 128);
background: var(--ActiveTitle);
background: linear-gradient(to right, rgb(0, 0, 128) 0%, rgb(16, 132, 208) 100%);
background: linear-gradient(to right, var(--ActiveTitle) 0%, var(--GradientActiveTitle) 100%);
color: rgb(255, 255, 255);
color: var(--TitleText);
}
.os-window .window-titlebar, body > .window-titlebar {
font-family: 'Segoe UI', sans-serif;
font-size: 12px;
}
.os-window.rtl .window-titlebar {
background: linear-gradient(to left, rgb(0, 0, 128) 0%, rgb(16, 132, 208) 100%);
background: linear-gradient(to left, var(--ActiveTitle) 0%, var(--GradientActiveTitle) 100%);
}
.os-window:not(.tool-window) .window-titlebar,
body > .window-titlebar {
font-weight: bold;
}
.os-window:not(.focused) .window-titlebar {
background: darkgray;
background: linear-gradient(to right, rgb(128, 128, 128) 0%, rgb(181, 181, 181) 100%);
background: linear-gradient(to right, var(--InactiveTitle) 0%, var(--GradientInactiveTitle) 100%);
color: rgb(192, 192, 192);
color: var(--InactiveTitleText);
}
.os-window.rtl:not(.focused) .window-titlebar {
background: linear-gradient(to left, rgb(128, 128, 128) 0%, rgb(181, 181, 181) 100%);
background: linear-gradient(to left, var(--InactiveTitle) 0%, var(--GradientInactiveTitle) 100%);
}
.os-window {
/* Needed for when maximized, otherwise would be provided by %outset-deep */
background: rgb(192, 192, 192);
background: var(--ButtonFace);
/* background: var(--Window); */
/*color: var(--WindowText);*/
/*border: 1px solid var(--WindowFrame);*/
/* TODO: use window-specific theme colors; also different types of windows */
}
.os-window:not(.maximized) {
border-style: solid;
border-width: 1px;
border-color: rgb(255, 255, 255) rgb(128, 128, 128) rgb(128, 128, 128) rgb(255, 255, 255);
border-color: var(--ButtonHilight) var(--ButtonShadow) var(--ButtonShadow) var(--ButtonHilight);
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
color: rgb(0, 0, 0);
color: var(--ButtonText);
/* as fallback */
position: relative;
/* for pseudo element(s) */
-o-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
-o-border-image: var(--button-normal-border-image);
border-image: var(--button-normal-border-image);
border-color: rgb(223, 223, 223) rgb(128, 128, 128) rgb(128, 128, 128) rgb(223, 223, 223);
border-color: var(--ButtonLight) var(--ButtonShadow) var(--ButtonShadow) var(--ButtonLight);
border-style: solid;
border-width: 2px 2px;
padding: 2px;
}
.window-button {
display: block;
width: 16px;
height: 14px;
padding: 0;
margin: 2px 0;
}
.window-button-icon {
display: block;
/* background-image: url("images/titlebar-buttons.png"); */
--sprite-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAAKCAYAAADo3z3CAAAAoUlEQVRIS9VVWw7AIAib9z/0FpZgCOFRgpluf9MClhYdV++7gfDhYLxYDw+UyiHd5F8S5lr6zNa6Xpv/KwhHOahQpLB1+CwfycgYrwmE0WK8MTsIR1aOGsR+NYkkYzN5/pGwVA9xA/diq8LeHCKuQxQ+aoYt2yJWtpSNZth0edRpGVC5eGQcSg4hXLml3fdpBeHs8evWyPKX9ruXVqnYCeAHA8IyC9K2kmkAAAAASUVORK5CYII=");
--sprite-y: 0;
-ms-interpolation-mode: nearest-neighbor;
image-rendering: -moz-crisp-edges;
image-rendering: pixelated;
width: 12px;
height: 10px;
position: relative;
pointer-events: none;
}
.os-window .window-button:enabled:hover:active .window-button-icon,
.os-window .window-button.pressing .window-button-icon {
top: 1px;
left: 1px;
}
.window-button:disabled .window-button-icon {
/* filter: saturate(0%) opacity(50%); fallback */
/* filter: url("#os-gui-black-to-inset-filter"); */
}
.window-button .window-button-icon::before,
.window-button .window-button-icon::after {
content: "";
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
-webkit-mask-image: var(--sprite-image);
mask-image: var(--sprite-image);
-webkit-mask-position: var(--sprite-x) var(--sprite-y);
mask-position: var(--sprite-x) var(--sprite-y);
background-color: rgb(0, 0, 0);
background-color: var(--ButtonText);
}
.window-button:disabled .window-button-icon::before {
background-color: rgb(255, 255, 255);
background-color: var(--ButtonHilight);
left: 1px;
top: 1px;
}
.window-button:enabled .window-button-icon::after {
display: none;
}
.window-button:disabled .window-button-icon::after {
background-color: rgb(128, 128, 128);
background-color: var(--GrayText);
}
.window-action-close .window-button-icon {
--sprite-x: calc(-3 * 13px - 1px);
}
.window-action-maximize .window-button-icon {
--sprite-x: calc(-1 * 13px - 1px);
}
.window-action-restore .window-button-icon {
--sprite-x: calc(-2 * 13px - 1px);
}
.window-action-minimize .window-button-icon {
--sprite-x: calc(-0 * 13px - 1px);
}
.window-close-button {
margin-left: 2px;
margin-right: 2px;
}
.os-window.tool-window .window-close-button {
width: 11px;
height: 11px;
}
.os-window.tool-window .window-close-button .window-button-icon {
width: 7px;
height: 7px;
--sprite-x: 7px;
}
.os-window .window-title-area {
height: 16px;
}
.os-window.tool-window .window-title-area {
height: 14px;
}
.os-window .window-titlebar {
height: 18px;
}
.os-window.tool-window .window-titlebar {
height: 15px;
}
.os-window .window-title {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
display: inline-block !important;
margin: 0;
padding: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-left: 2px;
}
.menus {
background: rgb(192, 192, 192);
background: var(--Menu);
color: rgb(0, 0, 0);
color: var(--MenuText);
}
.os-window:not(.focused) .menus {
color: rgb(128, 128, 128);
color: var(--GrayText);
}
.menus *, .menu-popup * {
font-family: 'Segoe UI', sans-serif;
font-size: 12px;
}
.menu-button {
box-sizing: border-box;
/* Using a balanced border to offset the contents on press */
border: 0px solid transparent;
border-top-width: 0px;
border-left-width: 0px;
border-bottom-width: 1px;
border-right-width: 1px;
/* Unfortunately, everything else has to be balanced by 1px (very carefully) in many places. */
height: 18px; /* (EFFECTIVELY NORMAL but...) +1px -1px: +1px due to transparent border, but needs to be metrically same as visual height for the menu popup positioning, so I used bottom: -1px on the pseudo element to get it so this can be -1px to 18px again */
line-height: 1;
margin-top: 1px; /* NORMAL MARGIN */
/* margin-bottom: 1px; consumed margin */
margin-right: -1px; /* keep menu items directly abutting */
/* need the overflow visible for the psuedo element's top and left borders to be visible */
overflow: visible;
-webkit-clip-path: inset(0 1px 0 0);
clip-path: inset(0 1px 0 0); /* clipping text off inside the border, without clipping the border (somewhat mysteriously) */
padding: 2px 5px; /* NORMAL PADDING; I took great lengths to make this easily changable from outside code (padding is an obvious strategy for making the press offset effect, but I think this is a common thing you might want to customize) */
position: relative;
outline: 0;
/* @extend button.lightweight; */
background: rgb(192, 192, 192);
background: var(--Menu);
}
.menu-button.highlight.active {
border-top-width: 1px;
border-left-width: 1px;
border-bottom-width: 0px;
border-right-width: 0px;
}
/* Note: In Windows 98, normal menu bars have an inset highlight if you use Esc and then the arrow keys,
whereas Explorer's menu bars are outset and match the hover effect, which I feel makes more sense,
so I think I'll immitate that. */
/* Also, to prevent duplicate highlight (via keyboard + mouse), and lingering highlight with touch, I'm using a class, rather than :hover/:focus/:active */
.menu-button.highlight::after {
content: "";
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: -1px;
box-shadow: 1px 1px 0 rgb(255, 255, 255) inset, -1px -1px 0 rgb(128, 128, 128) inset;
box-shadow: 1px 1px 0 var(--ButtonHilight) inset, -1px -1px 0 var(--ButtonShadow) inset;
}
.menu-button.highlight.active::after {
box-shadow: 1px 1px 0 rgb(128, 128, 128) inset, -1px -1px 0 rgb(255, 255, 255) inset;
box-shadow: 1px 1px 0 var(--ButtonShadow) inset, -1px -1px 0 var(--ButtonHilight) inset;
/* counteract the balanced border, in order to render this border, in the proper place */
left: -1px;
top: -1px;
right: 1px;
bottom: 0;
}
.menu-popup {
display: block;
padding: 2px;
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
border-top: 1px solid rgb(192, 192, 192);
border-top: 1px solid var(--ButtonFace);
border-left: 1px solid rgb(192, 192, 192);
border-left: 1px solid var(--ButtonFace);
border-right: 1px solid rgb(0, 0, 0);
border-right: 1px solid var(--ButtonDkShadow);
border-bottom: 1px solid rgb(0, 0, 0);
border-bottom: 1px solid var(--ButtonDkShadow);
box-shadow: 1px 1px 0 rgb(255, 255, 255) inset, -1px -1px 0 rgb(128, 128, 128) inset;
box-shadow: 1px 1px 0 var(--ButtonHilight) inset, -1px -1px 0 var(--ButtonShadow) inset;
background: rgb(192, 192, 192);
background: var(--Menu);
color: rgb(0, 0, 0);
color: var(--MenuText);
}
.menu-popup td {
padding: 0 1px;
}
.menu-item {
padding: 1px 3px;
margin: 2px;
height: 17px;
}
.menu-item[disabled] {
color: rgb(128, 128, 128);
color: var(--GrayText);
text-shadow: 0.8px 0.8px 0px rgb(255, 255, 255);
text-shadow: 0.8px 0.8px 0px var(--ButtonHilight);
}
.menu-item.highlight:not([disabled]),
.menu-item.active:not([disabled]) {
color: rgb(255, 255, 255);
color: var(--HilightText);
}
.menu-item.highlight,
.menu-item.active {
background: rgb(0, 0, 128);
background: var(--Hilight);
text-shadow: none;
outline: 0;
}
.menu-item .menu-item-shortcut {
padding-left: 10px;
}
/* Note: viewBox is needed for scaling the SVG, used in JS Paint's Eye Gaze Mode */
.menu-item-checkbox-area::after {
-webkit-mask-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg' style='fill:currentColor;display:inline-block;vertical-align:middle' %3E%3Cpath d='M5 7v3l2 2 5-5V4L7 9Z'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg' style='fill:currentColor;display:inline-block;vertical-align:middle' %3E%3Cpath d='M5 7v3l2 2 5-5V4L7 9Z'/%3E%3C/svg%3E");
}
.menu-item-checkbox-area.radio::after {
-webkit-mask-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg' style='fill:currentColor;display:inline-block;vertical-align:middle' %3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg' style='fill:currentColor;display:inline-block;vertical-align:middle' %3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E");
}
.has-submenu .menu-item-submenu-area::after {
-webkit-mask-image: url("data:image/svg+xml, %3Csvg width='16' height='16' viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg' style='fill:currentColor;display:inline-block;vertical-align:middle' %3E%3Cpath d='m6 4 4 4-4 4z'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml, %3Csvg width='16' height='16' viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg' style='fill:currentColor;display:inline-block;vertical-align:middle' %3E%3Cpath d='m6 4 4 4-4 4z'/%3E%3C/svg%3E");
}
.has-submenu .menu-item-submenu-area.point-right::after {
transform: scaleX(-1);
}
.menu-item-checkbox-area::after,
.menu-item-submenu-area::after {
content: "";
display: block;
width: 16px;
height: 16px;
/* no background means it's invisible by default here (masking transparent gives transparent, i.e. nothing) */
}
.menu-item[aria-checked=true] .menu-item-checkbox-area::after,
.menu-item.has-submenu .menu-item-submenu-area::after {
/* makes it visible */
background: currentColor;
}
.menu-hr {
border: 0;
border-top: 1px solid rgb(128, 128, 128);
border-top: 1px solid var(--ButtonShadow);
border-bottom: 1px solid rgb(255, 255, 255);
border-bottom: 1px solid var(--ButtonHilight);
margin: 0;
margin-top: 3px;
margin-bottom: 4px;
}
.menu-hotkey {
text-decoration: underline;
}
.menu-hotkey::-moz-selection {
/* prevent weird looking white underlines if menubar is contained in a selection, possible in the demo (minute edge case) */
text-decoration-color: rgb(0, 0, 0) !important;
text-decoration-color: var(--MenuText) !important;
}
.menu-hotkey::selection {
/* prevent weird looking white underlines if menubar is contained in a selection, possible in the demo (minute edge case) */
-webkit-text-decoration-color: rgb(0, 0, 0) !important;
text-decoration-color: rgb(0, 0, 0) !important;
-webkit-text-decoration-color: var(--MenuText) !important;
text-decoration-color: var(--MenuText) !important;
}
::-moz-selection {
background-color: rgb(0, 0, 128);
background-color: var(--Hilight);
color: rgb(255, 255, 255);
color: var(--HilightText);
}
::selection {
background-color: rgb(0, 0, 128);
background-color: var(--Hilight);
color: rgb(255, 255, 255);
color: var(--HilightText);
}
.scrollbar {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAG0lEQVQYV2P8/////4MHDzIwHjhw4L+9vT0DAHAFCj6esq3FAAAAAElFTkSuQmCC") repeat;
background: var(--checker) repeat;
-ms-interpolation-mode: nearest-neighbor;
image-rendering: -moz-crisp-edges;
image-rendering: pixelated;
}
.scrollbar-thumb {
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
border-top: 1px solid rgb(192, 192, 192);
border-top: 1px solid var(--ButtonFace);
border-left: 1px solid rgb(192, 192, 192);
border-left: 1px solid var(--ButtonFace);
border-right: 1px solid rgb(0, 0, 0);
border-right: 1px solid var(--ButtonDkShadow);
border-bottom: 1px solid rgb(0, 0, 0);
border-bottom: 1px solid var(--ButtonDkShadow);
box-shadow: 1px 1px 0 rgb(255, 255, 255) inset, -1px -1px 0 rgb(128, 128, 128) inset;
box-shadow: 1px 1px 0 var(--ButtonHilight) inset, -1px -1px 0 var(--ButtonShadow) inset;
}
.scrollbar-track-piece:hover:active {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAG0lEQVQYV2P8/////4MHDzIwHjhw4L+9vT0DAHAFCj6esq3FAAAAAElFTkSuQmCC") repeat;
background: var(--checker) repeat;
-ms-interpolation-mode: nearest-neighbor;
image-rendering: -moz-crisp-edges;
image-rendering: pixelated;
background-color: white;
background-blend-mode: difference;
/* background-attachment: fixed; breaks the checkered background in chrome */
}
.scrollbar-track-piece.increment {
background-position: bottom;
}
.scrollbar-corner {
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
}
.scrollbar-button {
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
border-top: 1px solid rgb(192, 192, 192);
border-top: 1px solid var(--ButtonFace);
border-left: 1px solid rgb(192, 192, 192);
border-left: 1px solid var(--ButtonFace);
border-right: 1px solid rgb(0, 0, 0);
border-right: 1px solid var(--ButtonDkShadow);
border-bottom: 1px solid rgb(0, 0, 0);
border-bottom: 1px solid var(--ButtonDkShadow);
box-shadow: 1px 1px 0 rgb(255, 255, 255) inset, -1px -1px 0 rgb(128, 128, 128) inset;
box-shadow: 1px 1px 0 var(--ButtonHilight) inset, -1px -1px 0 var(--ButtonShadow) inset;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAW0lEQVQ4T2NkGGSAcZC5h4FWDvrPwEC02ShqkR0EkkAHuBxMyEKYWYQ8jKEOXQOyo/A5BuZwqqvBZiA+3xMbilQLIWqlcUJRimwPzjRELcdQZA6hREeR4eRoBgBoXhAK6oiMhwAAAABJRU5ErkJggg==");
background-image: var(--scrollbar-arrows-ButtonText);
-ms-interpolation-mode: nearest-neighbor;
image-rendering: -moz-crisp-edges;
image-rendering: pixelated;
width: 13px;
width: var(--scrollbar-size);
height: 13px;
height: var(--scrollbar-size);
box-sizing: border-box;
}
.scrollbar-button:not(.disabled):hover:active {
border: 1px solid rgb(128, 128, 128);
border: 1px solid var(--ButtonShadow);
box-shadow: none;
}
.scrollbar-button.disabled {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAYElEQVQ4T2NkGGSAcZC5h4EmDmpoaPjf0NBAlNnoauGaQBLooYXLUEIWwswi5Chs6lB8gewofI6BOZwWajCCFZ/viQ1FqoUQtRI4oShFtgdnGqKWYyg1h6icQKklpOgHAM9mQArEvm5+AAAAAElFTkSuQmCC"), url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAYElEQVQ4T2NkGGSAcZC5h4EmDvr///9/RkZGosxGVwvXBJJADy1chhKyEGYWIUdhU4fiC2RH4XMMzOG0UIMRrPh8T2woUi2EqJXACUUpsj040xC1HEOpOUTlBEotIUU/AKXFQAqyTJ6DAAAAAElFTkSuQmCC");
background-image: var(--scrollbar-arrows-GrayText), var(--scrollbar-arrows-ButtonHilight);
}
.scrollbar-button.horizontal.decrement.disabled {
background-position: /* left arrow */
calc(9px * -3 + 1px) 1px,
calc(9px * -3 + 2px) 2px;
background-position: /* left arrow */
calc(var(--scrollbar-button-inner-size) * -3 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -3 + 2px) 2px;
}
.scrollbar-button.horizontal.increment.disabled {
background-position: /* right arrow */
calc(9px * -2 + 1px) 1px,
calc(9px * -2 + 2px) 2px;
background-position: /* right arrow */
calc(var(--scrollbar-button-inner-size) * -2 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -2 + 2px) 2px;
}
.scrollbar-button.vertical.decrement.disabled {
background-position: /* up arrow */
calc(9px * -1 + 1px) 1px,
calc(9px * -1 + 2px) 2px;
background-position: /* up arrow */
calc(var(--scrollbar-button-inner-size) * -1 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -1 + 2px) 2px;
}
.scrollbar-button.vertical.increment.disabled {
background-position: /* down arrow */
calc(9px * -0 + 1px) 1px,
calc(9px * -0 + 2px) 2px;
background-position: /* down arrow */
calc(var(--scrollbar-button-inner-size) * -0 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -0 + 2px) 2px;
}
.scrollbar-button.horizontal.decrement {
background-position: calc(9px * -3 + 1px) 1px;
background-position: calc(var(--scrollbar-button-inner-size) * -3 + 1px) 1px; /* left */
}
.scrollbar-button.horizontal.increment {
background-position: calc(9px * -2 + 1px) 1px;
background-position: calc(var(--scrollbar-button-inner-size) * -2 + 1px) 1px; /* right */
}
.scrollbar-button.vertical.decrement {
background-position: calc(9px * -1 + 1px) 1px;
background-position: calc(var(--scrollbar-button-inner-size) * -1 + 1px) 1px; /* up */
}
.scrollbar-button.vertical.increment {
background-position: calc(9px * -0 + 1px) 1px;
background-position: calc(var(--scrollbar-button-inner-size) * -0 + 1px) 1px; /* down */
}
::-webkit-scrollbar,
::-webkit-scrollbar-thumb,
::-webkit-scrollbar-button {
width: 13px;
width: var(--scrollbar-size);
height: 13px;
height: var(--scrollbar-size);
}
::-webkit-scrollbar {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAG0lEQVQYV2P8/////4MHDzIwHjhw4L+9vT0DAHAFCj6esq3FAAAAAElFTkSuQmCC") repeat;
background: var(--checker) repeat;
image-rendering: pixelated;
}
::-webkit-scrollbar-thumb {
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
border-top: 1px solid rgb(192, 192, 192);
border-top: 1px solid var(--ButtonFace);
border-left: 1px solid rgb(192, 192, 192);
border-left: 1px solid var(--ButtonFace);
border-right: 1px solid rgb(0, 0, 0);
border-right: 1px solid var(--ButtonDkShadow);
border-bottom: 1px solid rgb(0, 0, 0);
border-bottom: 1px solid var(--ButtonDkShadow);
box-shadow: 1px 1px 0 rgb(255, 255, 255) inset, -1px -1px 0 rgb(128, 128, 128) inset;
box-shadow: 1px 1px 0 var(--ButtonHilight) inset, -1px -1px 0 var(--ButtonShadow) inset;
}
::-webkit-scrollbar-corner {
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
}
::-webkit-scrollbar-button {
background-color: rgb(192, 192, 192);
background-color: var(--ButtonFace);
border-top: 1px solid rgb(192, 192, 192);
border-top: 1px solid var(--ButtonFace);
border-left: 1px solid rgb(192, 192, 192);
border-left: 1px solid var(--ButtonFace);
border-right: 1px solid rgb(0, 0, 0);
border-right: 1px solid var(--ButtonDkShadow);
border-bottom: 1px solid rgb(0, 0, 0);
border-bottom: 1px solid var(--ButtonDkShadow);
box-shadow: 1px 1px 0 rgb(255, 255, 255) inset, -1px -1px 0 rgb(128, 128, 128) inset;
box-shadow: 1px 1px 0 var(--ButtonHilight) inset, -1px -1px 0 var(--ButtonShadow) inset;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAW0lEQVQ4T2NkGGSAcZC5h4FWDvrPwEC02ShqkR0EkkAHuBxMyEKYWYQ8jKEOXQOyo/A5BuZwqqvBZiA+3xMbilQLIWqlcUJRimwPzjRELcdQZA6hREeR4eRoBgBoXhAK6oiMhwAAAABJRU5ErkJggg==");
background-image: var(--scrollbar-arrows-ButtonText);
image-rendering: pixelated;
width: 13px;
width: var(--scrollbar-size);
height: 13px;
height: var(--scrollbar-size);
box-sizing: border-box;
}
::-webkit-scrollbar-button:not(.disabled):hover:active {
border: 1px solid rgb(128, 128, 128);
border: 1px solid var(--ButtonShadow);
box-shadow: none;
}
::-webkit-scrollbar-button.disabled {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAYElEQVQ4T2NkGGSAcZC5h4EmDmpoaPjf0NBAlNnoauGaQBLooYXLUEIWwswi5Chs6lB8gewofI6BOZwWajCCFZ/viQ1FqoUQtRI4oShFtgdnGqKWYyg1h6icQKklpOgHAM9mQArEvm5+AAAAAElFTkSuQmCC"), url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAYElEQVQ4T2NkGGSAcZC5h4EmDvr///9/RkZGosxGVwvXBJJADy1chhKyEGYWIUdhU4fiC2RH4XMMzOG0UIMRrPh8T2woUi2EqJXACUUpsj040xC1HEOpOUTlBEotIUU/AKXFQAqyTJ6DAAAAAElFTkSuQmCC");
background-image: var(--scrollbar-arrows-GrayText), var(--scrollbar-arrows-ButtonHilight);
}
::-webkit-scrollbar-button.horizontal.decrement.disabled {
background-position: /* left arrow */
calc(9px * -3 + 1px) 1px,
calc(9px * -3 + 2px) 2px;
background-position: /* left arrow */
calc(var(--scrollbar-button-inner-size) * -3 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -3 + 2px) 2px;
}
::-webkit-scrollbar-button.horizontal.increment.disabled {
background-position: /* right arrow */
calc(9px * -2 + 1px) 1px,
calc(9px * -2 + 2px) 2px;
background-position: /* right arrow */
calc(var(--scrollbar-button-inner-size) * -2 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -2 + 2px) 2px;
}
::-webkit-scrollbar-button.vertical.decrement.disabled {
background-position: /* up arrow */
calc(9px * -1 + 1px) 1px,
calc(9px * -1 + 2px) 2px;
background-position: /* up arrow */
calc(var(--scrollbar-button-inner-size) * -1 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -1 + 2px) 2px;
}
::-webkit-scrollbar-button.vertical.increment.disabled {
background-position: /* down arrow */
calc(9px * -0 + 1px) 1px,
calc(9px * -0 + 2px) 2px;
background-position: /* down arrow */
calc(var(--scrollbar-button-inner-size) * -0 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -0 + 2px) 2px;
}
::-webkit-scrollbar-button.horizontal.decrement {
background-position: calc(9px * -3 + 1px) 1px;
background-position: calc(var(--scrollbar-button-inner-size) * -3 + 1px) 1px;
/* left */
}
::-webkit-scrollbar-button.horizontal.increment {
background-position: calc(9px * -2 + 1px) 1px;
background-position: calc(var(--scrollbar-button-inner-size) * -2 + 1px) 1px;
/* right */
}
::-webkit-scrollbar-button.vertical.decrement {
background-position: calc(9px * -1 + 1px) 1px;
background-position: calc(var(--scrollbar-button-inner-size) * -1 + 1px) 1px;
/* up */
}
::-webkit-scrollbar-button.vertical.increment {
background-position: calc(9px * -0 + 1px) 1px;
background-position: calc(var(--scrollbar-button-inner-size) * -0 + 1px) 1px;
/* down */
}
::-webkit-scrollbar-button:hover:active {
border: 1px solid rgb(128, 128, 128);
border: 1px solid var(--ButtonShadow);
box-shadow: none;
}
::-webkit-scrollbar-button:disabled {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAYElEQVQ4T2NkGGSAcZC5h4EmDmpoaPjf0NBAlNnoauGaQBLooYXLUEIWwswi5Chs6lB8gewofI6BOZwWajCCFZ/viQ1FqoUQtRI4oShFtgdnGqKWYyg1h6icQKklpOgHAM9mQArEvm5+AAAAAElFTkSuQmCC"), url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAYElEQVQ4T2NkGGSAcZC5h4EmDvr///9/RkZGosxGVwvXBJJADy1chhKyEGYWIUdhU4fiC2RH4XMMzOG0UIMRrPh8T2woUi2EqJXACUUpsj040xC1HEOpOUTlBEotIUU/AKXFQAqyTJ6DAAAAAElFTkSuQmCC");
background-image: var(--scrollbar-arrows-GrayText), var(--scrollbar-arrows-ButtonHilight);
}
::-webkit-scrollbar-button:horizontal:decrement:disabled {
background-position: /* left arrow */
calc(9px * -3 + 1px) 1px,
calc(9px * -3 + 2px) 2px;
background-position: /* left arrow */
calc(var(--scrollbar-button-inner-size) * -3 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -3 + 2px) 2px;
}
::-webkit-scrollbar-button:horizontal:increment:disabled {
background-position: /* right arrow */
calc(9px * -2 + 1px) 1px,
calc(9px * -2 + 2px) 2px;
background-position: /* right arrow */
calc(var(--scrollbar-button-inner-size) * -2 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -2 + 2px) 2px;
}
::-webkit-scrollbar-button:vertical:decrement:disabled {
background-position: /* up arrow */
calc(9px * -1 + 1px) 1px,
calc(9px * -1 + 2px) 2px;
background-position: /* up arrow */
calc(var(--scrollbar-button-inner-size) * -1 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -1 + 2px) 2px;
}
::-webkit-scrollbar-button:vertical:increment:disabled {
background-position: /* down arrow */
calc(9px * -0 + 1px) 1px,
calc(9px * -0 + 2px) 2px;
background-position: /* down arrow */
calc(var(--scrollbar-button-inner-size) * -0 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -0 + 2px) 2px;
}
::-webkit-scrollbar-button:horizontal:decrement.disabled {
background-position: /* left arrow */
calc(9px * -3 + 1px) 1px,
calc(9px * -3 + 2px) 2px;
background-position: /* left arrow */
calc(var(--scrollbar-button-inner-size) * -3 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -3 + 2px) 2px;
}
::-webkit-scrollbar-button:horizontal:decrement {
background-position: calc(9px * -3 + 1px) 1px;
background-position: calc(var(--scrollbar-button-inner-size) * -3 + 1px) 1px;
/* left */
}
::-webkit-scrollbar-button:horizontal:increment.disabled {
background-position: /* right arrow */
calc(9px * -2 + 1px) 1px,
calc(9px * -2 + 2px) 2px;
background-position: /* right arrow */
calc(var(--scrollbar-button-inner-size) * -2 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -2 + 2px) 2px;
}
::-webkit-scrollbar-button:horizontal:increment {
background-position: calc(9px * -2 + 1px) 1px;
background-position: calc(var(--scrollbar-button-inner-size) * -2 + 1px) 1px;
/* right */
}
::-webkit-scrollbar-button:vertical:decrement.disabled {
background-position: /* up arrow */
calc(9px * -1 + 1px) 1px,
calc(9px * -1 + 2px) 2px;
background-position: /* up arrow */
calc(var(--scrollbar-button-inner-size) * -1 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -1 + 2px) 2px;
}
::-webkit-scrollbar-button:vertical:decrement {
background-position: calc(9px * -1 + 1px) 1px;
background-position: calc(var(--scrollbar-button-inner-size) * -1 + 1px) 1px;
/* up */
}
::-webkit-scrollbar-button:vertical:increment.disabled {
background-position: /* down arrow */
calc(9px * -0 + 1px) 1px,
calc(9px * -0 + 2px) 2px;
background-position: /* down arrow */
calc(var(--scrollbar-button-inner-size) * -0 + 1px) 1px,
calc(var(--scrollbar-button-inner-size) * -0 + 2px) 2px;
}
::-webkit-scrollbar-button:vertical:increment {
background-position: calc(9px * -0 + 1px) 1px;
background-position: calc(var(--scrollbar-button-inner-size) * -0 + 1px) 1px;
/* down */
}
::-webkit-scrollbar-track-piece:hover:active {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAG0lEQVQYV2P8/////4MHDzIwHjhw4L+9vT0DAHAFCj6esq3FAAAAAElFTkSuQmCC") repeat;
background: var(--checker) repeat;
image-rendering: pixelated;
background-color: white;
background-blend-mode: difference;
/* background-attachment: fixed; breaks the checkered background in chrome */
}
::-webkit-scrollbar-track-piece.increment {
background-position: bottom;
}
::-webkit-scrollbar-track-piece:increment {
background-position: bottom;
}
/* turn off double buttons */
::-webkit-scrollbar-button:start:increment,
::-webkit-scrollbar-button:end:decrement {
display: none;
}
/*# sourceMappingURL=windows-98.css.map */

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,48 @@
:root {
/* These resources are generated. */
/* JS: makeThemeCSSFile(renderThemeGraphics(getComputedStyle(document.documentElement))) */
--checker: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAG0lEQVQYV2P8/////4MHDzIwHjhw4L+9vT0DAHAFCj6esq3FAAAAAElFTkSuQmCC");
--button-active-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h192v192h-192v-192z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--button-normal-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--inset-deep-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h224v32h-192v192h-32v-224z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M224%200h32v256h-256v-32h224v-224z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M192%2032h32v192h-192v-32h160v-160z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--button-default-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h160v32h-128v128h-32v-160z%22%20fill%3D%22%20rgb(255%2C%20255%2C%20255)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h96v32h-64v64h-32v-96z%22%20fill%3D%22%20rgb(223%2C%20223%2C%20223)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M160%2064h32v128h-128v-32h96v-96z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M96%2096h64v64h-64v-64z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%09%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22256%22%20height%3D%22256%22%20stroke-width%3D%2264%22%20stroke%3D%22%20rgb(0%2C%200%2C%200)%22%20fill%3D%22none%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 96 / 3px;
--button-default-active-border-image: url("data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22256px%22%20height%3D%22256px%22%20viewBox%3D%220%200%20256%20256%22%3E%0A%09%09%09%0A%09%09%3Cpath%20d%3D%22M0%200h256v256h-256v-256z%22%20fill%3D%22%20rgb(0%2C%200%2C%200)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M32%2032h192v192h-192v-192z%22%20fill%3D%22%20rgb(128%2C%20128%2C%20128)%22%2F%3E%0A%09%09%3Cpath%20d%3D%22M64%2064h128v128h-128v-128z%22%20fill%3D%22%20rgb(192%2C%20192%2C%20192)%22%2F%3E%0A%09%09%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22256%22%20height%3D%22256%22%20stroke-width%3D%2264%22%20stroke%3D%22%20rgb(0%2C%200%2C%200)%22%20fill%3D%22none%22%2F%3E%0A%09%0A%09%09%3C%2Fsvg%3E") 64 / 2px;
--scrollbar-arrows-ButtonText: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAW0lEQVQ4T2NkGGSAcZC5h4FWDvrPwEC02ShqkR0EkkAHuBxMyEKYWYQ8jKEOXQOyo/A5BuZwqqvBZiA+3xMbilQLIWqlcUJRimwPzjRELcdQZA6hREeR4eRoBgBoXhAK6oiMhwAAAABJRU5ErkJggg==");
--scrollbar-arrows-GrayText: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAYElEQVQ4T2NkGGSAcZC5h4EmDmpoaPjf0NBAlNnoauGaQBLooYXLUEIWwswi5Chs6lB8gewofI6BOZwWajCCFZ/viQ1FqoUQtRI4oShFtgdnGqKWYyg1h6icQKklpOgHAM9mQArEvm5+AAAAAElFTkSuQmCC");
--scrollbar-arrows-ButtonHilight: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAAYElEQVQ4T2NkGGSAcZC5h4EmDvr///9/RkZGosxGVwvXBJJADy1chhKyEGYWIUdhU4fiC2RH4XMMzOG0UIMRrPh8T2woUi2EqJXACUUpsj040xC1HEOpOUTlBEotIUU/AKXFQAqyTJ6DAAAAAElFTkSuQmCC");
--scrollbar-size: 13px;
--scrollbar-button-inner-size: 9px;
/* Colors */
--ActiveBorder: rgb(192, 192, 192);
--ActiveTitle: rgb(0, 0, 128);
--AppWorkspace: rgb(128, 128, 128);
--Background: rgb(0, 128, 128);
--ButtonAlternateFace: rgb(180, 180, 180);
--ButtonDkShadow: rgb(0, 0, 0);
--ButtonFace: rgb(192, 192, 192);
--ButtonHilight: rgb(255, 255, 255);
--ButtonLight: rgb(223, 223, 223);
--ButtonShadow: rgb(128, 128, 128);
--ButtonText: rgb(0, 0, 0);
--GradientActiveTitle: rgb(16, 132, 208);
--GradientInactiveTitle: rgb(181, 181, 181);
--GrayText: rgb(128, 128, 128);
--Hilight: rgb(0, 0, 128);
--HilightText: rgb(255, 255, 255);
--HotTrackingColor: rgb(0, 0, 255);
--InactiveBorder: rgb(192, 192, 192);
--InactiveTitle: rgb(128, 128, 128);
--InactiveTitleText: rgb(192, 192, 192);
--InfoText: rgb(0, 0, 0);
--InfoWindow: rgb(255, 255, 225);
--Menu: rgb(192, 192, 192);
--MenuText: rgb(0, 0, 0);
--Scrollbar: rgb(192, 192, 192);
--TitleText: rgb(255, 255, 255);
--Window: rgb(255, 255, 255);
--WindowFrame: rgb(0, 0, 0);
--WindowText: rgb(0, 0, 0);
}
/*# sourceMappingURL=windows-default.css.map */

File diff suppressed because one or more lines are too long