mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-26 14:31:59 +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:
+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()
|
||||
|
||||
Reference in New Issue
Block a user