mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-26 22:42:26 +01:00
Fix DPI scaling with TGUI, TGUI Say, and Tooltips (#20734)
Got tired of the issues here when working on something else. Ported several PRs from /tg/station to fix DPI scaling issues. This was not a problem before 516, however 516 now respects Window's DPI setting, causing misalignment in several of our UI elements. This PR implements these ~~four~~ ~~five~~ six PRs: https://github.com/tgstation/tgstation/pull/65686 https://github.com/tgstation/tgstation/pull/89994 https://github.com/tgstation/tgstation/pull/90416 https://github.com/tgstation/tgstation/pull/90418 https://github.com/tgstation/tgstation/pull/90796 https://github.com/cmss13-devs/cmss13/pull/8734 ~~Does not include fixes with TGUI-Say. /tg/station refactored TGUI-Say after their port to React before they fixed DPI scaling, and this would be pain to deconstruct to port over to Inferno. Since porting to React is "inevitable", I considered it not worth my time to fix this.~~ Thanks to the assistance of harry, TGUI-Say fixes now included.
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `ss13_player_preferences` ADD COLUMN `tgui_say_light_mode` TINYINT(1) NOT NULL DEFAULT 0 AFTER `tgui_lock`;
|
||||
ALTER TABLE `ss13_player_preferences` ADD COLUMN `ui_scale` TINYINT(1) NOT NULL DEFAULT 1 AFTER `tgui_say_light_mode`;
|
||||
@@ -36,3 +36,9 @@
|
||||
#define TGUI_CREATE_MESSAGE(type, payload) ( \
|
||||
"%7b%22type%22%3a%22[type]%22%2c%22payload%22%3a[url_encode(json_encode(payload))]%7d" \
|
||||
)
|
||||
|
||||
/// Creates a message packet for sending via output() specifically for opening tgsay using an embedded winget
|
||||
// This is {"type":"open","payload":{"channel":channel,"mapfocus":[[map.focus]]}}, but pre-encoded.
|
||||
#define TGUI_CREATE_OPEN_MESSAGE(channel) ( \
|
||||
"%7b%22type%22%3a%22open%22%2c%22payload%22%3a%7B%22channel%22%3a%22[channel]%22%2c%22mapfocus%22%3a\[\[map.focus\]\]%7d%7d" \
|
||||
)
|
||||
|
||||
+128
-86
@@ -1,13 +1,15 @@
|
||||
/datum/browser
|
||||
var/mob/user
|
||||
var/title
|
||||
var/window_id // window_id is used as the window name for browse and onclose
|
||||
var/title = ""
|
||||
/// window_id is used as the window name for browse and onclose
|
||||
var/window_id
|
||||
var/width = 0
|
||||
var/height = 0
|
||||
var/atom/ref = null
|
||||
var/window_options = "focus=0;can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id
|
||||
var/stylesheets[0]
|
||||
var/scripts[0]
|
||||
var/datum/weakref/source_ref = null
|
||||
/// window option is set using window_id
|
||||
var/window_options = "can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;"
|
||||
var/stylesheets = list()
|
||||
var/scripts = list()
|
||||
var/title_image
|
||||
var/head_elements
|
||||
var/body_elements
|
||||
@@ -16,70 +18,96 @@
|
||||
var/title_buttons = ""
|
||||
|
||||
|
||||
/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, var/skip_common_stylesheet = FALSE)
|
||||
/datum/browser/New(mob/user, window_id, title = "", width = 0, height = 0, atom/source = null, skip_common_stylesheet = FALSE)
|
||||
|
||||
user = nuser
|
||||
window_id = nwindow_id
|
||||
if (ntitle)
|
||||
title = format_text(ntitle)
|
||||
if (nwidth)
|
||||
width = nwidth
|
||||
if (nheight)
|
||||
height = nheight
|
||||
if (nref)
|
||||
ref = nref
|
||||
src.user = user
|
||||
RegisterSignal(user, COMSIG_QDELETING, PROC_REF(user_deleted))
|
||||
src.window_id = window_id
|
||||
if (title)
|
||||
src.title = format_text(title)
|
||||
if (width)
|
||||
src.width = width
|
||||
if (height)
|
||||
src.height = height
|
||||
if (source)
|
||||
src.source_ref = WEAKREF(source)
|
||||
if(!skip_common_stylesheet)
|
||||
add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs
|
||||
|
||||
/datum/browser/proc/set_user(nuser)
|
||||
user = nuser
|
||||
/datum/browser/proc/user_deleted(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
user = null
|
||||
|
||||
/datum/browser/proc/set_title(ntitle)
|
||||
title = format_text(ntitle)
|
||||
/datum/browser/proc/set_user(mob/user)
|
||||
src.user = user
|
||||
|
||||
/datum/browser/proc/add_head_content(nhead_content)
|
||||
head_content = nhead_content
|
||||
/datum/browser/proc/set_title(title)
|
||||
src.title = format_text(title)
|
||||
|
||||
/datum/browser/proc/set_title_buttons(ntitle_buttons)
|
||||
title_buttons = ntitle_buttons
|
||||
/datum/browser/proc/add_head_content(head_content)
|
||||
src.head_content += head_content
|
||||
|
||||
/datum/browser/proc/set_window_options(nwindow_options)
|
||||
window_options = nwindow_options
|
||||
/datum/browser/proc/set_head_content(head_content)
|
||||
src.head_content = head_content
|
||||
|
||||
/datum/browser/proc/set_title_buttons(title_buttons)
|
||||
src.title_buttons = title_buttons
|
||||
|
||||
/datum/browser/proc/set_window_options(window_options)
|
||||
src.window_options = window_options
|
||||
|
||||
/datum/browser/proc/set_title_image(ntitle_image)
|
||||
//title_image = ntitle_image
|
||||
|
||||
/datum/browser/proc/add_stylesheet(name, file)
|
||||
stylesheets["[ckey(name)].css"] = file
|
||||
SSassets.transport.register_asset("[ckey(name)].css", file)
|
||||
if (istype(name, /datum/asset/spritesheet))
|
||||
var/datum/asset/spritesheet/sheet = name
|
||||
stylesheets["spritesheet_[sheet.name].css"] = "data/spritesheets/[sheet.name]"
|
||||
else
|
||||
var/asset_name = "[name].css"
|
||||
|
||||
stylesheets[asset_name] = file
|
||||
|
||||
if (!SSassets.cache[asset_name])
|
||||
SSassets.transport.register_asset(asset_name, file)
|
||||
|
||||
/datum/browser/proc/add_script(name, file)
|
||||
scripts["[ckey(name)].js"] = file
|
||||
SSassets.transport.register_asset("[ckey(name)].js", file)
|
||||
|
||||
/datum/browser/proc/set_content(ncontent)
|
||||
content = ncontent
|
||||
/datum/browser/proc/set_content(content)
|
||||
src.content = content
|
||||
|
||||
/datum/browser/proc/add_content(ncontent)
|
||||
content += ncontent
|
||||
/datum/browser/proc/add_content(content)
|
||||
src.content += content
|
||||
|
||||
/datum/browser/proc/get_header()
|
||||
var/file
|
||||
for (file in stylesheets)
|
||||
head_content += "<link rel='stylesheet' type='text/css' href='[SSassets.transport.get_asset_url(file)]'>"
|
||||
var/list/new_head_content = list()
|
||||
for (var/file as anything in stylesheets)
|
||||
new_head_content += "<link rel='stylesheet' type='text/css' href='[SSassets.transport.get_asset_url(file)]'>"
|
||||
|
||||
for (file in scripts)
|
||||
head_content += "<script type='text/javascript' src='[SSassets.transport.get_asset_url(file)]'></script>"
|
||||
if(user.client?.window_scaling && user.client?.window_scaling != 1 && !user.client?.prefs.ui_scale && width && height)
|
||||
new_head_content += {"
|
||||
<style>
|
||||
body {
|
||||
zoom: [100 / user.client?.window_scaling]%;
|
||||
}
|
||||
</style>
|
||||
"}
|
||||
|
||||
for (var/file as anything in scripts)
|
||||
new_head_content += "<script type='text/javascript' src='[SSassets.transport.get_asset_url(file)]'></script>"
|
||||
|
||||
var/title_attributes = "class='uiTitle'"
|
||||
if (title_image)
|
||||
title_attributes = "class='uiTitle icon' style='background-image: url([title_image]);'"
|
||||
|
||||
head_content += new_head_content.Join()
|
||||
return {"<!DOCTYPE html>
|
||||
<html>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta http-equiv="Content-Type" content="text/html; utf-8">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta http-equiv="Content-Type" content="text/html; utf-8">
|
||||
[head_content]
|
||||
</head>
|
||||
<body scroll=auto>
|
||||
@@ -97,18 +125,27 @@
|
||||
|
||||
/datum/browser/proc/get_content()
|
||||
return {"
|
||||
[get_header()]
|
||||
[content]
|
||||
[get_footer()]
|
||||
[get_header()]
|
||||
[content]
|
||||
[get_footer()]
|
||||
"}
|
||||
|
||||
/datum/browser/proc/open(var/use_onclose = 1)
|
||||
if(isnull(window_id)) //null check because this can potentially nuke goonchat
|
||||
WARNING("Browser [title] tried to open with a null ID")
|
||||
to_chat(user, SPAN_DANGER("The [title] browser you tried to open failed a sanity check! Please report this on GitHub!"))
|
||||
return
|
||||
|
||||
var/window_size = ""
|
||||
if (width && height)
|
||||
window_size = "size=[width]x[height];"
|
||||
if (stylesheets.len)
|
||||
if(width && height)
|
||||
if(user.client?.prefs.ui_scale)
|
||||
var/scaling = user.client.window_scaling
|
||||
window_size = "size=[width * scaling]x[height * scaling];"
|
||||
else
|
||||
window_size = "size=[width]x[height];"
|
||||
if (length(stylesheets))
|
||||
SSassets.transport.send_assets(user.client, stylesheets)
|
||||
if (scripts.len)
|
||||
if (length(scripts))
|
||||
SSassets.transport.send_assets(user.client, scripts)
|
||||
user << browse(get_content(), "window=[window_id];[window_size][window_options]")
|
||||
if (use_onclose)
|
||||
@@ -118,9 +155,14 @@
|
||||
/datum/browser/proc/setup_onclose()
|
||||
set waitfor = 0
|
||||
for (var/i in 1 to 10)
|
||||
if (user && winexists(user, window_id))
|
||||
onclose(user, window_id, ref)
|
||||
break
|
||||
if (!user?.client || !winexists(user, window_id))
|
||||
continue
|
||||
var/atom/send_ref
|
||||
if(source_ref)
|
||||
send_ref = source_ref.resolve()
|
||||
if(!send_ref)
|
||||
source_ref = null
|
||||
onclose(user, window_id, send_ref)
|
||||
|
||||
/datum/browser/proc/update(var/force_open = 0, var/use_onclose = 1)
|
||||
if(force_open)
|
||||
@@ -130,6 +172,10 @@
|
||||
|
||||
/datum/browser/proc/close()
|
||||
user << browse(null, "window=[window_id]")
|
||||
if(!isnull(window_id))//null check because this can potentially nuke goonchat
|
||||
user << browse(null, "window=[window_id]")
|
||||
else
|
||||
WARNING("Browser [title] tried to close with a null ID")
|
||||
|
||||
// This will allow you to show an icon in the browse window
|
||||
// This is added to mob so that it can be used without a reference to the browser object
|
||||
@@ -149,47 +195,43 @@
|
||||
*/
|
||||
|
||||
|
||||
// Registers the on-close verb for a browse window (client/verb/.windowclose)
|
||||
// this will be called when the close-button of a window is pressed.
|
||||
//
|
||||
// This is usually only needed for devices that regularly update the browse window,
|
||||
// e.g. canisters, timers, etc.
|
||||
//
|
||||
// windowid should be the specified window name
|
||||
// e.g. code is : user << browse(text, "window=fred")
|
||||
// then use : onclose(user, "fred")
|
||||
//
|
||||
// Optionally, specify the "ref" parameter as the controlled atom (usually src)
|
||||
/// Registers the on-close verb for a browse window (client/verb/windowclose)
|
||||
/// this will be called when the close-button of a window is pressed.
|
||||
///
|
||||
/// This is usually only needed for devices that regularly update the browse window,
|
||||
/// e.g. canisters, timers, etc.
|
||||
///
|
||||
/// windowid should be the specified window name
|
||||
/// e.g. code is : user << browse(text, "window=fred")
|
||||
/// then use : onclose(user, "fred")
|
||||
///
|
||||
/// Optionally, specify the "source" parameter as the controlled atom (usually src)
|
||||
// to pass a "close=1" parameter to the atom's Topic() proc for special handling.
|
||||
// Otherwise, the user mob's machine var will be reset directly.
|
||||
//
|
||||
/proc/onclose(mob/user, windowid, var/atom/ref=null)
|
||||
/// Otherwise, the user mob's machine var will be reset directly.
|
||||
///
|
||||
/proc/onclose(mob/user, windowid, atom/source = null)
|
||||
if(!user || !user.client) return
|
||||
var/param = "null"
|
||||
if(ref)
|
||||
param = "[REF(ref)]"
|
||||
if(source)
|
||||
param = "[REF(source)]"
|
||||
|
||||
winset(user, windowid, "on-close=\".windowclose [param]\"")
|
||||
|
||||
|
||||
// the on-close client verb
|
||||
// called when a browser popup window is closed after registering with proc/onclose()
|
||||
// if a valid atom reference is supplied, call the atom's Topic() with "close=1"
|
||||
// otherwise, just reset the client mob's machine var.
|
||||
//
|
||||
/client/verb/windowclose(var/atomref as text)
|
||||
set hidden = 1 // hide this verb from the user's panel
|
||||
set name = ".windowclose" // no autocomplete on cmd line
|
||||
/// the on-close client verb
|
||||
/// called when a browser popup window is closed after registering with proc/onclose()
|
||||
/// if a valid atom reference is supplied, call the atom's Topic() with "close=1"
|
||||
/// otherwise, just reset the client mob's machine var.
|
||||
/client/verb/windowclose(atomref as text)
|
||||
set hidden = TRUE // hide this verb from the user's panel
|
||||
set name = ".windowclose" // no autocomplete on cmd line
|
||||
|
||||
if(atomref!="null") // if passed a real atomref
|
||||
var/hsrc = locate(atomref) // find the reffed atom
|
||||
if(hsrc)
|
||||
usr = src.mob
|
||||
src.Topic("close=1", list("close"="1"), hsrc) // this will direct to the atom's
|
||||
return // Topic() proc via client.Topic()
|
||||
|
||||
// no atomref specified (or not found)
|
||||
// so just reset the user mob's machine var
|
||||
if(src && src.mob)
|
||||
src.mob.unset_machine()
|
||||
return
|
||||
if(atomref == "null")
|
||||
return
|
||||
// if passed a real atomref
|
||||
var/atom/hsrc = locate(atomref) // find the reffed atom
|
||||
var/href = "close=1"
|
||||
if(!hsrc)
|
||||
return
|
||||
usr = src.mob
|
||||
src.Topic(href, params2list(href), hsrc) // this will direct to the atom's Topic() proc via client.Topic()
|
||||
|
||||
@@ -48,6 +48,8 @@ var/global/enabled_spooking = 0
|
||||
to_chat(usr, "Error: you are not an admin!")
|
||||
return
|
||||
|
||||
var/ui_scale = owner.prefs?.ui_scale
|
||||
|
||||
var/body = "<html><head><title>Options for [M.key]</title></head>"
|
||||
body += "<body>Options panel for <b>[M]</b>"
|
||||
if(M.client)
|
||||
@@ -219,7 +221,11 @@ var/global/enabled_spooking = 0
|
||||
</body></html>
|
||||
"}
|
||||
|
||||
usr << browse(body, "window=adminplayeropts;size=550x515")
|
||||
var/window_size = "size=550x515"
|
||||
if(owner.window_scaling && ui_scale)
|
||||
window_size = "size=[550 * owner.window_scaling]x[515 * owner.window_scaling]"
|
||||
|
||||
usr << browse(body, "window=adminplayeropts;[window_size]")
|
||||
feedback_add_details("admin_verb","SPP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
return
|
||||
|
||||
var/datum/browser/config_window = new(usr, "access_control", "Access Control")
|
||||
config_window.add_head_content("<title>Access Control</title>")
|
||||
config_window.set_head_content("<title>Access Control</title>")
|
||||
|
||||
var/data = "These settings control who can access the server during this round.<br>"
|
||||
data += "They must be reset every single time the server restarts.<br>"
|
||||
|
||||
@@ -78,6 +78,8 @@
|
||||
|
||||
///Hide top bars
|
||||
var/fullscreen = FALSE
|
||||
///Hide status bar (bottom left)
|
||||
var/show_status_bar = TRUE
|
||||
|
||||
/// our current tab
|
||||
var/stat_tab
|
||||
@@ -95,3 +97,6 @@
|
||||
var/drag_start = 0
|
||||
///The params we were passed at the start of the drag, in list form
|
||||
var/list/drag_details
|
||||
|
||||
/// The DPI scale of the client. 1 is equivalent to 100% window scaling, 2 will be 200% window scaling
|
||||
var/window_scaling
|
||||
|
||||
@@ -405,6 +405,8 @@ GLOBAL_LIST_INIT(localhost_addresses, list(
|
||||
)
|
||||
addtimer(CALLBACK(src, PROC_REF(check_panel_loaded)), 30 SECONDS)
|
||||
|
||||
INVOKE_ASYNC(src, PROC_REF(acquire_dpi))
|
||||
|
||||
// Initialize tgui panel
|
||||
tgui_panel.initialize()
|
||||
|
||||
@@ -701,6 +703,17 @@ GLOBAL_LIST_INIT(localhost_addresses, list(
|
||||
winset(src, "mainwindow", "menu=[fullscreen ? "" : "menu"];is-fullscreen=[fullscreen ? "true" : "false"];titlebar=[fullscreen ? "false" : "true"]")
|
||||
attempt_auto_fit_viewport()
|
||||
|
||||
/client/verb/toggle_status_bar()
|
||||
set name = "Toggle Status Bar"
|
||||
set category = "Preferences.Menu"
|
||||
|
||||
show_status_bar = !show_status_bar
|
||||
|
||||
if (show_status_bar)
|
||||
winset(src, "mapwindow.status_bar", "is-visible=true")
|
||||
else
|
||||
winset(src, "mapwindow.status_bar", "is-visible=false")
|
||||
|
||||
/client/verb/toggle_menu()
|
||||
set name = "Toggle Menu"
|
||||
set category = "Preferences.Menu"
|
||||
@@ -1002,3 +1015,7 @@ GLOBAL_LIST_INIT(localhost_addresses, list(
|
||||
if(stat_panel.is_ready())
|
||||
return
|
||||
to_chat(src, SPAN_DANGER("Statpanel failed to load, click <a href='byond://?src=[REF(src)];reload_statbrowser=1'>here</a> to reload the panel "))
|
||||
|
||||
/// This grabs the DPI of the user per their skin
|
||||
/client/proc/acquire_dpi()
|
||||
window_scaling = text2num(winget(src, null, "dpi"))
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
S["tgui_inputs"] >> pref.tgui_inputs
|
||||
S["tgui_buttons_large"] >> pref.tgui_buttons_large
|
||||
S["tgui_inputs_swapped"] >> pref.tgui_inputs_swapped
|
||||
S["tgui_say_light_mode"] >> pref.tgui_say_light_mode
|
||||
S["ui_scale"] >> pref.ui_scale
|
||||
|
||||
/datum/category_item/player_setup_item/player_global/ui/save_preferences(var/savefile/S)
|
||||
S["UI_style"] << pref.UI_style
|
||||
@@ -27,6 +29,8 @@
|
||||
S["tgui_inputs"] << pref.tgui_inputs
|
||||
S["tgui_buttons_large"] << pref.tgui_buttons_large
|
||||
S["tgui_inputs_swapped"] << pref.tgui_inputs_swapped
|
||||
S["tgui_say_light_mode"] << pref.tgui_say_light_mode
|
||||
S["ui_scale"] << pref.ui_scale
|
||||
|
||||
/datum/category_item/player_setup_item/player_global/ui/gather_load_query()
|
||||
return list(
|
||||
@@ -42,7 +46,9 @@
|
||||
"tooltip_style",
|
||||
"tgui_inputs",
|
||||
"tgui_buttons_large",
|
||||
"tgui_inputs_swapped"
|
||||
"tgui_inputs_swapped",
|
||||
"tgui_say_light_mode",
|
||||
"ui_scale",
|
||||
),
|
||||
"args" = list("ckey")
|
||||
)
|
||||
@@ -65,6 +71,7 @@
|
||||
"tgui_inputs",
|
||||
"tgui_buttons_large",
|
||||
"tgui_inputs_swapped",
|
||||
"ui_scale",
|
||||
"ckey" = 1
|
||||
)
|
||||
)
|
||||
@@ -82,7 +89,8 @@
|
||||
"tooltip_style" = pref.tooltip_style,
|
||||
"tgui_inputs" = pref.tgui_inputs,
|
||||
"tgui_buttons_large" = pref.tgui_buttons_large,
|
||||
"tgui_inputs_swapped" = pref.tgui_inputs_swapped
|
||||
"tgui_inputs_swapped" = pref.tgui_inputs_swapped,
|
||||
"ui_scale" = pref.ui_scale
|
||||
)
|
||||
|
||||
/datum/category_item/player_setup_item/player_global/ui/sanitize_preferences()
|
||||
@@ -110,6 +118,8 @@
|
||||
dat += "<b>TGUI Inputs:</b> <a href='byond://?src=[REF(src)];tgui_inputs=1'><b>[pref.tgui_inputs ? "ON" : "OFF"]</b></a><br>"
|
||||
dat += "<b>TGUI Input Large Buttons:</b> <a href='byond://?src=[REF(src)];tgui_inputs_large=1'><b>[pref.tgui_buttons_large ? "ON" : "OFF"]</b></a><br>"
|
||||
dat += "<b>TGUI Input Swapped Buttons:</b> <a href='byond://?src=[REF(src)];tgui_inputs_swapped=1'><b>[pref.tgui_inputs_swapped ? "ON" : "OFF"]</b></a><br>"
|
||||
dat += "<b>TGUI Say Light Mode:</b> <a href='byond://?src=[REF(src)];tgui_say_light_mode=1'><b>[pref.tgui_say_light_mode ? "ON" : "OFF"]</b></a><br>"
|
||||
dat += "<b>UI Scaling:</b> <a href='byond://?src=[REF(src)];ui_scale=1'><b>[pref.ui_scale ? "ON" : "OFF"]</b></a><br>"
|
||||
dat += "<b>FPS:</b> <a href='byond://?src=[REF(src)];select_fps=1'><b>[pref.clientfps]</b></a> - <a href='byond://?src=[REF(src)];reset=fps'>reset</a><br>"
|
||||
if(can_select_ooc_color(user))
|
||||
dat += "<b>OOC Color:</b> "
|
||||
@@ -159,6 +169,16 @@
|
||||
pref.tgui_inputs_swapped = !pref.tgui_inputs_swapped
|
||||
return TOPIC_REFRESH
|
||||
|
||||
else if(href_list["tgui_say_light_mode"])
|
||||
pref.tgui_say_light_mode = !pref.tgui_say_light_mode
|
||||
user.client.tgui_say?.load()
|
||||
return TOPIC_REFRESH
|
||||
|
||||
else if(href_list["ui_scale"])
|
||||
pref.ui_scale = !pref.ui_scale
|
||||
user.client.tgui_say?.load()
|
||||
return TOPIC_REFRESH
|
||||
|
||||
else if(href_list["select_ooc_color"])
|
||||
var/new_ooccolor = input(user, "Choose OOC color:", "Global Preference") as color|null
|
||||
if(new_ooccolor && can_select_ooc_color(user) && CanUseTopic(user))
|
||||
|
||||
@@ -31,6 +31,8 @@ GLOBAL_LIST_EMPTY_TYPED(preferences_datums, /datum/preferences)
|
||||
var/tgui_inputs = TRUE
|
||||
var/tgui_buttons_large = FALSE
|
||||
var/tgui_inputs_swapped = FALSE
|
||||
var/tgui_say_light_mode = FALSE
|
||||
var/ui_scale = TRUE
|
||||
//Style for popup tooltips
|
||||
var/tooltip_style = "Midnight"
|
||||
|
||||
|
||||
@@ -612,6 +612,7 @@
|
||||
/obj/item/clothing/under/rank/elyran_fatigues
|
||||
name = "elyran navy uniform"
|
||||
desc = "An utility uniform worn by Elyran navy staff serving aboard ships and in the field."
|
||||
icon = ""
|
||||
icon_state = "elyran_fatigues"
|
||||
item_state = "elyran_fatigues"
|
||||
armor = list(
|
||||
|
||||
@@ -27,7 +27,7 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache)
|
||||
/datum/error_viewer/proc/browse_to(client/user, html)
|
||||
var/datum/browser/browser = new(user.mob, "error_viewer", null, 600, 400)
|
||||
browser.set_content(html)
|
||||
browser.add_head_content({"
|
||||
browser.set_head_content({"
|
||||
<style>
|
||||
.runtime
|
||||
{
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"size" = window_size,
|
||||
"fancy" = user.client.prefs.tgui_fancy,
|
||||
"locked" = user.client.prefs.tgui_lock,
|
||||
"scale" = user.client.prefs.ui_scale,
|
||||
),
|
||||
"client" = list(
|
||||
"ckey" = user.client.ckey,
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
* string - A JSON encoded message to open the modal.
|
||||
*/
|
||||
/client/proc/tgui_say_create_open_command(channel)
|
||||
var/message = TGUI_CREATE_MESSAGE("open", list(
|
||||
channel = channel,
|
||||
))
|
||||
var/message = TGUI_CREATE_OPEN_MESSAGE(channel)
|
||||
return "\".output tgui_say.browser:update [message]\""
|
||||
|
||||
/**
|
||||
@@ -36,6 +34,7 @@
|
||||
/datum/tgui_say/New(client/client, id)
|
||||
src.client = client
|
||||
window = new(client, id)
|
||||
winset(client, "tgui_say", "size=1,1;is-visible=0;")
|
||||
window.subscribe(src, PROC_REF(on_message))
|
||||
window.is_browser = TRUE
|
||||
|
||||
@@ -62,11 +61,15 @@
|
||||
*/
|
||||
/datum/tgui_say/proc/load()
|
||||
window_open = FALSE
|
||||
winshow(client, "tgui_say", FALSE)
|
||||
|
||||
winset(client, "tgui_say", "pos=700,500;is-visible=0;")
|
||||
|
||||
window.send_message("props", list(
|
||||
lightMode = FALSE,
|
||||
maxLength = max_length,
|
||||
"lightMode" = client?.prefs.tgui_say_light_mode,
|
||||
"scale" = client?.prefs.ui_scale,
|
||||
"maxLength" = max_length,
|
||||
))
|
||||
|
||||
stop_thinking()
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -19,16 +19,16 @@
|
||||
// Failed to fix, using tgalert as fallback
|
||||
action = input(src, "Did that work?", "", "Yes") in list("Yes", "No, switch to old ui")
|
||||
if (action == "No, switch to old ui")
|
||||
winset(src, "legacy_output_selector", "left=output_legacy")
|
||||
winset(src, "output_selector.legacy_output_selector", "left=output_legacy")
|
||||
log_tgui(src, "Failed to fix.", context = "verb/fix_tgui_panel")
|
||||
|
||||
/client/proc/nuke_chat()
|
||||
// Catch all solution (kick the whole thing in the pants)
|
||||
winset(src, "legacy_output_selector", "left=output_legacy")
|
||||
winset(src, "output_selector.legacy_output_selector", "left=output_legacy")
|
||||
if(!tgui_panel || !istype(tgui_panel))
|
||||
log_tgui(src, "tgui_panel datum is missing",
|
||||
context = "verb/fix_tgui_panel")
|
||||
tgui_panel = new(src)
|
||||
tgui_panel.initialize(force = TRUE)
|
||||
// Force show the panel to see if there are any errors
|
||||
winset(src, "legacy_output_selector", "left=output_browser")
|
||||
winset(src, "output_selector.legacy_output_selector", "left=output_browser")
|
||||
|
||||
@@ -65,12 +65,12 @@
|
||||
|
||||
.hisgrace .wrap {border-color: #7C1414;}
|
||||
.hisgrace .content {color: #15D512; border-color: #9D1414; background-color: #861414;}
|
||||
|
||||
|
||||
/* TG: Themes */
|
||||
/* ScreenUI */
|
||||
.midnight .wrap {border-color: #2B2B33;}
|
||||
.midnight .content {color: #6087A0; border-color: #2B2B33; background-color: #36363C;}
|
||||
|
||||
|
||||
.plasmafire .wrap {border-color: #21213D;}
|
||||
.plasmafire .content {color: #FFA800 ; border-color: #21213D; background-color:#1D1D36;}
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
.clockwork .wrap {border-color: #170800;}
|
||||
.clockwork .content {color: #B18B25; border-color: #000000; background-color: #5F380E;}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
@@ -125,7 +125,7 @@
|
||||
tilesShown = tooltip.client_view_w
|
||||
realIconSize = mapWidth / tilesShown,
|
||||
resizeRatio = realIconSize / tooltip.tileSize,
|
||||
//Calculate letterboxing offsets
|
||||
//Calculate letterboxing offsets
|
||||
leftOffset = (map.size.x - mapWidth) / 2,
|
||||
topOffset = (map.size.y - mapHeight) / 2;
|
||||
|
||||
@@ -219,6 +219,13 @@
|
||||
|
||||
var docWidth = $wrap.outerWidth(),
|
||||
docHeight = $wrap.outerHeight();
|
||||
var pixelRatio = 1;
|
||||
if (window.devicePixelRatio) {
|
||||
pixelRatio = window.devicePixelRatio;
|
||||
}
|
||||
|
||||
var docWidth = Math.floor($wrap.outerWidth() * pixelRatio),
|
||||
docHeight = Math.floor($wrap.outerHeight() * pixelRatio);
|
||||
|
||||
if (posY + docHeight > map.size.y) { //Is the bottom edge below the window? Snap it up if so
|
||||
posY = (posY - docHeight) - realIconSize - tooltip.padding;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
################################
|
||||
# Example Changelog File
|
||||
#
|
||||
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
|
||||
#
|
||||
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
|
||||
# When it is, any changes listed below will disappear.
|
||||
#
|
||||
# Valid Prefixes:
|
||||
# bugfix
|
||||
# - (fixes bugs)
|
||||
# wip
|
||||
# - (work in progress)
|
||||
# qol
|
||||
# - (quality of life)
|
||||
# soundadd
|
||||
# - (adds a sound)
|
||||
# sounddel
|
||||
# - (removes a sound)
|
||||
# rscadd
|
||||
# - (adds a feature)
|
||||
# rscdel
|
||||
# - (removes a feature)
|
||||
# imageadd
|
||||
# - (adds an image or sprite)
|
||||
# imagedel
|
||||
# - (removes an image or sprite)
|
||||
# spellcheck
|
||||
# - (fixes spelling or grammar)
|
||||
# experiment
|
||||
# - (experimental change)
|
||||
# balance
|
||||
# - (balance changes)
|
||||
# code_imp
|
||||
# - (misc internal code change)
|
||||
# refactor
|
||||
# - (refactors code)
|
||||
# config
|
||||
# - (makes a change to the config files)
|
||||
# admin
|
||||
# - (makes changes to administrator tools)
|
||||
# server
|
||||
# - (miscellaneous changes to server)
|
||||
#################################
|
||||
|
||||
# Your name.
|
||||
author: GeneralCamo, LemonInTheDark
|
||||
|
||||
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
|
||||
delete-after: True
|
||||
|
||||
# Any changes you've made. See valid prefix list above.
|
||||
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
|
||||
# SCREW THIS UP AND IT WON'T WORK.
|
||||
# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
|
||||
# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
|
||||
changes:
|
||||
- code_imp: "Brought browser code up to standard with the rest of the codebase."
|
||||
- bugfix: "Repaired several hard dels that were likely occuring with browser datums."
|
||||
@@ -0,0 +1,61 @@
|
||||
################################
|
||||
# Example Changelog File
|
||||
#
|
||||
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
|
||||
#
|
||||
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
|
||||
# When it is, any changes listed below will disappear.
|
||||
#
|
||||
# Valid Prefixes:
|
||||
# bugfix
|
||||
# - (fixes bugs)
|
||||
# wip
|
||||
# - (work in progress)
|
||||
# qol
|
||||
# - (quality of life)
|
||||
# soundadd
|
||||
# - (adds a sound)
|
||||
# sounddel
|
||||
# - (removes a sound)
|
||||
# rscadd
|
||||
# - (adds a feature)
|
||||
# rscdel
|
||||
# - (removes a feature)
|
||||
# imageadd
|
||||
# - (adds an image or sprite)
|
||||
# imagedel
|
||||
# - (removes an image or sprite)
|
||||
# spellcheck
|
||||
# - (fixes spelling or grammar)
|
||||
# experiment
|
||||
# - (experimental change)
|
||||
# balance
|
||||
# - (balance changes)
|
||||
# code_imp
|
||||
# - (misc internal code change)
|
||||
# refactor
|
||||
# - (refactors code)
|
||||
# config
|
||||
# - (makes a change to the config files)
|
||||
# admin
|
||||
# - (makes changes to administrator tools)
|
||||
# server
|
||||
# - (miscellaneous changes to server)
|
||||
#################################
|
||||
|
||||
# Your name.
|
||||
author: GeneralCamo, harry
|
||||
|
||||
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
|
||||
delete-after: True
|
||||
|
||||
# Any changes you've made. See valid prefix list above.
|
||||
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
|
||||
# SCREW THIS UP AND IT WON'T WORK.
|
||||
# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
|
||||
# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
|
||||
changes:
|
||||
- qol: "Under the chat settings, you can now press \"Adjust UI Sizes\" to drag around some of the panel sizes."
|
||||
- bugfix: "The input at the bottom right is no longer so teeny tiny on 516 if you use a window scaling that is greater than 100%."
|
||||
- qol: "There's a new UI preference called UI scale which allows people that use windows scaling to have their UIs original size with the contents zoomed out, instead of the default, which is the UIs being larger with the contents 'normal' size."
|
||||
- bugfix: "Various UIs did not respect windows scaling, they now do."
|
||||
@@ -0,0 +1,59 @@
|
||||
################################
|
||||
# Example Changelog File
|
||||
#
|
||||
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
|
||||
#
|
||||
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
|
||||
# When it is, any changes listed below will disappear.
|
||||
#
|
||||
# Valid Prefixes:
|
||||
# bugfix
|
||||
# - (fixes bugs)
|
||||
# wip
|
||||
# - (work in progress)
|
||||
# qol
|
||||
# - (quality of life)
|
||||
# soundadd
|
||||
# - (adds a sound)
|
||||
# sounddel
|
||||
# - (removes a sound)
|
||||
# rscadd
|
||||
# - (adds a feature)
|
||||
# rscdel
|
||||
# - (removes a feature)
|
||||
# imageadd
|
||||
# - (adds an image or sprite)
|
||||
# imagedel
|
||||
# - (removes an image or sprite)
|
||||
# spellcheck
|
||||
# - (fixes spelling or grammar)
|
||||
# experiment
|
||||
# - (experimental change)
|
||||
# balance
|
||||
# - (balance changes)
|
||||
# code_imp
|
||||
# - (misc internal code change)
|
||||
# refactor
|
||||
# - (refactors code)
|
||||
# config
|
||||
# - (makes a change to the config files)
|
||||
# admin
|
||||
# - (makes changes to administrator tools)
|
||||
# server
|
||||
# - (miscellaneous changes to server)
|
||||
#################################
|
||||
|
||||
# Your name.
|
||||
author: GeneralCamo
|
||||
|
||||
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
|
||||
delete-after: True
|
||||
|
||||
# Any changes you've made. See valid prefix list above.
|
||||
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
|
||||
# SCREW THIS UP AND IT WON'T WORK.
|
||||
# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
|
||||
# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
|
||||
changes:
|
||||
- rscadd: "Added a setting to set TGUI Say to light mode."
|
||||
- bugfix: "Several radio channels that did not define a color in TGUI Say, now do so."
|
||||
@@ -0,0 +1,58 @@
|
||||
################################
|
||||
# Example Changelog File
|
||||
#
|
||||
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
|
||||
#
|
||||
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
|
||||
# When it is, any changes listed below will disappear.
|
||||
#
|
||||
# Valid Prefixes:
|
||||
# bugfix
|
||||
# - (fixes bugs)
|
||||
# wip
|
||||
# - (work in progress)
|
||||
# qol
|
||||
# - (quality of life)
|
||||
# soundadd
|
||||
# - (adds a sound)
|
||||
# sounddel
|
||||
# - (removes a sound)
|
||||
# rscadd
|
||||
# - (adds a feature)
|
||||
# rscdel
|
||||
# - (removes a feature)
|
||||
# imageadd
|
||||
# - (adds an image or sprite)
|
||||
# imagedel
|
||||
# - (removes an image or sprite)
|
||||
# spellcheck
|
||||
# - (fixes spelling or grammar)
|
||||
# experiment
|
||||
# - (experimental change)
|
||||
# balance
|
||||
# - (balance changes)
|
||||
# code_imp
|
||||
# - (misc internal code change)
|
||||
# refactor
|
||||
# - (refactors code)
|
||||
# config
|
||||
# - (makes a change to the config files)
|
||||
# admin
|
||||
# - (makes changes to administrator tools)
|
||||
# server
|
||||
# - (miscellaneous changes to server)
|
||||
#################################
|
||||
|
||||
# Your name.
|
||||
author: willox, GeneralCamo
|
||||
|
||||
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
|
||||
delete-after: True
|
||||
|
||||
# Any changes you've made. See valid prefix list above.
|
||||
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
|
||||
# SCREW THIS UP AND IT WON'T WORK.
|
||||
# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
|
||||
# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
|
||||
changes:
|
||||
- bugfix: "TGUI and Tooltip windows now work with high-DPI settings."
|
||||
+40
-17
@@ -3,12 +3,13 @@
|
||||
set name = "wiki"
|
||||
set desc = "Visit the wiki."
|
||||
set hidden = 1
|
||||
var/wikiurl = GLOB.config.wikiurl
|
||||
|
||||
if(GLOB.config.wikiurl)
|
||||
if(tgui_alert(usr, "This will open the wiki in your browser. Are you sure?", "Wiki", list("Yes", "No")) == "No")
|
||||
if(wikiurl)
|
||||
if(tgui_alert(usr, "This will open the wiki in your browser. Are you sure?", "Wiki", list("Yes", "No")) != "Yes")
|
||||
return
|
||||
|
||||
var/to_open = GLOB.config.wikiurl
|
||||
var/to_open = wikiurl
|
||||
if (sub_page)
|
||||
to_open += sub_page
|
||||
|
||||
@@ -20,40 +21,62 @@
|
||||
set name = "forum"
|
||||
set desc = "Visit the forum."
|
||||
set hidden = 1
|
||||
if(GLOB.config.forumurl)
|
||||
if(tgui_alert(usr, "This will open the forum in your browser. Are you sure?", "Forum", list("Yes", "No")) == "No")
|
||||
var/forumurl = GLOB.config.forumurl
|
||||
|
||||
if(forumurl)
|
||||
if(tgui_alert(usr, "This will open the forum in your browser. Are you sure?", "Forum", list("Yes", "No")) != "Yes")
|
||||
return
|
||||
send_link(src, GLOB.config.forumurl)
|
||||
send_link(src, forumurl)
|
||||
else
|
||||
to_chat(src, SPAN_WARNING("The forum URL is not set in the server configuration."))
|
||||
return
|
||||
|
||||
/client/verb/reportbug()
|
||||
set name = "reportbug"
|
||||
set desc = "Report a bug."
|
||||
set hidden = 1
|
||||
/client/verb/reportissue()
|
||||
set name = "report-issue"
|
||||
set desc = "Report an issue."
|
||||
set hidden = TRUE
|
||||
var/githuburl = GLOB.config.githuburl
|
||||
|
||||
if(GLOB.config.githuburl)
|
||||
if(tgui_alert(usr, "This will open the issue tracker in your browser. Are you sure?", "Issue Tracker", list("Yes", "No")) == "No")
|
||||
var/message = "This will open the GitHub issue reporter in your browser. Are you sure?"
|
||||
|
||||
if(githuburl)
|
||||
// We still use alert here because some people were concerned that if someone wanted to report that tgui wasn't working
|
||||
// then the report issue button being tgui-based would be problematic.
|
||||
if(alert(src, message, "Report Issue", "Yes", "No") != "Yes")
|
||||
return
|
||||
send_link(src, GLOB.config.githuburl + "/issues")
|
||||
send_link(src, githuburl + "/issues")
|
||||
else
|
||||
to_chat(src, SPAN_WARNING("The issue tracker URL is not set in the server configuration."))
|
||||
return
|
||||
|
||||
/client/verb/rules()
|
||||
set name = "Rules"
|
||||
set name = "rules"
|
||||
set desc = "Show Server Rules."
|
||||
set hidden = 1
|
||||
var/rulesurl = GLOB.config.rulesurl
|
||||
|
||||
if(GLOB.config.rulesurl)
|
||||
if(tgui_alert(usr, "This will open the rules in your browser. Are you sure?", "Rules", list("Yes", "No")) == "No")
|
||||
if(rulesurl)
|
||||
if(tgui_alert(usr, "This will open the rules in your browser. Are you sure?", "Rules", list("Yes", "No")) != "Yes")
|
||||
return
|
||||
send_link(src, GLOB.config.rulesurl)
|
||||
send_link(src, rulesurl)
|
||||
else
|
||||
to_chat(src, SPAN_WARNING("The rules URL is not set in the server configuration."))
|
||||
return
|
||||
|
||||
/client/verb/github()
|
||||
set name = "github"
|
||||
set desc = "Visit Github"
|
||||
set hidden = TRUE
|
||||
var/githuburl = GLOB.config.githuburl
|
||||
|
||||
if(githuburl)
|
||||
if(tgui_alert(src, "This will open the GitHub repository in your browser. Are you sure?", "GitHub", list("Yes","No")) !="Yes")
|
||||
return
|
||||
send_link(src, githuburl)
|
||||
else
|
||||
to_chat(src, SPAN_WARNING("The GitHub URL is not set in the server configuration."))
|
||||
return
|
||||
|
||||
/client/verb/hotkeys_help()
|
||||
set name = "hotkeys-help"
|
||||
set category = "OOC"
|
||||
|
||||
+218
-120
@@ -926,7 +926,7 @@ window "mainwindow"
|
||||
anchor2 = 100,100
|
||||
saved-params = "splitter"
|
||||
left = "mapwindow"
|
||||
right = "infowindow"
|
||||
right = "info_and_buttons"
|
||||
is-vert = true
|
||||
elem "asset_cache_browser"
|
||||
type = BROWSER
|
||||
@@ -968,149 +968,233 @@ window "mapwindow"
|
||||
style = ".center { text-align: center; } .maptext { font-family: 'Grand9K Pixel'; font-size: 6pt; -dm-text-outline: 1px black; color: white; line-height: 1.0; } .command_headset { font-weight: bold; } .context { font-family: 'Pixellari'; font-size: 12pt; -dm-text-outline: 1px black; } .subcontext { font-family: 'TinyUnicode'; font-size: 12pt; line-height: 0.75; } .small { font-family: 'Spess Font'; font-size: 6pt; line-height: 1.4; } .big { font-family: 'Pixellari'; font-size: 12pt; } .reallybig { font-size: 12pt; } .extremelybig { font-size: 12pt; } .greentext { color: #00FF00; font-size: 6pt; } .redtext { color: #FF0000; font-size: 6pt; } .clown { color: #FF69BF; font-weight: bold; } .his_grace { color: #15D512; } .hypnophrase { color: #0d0d0d; font-weight: bold; } .yell { font-weight: bold; } .italics { font-family: 'Spess Font'; font-size: 6pt; line-height: 1.4; }"
|
||||
elem "status_bar"
|
||||
type = LABEL
|
||||
pos = 0,464
|
||||
size = 280x16
|
||||
anchor1 = 0,100
|
||||
is-visible = true
|
||||
pos = 0,470
|
||||
size = 128x10
|
||||
anchor1 = 0,99
|
||||
anchor2 = 20,100
|
||||
text = ""
|
||||
align = left
|
||||
background-color = #222222
|
||||
text-color = #ffffff
|
||||
border = line
|
||||
|
||||
window "info_and_buttons"
|
||||
elem "info_and_buttons"
|
||||
type = MAIN
|
||||
pos = 0,0
|
||||
size = 640x480
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,100
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
is-pane = true
|
||||
elem "info_button_child"
|
||||
type = CHILD
|
||||
pos = 0,0
|
||||
size = 640x477
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,100
|
||||
background-color = #ffc41f
|
||||
saved-params = "splitter"
|
||||
left = "infobuttons"
|
||||
right = "infowindow"
|
||||
is-vert = false
|
||||
splitter = 2
|
||||
show-splitter = false
|
||||
|
||||
window "infobuttons"
|
||||
elem "infobuttons"
|
||||
type = MAIN
|
||||
pos = 291,0
|
||||
size = 640x30
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,100
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
is-pane = true
|
||||
elem "rules"
|
||||
type = BUTTON
|
||||
pos = 0,5
|
||||
size = 87x25
|
||||
anchor1 = 0,0
|
||||
anchor2 = 15,100
|
||||
saved-params = "is-checked"
|
||||
text = "Rules"
|
||||
command = "rules"
|
||||
elem "wiki"
|
||||
type = BUTTON
|
||||
pos = 92,5
|
||||
size = 88x25
|
||||
anchor1 = 15,0
|
||||
anchor2 = 29,100
|
||||
saved-params = "is-checked"
|
||||
text = "Wiki"
|
||||
command = "wiki"
|
||||
elem "forum"
|
||||
type = BUTTON
|
||||
pos = 185,5
|
||||
size = 87x25
|
||||
anchor1 = 29,0
|
||||
anchor2 = 43,100
|
||||
saved-params = "is-checked"
|
||||
text = "Forum"
|
||||
command = "forum"
|
||||
elem "github"
|
||||
type = BUTTON
|
||||
pos = 277,5
|
||||
size = 87x25
|
||||
anchor1 = 43,0
|
||||
anchor2 = 57,100
|
||||
saved-params = "is-checked"
|
||||
text = "GitHub"
|
||||
command = "github"
|
||||
elem "report-issue"
|
||||
type = BUTTON
|
||||
pos = 369,5
|
||||
size = 87x25
|
||||
anchor1 = 57,0
|
||||
anchor2 = 71,100
|
||||
saved-params = "is-checked"
|
||||
text = "Report Issue"
|
||||
command = "report-issue"
|
||||
elem "interface"
|
||||
type = BUTTON
|
||||
pos = 461,5
|
||||
size = 87x25
|
||||
anchor1 = 71,0
|
||||
anchor2 = 85,100
|
||||
saved-params = "is-checked"
|
||||
text = "Web Interface"
|
||||
command = "open_webint"
|
||||
elem "discord"
|
||||
type = BUTTON
|
||||
pos = 553,5
|
||||
size = 89x25
|
||||
anchor1 = 85,0
|
||||
anchor2 = 99,100
|
||||
saved-params = "is-checked"
|
||||
text = "Discord"
|
||||
command = "open_discord"
|
||||
|
||||
window "infowindow"
|
||||
elem "infowindow"
|
||||
type = MAIN
|
||||
pos = 281,0
|
||||
size = 640x480
|
||||
size = 640x475
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
is-pane = true
|
||||
outer-size = 656x538
|
||||
inner-size = 640x499
|
||||
elem "info"
|
||||
type = CHILD
|
||||
pos = 0,30
|
||||
size = 640x445
|
||||
pos = 0,5
|
||||
size = 640x475
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,100
|
||||
background-color = none
|
||||
saved-params = "splitter"
|
||||
left = "statwindow"
|
||||
right = "outputwindow"
|
||||
is-vert = false
|
||||
elem "wikib"
|
||||
type = BUTTON
|
||||
pos = 0,0
|
||||
size = 60x16
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
saved-params = "is-checked"
|
||||
text = "Wiki"
|
||||
command = "wiki"
|
||||
elem "forumb"
|
||||
type = BUTTON
|
||||
pos = 64,0
|
||||
size = 60x16
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
saved-params = "is-checked"
|
||||
text = "Forum"
|
||||
command = "forum"
|
||||
elem "rulesb"
|
||||
type = BUTTON
|
||||
pos = 128,0
|
||||
size = 60x16
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
saved-params = "is-checked"
|
||||
text = "Rules"
|
||||
command = "rules"
|
||||
elem "changelog"
|
||||
type = BUTTON
|
||||
pos = 192,0
|
||||
size = 67x16
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
saved-params = "is-checked"
|
||||
text = "Changelog"
|
||||
command = "Changelog"
|
||||
elem "reportbugb"
|
||||
type = BUTTON
|
||||
pos = 264,0
|
||||
size = 67x16
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
saved-params = "is-checked"
|
||||
text = "Report Bug"
|
||||
command = "reportbug"
|
||||
elem "interfaceb"
|
||||
type = BUTTON
|
||||
pos = 336,0
|
||||
size = 60x16
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
saved-params = "is-checked"
|
||||
text = "WI Link"
|
||||
command = "open_webint"
|
||||
elem "discordb"
|
||||
type = BUTTON
|
||||
pos = 400,0
|
||||
size = 60x16
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
saved-params = "is-checked"
|
||||
text = "Discord"
|
||||
command = "open_discord"
|
||||
|
||||
window "outputwindow"
|
||||
elem "outputwindow"
|
||||
type = MAIN
|
||||
pos = 0,0
|
||||
size = 640x480
|
||||
size = 640x475
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
is-pane = true
|
||||
elem "output_input_child"
|
||||
type = CHILD
|
||||
pos = 0,0
|
||||
size = 640x475
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,100
|
||||
background-color = #ffc41f
|
||||
saved-params = "splitter"
|
||||
left = "output_selector"
|
||||
right = "input_and_buttons"
|
||||
is-vert = false
|
||||
splitter = 96
|
||||
show-splitter = false
|
||||
|
||||
window "output_selector"
|
||||
elem "output_selector"
|
||||
type = MAIN
|
||||
pos = 0,0
|
||||
size = 640x475
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
is-pane = true
|
||||
elem "legacy_output_selector"
|
||||
type = CHILD
|
||||
pos = 0,0
|
||||
size = 640x475
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,100
|
||||
saved-params = "splitter"
|
||||
left = "output_legacy"
|
||||
is-vert = false
|
||||
|
||||
window "input_and_buttons"
|
||||
elem "input_and_buttons"
|
||||
type = MAIN
|
||||
pos = 291,0
|
||||
size = 640x20
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
is-pane = true
|
||||
elem "input_buttons_child"
|
||||
type = CHILD
|
||||
pos = 0,0
|
||||
size = 640x20
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,100
|
||||
background-color = #ffc41f
|
||||
saved-params = "splitter"
|
||||
left = "inputwindow"
|
||||
right = "inputbuttons"
|
||||
is-vert = true
|
||||
splitter = 80
|
||||
show-splitter = false
|
||||
|
||||
window "inputwindow"
|
||||
elem "inputwindow"
|
||||
type = MAIN
|
||||
pos = 575,0
|
||||
size = 520x25
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
is-pane = true
|
||||
outer-size = 656x538
|
||||
inner-size = 640x499
|
||||
elem "input"
|
||||
type = INPUT
|
||||
pos = 2,460
|
||||
size = 517x20
|
||||
anchor1 = 0,100
|
||||
pos = 0,0
|
||||
size = 805x20
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,100
|
||||
is-default = true
|
||||
border = line
|
||||
saved-params = "command"
|
||||
elem "hotkey_toggle"
|
||||
type = BUTTON
|
||||
pos = 599,460
|
||||
size = 80x20
|
||||
anchor1 = 100,100
|
||||
anchor2 = -1,-1
|
||||
saved-params = ""
|
||||
text = "Hotkey Toggle"
|
||||
command = ".winset \"mainwindow.macro!=macro ? mainwindow.macro=macro hotkey_toggle.is-checked=false input.focus=true : mainwindow.macro=hotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true\""
|
||||
is-flat = true
|
||||
button-type = pushbox
|
||||
|
||||
window "inputbuttons"
|
||||
elem "inputbuttons"
|
||||
type = MAIN
|
||||
pos = 291,0
|
||||
size = 120x25
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,100
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
is-pane = true
|
||||
elem "saybutton"
|
||||
type = BUTTON
|
||||
pos = 519,460
|
||||
size = 40x20
|
||||
anchor1 = 100,100
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
pos = 0,0
|
||||
size = 30x20
|
||||
anchor1 = 0,0
|
||||
anchor2 = 25,100
|
||||
font-size = 4
|
||||
border = line
|
||||
saved-params = "is-checked"
|
||||
text = "Say"
|
||||
@@ -1119,26 +1203,43 @@ window "outputwindow"
|
||||
button-type = pushbox
|
||||
elem "mebutton"
|
||||
type = BUTTON
|
||||
pos = 559,460
|
||||
size = 40x20
|
||||
anchor1 = 100,100
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
pos = 30,0
|
||||
size = 30x20
|
||||
anchor1 = 25,0
|
||||
anchor2 = 50,100
|
||||
font-size = 4
|
||||
border = line
|
||||
saved-params = "is-checked"
|
||||
text = "Me"
|
||||
command = ".winset \"mebutton.is-checked=true ? input.command=\"!me \\\"\" : input.command=\"\"mebutton.is-checked=true ? saybutton.is-checked=false\"\"mebutton.is-checked=true ? oocbutton.is-checked=false\""
|
||||
is-flat = true
|
||||
button-type = pushbox
|
||||
elem "legacy_output_selector"
|
||||
type = CHILD
|
||||
pos = 0,0
|
||||
size = 640x456
|
||||
anchor1 = 0,0
|
||||
elem "oocbutton"
|
||||
type = BUTTON
|
||||
pos = 60,0
|
||||
size = 30x20
|
||||
anchor1 = 50,0
|
||||
anchor2 = 75,100
|
||||
font-size = 4
|
||||
border = line
|
||||
saved-params = "is-checked"
|
||||
text = "OOC"
|
||||
command = ".winset \"oocbutton.is-checked=true ? input.command=\"!ooc \\\"\" : input.command=\"\"oocbutton.is-checked=true ? mebutton.is-checked=false\"\"oocbutton.is-checked=true ? saybutton.is-checked=false\""
|
||||
is-flat = true
|
||||
button-type = pushbox
|
||||
elem "hotkey_toggle"
|
||||
type = BUTTON
|
||||
pos = 90,0
|
||||
size = 30x20
|
||||
anchor1 = 75,0
|
||||
anchor2 = 100,100
|
||||
saved-params = "splitter"
|
||||
left = "output_legacy"
|
||||
is-vert = false
|
||||
font-size = 4
|
||||
border = line
|
||||
saved-params = "is-checked"
|
||||
text = "Hotkey Toggle"
|
||||
command = ".winset \"mainwindow.macro!=macro ? mainwindow.macro=macro hotkey_toggle.is-checked=false input.focus=true : mainwindow.macro=hotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true\""
|
||||
is-flat = true
|
||||
button-type = pushbox
|
||||
|
||||
window "output_legacy"
|
||||
elem "output_legacy"
|
||||
@@ -1147,7 +1248,6 @@ window "output_legacy"
|
||||
size = 640x456
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
is-pane = true
|
||||
elem "output"
|
||||
@@ -1165,7 +1265,6 @@ window "output_browser"
|
||||
size = 640x456
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
is-pane = true
|
||||
elem "browseroutput"
|
||||
@@ -1174,7 +1273,6 @@ window "output_browser"
|
||||
size = 640x456
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,100
|
||||
background-color = none
|
||||
saved-params = ""
|
||||
|
||||
window "preferences_window"
|
||||
|
||||
@@ -75,7 +75,7 @@ const setupApp = () => {
|
||||
Byond.subscribe((type, payload) => store.dispatch({ type, payload }));
|
||||
|
||||
// Unhide the panel
|
||||
Byond.winset('legacy_output_selector', {
|
||||
Byond.winset('output_selector.legacy_output_selector', {
|
||||
left: 'output_browser',
|
||||
});
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import { rebuildChat, saveChatToDisk, clearChatMessages } from '../chat/actions'
|
||||
import { THEMES } from '../themes';
|
||||
import { changeSettingsTab, updateSettings, addHighlightSetting, removeHighlightSetting, updateHighlightSetting } from './actions';
|
||||
import { SETTINGS_TABS, FONTS, MAX_HIGHLIGHT_SETTINGS } from './constants';
|
||||
import { resetPaneSplitters, setEditPaneSplitters } from './scaling';
|
||||
import { selectActiveTab, selectSettings, selectHighlightSettings, selectHighlightSettingById } from './selectors';
|
||||
import { IMPL_IFRAME_INDEXED_DB, storage } from 'common/storage';
|
||||
|
||||
@@ -57,6 +58,11 @@ export const SettingsGeneral = (props, context) => {
|
||||
);
|
||||
const dispatch = useDispatch(context);
|
||||
const [freeFont, setFreeFont] = useLocalState(context, 'freeFont', false);
|
||||
const [editingPanes, setEditingPanes] = useLocalState(
|
||||
context,
|
||||
'uiScaling',
|
||||
false
|
||||
);
|
||||
return (
|
||||
<Section>
|
||||
<LabeledList>
|
||||
@@ -73,6 +79,28 @@ export const SettingsGeneral = (props, context) => {
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="UI sizes">
|
||||
<Stack>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
onClick={() =>
|
||||
setEditingPanes((val) => {
|
||||
setEditPaneSplitters(!val);
|
||||
return !val;
|
||||
})
|
||||
}
|
||||
color={editingPanes ? 'red' : undefined}
|
||||
icon={editingPanes ? 'save' : undefined}>
|
||||
{editingPanes ? 'Save' : 'Adjust UI Sizes'}
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button onClick={resetPaneSplitters} icon="refresh" color="red">
|
||||
Reset
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Font style">
|
||||
<Stack inline align="baseline">
|
||||
<Stack.Item>
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* @copyright 2020 Aleksej Komarov
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { storage } from 'common/storage';
|
||||
import { setClientTheme } from '../themes';
|
||||
import { loadSettings, updateSettings, addHighlightSetting, removeHighlightSetting, updateHighlightSetting } from './actions';
|
||||
import { selectSettings } from './selectors';
|
||||
import { FONTS_DISABLED } from './constants';
|
||||
|
||||
const setGlobalFontSize = (fontSize) => {
|
||||
document.documentElement.style.setProperty('font-size', fontSize + 'px');
|
||||
document.body.style.setProperty('font-size', fontSize + 'px');
|
||||
};
|
||||
|
||||
const setGlobalFontFamily = (fontFamily) => {
|
||||
if (fontFamily === FONTS_DISABLED) fontFamily = null;
|
||||
|
||||
document.documentElement.style.setProperty('font-family', fontFamily);
|
||||
document.body.style.setProperty('font-family', fontFamily);
|
||||
};
|
||||
|
||||
export const settingsMiddleware = (store) => {
|
||||
let initialized = false;
|
||||
return (next) => (action) => {
|
||||
const { type, payload } = action;
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
storage.get('panel-settings').then((settings) => {
|
||||
store.dispatch(loadSettings(settings));
|
||||
});
|
||||
}
|
||||
if (
|
||||
type === updateSettings.type ||
|
||||
type === loadSettings.type ||
|
||||
type === addHighlightSetting.type ||
|
||||
type === removeHighlightSetting.type ||
|
||||
type === updateHighlightSetting.type
|
||||
) {
|
||||
// Set client theme
|
||||
const theme = payload?.theme;
|
||||
if (theme) {
|
||||
setClientTheme(theme);
|
||||
}
|
||||
// Pass action to get an updated state
|
||||
next(action);
|
||||
const settings = selectSettings(store.getState());
|
||||
// Update global UI font size
|
||||
setGlobalFontSize(settings.fontSize);
|
||||
setGlobalFontFamily(settings.fontFamily);
|
||||
// Save settings to the web storage
|
||||
storage.set('panel-settings', settings);
|
||||
return;
|
||||
}
|
||||
return next(action);
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* @file
|
||||
* @copyright 2020 Aleksej Komarov
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { storage } from 'common/storage';
|
||||
import { setClientTheme } from '../themes';
|
||||
import { addHighlightSetting, loadSettings, removeHighlightSetting, updateHighlightSetting, updateSettings } from './actions';
|
||||
import { selectSettings } from './selectors';
|
||||
import { FONTS_DISABLED } from './constants';
|
||||
import { setDisplayScaling } from './scaling';
|
||||
|
||||
let statFontTimer: NodeJS.Timeout;
|
||||
let statTabsTimer: NodeJS.Timeout;
|
||||
let overrideRule: HTMLStyleElement;
|
||||
let overrideFontFamily: string | undefined;
|
||||
let overrideFontSize: string;
|
||||
|
||||
/** Updates the global CSS rule to override the font family and size. */
|
||||
function updateGlobalOverrideRule() {
|
||||
let fontFamily = '';
|
||||
|
||||
if (overrideFontFamily !== undefined) {
|
||||
fontFamily = `font-family: ${overrideFontFamily} !important;`;
|
||||
}
|
||||
|
||||
const constructedRule = `body * :not(.Icon) {
|
||||
${fontFamily}
|
||||
}`;
|
||||
|
||||
if (overrideRule === undefined) {
|
||||
overrideRule = document.createElement('style');
|
||||
document.querySelector('head')?.append(overrideRule);
|
||||
}
|
||||
|
||||
// no other way to force a CSS refresh other than to update its innerText
|
||||
overrideRule.innerText = constructedRule;
|
||||
|
||||
document.body.style.setProperty('font-size', overrideFontSize);
|
||||
}
|
||||
|
||||
function setGlobalFontSize(
|
||||
fontSize: string,
|
||||
statFontSize: string,
|
||||
statLinked: boolean
|
||||
) {
|
||||
overrideFontSize = `${fontSize}px`;
|
||||
|
||||
// Used solution from theme.ts
|
||||
clearInterval(statFontTimer);
|
||||
Byond.command(
|
||||
`.output statbrowser:set_font_size ${
|
||||
statLinked ? fontSize : statFontSize
|
||||
}px`
|
||||
);
|
||||
statFontTimer = setTimeout(() => {
|
||||
Byond.command(
|
||||
`.output statbrowser:set_font_size ${
|
||||
statLinked ? fontSize : statFontSize
|
||||
}px`
|
||||
);
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
function setGlobalFontFamily(fontFamily: string) {
|
||||
overrideFontFamily = fontFamily === FONTS_DISABLED ? undefined : fontFamily;
|
||||
}
|
||||
|
||||
function setStatTabsStyle(style: string) {
|
||||
clearInterval(statTabsTimer);
|
||||
Byond.command(`.output statbrowser:set_tabs_style ${style}`);
|
||||
statTabsTimer = setTimeout(() => {
|
||||
Byond.command(`.output statbrowser:set_tabs_style ${style}`);
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
export const settingsMiddleware = (store) => {
|
||||
let initialized = false;
|
||||
return (next) => (action) => {
|
||||
const { type, payload } = action;
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
|
||||
setDisplayScaling();
|
||||
|
||||
storage.get('panel-settings').then((settings) => {
|
||||
store.dispatch(loadSettings(settings));
|
||||
});
|
||||
}
|
||||
if (
|
||||
type === updateSettings.type ||
|
||||
type === loadSettings.type ||
|
||||
type === addHighlightSetting.type ||
|
||||
type === removeHighlightSetting.type ||
|
||||
type === updateHighlightSetting.type
|
||||
) {
|
||||
// Set client theme
|
||||
const theme = payload?.theme;
|
||||
if (theme) {
|
||||
setClientTheme(theme);
|
||||
}
|
||||
// Pass action to get an updated state
|
||||
next(action);
|
||||
|
||||
const settings = selectSettings(store.getState());
|
||||
|
||||
// Update stat panel settings
|
||||
setStatTabsStyle(settings.statTabsStyle);
|
||||
// Update global UI font size
|
||||
setGlobalFontSize(
|
||||
settings.fontSize,
|
||||
settings.statFontSize,
|
||||
settings.statLinked
|
||||
);
|
||||
setGlobalFontFamily(settings.fontFamily);
|
||||
updateGlobalOverrideRule();
|
||||
// Save settings to the web storage
|
||||
storage.set('panel-settings', settings);
|
||||
return;
|
||||
}
|
||||
return next(action);
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
// This is the elements from the skin.dmf that we need to adjust the fontsize of
|
||||
const ELEMENTS_TO_ADJUST = [
|
||||
'infobuttons.rules',
|
||||
'infobuttons.wiki',
|
||||
'infobuttons.forum',
|
||||
'infobuttons.github',
|
||||
'infobuttons.report-issue',
|
||||
'infobuttons.interface',
|
||||
'infobuttons.discord',
|
||||
'inputwindow.input',
|
||||
'inputbuttons.saybutton',
|
||||
'inputbuttons.mebutton',
|
||||
'inputbuttons.oocbutton',
|
||||
'inputbuttons.hotkey_toggle',
|
||||
'mapwindow.status_bar',
|
||||
];
|
||||
|
||||
const DEFAULT_BUTTON_FONT_SIZE = 4;
|
||||
|
||||
export async function setDisplayScaling() {
|
||||
if (window.devicePixelRatio === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newSizes: { [element: string]: number } = {};
|
||||
|
||||
for (const element of ELEMENTS_TO_ADJUST) {
|
||||
newSizes[`${element}.font-size`] =
|
||||
DEFAULT_BUTTON_FONT_SIZE * window.devicePixelRatio;
|
||||
}
|
||||
|
||||
Byond.winset(null, newSizes);
|
||||
}
|
||||
|
||||
const PANE_SPLITTERS = {
|
||||
info_button_child: 2,
|
||||
input_buttons_child: 80,
|
||||
output_input_child: 96,
|
||||
};
|
||||
|
||||
export function setEditPaneSplitters(editing: boolean) {
|
||||
const toSet: { [element: string]: any } = {};
|
||||
|
||||
for (const pane of Object.keys(PANE_SPLITTERS)) {
|
||||
toSet[`${pane}.show-splitter`] = editing;
|
||||
}
|
||||
|
||||
Byond.winset(null, toSet);
|
||||
}
|
||||
|
||||
export function resetPaneSplitters() {
|
||||
const toSet: { [element: string]: any } = {};
|
||||
|
||||
for (const default_obj of Object.entries(PANE_SPLITTERS)) {
|
||||
toSet[`${default_obj[0]}.splitter`] = default_obj[1];
|
||||
}
|
||||
|
||||
Byond.winset(null, toSet);
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* @copyright 2020 Aleksej Komarov
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
export const THEMES = ['light', 'dark'];
|
||||
|
||||
const COLOR_DARK_BG = '#202020';
|
||||
const COLOR_DARK_BG_DARKER = '#171717';
|
||||
const COLOR_DARK_TEXT = '#a4bad6';
|
||||
|
||||
let setClientThemeTimer = null;
|
||||
|
||||
/**
|
||||
* Darkmode preference, originally by Kmc2000.
|
||||
*
|
||||
* This lets you switch client themes by using winset.
|
||||
*
|
||||
* If you change ANYTHING in interface/skin.dmf you need to change it here.
|
||||
*
|
||||
* There's no way round it. We're essentially changing the skin by hand.
|
||||
* It's painful but it works, and is the way Lummox suggested.
|
||||
*/
|
||||
export const setClientTheme = (name) => {
|
||||
// Transmit once for fast updates and again in a little while in case we won
|
||||
// the race against statbrowser init.
|
||||
clearInterval(setClientThemeTimer);
|
||||
Byond.command(`.output statbrowser:set_theme ${name}`);
|
||||
setClientThemeTimer = setTimeout(() => {
|
||||
Byond.command(`.output statbrowser:set_theme ${name}`);
|
||||
}, 1500);
|
||||
|
||||
if (name === 'light') {
|
||||
return Byond.winset({
|
||||
// Main windows
|
||||
'mainwindow.background-color': 'none',
|
||||
'mainwindow.text-color': '#000000',
|
||||
'info.background-color': 'none',
|
||||
'info.text-color': '#000000',
|
||||
'infowindow.background-color': 'none',
|
||||
'infowindow.text-color': '#000000',
|
||||
'split.background-color': 'none',
|
||||
'split.text-color': '#000000',
|
||||
'browseroutput.background-color': 'none',
|
||||
'browseroutput.text-color': '#000000',
|
||||
'outputwindow.background-color': 'none',
|
||||
'outputwindow.text-color': '#000000',
|
||||
// Buttons
|
||||
'changelog.background-color': 'none',
|
||||
'changelog.text-color': '#000000',
|
||||
'rulesb.background-color': 'none',
|
||||
'rulesb.text-color': '#000000',
|
||||
'wikib.background-color': 'none',
|
||||
'wikib.text-color': '#000000',
|
||||
'forumb.background-color': 'none',
|
||||
'forumb.text-color': '#000000',
|
||||
'interfaceb.background-color': 'none',
|
||||
'interfaceb.text-color': '#000000',
|
||||
'discordb.background-color': 'none',
|
||||
'discordb.text-color': '#000000',
|
||||
'reportbugb.background-color': 'none',
|
||||
'reportbugb.text-color': '#000000',
|
||||
'hotkey_toggle.background-color': '#494949',
|
||||
'hotkey_toggle.text-color': '#000000',
|
||||
// Status and verb tabs
|
||||
'output.background-color': 'none',
|
||||
'output.text-color': '#000000',
|
||||
'statwindow.background-color': 'none',
|
||||
'statwindow.text-color': '#000000',
|
||||
// Say, OOC, me Buttons etc.
|
||||
'asset_cache_browser.background-color': 'none',
|
||||
'asset_cache_browser.text-color': '#000000',
|
||||
'tooltip.background-color': 'none',
|
||||
'tooltip.text-color': '#000000',
|
||||
'input.background-color': '#FFFFFF',
|
||||
'input.text-color': '#000000',
|
||||
});
|
||||
}
|
||||
if (name === 'dark') {
|
||||
Byond.winset({
|
||||
// Main windows
|
||||
'mainwindow.background-color': COLOR_DARK_BG,
|
||||
'mainwindow.text-color': COLOR_DARK_TEXT,
|
||||
'info.background-color': COLOR_DARK_BG,
|
||||
'info.text-color': COLOR_DARK_TEXT,
|
||||
'infowindow.background-color': COLOR_DARK_BG,
|
||||
'infowindow.text-color': COLOR_DARK_TEXT,
|
||||
'split.background-color': COLOR_DARK_BG,
|
||||
'split.text-color': COLOR_DARK_TEXT,
|
||||
'browseroutput.background-color': COLOR_DARK_BG,
|
||||
'browseroutput.text-color': COLOR_DARK_TEXT,
|
||||
'outputwindow.background-color': COLOR_DARK_BG,
|
||||
'outputwindow.text-color': COLOR_DARK_TEXT,
|
||||
// Buttons
|
||||
'changelog.background-color': '#494949',
|
||||
'changelog.text-color': COLOR_DARK_TEXT,
|
||||
'rulesb.background-color': '#494949',
|
||||
'rulesb.text-color': COLOR_DARK_TEXT,
|
||||
'wikib.background-color': '#494949',
|
||||
'wikib.text-color': COLOR_DARK_TEXT,
|
||||
'forumb.background-color': '#494949',
|
||||
'forumb.text-color': COLOR_DARK_TEXT,
|
||||
'discordb.background-color': '#494949',
|
||||
'discordb.text-color': COLOR_DARK_TEXT,
|
||||
'interfaceb.background-color': '#494949',
|
||||
'interfaceb.text-color': COLOR_DARK_TEXT,
|
||||
'reportbugb.background-color': '#492020',
|
||||
'reportbugb.text-color': COLOR_DARK_TEXT,
|
||||
'hotkey_toggle.background-color': '#492020',
|
||||
'hotkey_toggle.text-color': COLOR_DARK_TEXT,
|
||||
// Status and verb tabs
|
||||
'output.background-color': COLOR_DARK_BG_DARKER,
|
||||
'output.text-color': COLOR_DARK_TEXT,
|
||||
'statwindow.background-color': COLOR_DARK_BG_DARKER,
|
||||
'statwindow.text-color': COLOR_DARK_TEXT,
|
||||
// Say, OOC, me Buttons etc.
|
||||
'saybutton.background-color': COLOR_DARK_BG,
|
||||
'saybutton.text-color': COLOR_DARK_TEXT,
|
||||
'asset_cache_browser.background-color': COLOR_DARK_BG,
|
||||
'asset_cache_browser.text-color': COLOR_DARK_TEXT,
|
||||
'tooltip.background-color': COLOR_DARK_BG,
|
||||
'tooltip.text-color': COLOR_DARK_TEXT,
|
||||
'input.background-color': COLOR_DARK_BG_DARKER,
|
||||
'input.text-color': COLOR_DARK_TEXT,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @file
|
||||
* @copyright 2020 Aleksej Komarov
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
export const THEMES = ['light', 'dark'];
|
||||
|
||||
const COLORS = {
|
||||
DARK: {
|
||||
BG_BASE: '#212020',
|
||||
BG_SECOND: '#161515',
|
||||
BUTTON: '#414040',
|
||||
TEXT: '#A6A6A6',
|
||||
// AURORA SNOWFLAKE
|
||||
HOTKEY_BACKGROUND: '#492020',
|
||||
},
|
||||
LIGHT: {
|
||||
BG_BASE: '#EFEEEE',
|
||||
BG_SECOND: '#FFFFFF',
|
||||
BUTTON: '#FFFEFE',
|
||||
TEXT: '#000000',
|
||||
// AURORA SNOWFLAKE
|
||||
HOTKEY_BACKGROUND: '#494949',
|
||||
},
|
||||
};
|
||||
|
||||
let setClientThemeTimer: NodeJS.Timeout;
|
||||
|
||||
/**
|
||||
* Darkmode preference, originally by Kmc2000.
|
||||
*
|
||||
* This lets you switch client themes by using winset.
|
||||
*
|
||||
* If you change ANYTHING in interface/skin.dmf you need to change it here.
|
||||
*
|
||||
* There's no way round it. We're essentially changing the skin by hand.
|
||||
* It's painful but it works, and is the way Lummox suggested.
|
||||
*/
|
||||
export const setClientTheme = (name) => {
|
||||
// Transmit once for fast updates and again in a little while in case we won
|
||||
// the race against statbrowser init.
|
||||
clearInterval(setClientThemeTimer);
|
||||
Byond.command(`.output statbrowser:set_theme ${name}`);
|
||||
setClientThemeTimer = setTimeout(() => {
|
||||
Byond.command(`.output statbrowser:set_theme ${name}`);
|
||||
}, 1500);
|
||||
|
||||
const themeColor = COLORS[name.toUpperCase()];
|
||||
if (!themeColor) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Byond.winset({
|
||||
// Main windows
|
||||
'infobuttons.background-color': themeColor.BG_BASE,
|
||||
'infobuttons.text-color': themeColor.TEXT,
|
||||
'infowindow.background-color': themeColor.BG_BASE,
|
||||
'infowindow.text-color': themeColor.TEXT,
|
||||
'info_and_buttons.background-color': themeColor.BG_BASE,
|
||||
'info.background-color': themeColor.BG_BASE,
|
||||
'info.text-color': themeColor.TEXT,
|
||||
'browseroutput.background-color': themeColor.BG_BASE,
|
||||
'browseroutput.text-color': themeColor.TEXT,
|
||||
'outputwindow.background-color': themeColor.BG_BASE,
|
||||
'outputwindow.text-color': themeColor.TEXT,
|
||||
'mainwindow.background-color': themeColor.BG_BASE,
|
||||
'split.background-color': themeColor.BG_BASE,
|
||||
// Buttons
|
||||
'rules.background-color': themeColor.BUTTON,
|
||||
'rules.text-color': themeColor.TEXT,
|
||||
'wiki.background-color': themeColor.BUTTON,
|
||||
'wiki.text-color': themeColor.TEXT,
|
||||
'forum.background-color': themeColor.BUTTON,
|
||||
'forum.text-color': themeColor.TEXT,
|
||||
'discord.background-color': themeColor.BUTTON,
|
||||
'discord.text-color': themeColor.TEXT,
|
||||
'interface.background-color': themeColor.BUTTON,
|
||||
'interface.text-color': themeColor.TEXT,
|
||||
'github.background-color': themeColor.BUTTON,
|
||||
'github.text-color': themeColor.TEXT,
|
||||
'report-issue.background-color': themeColor.BUTTON,
|
||||
'report-issue.text-color': themeColor.TEXT,
|
||||
// Status and verb tabs
|
||||
'output.background-color': themeColor.BG_BASE,
|
||||
'output.text-color': themeColor.TEXT,
|
||||
// Say, OOC, me Buttons etc.
|
||||
'saybutton.background-color': themeColor.BG_BASE,
|
||||
'saybutton.text-color': themeColor.TEXT,
|
||||
'oocbutton.background-color': themeColor.BG_BASE,
|
||||
'oocbutton.text-color': themeColor.TEXT,
|
||||
'mebutton.background-color': themeColor.BG_BASE,
|
||||
'mebutton.text-color': themeColor.TEXT,
|
||||
'hotkey_toggle.background-color': themeColor.HOTKEY_BACKGROUND,
|
||||
'hotkey_toggle.text-color': themeColor.TEXT,
|
||||
'asset_cache_browser.background-color': themeColor.BG_BASE,
|
||||
'asset_cache_browser.text-color': themeColor.TEXT,
|
||||
'tooltip.background-color': themeColor.BG_BASE,
|
||||
'tooltip.text-color': themeColor.TEXT,
|
||||
'input.background-color': themeColor.BG_SECOND,
|
||||
'input.text-color': themeColor.TEXT,
|
||||
});
|
||||
};
|
||||
@@ -10,11 +10,13 @@ import { isEscape, KEY } from 'common/keys';
|
||||
|
||||
type ByondOpen = {
|
||||
channel: Channel;
|
||||
mapfocus: BooleanLike;
|
||||
};
|
||||
|
||||
type ByondProps = {
|
||||
maxLength: number;
|
||||
lightMode: BooleanLike;
|
||||
scale: BooleanLike;
|
||||
};
|
||||
|
||||
type State = {
|
||||
@@ -24,19 +26,13 @@ type State = {
|
||||
|
||||
const CHANNEL_REGEX = /^[:.]\w\s/;
|
||||
|
||||
const ROWS: Record<keyof typeof WINDOW_SIZES, number> = {
|
||||
small: 1,
|
||||
medium: 2,
|
||||
large: 3,
|
||||
width: 1, // not used
|
||||
} as const;
|
||||
|
||||
export class TguiSay extends Component<{}, State> {
|
||||
private channelIterator: ChannelIterator;
|
||||
private chatHistory: ChatHistory;
|
||||
private currentPrefix: keyof typeof RADIO_PREFIXES | null;
|
||||
private innerRef: RefObject<HTMLTextAreaElement>;
|
||||
private lightMode: boolean;
|
||||
private scale: boolean;
|
||||
private maxLength: number;
|
||||
private messages: typeof byondMessages;
|
||||
state: State;
|
||||
@@ -72,6 +68,8 @@ export class TguiSay extends Component<{}, State> {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
windowSet(WINDOW_SIZES.small, this.scale);
|
||||
|
||||
Byond.subscribeTo('props', this.handleProps);
|
||||
Byond.subscribeTo('force', this.handleForceSay);
|
||||
Byond.subscribeTo('open', this.handleOpen);
|
||||
@@ -140,7 +138,7 @@ export class TguiSay extends Component<{}, State> {
|
||||
this.chatHistory.reset();
|
||||
this.channelIterator.reset();
|
||||
this.currentPrefix = null;
|
||||
windowClose();
|
||||
windowClose(this.scale);
|
||||
}
|
||||
|
||||
handleEnter() {
|
||||
@@ -260,24 +258,38 @@ export class TguiSay extends Component<{}, State> {
|
||||
}
|
||||
|
||||
handleOpen = (data: ByondOpen) => {
|
||||
const { channel, mapfocus } = data;
|
||||
|
||||
if (!mapfocus) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.innerRef.current?.focus();
|
||||
}, 0);
|
||||
|
||||
const { channel } = data;
|
||||
// Catches the case where the modal is already open
|
||||
if (this.channelIterator.isSay()) {
|
||||
this.channelIterator.set(channel);
|
||||
}
|
||||
this.setState({ buttonContent: this.channelIterator.current() });
|
||||
|
||||
windowOpen(this.channelIterator.current());
|
||||
windowOpen(this.channelIterator.current(), this.scale);
|
||||
};
|
||||
|
||||
handleProps = (data: ByondProps) => {
|
||||
const { maxLength, lightMode } = data;
|
||||
const { maxLength, lightMode, scale } = data;
|
||||
this.maxLength = maxLength;
|
||||
this.lightMode = !!lightMode;
|
||||
this.scale = !!scale;
|
||||
|
||||
if (!this.scale) {
|
||||
window.document.body.style.setProperty(
|
||||
'zoom',
|
||||
`${100 / window.devicePixelRatio}%`
|
||||
);
|
||||
} else {
|
||||
window.document.body.style.setProperty('zoom', '');
|
||||
}
|
||||
};
|
||||
|
||||
reset() {
|
||||
@@ -301,7 +313,7 @@ export class TguiSay extends Component<{}, State> {
|
||||
|
||||
if (this.state.size !== newSize) {
|
||||
this.setState({ size: newSize });
|
||||
windowSet(newSize);
|
||||
windowSet(newSize, this.scale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,30 +331,35 @@ export class TguiSay extends Component<{}, State> {
|
||||
this.channelIterator.current();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`window window-${theme} window-${this.state.size}`}
|
||||
$HasKeyedChildren>
|
||||
<div className={`window window-${theme} window-${this.state.size}`}>
|
||||
<Dragzone position="top" theme={theme} />
|
||||
<div className="center" $HasKeyedChildren>
|
||||
<div className="center">
|
||||
<Dragzone position="left" theme={theme} />
|
||||
<div className="input" $HasKeyedChildren>
|
||||
{!!theme && (
|
||||
<button
|
||||
className={`button button-${theme}`}
|
||||
onClick={this.handleIncrementChannel}
|
||||
type="button">
|
||||
{this.state.buttonContent}
|
||||
</button>
|
||||
<textarea
|
||||
autoCorrect="off"
|
||||
className={`textarea textarea-${theme}`}
|
||||
maxLength={this.maxLength}
|
||||
onInput={this.handleInput}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
ref={this.innerRef}
|
||||
spellCheck={false}
|
||||
rows={ROWS[this.state.size] || 1}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<textarea
|
||||
className={`textarea textarea-${theme}`}
|
||||
maxLength={this.maxLength}
|
||||
onInput={this.handleInput}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
ref={this.innerRef}
|
||||
/>
|
||||
{!!theme && (
|
||||
<button
|
||||
key="escape"
|
||||
className={`button button-${theme}`}
|
||||
onClick={this.handleClose}
|
||||
type="submit"
|
||||
style={{ width: '2rem', marginRight: '5px' }}>
|
||||
X
|
||||
</button>
|
||||
)}
|
||||
<Dragzone position="right" theme={theme} />
|
||||
</div>
|
||||
<Dragzone position="bottom" theme={theme} />
|
||||
@@ -351,7 +368,13 @@ export class TguiSay extends Component<{}, State> {
|
||||
}
|
||||
}
|
||||
|
||||
const Dragzone = ({ theme, position }: { theme: string; position: string }) => {
|
||||
const Dragzone = ({
|
||||
theme,
|
||||
position,
|
||||
}: {
|
||||
readonly theme: string;
|
||||
readonly position: string;
|
||||
}) => {
|
||||
// Horizontal or vertical?
|
||||
const location =
|
||||
position === 'left' || position === 'right' ? 'vertical' : 'horizontal';
|
||||
|
||||
@@ -5,8 +5,8 @@ import { WINDOW_SIZES } from './constants';
|
||||
* Once byond signals this via keystroke, it
|
||||
* ensures window size, visibility, and focus.
|
||||
*/
|
||||
export const windowOpen = (channel: Channel) => {
|
||||
setWindowVisibility(true);
|
||||
export const windowOpen = (channel: Channel, scale: boolean) => {
|
||||
setWindowVisibility(true, scale);
|
||||
Byond.sendMessage('open', { channel });
|
||||
};
|
||||
|
||||
@@ -14,8 +14,8 @@ export const windowOpen = (channel: Channel) => {
|
||||
* Resets the state of the window and hides it from user view.
|
||||
* Sending "close" logs it server side.
|
||||
*/
|
||||
export const windowClose = () => {
|
||||
setWindowVisibility(false);
|
||||
export const windowClose = (scale: boolean) => {
|
||||
setWindowVisibility(false, scale);
|
||||
Byond.winset('map', {
|
||||
focus: true,
|
||||
});
|
||||
@@ -25,22 +25,34 @@ export const windowClose = () => {
|
||||
/**
|
||||
* Modifies the window size.
|
||||
*/
|
||||
export const windowSet = (size = WINDOW_SIZES.small) => {
|
||||
let sizeStr = `${WINDOW_SIZES.width}x${size}`;
|
||||
export const windowSet = (size = WINDOW_SIZES.small, scale: boolean) => {
|
||||
const pixelRatio = scale ? window.devicePixelRatio : 1;
|
||||
|
||||
Byond.winset('tgui_say.browser', {
|
||||
const sizeStr = `${WINDOW_SIZES.width * pixelRatio}x${size * pixelRatio}`;
|
||||
|
||||
Byond.winset('tgui_say', {
|
||||
size: sizeStr,
|
||||
});
|
||||
|
||||
Byond.winset('tgui_say', {
|
||||
Byond.winset('tgui_say.browser', {
|
||||
size: sizeStr,
|
||||
});
|
||||
};
|
||||
|
||||
/** Helper function to set window size and visibility */
|
||||
const setWindowVisibility = (visible: boolean) => {
|
||||
const setWindowVisibility = (visible: boolean, scale: boolean) => {
|
||||
const pixelRatio = scale ? window.devicePixelRatio : 1;
|
||||
|
||||
const sizeString = `${WINDOW_SIZES.width * pixelRatio}x${
|
||||
WINDOW_SIZES.small * pixelRatio
|
||||
}`;
|
||||
|
||||
Byond.winset('tgui_say', {
|
||||
'is-visible': visible,
|
||||
size: `${WINDOW_SIZES.width}x${WINDOW_SIZES.small}`,
|
||||
size: sizeString,
|
||||
});
|
||||
|
||||
Byond.winset('tgui_say.browser', {
|
||||
size: sizeString,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,18 +2,19 @@
|
||||
@use './colors.scss';
|
||||
|
||||
.button {
|
||||
align-items: center;
|
||||
background-color: colors.$button;
|
||||
border-radius: 0.3rem;
|
||||
border: thin solid;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
font-family: inherit;
|
||||
font-size: 0.9rem;
|
||||
border-radius: 2px;
|
||||
color: colors.$background;
|
||||
font-family: 'Consolas', monospace;
|
||||
font-weight: bold;
|
||||
justify-content: center;
|
||||
font-size: 0.9rem;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
width: 2.6rem;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
width: 5rem;
|
||||
|
||||
&:hover {
|
||||
background-color: lighten(colors.$button, 10%);
|
||||
}
|
||||
@@ -30,6 +31,7 @@
|
||||
background-color: colors.$lightBorder;
|
||||
border: none;
|
||||
color: black;
|
||||
|
||||
&:hover {
|
||||
background-color: colors.$lightHover;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ $say: #a4bad6;
|
||||
$radio: #1ecc43;
|
||||
$me: #5975da;
|
||||
$ooc: #cca300;
|
||||
$looc: #e362b4;
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// Subchannel chat colors
|
||||
@@ -31,12 +32,15 @@ $service: #7fc732;
|
||||
$supply: #c09141;
|
||||
$hail: #8b4cd8;
|
||||
$ent: #cfcfcf;
|
||||
$cling: #376340;
|
||||
|
||||
$_channel_map: (
|
||||
'Say': $say,
|
||||
'Comm': $radio,
|
||||
'Radio': $radio,
|
||||
'Me': $me,
|
||||
'OOC': $ooc,
|
||||
'LOOC': $looc,
|
||||
'AI': $ai,
|
||||
'io': $binary,
|
||||
'Cmd': $command,
|
||||
@@ -44,11 +48,14 @@ $_channel_map: (
|
||||
'Med': $medical,
|
||||
'Sci': $science,
|
||||
'Sec': $security,
|
||||
'Merc': $syndicate,
|
||||
'Synd': $syndicate,
|
||||
'Pen': $syndicate,
|
||||
'Svc': $service,
|
||||
'Supp': $supply,
|
||||
'Hail': $hail,
|
||||
'Ent': $ent,
|
||||
'Cling': $cling,
|
||||
);
|
||||
|
||||
$channel_keys: map.keys($_channel_map) !default;
|
||||
|
||||
@@ -10,5 +10,4 @@
|
||||
flex: 1 1 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
font-family: 'Consolas', monospace;
|
||||
}
|
||||
|
||||
@@ -1,27 +1,42 @@
|
||||
@use 'sass:color';
|
||||
@use './colors.scss';
|
||||
|
||||
$dragSize: 0.6rem;
|
||||
$borderSize: 0.2rem;
|
||||
// Remove conditionals with 516
|
||||
@supports (not (-webkit-hyphens: none)) and (not (-moz-appearance: none)) {
|
||||
$dragSize: 0.3rem;
|
||||
}
|
||||
|
||||
// Remove with 516
|
||||
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
|
||||
$dragSize: 0.6rem;
|
||||
}
|
||||
|
||||
$dragSize: 0.3rem;
|
||||
$borderSize: 2px;
|
||||
|
||||
.dragzone-horizontal {
|
||||
border-left: $borderSize solid;
|
||||
border-right: $borderSize solid;
|
||||
color: transparent;
|
||||
width: 100%;
|
||||
height: $dragSize;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dragzone-left {
|
||||
border-left: $borderSize solid;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.dragzone-right {
|
||||
border-right: $borderSize solid;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.dragzone-vertical {
|
||||
color: transparent;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: $dragSize;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,51 @@
|
||||
@use 'sass:color';
|
||||
@use './colors.scss';
|
||||
|
||||
@supports (not (-webkit-hyphens: none)) and (not (-moz-appearance: none)) {
|
||||
* {
|
||||
&::-webkit-scrollbar {
|
||||
width: 0.8rem;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: color.scale(
|
||||
colors.$button,
|
||||
$lightness: -25% * colors.$scrollbar-color-multiplier
|
||||
);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: color.scale(
|
||||
colors.$button,
|
||||
$lightness: 10% * colors.$scrollbar-color-multiplier
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.textarea {
|
||||
align-items: center;
|
||||
background: transparent;
|
||||
border: none;
|
||||
display: flex;
|
||||
flex-grow: 4;
|
||||
font-family: inherit;
|
||||
font-size: 1.1rem;
|
||||
overflow: hidden;
|
||||
margin: 0.1rem 0 0 0.4rem;
|
||||
}
|
||||
|
||||
// Remove conditionals with 516
|
||||
@supports (not (-webkit-hyphens: none)) and (not (-moz-appearance: none)) {
|
||||
.textarea {
|
||||
flex-grow: 8;
|
||||
outline: none;
|
||||
resize: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove with 516
|
||||
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
|
||||
.textarea {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-grow: 4;
|
||||
overflow: hidden;
|
||||
margin: 0.1rem 0 0 0.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,28 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 380px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// Remove with 516
|
||||
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
|
||||
.window {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.window-lightMode {
|
||||
background-color: colors.$lightMode;
|
||||
}
|
||||
|
||||
.window__content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
padding: 1px 0 1px 5px;
|
||||
}
|
||||
|
||||
/** Window sizes */
|
||||
.window-30 {
|
||||
height: 30px;
|
||||
|
||||
@@ -244,6 +244,7 @@ type BackendState<TData> = {
|
||||
size: [number, number];
|
||||
fancy: boolean;
|
||||
locked: boolean;
|
||||
scale: boolean;
|
||||
};
|
||||
client: {
|
||||
ckey: string;
|
||||
|
||||
@@ -42,14 +42,14 @@ export const getWindowSize = (): [number, number] => [
|
||||
const setWindowPosition = (vec: [number, number]) => {
|
||||
const byondPos = vecAdd(vec, screenOffset);
|
||||
return Byond.winset(Byond.windowId, {
|
||||
pos: byondPos[0] + ',' + byondPos[1],
|
||||
pos: `${byondPos[0]},${byondPos[1]}`,
|
||||
});
|
||||
};
|
||||
|
||||
// Set window size
|
||||
const setWindowSize = (vec: [number, number]) => {
|
||||
return Byond.winset(Byond.windowId, {
|
||||
size: vec[0] + 'x' + vec[1],
|
||||
size: `${vec[0]}x${vec[1]}`,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -120,6 +120,7 @@ export const recallWindowGeometry = async (
|
||||
pos?: [number, number];
|
||||
size?: [number, number];
|
||||
locked?: boolean;
|
||||
scale?: boolean;
|
||||
} = {}
|
||||
) => {
|
||||
const geometry = options.fancy && (await storage.get(windowKey));
|
||||
@@ -130,9 +131,22 @@ export const recallWindowGeometry = async (
|
||||
let pos = geometry?.pos || options.pos;
|
||||
let size = options.size;
|
||||
// Convert size from css-pixels to display-pixels
|
||||
if (size) {
|
||||
if (options.scale && size) {
|
||||
size = [size[0] * pixelRatio, size[1] * pixelRatio];
|
||||
}
|
||||
if (!options.scale) {
|
||||
document.body.style.setProperty(
|
||||
'zoom',
|
||||
`${100 / window.devicePixelRatio}%`
|
||||
);
|
||||
document.documentElement.style.setProperty(
|
||||
'--scaling-amount',
|
||||
window.devicePixelRatio.toString()
|
||||
);
|
||||
} else {
|
||||
document.body.style.setProperty('zoom', '');
|
||||
document.documentElement.style.setProperty('--scaling-amount', null);
|
||||
}
|
||||
// Wait until screen offset gets resolved
|
||||
await screenOffsetPromise;
|
||||
const areaAvailable = getScreenSize();
|
||||
@@ -166,7 +180,7 @@ export const recallWindowGeometry = async (
|
||||
// Setup draggable window
|
||||
export const setupDrag = async () => {
|
||||
// Calculate screen offset caused by the windows taskbar
|
||||
let windowPosition = getWindowPosition();
|
||||
const windowPosition = getWindowPosition();
|
||||
|
||||
screenOffsetPromise = Byond.winget(Byond.windowId, 'pos').then((pos) => [
|
||||
pos.x - windowPosition[0],
|
||||
@@ -207,7 +221,7 @@ export const dragStartHandler = (event: MouseEvent) => {
|
||||
logger.log('drag start');
|
||||
dragging = true;
|
||||
dragPointOffset = vecSubtract(
|
||||
[event.screenX, event.screenY],
|
||||
[event.screenX * pixelRatio, event.screenY * pixelRatio],
|
||||
getWindowPosition()
|
||||
);
|
||||
// Focus click target
|
||||
@@ -234,7 +248,10 @@ const dragMoveHandler = (event: MouseEvent) => {
|
||||
}
|
||||
event.preventDefault();
|
||||
setWindowPosition(
|
||||
vecSubtract([event.screenX, event.screenY], dragPointOffset)
|
||||
vecSubtract(
|
||||
[event.screenX * pixelRatio, event.screenY * pixelRatio],
|
||||
dragPointOffset
|
||||
) as [number, number]
|
||||
);
|
||||
};
|
||||
|
||||
@@ -245,7 +262,7 @@ export const resizeStartHandler =
|
||||
logger.log('resize start', resizeMatrix);
|
||||
resizing = true;
|
||||
dragPointOffset = vecSubtract(
|
||||
[event.screenX, event.screenY],
|
||||
[event.screenX * pixelRatio, event.screenY * pixelRatio],
|
||||
getWindowPosition()
|
||||
);
|
||||
initialSize = getWindowSize();
|
||||
@@ -273,7 +290,7 @@ const resizeMoveHandler = (event: MouseEvent) => {
|
||||
}
|
||||
event.preventDefault();
|
||||
const currentOffset = vecSubtract(
|
||||
[event.screenX, event.screenY],
|
||||
[event.screenX * pixelRatio, event.screenY * pixelRatio],
|
||||
getWindowPosition()
|
||||
);
|
||||
const delta = vecSubtract(currentOffset, dragPointOffset);
|
||||
|
||||
@@ -201,9 +201,9 @@ export class KeyEvent {
|
||||
if (this.code >= 48 && this.code <= 90) {
|
||||
this._str += String.fromCharCode(this.code);
|
||||
} else if (this.code >= KEY_F1 && this.code <= KEY_F12) {
|
||||
this._str += 'F' + (this.code - 111);
|
||||
this._str += `F${this.code - 111}`;
|
||||
} else {
|
||||
this._str += '[' + this.code + ']';
|
||||
this._str += `[${this.code}]`;
|
||||
}
|
||||
return this._str;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ $text-color: base.$color-fg !default;
|
||||
$background-color: #0a0a0a !default;
|
||||
$border-color: #88bfff !default;
|
||||
$border-radius: base.$border-radius !default;
|
||||
$font-family: Verdana, sans-serif !default;
|
||||
|
||||
.Input {
|
||||
position: relative;
|
||||
@@ -51,11 +52,17 @@ $border-radius: base.$border-radius !default;
|
||||
height: base.em(17px);
|
||||
margin: 0;
|
||||
padding: 0 0.5em;
|
||||
font-family: Verdana, sans-serif;
|
||||
font-family: $font-family;
|
||||
background-color: transparent;
|
||||
color: $text-color;
|
||||
color: inherit;
|
||||
|
||||
&::placeholder {
|
||||
font-style: italic;
|
||||
color: #777;
|
||||
color: rgba(255, 255, 255, 0.45);
|
||||
}
|
||||
|
||||
&:-ms-input-placeholder {
|
||||
font-style: italic;
|
||||
color: #777;
|
||||
|
||||
@@ -65,6 +65,12 @@ $border-radius: Input.$border-radius !default;
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
|
||||
&::placeholder {
|
||||
font-style: italic;
|
||||
color: #777;
|
||||
color: rgba(255, 255, 255, 0.45);
|
||||
}
|
||||
|
||||
&:-ms-input-placeholder {
|
||||
font-style: italic;
|
||||
color: #777;
|
||||
|
||||
@@ -76,3 +76,9 @@
|
||||
color.alpha($color-rgba) * 100%
|
||||
);
|
||||
}
|
||||
|
||||
// Multiplies our viewport units by the DPI scaling amount
|
||||
// to ensure that they display correctly when using differently-scaled windows
|
||||
@function vp($viewportUnit) {
|
||||
@return calc(var(--scaling-amount) * $viewportUnit);
|
||||
}
|
||||
|
||||
@@ -69,3 +69,8 @@
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
// A default, in case someone uses the vp() function outside of a <Window>
|
||||
:root {
|
||||
--scaling-amount: 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user