mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'imbris/icing' into 'master'
Iced Closes #831, #518, #529, #644, #709, #627, #739, and #734 See merge request veloren/veloren!1467
This commit is contained in:
commit
d8ce666a9e
@ -67,6 +67,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Switched to procedural snow cover on trees
|
||||
- Significantly improved terrain generation performance
|
||||
- Significantly stabilized the game clock, to produce more "constant" TPS
|
||||
- Transitioned main menu and character selection screen to a using iced for the ui (fixes paste keybinding on macos, removes password field limits, adds tabbing between input fields in the main menu, adds language selection in the main menu)
|
||||
|
||||
### Removed
|
||||
|
||||
|
395
Cargo.lock
generated
395
Cargo.lock
generated
@ -1,5 +1,15 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "ab_glyph"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26a685fe66654266f321a8b572660953f4df36a2135706503a4c89981d76e1a2"
|
||||
dependencies = [
|
||||
"ab_glyph_rasterizer",
|
||||
"owned_ttf_parser 0.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph_rasterizer"
|
||||
version = "0.1.3"
|
||||
@ -117,6 +127,15 @@ dependencies = [
|
||||
"num-traits 0.2.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "approx"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278"
|
||||
dependencies = [
|
||||
"num-traits 0.2.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "0.4.7"
|
||||
@ -192,7 +211,7 @@ dependencies = [
|
||||
"async-task",
|
||||
"broadcaster",
|
||||
"crossbeam-channel 0.4.4",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-deque 0.7.3",
|
||||
"crossbeam-utils 0.7.2",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
@ -535,6 +554,46 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clipboard-win"
|
||||
version = "4.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5123c6b97286809fea9e38d2c9bf530edbcb9fc0d8f8272c28b0c95f067fa92d"
|
||||
dependencies = [
|
||||
"error-code",
|
||||
"str-buf",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clipboard_macos"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "145a7f9e9b89453bc0a5e32d166456405d389cea5b578f57f1274b1397588a95"
|
||||
dependencies = [
|
||||
"objc",
|
||||
"objc-foundation",
|
||||
"objc_id",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clipboard_wayland"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "926d872adca0fc88173f8b7532c651e29ce67dc97323f4546c1c8af6610937fb"
|
||||
dependencies = [
|
||||
"smithay-clipboard 0.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clipboard_x11"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "137cbd60c42327a8d63e710cee5a4d6a1ac41cdc90449ea2c2c63bd5e186290a"
|
||||
dependencies = [
|
||||
"xcb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
@ -553,21 +612,6 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c49e86fc36d5704151f5996b7b3795385f50ce09e3be0f47a0cfde869681cf8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"block",
|
||||
"core-foundation 0.7.0",
|
||||
"core-graphics 0.19.2",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa"
|
||||
version = "0.23.0"
|
||||
@ -677,6 +721,12 @@ dependencies = [
|
||||
"syn 1.0.42",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const_fn"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c478836e029dcef17fb47c89023448c64f781a046e0300e257ad8225ae59afab"
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
@ -708,11 +758,11 @@ version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4423d79fed83ebd9ab81ec21fa97144300a961782158287dc9bf7eddac37ff0b"
|
||||
dependencies = [
|
||||
"clipboard-win",
|
||||
"clipboard-win 3.1.1",
|
||||
"objc",
|
||||
"objc-foundation",
|
||||
"objc_id",
|
||||
"smithay-clipboard",
|
||||
"smithay-clipboard 0.6.1",
|
||||
"x11-clipboard",
|
||||
]
|
||||
|
||||
@ -903,7 +953,7 @@ checksum = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"crossbeam-channel 0.3.9",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-deque 0.7.3",
|
||||
"crossbeam-epoch 0.7.2",
|
||||
"crossbeam-queue 0.1.2",
|
||||
"crossbeam-utils 0.6.6",
|
||||
@ -928,6 +978,16 @@ dependencies = [
|
||||
"maybe-uninit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils 0.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.7.3"
|
||||
@ -939,6 +999,17 @@ dependencies = [
|
||||
"maybe-uninit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-epoch 0.9.0",
|
||||
"crossbeam-utils 0.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.7.2"
|
||||
@ -968,6 +1039,20 @@ dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0f606a85340376eef0d6d8fec399e6d4a544d648386c6645eb6d0653b27d9f"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"const_fn",
|
||||
"crossbeam-utils 0.8.0",
|
||||
"lazy_static",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.1.2"
|
||||
@ -1009,6 +1094,18 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5"
|
||||
dependencies = [
|
||||
"autocfg 1.0.1",
|
||||
"cfg-if 1.0.0",
|
||||
"const_fn",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.17.7"
|
||||
@ -1324,6 +1421,16 @@ dependencies = [
|
||||
"version_check 0.9.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "error-code"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b49c94f66f2d2c5ee8685039e458b4e6c9f13af7c28736baf10ce42966a5ab52"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"str-buf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "euc"
|
||||
version = "0.5.1"
|
||||
@ -1723,6 +1830,12 @@ dependencies = [
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glam"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8637c7ec4fd0776c51eeab3e0d5d1aa7e440ece3fc2ee7d674e13c957287bfc1"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
@ -1741,14 +1854,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "glutin"
|
||||
version = "0.24.1"
|
||||
source = "git+https://github.com/rust-windowing/glutin.git?rev=63a1ea7d6e64c5112418cab9f21cd409f0afd7c2#63a1ea7d6e64c5112418cab9f21cd409f0afd7c2"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8bae26a39a728b003e9fad473ea89527de0de050143b4df866f18bb154bc86e"
|
||||
dependencies = [
|
||||
"android_glue",
|
||||
"cgl",
|
||||
"cocoa 0.20.2",
|
||||
"core-foundation 0.7.0",
|
||||
"core-graphics 0.19.2",
|
||||
"cocoa",
|
||||
"core-foundation 0.9.1",
|
||||
"glutin_egl_sys",
|
||||
"glutin_emscripten_sys",
|
||||
"glutin_gles2_sys",
|
||||
@ -1759,8 +1872,8 @@ dependencies = [
|
||||
"log",
|
||||
"objc",
|
||||
"osmesa-sys",
|
||||
"parking_lot 0.10.2",
|
||||
"wayland-client 0.27.0",
|
||||
"parking_lot 0.11.0",
|
||||
"wayland-client 0.28.1",
|
||||
"wayland-egl",
|
||||
"winapi 0.3.9",
|
||||
"winit",
|
||||
@ -1769,7 +1882,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "glutin_egl_sys"
|
||||
version = "0.1.5"
|
||||
source = "git+https://github.com/rust-windowing/glutin.git?rev=63a1ea7d6e64c5112418cab9f21cd409f0afd7c2#63a1ea7d6e64c5112418cab9f21cd409f0afd7c2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2abb6aa55523480c4adc5a56bbaa249992e2dddb2fc63dc96e04a3355364c211"
|
||||
dependencies = [
|
||||
"gl_generator",
|
||||
"winapi 0.3.9",
|
||||
@ -1778,12 +1892,14 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "glutin_emscripten_sys"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/rust-windowing/glutin.git?rev=63a1ea7d6e64c5112418cab9f21cd409f0afd7c2#63a1ea7d6e64c5112418cab9f21cd409f0afd7c2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80de4146df76e8a6c32b03007bc764ff3249dcaeb4f675d68a06caf1bac363f1"
|
||||
|
||||
[[package]]
|
||||
name = "glutin_gles2_sys"
|
||||
version = "0.1.5"
|
||||
source = "git+https://github.com/rust-windowing/glutin.git?rev=63a1ea7d6e64c5112418cab9f21cd409f0afd7c2#63a1ea7d6e64c5112418cab9f21cd409f0afd7c2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8094e708b730a7c8a1954f4f8a31880af00eb8a1c5b5bf85d28a0a3c6d69103"
|
||||
dependencies = [
|
||||
"gl_generator",
|
||||
"objc",
|
||||
@ -1792,7 +1908,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "glutin_glx_sys"
|
||||
version = "0.1.7"
|
||||
source = "git+https://github.com/rust-windowing/glutin.git?rev=63a1ea7d6e64c5112418cab9f21cd409f0afd7c2#63a1ea7d6e64c5112418cab9f21cd409f0afd7c2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e393c8fc02b807459410429150e9c4faffdb312d59b8c038566173c81991351"
|
||||
dependencies = [
|
||||
"gl_generator",
|
||||
"x11-dl",
|
||||
@ -1801,11 +1918,51 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "glutin_wgl_sys"
|
||||
version = "0.1.5"
|
||||
source = "git+https://github.com/rust-windowing/glutin.git?rev=63a1ea7d6e64c5112418cab9f21cd409f0afd7c2#63a1ea7d6e64c5112418cab9f21cd409f0afd7c2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3da5951a1569dbab865c6f2a863efafff193a93caf05538d193e9e3816d21696"
|
||||
dependencies = [
|
||||
"gl_generator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glyph_brush"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afd3e2cfd503a5218dd56172a8bf7c8655a4a7cf745737c606a6edfeea1b343f"
|
||||
dependencies = [
|
||||
"glyph_brush_draw_cache",
|
||||
"glyph_brush_layout",
|
||||
"log",
|
||||
"ordered-float 1.1.0",
|
||||
"rustc-hash",
|
||||
"twox-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glyph_brush_draw_cache"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cef969a091be5565c2c10b31fd2f115cbeed9f783a27c96ae240ff8ceee067c"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"crossbeam-channel 0.5.0",
|
||||
"crossbeam-deque 0.8.0",
|
||||
"linked-hash-map",
|
||||
"rayon",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glyph_brush_layout"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10bc06d530bf20c1902f1b02799ab7372ff43f6119770c49b0bc3f21bd148820"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"approx 0.4.0",
|
||||
"xi-unicode",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "guillotiere"
|
||||
version = "0.5.2"
|
||||
@ -1988,6 +2145,69 @@ dependencies = [
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iced_core"
|
||||
version = "0.2.1"
|
||||
source = "git+https://github.com/hecrj/iced?rev=f464316#f46431600cb61d4e83e0ded1ca79525478436be3"
|
||||
|
||||
[[package]]
|
||||
name = "iced_futures"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/hecrj/iced?rev=f464316#f46431600cb61d4e83e0ded1ca79525478436be3"
|
||||
dependencies = [
|
||||
"futures 0.3.5",
|
||||
"log",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iced_graphics"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/hecrj/iced?rev=f464316#f46431600cb61d4e83e0ded1ca79525478436be3"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"glam",
|
||||
"iced_native",
|
||||
"iced_style",
|
||||
"raw-window-handle",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iced_native"
|
||||
version = "0.2.2"
|
||||
source = "git+https://github.com/hecrj/iced?rev=f464316#f46431600cb61d4e83e0ded1ca79525478436be3"
|
||||
dependencies = [
|
||||
"iced_core",
|
||||
"iced_futures",
|
||||
"num-traits 0.2.12",
|
||||
"twox-hash",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iced_style"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/hecrj/iced?rev=f464316#f46431600cb61d4e83e0ded1ca79525478436be3"
|
||||
dependencies = [
|
||||
"iced_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iced_winit"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/hecrj/iced?rev=f464316#f46431600cb61d4e83e0ded1ca79525478436be3"
|
||||
dependencies = [
|
||||
"iced_futures",
|
||||
"iced_graphics",
|
||||
"iced_native",
|
||||
"log",
|
||||
"thiserror",
|
||||
"winapi 0.3.9",
|
||||
"window_clipboard",
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
@ -2916,9 +3136,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "old_school_gfx_glutin_ext"
|
||||
version = "0.24.0"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0557cea37cc48d238c938ded2873a6cc772704ee1eb01e832b43c2dd99624bc"
|
||||
checksum = "97d3bf7a77b32b947b6eaa3bc3671d50a74cd9aafdbbd4f9a4feb03ed3a0ee94"
|
||||
dependencies = [
|
||||
"gfx_core",
|
||||
"gfx_device_gl",
|
||||
@ -3010,7 +3230,16 @@ version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3"
|
||||
dependencies = [
|
||||
"ttf-parser",
|
||||
"ttf-parser 0.6.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "owned_ttf_parser"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb477c7fd2a3a6e04e1dc6ca2e4e9b04f2df702021dc5a5d1cf078c587dc59f7"
|
||||
dependencies = [
|
||||
"ttf-parser 0.8.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3525,7 +3754,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfd016f0c045ad38b5251be2c9c0ab806917f82da4d36b2a327e5166adad9270"
|
||||
dependencies = [
|
||||
"autocfg 1.0.1",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-deque 0.7.3",
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
@ -3537,7 +3766,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8c4fec834fb6e6d2dd5eece3c7b432a52f0ba887cf40e595190c4107edc08bf"
|
||||
dependencies = [
|
||||
"crossbeam-channel 0.4.4",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-deque 0.7.3",
|
||||
"crossbeam-utils 0.7.2",
|
||||
"lazy_static",
|
||||
"num_cpus",
|
||||
@ -3708,8 +3937,8 @@ version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f61411055101f7b60ecf1041d87fb74205fb20b0c7a723f07ef39174cf6b4c0"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"crossbeam-deque",
|
||||
"approx 0.3.2",
|
||||
"crossbeam-deque 0.7.3",
|
||||
"crossbeam-utils 0.7.2",
|
||||
"linked-hash-map",
|
||||
"num_cpus",
|
||||
@ -3725,7 +3954,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59"
|
||||
dependencies = [
|
||||
"ab_glyph_rasterizer",
|
||||
"owned_ttf_parser",
|
||||
"owned_ttf_parser 0.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4007,10 +4236,8 @@ version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "562da6f2f0836e144f2e92118b35add58368280556af94f399666ebfd7d1e731"
|
||||
dependencies = [
|
||||
"andrew",
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"calloop",
|
||||
"dlib",
|
||||
"lazy_static",
|
||||
"log",
|
||||
@ -4027,8 +4254,10 @@ version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ec5c077def8af49f9b5aeeb5fcf8079c638c6615c3a8f9305e2dea601de57f7"
|
||||
dependencies = [
|
||||
"andrew",
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"calloop",
|
||||
"dlib",
|
||||
"lazy_static",
|
||||
"log",
|
||||
@ -4039,6 +4268,16 @@ dependencies = [
|
||||
"wayland-protocols 0.28.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smithay-clipboard"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e9db50a9b272938b767b731a1291f22f407315def4049db93871e8828034d5"
|
||||
dependencies = [
|
||||
"smithay-client-toolkit 0.11.0",
|
||||
"wayland-client 0.27.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smithay-clipboard"
|
||||
version = "0.6.1"
|
||||
@ -4173,6 +4412,12 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
|
||||
|
||||
[[package]]
|
||||
name = "str-buf"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a"
|
||||
|
||||
[[package]]
|
||||
name = "string"
|
||||
version = "0.2.1"
|
||||
@ -4472,7 +4717,7 @@ version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-deque 0.7.3",
|
||||
"crossbeam-queue 0.2.3",
|
||||
"crossbeam-utils 0.7.2",
|
||||
"futures 0.1.29",
|
||||
@ -4646,6 +4891,12 @@ version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc"
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d973cfa0e6124166b50a1105a67c85de40bbc625082f35c0f56f84cb1fb0a827"
|
||||
|
||||
[[package]]
|
||||
name = "tui"
|
||||
version = "0.10.0"
|
||||
@ -4669,6 +4920,9 @@ name = "twox-hash"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56"
|
||||
dependencies = [
|
||||
"rand 0.7.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tynm"
|
||||
@ -4815,7 +5069,7 @@ version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2657d8704e5e0be82b60157c8dbc71a269273ad766984508fdc54030a0690c4d"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"approx 0.3.2",
|
||||
"num-integer",
|
||||
"num-traits 0.2.12",
|
||||
"rustc_version",
|
||||
@ -4828,7 +5082,7 @@ name = "vek"
|
||||
version = "0.12.0"
|
||||
source = "git+https://gitlab.com/veloren/vek.git?branch=fix_intrinsics#237a78528b505f34f6dde5dc77db3b642388fe4a"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"approx 0.3.2",
|
||||
"num-integer",
|
||||
"num-traits 0.2.12",
|
||||
"rustc_version",
|
||||
@ -4987,8 +5241,11 @@ dependencies = [
|
||||
"git2",
|
||||
"glsl-include",
|
||||
"glutin",
|
||||
"glyph_brush",
|
||||
"guillotiere",
|
||||
"hashbrown 0.7.2",
|
||||
"iced_native",
|
||||
"iced_winit",
|
||||
"image",
|
||||
"inline_tweak",
|
||||
"itertools",
|
||||
@ -5014,6 +5271,7 @@ dependencies = [
|
||||
"veloren-server",
|
||||
"veloren-voxygen-anim",
|
||||
"veloren-world",
|
||||
"window_clipboard",
|
||||
"winit",
|
||||
"winres",
|
||||
]
|
||||
@ -5171,6 +5429,18 @@ dependencies = [
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.68"
|
||||
@ -5280,12 +5550,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wayland-egl"
|
||||
version = "0.27.0"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "123b47be6f258fffd854f016e8e7397adb8c04d984fcf308dce13714ae2231ae"
|
||||
checksum = "e7ca6190c84bcdc58beccc619bf4866709db32d653255e89da38867f97f90d61"
|
||||
dependencies = [
|
||||
"wayland-client 0.27.0",
|
||||
"wayland-sys 0.27.0",
|
||||
"wayland-client 0.28.1",
|
||||
"wayland-sys 0.28.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5448,13 +5718,26 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "window_clipboard"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b849e24b344ea3535bcda7320b8b7f3560bd2c3692de73153d3c64acc84203e5"
|
||||
dependencies = [
|
||||
"clipboard-win 4.0.3",
|
||||
"clipboard_macos",
|
||||
"clipboard_wayland",
|
||||
"clipboard_x11",
|
||||
"raw-window-handle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winit"
|
||||
version = "0.22.2"
|
||||
source = "git+https://gitlab.com/veloren/winit.git?branch=macos-test-rebased#5efbaa7e4644c627201a9c4d24217f448795ce0f"
|
||||
version = "0.23.0"
|
||||
source = "git+https://gitlab.com/veloren/winit.git?branch=macos-test-spiffed#7c8c5f21384c898f50d37298d229093549b08803"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cocoa 0.23.0",
|
||||
"cocoa",
|
||||
"core-foundation 0.9.1",
|
||||
"core-graphics 0.22.1",
|
||||
"core-video-sys",
|
||||
@ -5473,8 +5756,8 @@ dependencies = [
|
||||
"percent-encoding 2.1.0",
|
||||
"raw-window-handle",
|
||||
"serde",
|
||||
"smithay-client-toolkit 0.11.0",
|
||||
"wayland-client 0.27.0",
|
||||
"smithay-client-toolkit 0.12.0",
|
||||
"wayland-client 0.28.1",
|
||||
"winapi 0.3.9",
|
||||
"x11-dl",
|
||||
]
|
||||
@ -5544,6 +5827,12 @@ version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
|
||||
|
||||
[[package]]
|
||||
name = "xi-unicode"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a"
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.3"
|
||||
|
@ -79,6 +79,5 @@ debug = 1
|
||||
|
||||
[patch.crates-io]
|
||||
# cpal conflict fix isn't released yet
|
||||
winit = { git = "https://gitlab.com/veloren/winit.git", branch = "macos-test-rebased" }
|
||||
glutin = {git = "https://github.com/rust-windowing/glutin.git", rev="63a1ea7d6e64c5112418cab9f21cd409f0afd7c2"}
|
||||
winit = { git = "https://gitlab.com/veloren/winit.git", branch = "macos-test-spiffed" }
|
||||
vek = { git = "https://gitlab.com/veloren/vek.git", branch = "fix_intrinsics" }
|
||||
|
BIN
assets/voxygen/element/buttons/button.png
(Stored with Git LFS)
BIN
assets/voxygen/element/buttons/button.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/buttons/x_red.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/buttons/x_red.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/buttons/x_red.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/buttons/x_red.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/buttons/x_red_hover.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/buttons/x_red_hover.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/buttons/x_red_hover.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/buttons/x_red_hover.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/buttons/x_red_press.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/buttons/x_red_press.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/buttons/x_red_press.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/buttons/x_red_press.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/frames/banner.png
(Stored with Git LFS)
BIN
assets/voxygen/element/frames/banner.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/frames/banner_bottom.png
(Stored with Git LFS)
BIN
assets/voxygen/element/frames/banner_bottom.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/frames/banner_gradient_bottom.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/frames/banner_gradient_bottom.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/frames/banner_top.png
(Stored with Git LFS)
BIN
assets/voxygen/element/frames/banner_top.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/frames/info_frame_2.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/frames/info_frame_2.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/frames/loading_screen/loading_bg.png
(Stored with Git LFS)
BIN
assets/voxygen/element/frames/loading_screen/loading_bg.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/frames/loading_screen/loading_bg_l.png
(Stored with Git LFS)
BIN
assets/voxygen/element/frames/loading_screen/loading_bg_l.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/frames/loading_screen/loading_bg_r.png
(Stored with Git LFS)
BIN
assets/voxygen/element/frames/loading_screen/loading_bg_r.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/frames/server_frame.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/frames/server_frame.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/frames/tooltip/corner.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/frames/tooltip/corner.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/frames/tooltip/edge.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/frames/tooltip/edge.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/frames/window_4.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/frames/window_4.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/misc_bg/textbox.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/misc_bg/textbox.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/misc_bg/textbox_bot.png
(Stored with Git LFS)
BIN
assets/voxygen/element/misc_bg/textbox_bot.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/misc_bg/textbox_mid.png
(Stored with Git LFS)
BIN
assets/voxygen/element/misc_bg/textbox_mid.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/misc_bg/textbox_top.png
(Stored with Git LFS)
BIN
assets/voxygen/element/misc_bg/textbox_top.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/font/haxrcorp_4089_cyrillic_altgr_extended.ttf
(Stored with Git LFS)
BIN
assets/voxygen/font/haxrcorp_4089_cyrillic_altgr_extended.ttf
(Stored with Git LFS)
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
/// Localization for Polish / Tłumaczenia dla języka polskiego
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "Polish",
|
||||
language_identifier: "PL",
|
||||
|
@ -11,7 +11,7 @@
|
||||
/// `assets/voxygen/i18n` and that's it!
|
||||
|
||||
/// Lokalisation für Deutsch/Deutschland
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "Deutsch",
|
||||
language_identifier: "de_DE",
|
||||
@ -470,10 +470,10 @@ magischen Gegenstände ergattern?"#,
|
||||
"char_selection.change_server": "Server wechseln.",
|
||||
"char_selection.enter_world": "Betreten",
|
||||
"char_selection.logout": "Ausloggen",
|
||||
"char_selection.create_charater": "Charakter erstellen",
|
||||
"char_selection.create_character": "Charakter erstellen",
|
||||
"char_selection.create_new_character": "Neuen Charakter erstellen",
|
||||
"char_selection.creating_character": "Erstelle Charakter...",
|
||||
"char_selection.character_creation": "Charaktererstellung",
|
||||
"char_selection.create_new_charater": "Neuen Charakter erstellen",
|
||||
|
||||
"char_selection.human_default": "Human Default",
|
||||
"char_selection.level_fmt": "Level {level_nb}",
|
||||
|
@ -13,7 +13,7 @@
|
||||
/// WARNING: Localization files shall be saved in UTF-8 format without BOM
|
||||
|
||||
/// Localization for "global" English
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "English",
|
||||
language_identifier: "en",
|
||||
@ -65,6 +65,7 @@ VoxygenLocalization(
|
||||
"common.back": "Back",
|
||||
"common.create": "Create",
|
||||
"common.okay": "Okay",
|
||||
"common.add": "Add",
|
||||
"common.accept": "Accept",
|
||||
"common.decline": "Decline",
|
||||
"common.disclaimer": "Disclaimer",
|
||||
@ -107,6 +108,9 @@ Is the client up to date?"#,
|
||||
|
||||
|
||||
/// Start Main screen section
|
||||
"main.username": "Username",
|
||||
"main.server": "Server",
|
||||
"main.password": "Password",
|
||||
"main.connecting": "Connecting",
|
||||
"main.creating_world": "Creating world",
|
||||
"main.tip": "Tip:",
|
||||
@ -154,6 +158,9 @@ https://veloren.net/account/."#,
|
||||
"main.login.not_on_whitelist": "You need a Whitelist entry by an Admin to join",
|
||||
"main.login.banned": "You have been banned with the following reason",
|
||||
"main.login.kicked": "You have been kicked with the following reason",
|
||||
"main.login.select_language": "Select a language",
|
||||
|
||||
"main.servers.select_server": "Select a server",
|
||||
|
||||
/// End Main screen section
|
||||
|
||||
@ -476,7 +483,7 @@ magically infused items?"#,
|
||||
"char_selection.change_server": "Change Server",
|
||||
"char_selection.enter_world": "Enter World",
|
||||
"char_selection.logout": "Logout",
|
||||
"char_selection.create_new_charater": "Create New Character",
|
||||
"char_selection.create_new_character": "Create New Character",
|
||||
"char_selection.creating_character": "Creating Character...",
|
||||
"char_selection.character_creation": "Character Creation",
|
||||
|
||||
@ -493,7 +500,7 @@ magically infused items?"#,
|
||||
"char_selection.accessories": "Accessories",
|
||||
"char_selection.create_info_name": "Your Character needs a name!",
|
||||
|
||||
/// End chracter selection section
|
||||
/// End character selection section
|
||||
|
||||
|
||||
/// Start character window section
|
||||
|
@ -12,7 +12,7 @@
|
||||
///
|
||||
/// Localization for Spanish (Spain)
|
||||
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "Español de España",
|
||||
language_identifier: "es_ES",
|
||||
@ -358,7 +358,7 @@ objetos imbuidos de magia?"#,
|
||||
"char_selection.change_server": "Cambiar de servidor",
|
||||
"char_selection.enter_world": "Entrar al mundo",
|
||||
"char_selection.logout": "Salir",
|
||||
"char_selection.create_new_charater": "Crear nuevo personaje",
|
||||
"char_selection.create_new_character": "Crear nuevo personaje",
|
||||
"char_selection.creating_character": "Creando personaje...",
|
||||
"char_selection.character_creation": "Creación de personaje",
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
/// WARNING: Localization files shall be saved in UTF-8 format without BOM
|
||||
|
||||
/// Localization for "latinoamericano" Latin-American
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "Español Latino",
|
||||
language_identifier: "es_la",
|
||||
|
@ -1,5 +1,5 @@
|
||||
/// Localization for French (France locale)
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "Français",
|
||||
language_identifier: "fr_FR",
|
||||
@ -372,7 +372,7 @@ objets magiques ?"#,
|
||||
"char_selection.change_server": "Changer de serveur",
|
||||
"char_selection.enter_world": "Entrer dans le monde",
|
||||
"char_selection.logout": "Se déconnecter",
|
||||
"char_selection.create_new_charater": "Créer un nouveau personnage",
|
||||
"char_selection.create_new_character": "Créer un nouveau personnage",
|
||||
"char_selection.creating_character": "Création du personnage...",
|
||||
"char_selection.character_creation": "Création de personnage",
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
|
||||
/// Localization for "global" Italian
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "Italiano",
|
||||
language_identifier: "it_IT",
|
||||
@ -462,7 +462,7 @@ oggetti infusi di magia?"#,
|
||||
"char_selection.change_server": "Cambia Server",
|
||||
"char_selection.enter_world": "Unisciti al Mondo",
|
||||
"char_selection.logout": "Disconnettiti",
|
||||
"char_selection.create_new_charater": "Crea un nuovo Personaggio",
|
||||
"char_selection.create_new_character": "Crea un nuovo Personaggio",
|
||||
"char_selection.creating_character": "Creazione Personaggio...",
|
||||
"char_selection.character_creation": "Creazione Personaggio",
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
/// WARNING: Localization files shall be saved in UTF-8 format without BOM
|
||||
|
||||
/// Localization for "global" English
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "Nederlands",
|
||||
language_identifier: "nl",
|
||||
|
@ -1,5 +1,5 @@
|
||||
/// Localization for Portuguese (Brazil)
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "Português Brasileiro",
|
||||
language_identifier: "pt_BR",
|
||||
|
@ -1,5 +1,5 @@
|
||||
/// Localization for portuguese (Portugal)
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "Português",
|
||||
language_identifier: "pt_PT",
|
||||
@ -343,7 +343,7 @@ Comandos de chat:
|
||||
"char_selection.change_server": "Mudar de servidor",
|
||||
"char_selection.enter_world": "Entrar no mundo",
|
||||
"char_selection.logout": "Desconectar",
|
||||
"char_selection.create_new_charater": "Criar nova personagem",
|
||||
"char_selection.create_new_character": "Criar nova personagem",
|
||||
"char_selection.character_creation": "Criação de personagem",
|
||||
|
||||
"char_selection.human_default": "Humano padrão",
|
||||
|
@ -1,5 +1,5 @@
|
||||
/// Localization for "global" Russian
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "Русский",
|
||||
language_identifier: "ru_RU",
|
||||
@ -400,7 +400,7 @@ https://veloren.net/account/."#,
|
||||
"char_selection.change_server": "Сменить сервер",
|
||||
"char_selection.enter_world": "Войти в мир",
|
||||
"char_selection.logout": "Выйти в меню",
|
||||
"char_selection.create_new_charater": "Создать нового персонажа",
|
||||
"char_selection.create_new_character": "Создать нового персонажа",
|
||||
"char_selection.creating_character": "Создание персонажа...",
|
||||
"char_selection.character_creation": "Создание персонажа",
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
/// `assets/voxygen/i18n` and that's it!
|
||||
|
||||
/// Localization for Swedish
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "Svenska",
|
||||
language_identifier: "sv",
|
||||
|
@ -13,7 +13,7 @@
|
||||
/// WARNING: Localization files shall be saved in UTF-8 format without BOM
|
||||
|
||||
/// Localization for Turkish (Turkey)
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "Türkçe (Türkiye)",
|
||||
language_identifier: "tr_TR",
|
||||
|
@ -13,7 +13,7 @@
|
||||
/// 注意: 本地化文件应以 UTF-8无BOM 格式保存
|
||||
|
||||
/// "全局"本地化 Simplified Chinese-简体中文
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "Simplified Chinese",
|
||||
language_identifier: "zh_CN",
|
||||
|
@ -1,5 +1,5 @@
|
||||
/// Localization for Traditional Chinese
|
||||
VoxygenLocalization(
|
||||
(
|
||||
metadata: (
|
||||
language_name: "繁體中文",
|
||||
language_identifier: "zh_TW",
|
||||
|
@ -58,7 +58,7 @@ impl Body {
|
||||
self.hair_color = self.hair_color.min(self.species.num_hair_colors() - 1);
|
||||
self.skin = self.skin.min(self.species.num_skin_colors() - 1);
|
||||
self.eyes = self.eyes.min(self.species.num_eyes(self.body_type) - 1);
|
||||
self.eye_color = self.hair_style.min(self.species.num_eye_colors() - 1);
|
||||
self.eye_color = self.eye_color.min(self.species.num_eye_colors() - 1);
|
||||
self.accessory = self
|
||||
.accessory
|
||||
.min(self.species.num_accessories(self.body_type) - 1);
|
||||
|
@ -24,15 +24,21 @@ common = {package = "veloren-common", path = "../common"}
|
||||
anim = {package = "veloren-voxygen-anim", path = "src/anim", default-features = false}
|
||||
|
||||
# Graphics
|
||||
conrod_core = {git = "https://gitlab.com/veloren/conrod.git", branch="copypasta_0.7"}
|
||||
conrod_winit = {git = "https://gitlab.com/veloren/conrod.git", branch="copypasta_0.7"}
|
||||
euc = {git = "https://github.com/zesterer/euc.git"}
|
||||
gfx = "0.18.2"
|
||||
gfx_device_gl = {version = "0.16.2", optional = true}
|
||||
gfx_gl = {version = "0.6.1", optional = true}
|
||||
glutin = {git = "https://github.com/rust-windowing/glutin.git", rev="63a1ea7d6e64c5112418cab9f21cd409f0afd7c2"}
|
||||
old_school_gfx_glutin_ext = "0.24"
|
||||
winit = {version = "0.22.2", features = ["serde"]}
|
||||
glutin = "0.25.1"
|
||||
old_school_gfx_glutin_ext = "0.25"
|
||||
winit = {version = "0.23.0", features = ["serde"]}
|
||||
|
||||
# Ui
|
||||
conrod_core = {git = "https://gitlab.com/veloren/conrod.git", branch="copypasta_0.7"}
|
||||
conrod_winit = {git = "https://gitlab.com/veloren/conrod.git", branch="copypasta_0.7"}
|
||||
euc = {git = "https://github.com/zesterer/euc.git"}
|
||||
iced = {package = "iced_native", git = "https://github.com/hecrj/iced", rev = "f464316"}
|
||||
iced_winit = {git = "https://github.com/hecrj/iced", rev = "f464316"}
|
||||
window_clipboard = "0.1.1"
|
||||
glyph_brush = "0.7.0"
|
||||
|
||||
# ECS
|
||||
specs = {git = "https://github.com/amethyst/specs.git", rev = "7a2e348ab2223818bad487695c66c43db88050a5"}
|
||||
|
@ -8,9 +8,9 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
hud::get_quality_col,
|
||||
i18n::VoxygenLocalization,
|
||||
i18n::Localization,
|
||||
ui::{
|
||||
fonts::ConrodVoxygenFonts,
|
||||
fonts::Fonts,
|
||||
slot::{ContentSize, SlotMaker},
|
||||
ImageFrame, Tooltip, TooltipManager, Tooltipable,
|
||||
},
|
||||
@ -90,14 +90,14 @@ pub struct Bag<'a> {
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
item_imgs: &'a ItemImgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
slot_manager: &'a mut SlotManager,
|
||||
_pulse: f32,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
localized_strings: &'a Localization,
|
||||
|
||||
stats: &'a Stats,
|
||||
show: &'a Show,
|
||||
@ -109,12 +109,12 @@ impl<'a> Bag<'a> {
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
item_imgs: &'a ItemImgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
slot_manager: &'a mut SlotManager,
|
||||
pulse: f32,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
localized_strings: &'a Localization,
|
||||
stats: &'a Stats,
|
||||
show: &'a Show,
|
||||
) -> Self {
|
||||
|
@ -4,8 +4,8 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
hud::{get_buff_info, BuffPosition},
|
||||
i18n::VoxygenLocalization,
|
||||
ui::{fonts::ConrodVoxygenFonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
i18n::Localization,
|
||||
ui::{fonts::Fonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
GlobalState,
|
||||
};
|
||||
|
||||
@ -34,12 +34,12 @@ widget_ids! {
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct BuffsBar<'a> {
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
localized_strings: &'a Localization,
|
||||
buffs: &'a Buffs,
|
||||
pulse: f32,
|
||||
global_state: &'a GlobalState,
|
||||
@ -49,10 +49,10 @@ impl<'a> BuffsBar<'a> {
|
||||
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
|
||||
pub fn new(
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
localized_strings: &'a Localization,
|
||||
buffs: &'a Buffs,
|
||||
pulse: f32,
|
||||
global_state: &'a GlobalState,
|
||||
|
@ -3,8 +3,8 @@ use super::{
|
||||
BLACK, CRITICAL_HP_COLOR, LOW_HP_COLOR, TEXT_COLOR,
|
||||
};
|
||||
use crate::{
|
||||
i18n::VoxygenLocalization,
|
||||
ui::{fonts::ConrodVoxygenFonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
i18n::Localization,
|
||||
ui::{fonts::Fonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
window::GameInput,
|
||||
GlobalState,
|
||||
};
|
||||
@ -49,13 +49,13 @@ pub struct Buttons<'a> {
|
||||
client: &'a Client,
|
||||
show_bag: bool,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
global_state: &'a GlobalState,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
localized_strings: &'a Localization,
|
||||
stats: &'a Stats,
|
||||
}
|
||||
|
||||
@ -65,11 +65,11 @@ impl<'a> Buttons<'a> {
|
||||
client: &'a Client,
|
||||
show_bag: bool,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
global_state: &'a GlobalState,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
localized_strings: &'a Localization,
|
||||
stats: &'a Stats,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -2,7 +2,7 @@ use super::{
|
||||
img_ids::Imgs, ERROR_COLOR, FACTION_COLOR, GROUP_COLOR, INFO_COLOR, KILL_COLOR, LOOT_COLOR,
|
||||
OFFLINE_COLOR, ONLINE_COLOR, REGION_COLOR, SAY_COLOR, TELL_COLOR, TEXT_COLOR, WORLD_COLOR,
|
||||
};
|
||||
use crate::{i18n::VoxygenLocalization, ui::fonts::ConrodVoxygenFonts, GlobalState};
|
||||
use crate::{i18n::Localization, ui::fonts::Fonts, GlobalState};
|
||||
use client::{cmd, Client};
|
||||
use common::{
|
||||
comp::{
|
||||
@ -52,7 +52,7 @@ pub struct Chat<'a> {
|
||||
|
||||
global_state: &'a GlobalState,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
@ -60,7 +60,7 @@ pub struct Chat<'a> {
|
||||
// TODO: add an option to adjust this
|
||||
history_max: usize,
|
||||
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
localized_strings: &'a Localization,
|
||||
}
|
||||
|
||||
impl<'a> Chat<'a> {
|
||||
@ -69,8 +69,8 @@ impl<'a> Chat<'a> {
|
||||
client: &'a Client,
|
||||
global_state: &'a GlobalState,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
fonts: &'a Fonts,
|
||||
localized_strings: &'a Localization,
|
||||
) -> Self {
|
||||
Self {
|
||||
new_messages,
|
||||
@ -536,12 +536,7 @@ fn do_tab_completion(cursor: usize, input: &str, word: &str) -> (String, usize)
|
||||
}
|
||||
}
|
||||
|
||||
fn cursor_offset_to_index(
|
||||
offset: usize,
|
||||
text: &str,
|
||||
ui: &Ui,
|
||||
fonts: &ConrodVoxygenFonts,
|
||||
) -> Option<Index> {
|
||||
fn cursor_offset_to_index(offset: usize, text: &str, ui: &Ui, fonts: &Fonts) -> Option<Index> {
|
||||
// This moves the cursor to the given offset. Conrod is a pain.
|
||||
//
|
||||
// Width and font must match that of the chat TextEdit
|
||||
|
@ -5,8 +5,8 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
hud::get_quality_col,
|
||||
i18n::VoxygenLocalization,
|
||||
ui::{fonts::ConrodVoxygenFonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
i18n::Localization,
|
||||
ui::{fonts::Fonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
};
|
||||
use client::{self, Client};
|
||||
use common::comp::{
|
||||
@ -55,8 +55,8 @@ pub enum Event {
|
||||
pub struct Crafting<'a> {
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
fonts: &'a Fonts,
|
||||
localized_strings: &'a Localization,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
item_imgs: &'a ItemImgs,
|
||||
@ -69,8 +69,8 @@ impl<'a> Crafting<'a> {
|
||||
pub fn new(
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
fonts: &'a Fonts,
|
||||
localized_strings: &'a Localization,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
item_imgs: &'a ItemImgs,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::{img_ids::Imgs, settings_window::SettingsTab, TEXT_COLOR};
|
||||
use crate::{i18n::VoxygenLocalization, ui::fonts::ConrodVoxygenFonts};
|
||||
use crate::{i18n::Localization, ui::fonts::Fonts};
|
||||
use conrod_core::{
|
||||
widget::{self, Button, Image},
|
||||
widget_ids, Color, Labelable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||
@ -22,19 +22,15 @@ widget_ids! {
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct EscMenu<'a> {
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
fonts: &'a Fonts,
|
||||
localized_strings: &'a Localization,
|
||||
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
}
|
||||
|
||||
impl<'a> EscMenu<'a> {
|
||||
pub fn new(
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
) -> Self {
|
||||
pub fn new(imgs: &'a Imgs, fonts: &'a Fonts, localized_strings: &'a Localization) -> Self {
|
||||
Self {
|
||||
imgs,
|
||||
fonts,
|
||||
|
@ -6,9 +6,9 @@ use super::{
|
||||
|
||||
use crate::{
|
||||
hud::get_buff_info,
|
||||
i18n::VoxygenLocalization,
|
||||
i18n::Localization,
|
||||
settings::Settings,
|
||||
ui::{fonts::ConrodVoxygenFonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
ui::{fonts::Fonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
window::GameInput,
|
||||
GlobalState,
|
||||
};
|
||||
@ -70,8 +70,8 @@ pub struct Group<'a> {
|
||||
settings: &'a Settings,
|
||||
imgs: &'a Imgs,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
fonts: &'a Fonts,
|
||||
localized_strings: &'a Localization,
|
||||
pulse: f32,
|
||||
global_state: &'a GlobalState,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
@ -88,8 +88,8 @@ impl<'a> Group<'a> {
|
||||
settings: &'a Settings,
|
||||
imgs: &'a Imgs,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
fonts: &'a Fonts,
|
||||
localized_strings: &'a Localization,
|
||||
pulse: f32,
|
||||
global_state: &'a GlobalState,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
|
@ -3,8 +3,8 @@ use super::{
|
||||
Show, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
||||
};
|
||||
use crate::{
|
||||
i18n::VoxygenLocalization,
|
||||
ui::{fonts::ConrodVoxygenFonts, img_ids, ImageSlider},
|
||||
i18n::Localization,
|
||||
ui::{fonts::Fonts, img_ids, ImageSlider},
|
||||
GlobalState,
|
||||
};
|
||||
use client::{self, Client};
|
||||
@ -41,11 +41,11 @@ pub struct Map<'a> {
|
||||
world_map: &'a (img_ids::Rotations, Vec2<u32>),
|
||||
imgs: &'a Imgs,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
_pulse: f32,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
localized_strings: &'a Localization,
|
||||
global_state: &'a GlobalState,
|
||||
}
|
||||
impl<'a> Map<'a> {
|
||||
@ -56,9 +56,9 @@ impl<'a> Map<'a> {
|
||||
imgs: &'a Imgs,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
world_map: &'a (img_ids::Rotations, Vec2<u32>),
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
pulse: f32,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
localized_strings: &'a Localization,
|
||||
global_state: &'a GlobalState,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -2,7 +2,7 @@ use super::{
|
||||
img_ids::{Imgs, ImgsRot},
|
||||
Show, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
||||
};
|
||||
use crate::ui::{fonts::ConrodVoxygenFonts, img_ids};
|
||||
use crate::ui::{fonts::Fonts, img_ids};
|
||||
use client::{self, Client};
|
||||
use common::{comp, terrain::TerrainChunkSize, vol::RectVolSize};
|
||||
use conrod_core::{
|
||||
@ -40,7 +40,7 @@ pub struct MiniMap<'a> {
|
||||
imgs: &'a Imgs,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
world_map: &'a (img_ids::Rotations, Vec2<u32>),
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
ori: Vec3<f32>,
|
||||
@ -53,7 +53,7 @@ impl<'a> MiniMap<'a> {
|
||||
imgs: &'a Imgs,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
world_map: &'a (img_ids::Rotations, Vec2<u32>),
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
ori: Vec3<f32>,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -46,13 +46,13 @@ use spell::Spell;
|
||||
use crate::{
|
||||
ecs::{comp as vcomp, comp::HpFloaterList},
|
||||
hud::img_ids::ImgsRot,
|
||||
i18n::{i18n_asset_key, LanguageMetadata, VoxygenLocalization},
|
||||
i18n::{i18n_asset_key, LanguageMetadata, Localization},
|
||||
render::{Consts, Globals, RenderMode, Renderer},
|
||||
scene::{
|
||||
camera::{self, Camera},
|
||||
lod,
|
||||
},
|
||||
ui::{fonts::ConrodVoxygenFonts, img_ids::Rotations, slot, Graphic, Ingameable, ScaleMode, Ui},
|
||||
ui::{fonts::Fonts, img_ids::Rotations, slot, Graphic, Ingameable, ScaleMode, Ui},
|
||||
window::{Event as WinEvent, FullScreenSettings, GameInput},
|
||||
GlobalState,
|
||||
};
|
||||
@ -598,7 +598,7 @@ pub struct Hud {
|
||||
world_map: (/* Id */ Rotations, Vec2<u32>),
|
||||
imgs: Imgs,
|
||||
item_imgs: ItemImgs,
|
||||
fonts: ConrodVoxygenFonts,
|
||||
fonts: Fonts,
|
||||
rot_imgs: ImgsRot,
|
||||
new_messages: VecDeque<comp::ChatMsg>,
|
||||
new_notifications: VecDeque<common::msg::Notification>,
|
||||
@ -614,7 +614,7 @@ pub struct Hud {
|
||||
tab_complete: Option<String>,
|
||||
pulse: f32,
|
||||
velocity: f32,
|
||||
voxygen_i18n: std::sync::Arc<VoxygenLocalization>,
|
||||
i18n: std::sync::Arc<Localization>,
|
||||
slot_manager: slots::SlotManager,
|
||||
hotbar: hotbar::State,
|
||||
events: Vec<Event>,
|
||||
@ -649,12 +649,11 @@ impl Hud {
|
||||
// Load item images.
|
||||
let item_imgs = ItemImgs::new(&mut ui, imgs.not_found);
|
||||
// Load language.
|
||||
let voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key(
|
||||
let i18n = Localization::load_expect(&i18n_asset_key(
|
||||
&global_state.settings.language.selected_language,
|
||||
));
|
||||
// Load fonts.
|
||||
let fonts = ConrodVoxygenFonts::load(&voxygen_i18n.fonts, &mut ui)
|
||||
.expect("Impossible to load fonts!");
|
||||
let fonts = Fonts::load(&i18n.fonts, &mut ui).expect("Impossible to load fonts!");
|
||||
// Get the server name.
|
||||
let server = &client.server_info.name;
|
||||
// Get the id, unwrap is safe because this CANNOT be None at this
|
||||
@ -715,7 +714,7 @@ impl Hud {
|
||||
tab_complete: None,
|
||||
pulse: 0.0,
|
||||
velocity: 0.0,
|
||||
voxygen_i18n,
|
||||
i18n,
|
||||
slot_manager,
|
||||
hotbar: hotbar_state,
|
||||
events: Vec::new(),
|
||||
@ -723,10 +722,10 @@ impl Hud {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_language(&mut self, voxygen_i18n: std::sync::Arc<VoxygenLocalization>) {
|
||||
self.voxygen_i18n = voxygen_i18n;
|
||||
self.fonts = ConrodVoxygenFonts::load(&self.voxygen_i18n.fonts, &mut self.ui)
|
||||
.expect("Impossible to load fonts!");
|
||||
pub fn update_language(&mut self, i18n: std::sync::Arc<Localization>) {
|
||||
self.i18n = i18n;
|
||||
self.fonts =
|
||||
Fonts::load(&self.i18n.fonts, &mut self.ui).expect("Impossible to load fonts!");
|
||||
}
|
||||
|
||||
#[allow(clippy::assign_op_pattern)] // TODO: Pending review in #587
|
||||
@ -1256,7 +1255,7 @@ impl Hud {
|
||||
in_group,
|
||||
&global_state.settings.gameplay,
|
||||
self.pulse,
|
||||
&self.voxygen_i18n,
|
||||
&self.i18n,
|
||||
&self.imgs,
|
||||
&self.fonts,
|
||||
)
|
||||
@ -1459,8 +1458,8 @@ impl Hud {
|
||||
Intro::Show => {
|
||||
if self.pulse > 20.0 {
|
||||
self.show.want_grab = false;
|
||||
let quest_headline = &self.voxygen_i18n.get("hud.temp_quest_headline");
|
||||
let quest_text = &self.voxygen_i18n.get("hud.temp_quest_text");
|
||||
let quest_headline = &self.i18n.get("hud.temp_quest_headline");
|
||||
let quest_text = &self.i18n.get("hud.temp_quest_text");
|
||||
Image::new(self.imgs.quest_bg)
|
||||
.w_h(404.0, 858.0)
|
||||
.middle_of(ui_widgets.window)
|
||||
@ -1497,7 +1496,7 @@ impl Hud {
|
||||
.hover_image(self.imgs.button_hover)
|
||||
.press_image(self.imgs.button_press)
|
||||
.mid_bottom_with_margin_on(self.ids.q_text_bg, -120.0)
|
||||
.label(&self.voxygen_i18n.get("common.accept"))
|
||||
.label(&self.i18n.get("common.accept"))
|
||||
.label_font_id(self.fonts.cyri.conrod_id)
|
||||
.label_font_size(self.fonts.cyri.scale(22))
|
||||
.label_color(TEXT_COLOR)
|
||||
@ -1675,7 +1674,7 @@ impl Hud {
|
||||
if let Some(help_key) = global_state.settings.controls.get_binding(GameInput::Help) {
|
||||
Text::new(
|
||||
&self
|
||||
.voxygen_i18n
|
||||
.i18n
|
||||
.get("hud.press_key_to_toggle_keybindings_fmt")
|
||||
.replace("{key}", help_key.to_string().as_str()),
|
||||
)
|
||||
@ -1693,7 +1692,7 @@ impl Hud {
|
||||
{
|
||||
Text::new(
|
||||
&self
|
||||
.voxygen_i18n
|
||||
.i18n
|
||||
.get("hud.press_key_to_toggle_debug_info_fmt")
|
||||
.replace("{key}", toggle_debug_key.to_string().as_str()),
|
||||
)
|
||||
@ -1708,7 +1707,7 @@ impl Hud {
|
||||
if let Some(help_key) = global_state.settings.controls.get_binding(GameInput::Help) {
|
||||
Text::new(
|
||||
&self
|
||||
.voxygen_i18n
|
||||
.i18n
|
||||
.get("hud.press_key_to_show_keybindings_fmt")
|
||||
.replace("{key}", help_key.to_string().as_str()),
|
||||
)
|
||||
@ -1726,7 +1725,7 @@ impl Hud {
|
||||
{
|
||||
Text::new(
|
||||
&self
|
||||
.voxygen_i18n
|
||||
.i18n
|
||||
.get("hud.press_key_to_show_debug_info_fmt")
|
||||
.replace("{key}", toggle_debug_key.to_string().as_str()),
|
||||
)
|
||||
@ -1744,7 +1743,7 @@ impl Hud {
|
||||
{
|
||||
Text::new(
|
||||
&self
|
||||
.voxygen_i18n
|
||||
.i18n
|
||||
.get("hud.press_key_to_toggle_lantern_fmt")
|
||||
.replace("{key}", toggle_lantern_key.to_string().as_str()),
|
||||
)
|
||||
@ -1789,7 +1788,7 @@ impl Hud {
|
||||
global_state,
|
||||
&self.rot_imgs,
|
||||
tooltip_manager,
|
||||
&self.voxygen_i18n,
|
||||
&self.i18n,
|
||||
&player_stats,
|
||||
)
|
||||
.set(self.ids.buttons, ui_widgets)
|
||||
@ -1811,7 +1810,7 @@ impl Hud {
|
||||
&self.fonts,
|
||||
&self.rot_imgs,
|
||||
tooltip_manager,
|
||||
&self.voxygen_i18n,
|
||||
&self.i18n,
|
||||
&player_buffs,
|
||||
self.pulse,
|
||||
&global_state,
|
||||
@ -1831,7 +1830,7 @@ impl Hud {
|
||||
&self.imgs,
|
||||
&self.rot_imgs,
|
||||
&self.fonts,
|
||||
&self.voxygen_i18n,
|
||||
&self.i18n,
|
||||
self.pulse,
|
||||
&global_state,
|
||||
tooltip_manager,
|
||||
@ -1848,7 +1847,7 @@ impl Hud {
|
||||
}
|
||||
// Popup (waypoint saved and similar notifications)
|
||||
Popup::new(
|
||||
&self.voxygen_i18n,
|
||||
&self.i18n,
|
||||
client,
|
||||
&self.new_notifications,
|
||||
&self.fonts,
|
||||
@ -1884,7 +1883,7 @@ impl Hud {
|
||||
tooltip_manager,
|
||||
&mut self.slot_manager,
|
||||
self.pulse,
|
||||
&self.voxygen_i18n,
|
||||
&self.i18n,
|
||||
&player_stats,
|
||||
&self.show,
|
||||
)
|
||||
@ -1951,7 +1950,7 @@ impl Hud {
|
||||
&self.hotbar,
|
||||
tooltip_manager,
|
||||
&mut self.slot_manager,
|
||||
&self.voxygen_i18n,
|
||||
&self.i18n,
|
||||
&self.show,
|
||||
)
|
||||
.set(self.ids.skillbar, ui_widgets);
|
||||
@ -1965,7 +1964,7 @@ impl Hud {
|
||||
client,
|
||||
&self.imgs,
|
||||
&self.fonts,
|
||||
&self.voxygen_i18n,
|
||||
&self.i18n,
|
||||
&self.rot_imgs,
|
||||
tooltip_manager,
|
||||
&self.item_imgs,
|
||||
@ -2004,7 +2003,7 @@ impl Hud {
|
||||
global_state,
|
||||
&self.imgs,
|
||||
&self.fonts,
|
||||
&self.voxygen_i18n,
|
||||
&self.i18n,
|
||||
)
|
||||
.and_then(self.force_chat_input.take(), |c, input| c.input(input))
|
||||
.and_then(self.tab_complete.take(), |c, input| {
|
||||
@ -2041,7 +2040,7 @@ impl Hud {
|
||||
&self.show,
|
||||
&self.imgs,
|
||||
&self.fonts,
|
||||
&self.voxygen_i18n,
|
||||
&self.i18n,
|
||||
fps as f32,
|
||||
)
|
||||
.set(self.ids.settings_window, ui_widgets)
|
||||
@ -2194,7 +2193,7 @@ impl Hud {
|
||||
client,
|
||||
&self.imgs,
|
||||
&self.fonts,
|
||||
&self.voxygen_i18n,
|
||||
&self.i18n,
|
||||
info.selected_entity,
|
||||
&self.rot_imgs,
|
||||
tooltip_manager,
|
||||
@ -2222,14 +2221,8 @@ impl Hud {
|
||||
|
||||
// Spellbook
|
||||
if self.show.spell {
|
||||
match Spell::new(
|
||||
&self.show,
|
||||
client,
|
||||
&self.imgs,
|
||||
&self.fonts,
|
||||
&self.voxygen_i18n,
|
||||
)
|
||||
.set(self.ids.spell, ui_widgets)
|
||||
match Spell::new(&self.show, client, &self.imgs, &self.fonts, &self.i18n)
|
||||
.set(self.ids.spell, ui_widgets)
|
||||
{
|
||||
Some(spell::Event::Close) => {
|
||||
self.show.spell(false);
|
||||
@ -2249,7 +2242,7 @@ impl Hud {
|
||||
&self.world_map,
|
||||
&self.fonts,
|
||||
self.pulse,
|
||||
&self.voxygen_i18n,
|
||||
&self.i18n,
|
||||
&global_state,
|
||||
)
|
||||
.set(self.ids.map, ui_widgets)
|
||||
@ -2268,7 +2261,7 @@ impl Hud {
|
||||
}
|
||||
|
||||
if self.show.esc_menu {
|
||||
match EscMenu::new(&self.imgs, &self.fonts, &self.voxygen_i18n)
|
||||
match EscMenu::new(&self.imgs, &self.fonts, &self.i18n)
|
||||
.set(self.ids.esc_menu, ui_widgets)
|
||||
{
|
||||
Some(esc_menu::Event::OpenSettings(tab)) => {
|
||||
@ -2311,7 +2304,7 @@ impl Hud {
|
||||
if self.show.free_look {
|
||||
Text::new(
|
||||
&self
|
||||
.voxygen_i18n
|
||||
.i18n
|
||||
.get("hud.free_look_indicator")
|
||||
.replace("{key}", freelook_key.to_string().as_str()),
|
||||
)
|
||||
@ -2322,7 +2315,7 @@ impl Hud {
|
||||
.set(self.ids.free_look_bg, ui_widgets);
|
||||
Text::new(
|
||||
&self
|
||||
.voxygen_i18n
|
||||
.i18n
|
||||
.get("hud.free_look_indicator")
|
||||
.replace("{key}", freelook_key.to_string().as_str()),
|
||||
)
|
||||
@ -2336,13 +2329,13 @@ impl Hud {
|
||||
|
||||
// Auto walk indicator
|
||||
if self.show.auto_walk {
|
||||
Text::new(&self.voxygen_i18n.get("hud.auto_walk_indicator"))
|
||||
Text::new(&self.i18n.get("hud.auto_walk_indicator"))
|
||||
.color(TEXT_BG)
|
||||
.mid_top_with_margin_on(ui_widgets.window, 70.0)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(self.fonts.cyri.scale(20))
|
||||
.set(self.ids.auto_walk_bg, ui_widgets);
|
||||
Text::new(&self.voxygen_i18n.get("hud.auto_walk_indicator"))
|
||||
Text::new(&self.i18n.get("hud.auto_walk_indicator"))
|
||||
.color(KILL_COLOR)
|
||||
.top_left_with_margins_on(self.ids.auto_walk_bg, -1.0, -1.0)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
|
@ -4,9 +4,9 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
hud::get_buff_info,
|
||||
i18n::VoxygenLocalization,
|
||||
i18n::Localization,
|
||||
settings::GameplaySettings,
|
||||
ui::{fonts::ConrodVoxygenFonts, Ingameable},
|
||||
ui::{fonts::Fonts, Ingameable},
|
||||
};
|
||||
use common::comp::{BuffKind, Buffs, Energy, Health, SpeechBubble, SpeechBubbleType, Stats};
|
||||
use conrod_core::{
|
||||
@ -76,9 +76,9 @@ pub struct Overhead<'a> {
|
||||
in_group: bool,
|
||||
settings: &'a GameplaySettings,
|
||||
pulse: f32,
|
||||
voxygen_i18n: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
i18n: &'a Localization,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
@ -93,9 +93,9 @@ impl<'a> Overhead<'a> {
|
||||
in_group: bool,
|
||||
settings: &'a GameplaySettings,
|
||||
pulse: f32,
|
||||
voxygen_i18n: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
i18n: &'a Localization,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
) -> Self {
|
||||
Self {
|
||||
info,
|
||||
@ -104,7 +104,7 @@ impl<'a> Overhead<'a> {
|
||||
in_group,
|
||||
settings,
|
||||
pulse,
|
||||
voxygen_i18n,
|
||||
i18n,
|
||||
imgs,
|
||||
fonts,
|
||||
common: widget::CommonBuilder::default(),
|
||||
@ -336,7 +336,7 @@ impl<'a> Widget for Overhead<'a> {
|
||||
.set(state.ids.health_bar, ui);
|
||||
let mut txt = format!("{}/{}", health_cur_txt, health_max_txt);
|
||||
if health.is_dead {
|
||||
txt = self.voxygen_i18n.get("hud.group.dead").to_string()
|
||||
txt = self.i18n.get("hud.group.dead").to_string()
|
||||
};
|
||||
Text::new(&txt)
|
||||
.mid_top_with_margin_on(state.ids.health_bar_bg, 2.0)
|
||||
@ -420,8 +420,7 @@ impl<'a> Widget for Overhead<'a> {
|
||||
// Speech bubble
|
||||
if let Some(bubble) = self.bubble {
|
||||
let dark_mode = self.settings.speech_bubble_dark_mode;
|
||||
let localizer =
|
||||
|s: &str, i| -> String { self.voxygen_i18n.get_variation(&s, i).to_string() };
|
||||
let localizer = |s: &str, i| -> String { self.i18n.get_variation(&s, i).to_string() };
|
||||
let bubble_contents: String = bubble.message(localizer);
|
||||
let (text_color, shadow_color) = bubble_color(&bubble, dark_mode);
|
||||
let mut text = Text::new(&bubble_contents)
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
settings::ControlSettings,
|
||||
ui::{fonts::ConrodVoxygenFonts, Ingameable},
|
||||
ui::{fonts::Fonts, Ingameable},
|
||||
window::GameInput,
|
||||
};
|
||||
use conrod_core::{
|
||||
@ -25,7 +25,7 @@ widget_ids! {
|
||||
pub struct Overitem<'a> {
|
||||
name: &'a str,
|
||||
distance_from_player_sqr: &'a f32,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
controls: &'a ControlSettings,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
@ -35,7 +35,7 @@ impl<'a> Overitem<'a> {
|
||||
pub fn new(
|
||||
name: &'a str,
|
||||
distance_from_player_sqr: &'a f32,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
controls: &'a ControlSettings,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::Show;
|
||||
use crate::{i18n::VoxygenLocalization, ui::fonts::ConrodVoxygenFonts};
|
||||
use crate::{i18n::Localization, ui::fonts::Fonts};
|
||||
use client::{self, Client};
|
||||
use common::msg::Notification;
|
||||
use conrod_core::{
|
||||
@ -21,10 +21,10 @@ widget_ids! {
|
||||
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct Popup<'a> {
|
||||
voxygen_i18n: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
i18n: &'a Localization,
|
||||
client: &'a Client,
|
||||
new_notifications: &'a VecDeque<Notification>,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
show: &'a Show,
|
||||
@ -34,14 +34,14 @@ pub struct Popup<'a> {
|
||||
/// Dungeon Cleared (TODO), and Quest Completed (TODO)
|
||||
impl<'a> Popup<'a> {
|
||||
pub fn new(
|
||||
voxygen_i18n: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
i18n: &'a Localization,
|
||||
client: &'a Client,
|
||||
new_notifications: &'a VecDeque<Notification>,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
show: &'a Show,
|
||||
) -> Self {
|
||||
Self {
|
||||
voxygen_i18n,
|
||||
i18n,
|
||||
client,
|
||||
new_notifications,
|
||||
fonts,
|
||||
@ -126,7 +126,7 @@ impl<'a> Widget for Popup<'a> {
|
||||
if s.infos.is_empty() {
|
||||
s.last_info_update = Instant::now();
|
||||
}
|
||||
let text = self.voxygen_i18n.get("hud.waypoint_saved");
|
||||
let text = self.i18n.get("hud.waypoint_saved");
|
||||
s.infos.push_back(text.to_string());
|
||||
});
|
||||
},
|
||||
|
@ -5,9 +5,9 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
hud::BuffPosition,
|
||||
i18n::{list_localizations, LanguageMetadata, VoxygenLocalization},
|
||||
i18n::{list_localizations, LanguageMetadata, Localization},
|
||||
render::{AaMode, CloudMode, FluidMode, LightingMode, RenderMode, ShadowMapMode, ShadowMode},
|
||||
ui::{fonts::ConrodVoxygenFonts, ImageSlider, ScaleMode, ToggleButton},
|
||||
ui::{fonts::Fonts, ImageSlider, ScaleMode, ToggleButton},
|
||||
window::{FullScreenSettings, FullscreenMode, GameInput},
|
||||
GlobalState,
|
||||
};
|
||||
@ -227,8 +227,8 @@ pub struct SettingsWindow<'a> {
|
||||
global_state: &'a GlobalState,
|
||||
show: &'a Show,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
fonts: &'a Fonts,
|
||||
localized_strings: &'a Localization,
|
||||
fps: f32,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
@ -239,8 +239,8 @@ impl<'a> SettingsWindow<'a> {
|
||||
global_state: &'a GlobalState,
|
||||
show: &'a Show,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
fonts: &'a Fonts,
|
||||
localized_strings: &'a Localization,
|
||||
fps: f32,
|
||||
) -> Self {
|
||||
Self {
|
||||
@ -2317,7 +2317,6 @@ impl<'a> Widget for SettingsWindow<'a> {
|
||||
.global_state
|
||||
.window
|
||||
.window()
|
||||
.window()
|
||||
.current_monitor()
|
||||
.unwrap()
|
||||
.video_modes()
|
||||
|
@ -6,9 +6,9 @@ use super::{
|
||||
STAMINA_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN, XP_COLOR,
|
||||
};
|
||||
use crate::{
|
||||
i18n::VoxygenLocalization,
|
||||
i18n::Localization,
|
||||
ui::{
|
||||
fonts::ConrodVoxygenFonts,
|
||||
fonts::Fonts,
|
||||
slot::{ContentSize, SlotMaker},
|
||||
ImageFrame, Tooltip, TooltipManager, Tooltipable,
|
||||
},
|
||||
@ -121,7 +121,7 @@ pub struct Skillbar<'a> {
|
||||
global_state: &'a GlobalState,
|
||||
imgs: &'a Imgs,
|
||||
item_imgs: &'a ItemImgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
stats: &'a Stats,
|
||||
health: &'a Health,
|
||||
@ -133,7 +133,7 @@ pub struct Skillbar<'a> {
|
||||
hotbar: &'a hotbar::State,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
slot_manager: &'a mut slots::SlotManager,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
localized_strings: &'a Localization,
|
||||
pulse: f32,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
@ -146,7 +146,7 @@ impl<'a> Skillbar<'a> {
|
||||
global_state: &'a GlobalState,
|
||||
imgs: &'a Imgs,
|
||||
item_imgs: &'a ItemImgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
fonts: &'a Fonts,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
stats: &'a Stats,
|
||||
health: &'a Health,
|
||||
@ -159,7 +159,7 @@ impl<'a> Skillbar<'a> {
|
||||
hotbar: &'a hotbar::State,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
slot_manager: &'a mut slots::SlotManager,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
localized_strings: &'a Localization,
|
||||
show: &'a Show,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -4,8 +4,8 @@ use super::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
i18n::VoxygenLocalization,
|
||||
ui::{fonts::ConrodVoxygenFonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
i18n::Localization,
|
||||
ui::{fonts::Fonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
};
|
||||
use client::{self, Client};
|
||||
use common::{comp::group, sync::Uid};
|
||||
@ -66,8 +66,8 @@ pub struct Social<'a> {
|
||||
show: &'a Show,
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
fonts: &'a Fonts,
|
||||
localized_strings: &'a Localization,
|
||||
selected_entity: Option<(specs::Entity, Instant)>,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
@ -82,8 +82,8 @@ impl<'a> Social<'a> {
|
||||
show: &'a Show,
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
fonts: &'a Fonts,
|
||||
localized_strings: &'a Localization,
|
||||
selected_entity: Option<(specs::Entity, Instant)>,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::{img_ids::Imgs, Show, TEXT_COLOR, UI_MAIN};
|
||||
use crate::{i18n::VoxygenLocalization, ui::fonts::ConrodVoxygenFonts};
|
||||
use crate::{i18n::Localization, ui::fonts::Fonts};
|
||||
use conrod_core::{
|
||||
color,
|
||||
widget::{self, Button, Image, Rectangle, Text},
|
||||
@ -24,8 +24,8 @@ pub struct Spell<'a> {
|
||||
_client: &'a Client,
|
||||
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
fonts: &'a Fonts,
|
||||
localized_strings: &'a Localization,
|
||||
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
@ -36,8 +36,8 @@ impl<'a> Spell<'a> {
|
||||
show: &'a Show,
|
||||
_client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
fonts: &'a Fonts,
|
||||
localized_strings: &'a Localization,
|
||||
) -> Self {
|
||||
Self {
|
||||
_show: show,
|
||||
|
@ -44,11 +44,11 @@ impl Font {
|
||||
}
|
||||
|
||||
/// Store font metadata
|
||||
pub type VoxygenFonts = HashMap<String, Font>;
|
||||
pub type Fonts = HashMap<String, Font>;
|
||||
|
||||
/// Store internationalization data
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct VoxygenLocalization {
|
||||
pub struct Localization {
|
||||
/// A map storing the localized texts
|
||||
///
|
||||
/// Localized content can be accessed using a String key.
|
||||
@ -64,12 +64,12 @@ pub struct VoxygenLocalization {
|
||||
pub convert_utf8_to_ascii: bool,
|
||||
|
||||
/// Font configuration is stored here
|
||||
pub fonts: VoxygenFonts,
|
||||
pub fonts: Fonts,
|
||||
|
||||
pub metadata: LanguageMetadata,
|
||||
}
|
||||
|
||||
impl VoxygenLocalization {
|
||||
impl Localization {
|
||||
/// Get a localized text from the given key
|
||||
///
|
||||
/// If the key is not present in the localization object
|
||||
@ -97,7 +97,7 @@ impl VoxygenLocalization {
|
||||
/// Return the missing keys compared to the reference language
|
||||
pub fn list_missing_entries(&self) -> (HashSet<String>, HashSet<String>) {
|
||||
let reference_localization =
|
||||
VoxygenLocalization::load_expect(i18n_asset_key(REFERENCE_LANG).as_ref());
|
||||
Localization::load_expect(i18n_asset_key(REFERENCE_LANG).as_ref());
|
||||
|
||||
let reference_string_keys: HashSet<_> =
|
||||
reference_localization.string_map.keys().cloned().collect();
|
||||
@ -136,14 +136,14 @@ impl VoxygenLocalization {
|
||||
}
|
||||
}
|
||||
|
||||
impl Asset for VoxygenLocalization {
|
||||
impl Asset for Localization {
|
||||
const ENDINGS: &'static [&'static str] = &["ron"];
|
||||
|
||||
/// Load the translations located in the input buffer and convert them
|
||||
/// into a `VoxygenLocalization` object.
|
||||
/// into a `Localization` object.
|
||||
#[allow(clippy::into_iter_on_ref)] // TODO: Pending review in #587
|
||||
fn parse(buf_reader: BufReader<File>, _specifier: &str) -> Result<Self, assets::Error> {
|
||||
let mut asked_localization: VoxygenLocalization =
|
||||
let mut asked_localization: Localization =
|
||||
from_reader(buf_reader).map_err(assets::Error::parse_error)?;
|
||||
|
||||
// Update the text if UTF-8 to ASCII conversion is enabled
|
||||
@ -163,10 +163,10 @@ impl Asset for VoxygenLocalization {
|
||||
}
|
||||
}
|
||||
|
||||
/// Load all the available languages located in the Voxygen asset directory
|
||||
/// Load all the available languages located in the voxygen asset directory
|
||||
pub fn list_localizations() -> Vec<LanguageMetadata> {
|
||||
let voxygen_locales_assets = "voxygen.i18n.*";
|
||||
let lang_list = VoxygenLocalization::load_glob(voxygen_locales_assets).unwrap();
|
||||
let lang_list = Localization::load_glob(voxygen_locales_assets).unwrap();
|
||||
lang_list.iter().map(|e| (*e).metadata.clone()).collect()
|
||||
}
|
||||
|
||||
@ -175,7 +175,7 @@ pub fn i18n_asset_key(language_id: &str) -> String { "voxygen.i18n.".to_string()
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::VoxygenLocalization;
|
||||
use super::Localization;
|
||||
use git2::Repository;
|
||||
use ron::de::{from_bytes, from_reader};
|
||||
use std::{
|
||||
@ -248,7 +248,7 @@ mod tests {
|
||||
|
||||
fn generate_key_version<'a>(
|
||||
repo: &'a git2::Repository,
|
||||
localization: &VoxygenLocalization,
|
||||
localization: &Localization,
|
||||
path: &std::path::Path,
|
||||
file_blob: &git2::Blob,
|
||||
) -> HashMap<String, LocalizationEntryState> {
|
||||
@ -348,7 +348,7 @@ mod tests {
|
||||
);
|
||||
for path in i18n_files {
|
||||
let f = fs::File::open(&path).expect("Failed opening file");
|
||||
let _: VoxygenLocalization = match from_reader(f) {
|
||||
let _: Localization = match from_reader(f) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
panic!(
|
||||
@ -387,7 +387,7 @@ mod tests {
|
||||
|
||||
// Read HEAD for the reference language file
|
||||
let i18n_en_blob = read_file_from_path(&repo, &head_ref, &en_i18n_path);
|
||||
let loc: VoxygenLocalization = from_bytes(i18n_en_blob.content())
|
||||
let loc: Localization = from_bytes(i18n_en_blob.content())
|
||||
.expect("Expect to parse reference i18n RON file, can't proceed without it");
|
||||
let i18n_references: HashMap<String, LocalizationEntryState> =
|
||||
generate_key_version(&repo, &loc, &en_i18n_path, &i18n_en_blob);
|
||||
@ -406,7 +406,7 @@ mod tests {
|
||||
|
||||
// Find the localization entry state
|
||||
let current_blob = read_file_from_path(&repo, &head_ref, &relfile);
|
||||
let current_loc: VoxygenLocalization = match from_bytes(current_blob.content()) {
|
||||
let current_loc: Localization = match from_bytes(current_blob.content()) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
use veloren_voxygen::{
|
||||
audio::{self, AudioFrontend},
|
||||
i18n::{self, i18n_asset_key, VoxygenLocalization},
|
||||
i18n::{self, i18n_asset_key, Localization},
|
||||
logging,
|
||||
profile::Profile,
|
||||
run,
|
||||
@ -157,7 +157,7 @@ fn main() {
|
||||
let profile = Profile::load();
|
||||
|
||||
let mut localization_watcher = watch::ReloadIndicator::new();
|
||||
let localized_strings = VoxygenLocalization::load_watched(
|
||||
let localized_strings = Localization::load_watched(
|
||||
&i18n_asset_key(&settings.language.selected_language),
|
||||
&mut localization_watcher,
|
||||
)
|
||||
@ -169,7 +169,7 @@ fn main() {
|
||||
"Impossible to load language: change to the default language (English) instead.",
|
||||
);
|
||||
settings.language.selected_language = i18n::REFERENCE_LANG.to_owned();
|
||||
VoxygenLocalization::load_watched(
|
||||
Localization::load_watched(
|
||||
&i18n_asset_key(&settings.language.selected_language),
|
||||
&mut localization_watcher,
|
||||
)
|
||||
|
@ -1,7 +1,7 @@
|
||||
mod ui;
|
||||
|
||||
use crate::{
|
||||
i18n::{i18n_asset_key, VoxygenLocalization},
|
||||
i18n::{i18n_asset_key, Localization},
|
||||
render::Renderer,
|
||||
scene::simple::{self as scene, Scene},
|
||||
session::SessionState,
|
||||
@ -37,19 +37,22 @@ impl CharSelectionState {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_humanoid_body(&self) -> Option<comp::humanoid::Body> {
|
||||
self.char_selection_ui
|
||||
.get_character_list()
|
||||
.and_then(|data| {
|
||||
if let Some(character) = data.get(self.char_selection_ui.selected_character) {
|
||||
match character.body {
|
||||
fn get_humanoid_body_loadout<'a>(
|
||||
char_selection_ui: &'a CharSelectionUi,
|
||||
client: &'a Client,
|
||||
) -> (Option<comp::humanoid::Body>, Option<&'a comp::Loadout>) {
|
||||
char_selection_ui
|
||||
.display_body_loadout(&client.character_list.characters)
|
||||
.map(|(body, loadout)| {
|
||||
(
|
||||
match body {
|
||||
comp::Body::Humanoid(body) => Some(body),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
Some(loadout),
|
||||
)
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,39 +96,34 @@ impl PlayState for CharSelectionState {
|
||||
return PlayStateResult::Pop;
|
||||
},
|
||||
ui::Event::AddCharacter { alias, tool, body } => {
|
||||
self.client.borrow_mut().create_character(alias, tool, body);
|
||||
self.client
|
||||
.borrow_mut()
|
||||
.create_character(alias, Some(tool), body);
|
||||
},
|
||||
ui::Event::DeleteCharacter(character_id) => {
|
||||
self.client.borrow_mut().delete_character(character_id);
|
||||
},
|
||||
ui::Event::Play => {
|
||||
let char_data = self
|
||||
.char_selection_ui
|
||||
.get_character_list()
|
||||
.expect("Character data is required to play");
|
||||
|
||||
if let Some(selected_character) =
|
||||
char_data.get(self.char_selection_ui.selected_character)
|
||||
{
|
||||
if let Some(character_id) = selected_character.character.id {
|
||||
self.client.borrow_mut().request_character(character_id);
|
||||
}
|
||||
}
|
||||
ui::Event::Play(character_id) => {
|
||||
self.client.borrow_mut().request_character(character_id);
|
||||
|
||||
return PlayStateResult::Switch(Box::new(SessionState::new(
|
||||
global_state,
|
||||
Rc::clone(&self.client),
|
||||
)));
|
||||
},
|
||||
ui::Event::ClearCharacterListError => {
|
||||
self.client.borrow_mut().character_list.error = None;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let humanoid_body = self.get_humanoid_body();
|
||||
let loadout = self.char_selection_ui.get_loadout();
|
||||
|
||||
// Maintain the scene.
|
||||
{
|
||||
let client = self.client.borrow();
|
||||
let (humanoid_body, loadout) =
|
||||
Self::get_humanoid_body_loadout(&self.char_selection_ui, &client);
|
||||
|
||||
// Maintain the scene.
|
||||
let scene_data = scene::SceneData {
|
||||
time: client.state().get_time(),
|
||||
delta_time: client.state().ecs().read_resource::<DeltaTime>().0,
|
||||
@ -141,15 +139,13 @@ impl PlayState for CharSelectionState {
|
||||
.figure_lod_render_distance
|
||||
as f32,
|
||||
};
|
||||
self.scene.maintain(
|
||||
global_state.window.renderer_mut(),
|
||||
scene_data,
|
||||
loadout.as_ref(),
|
||||
);
|
||||
|
||||
self.scene
|
||||
.maintain(global_state.window.renderer_mut(), scene_data, loadout);
|
||||
}
|
||||
|
||||
// Tick the client (currently only to keep the connection alive).
|
||||
let localized_strings = VoxygenLocalization::load_expect(&i18n_asset_key(
|
||||
let localized_strings = Localization::load_expect(&i18n_asset_key(
|
||||
&global_state.settings.language.selected_language,
|
||||
));
|
||||
|
||||
@ -199,19 +195,15 @@ impl PlayState for CharSelectionState {
|
||||
fn name(&self) -> &'static str { "Title" }
|
||||
|
||||
fn render(&mut self, renderer: &mut Renderer, _: &Settings) {
|
||||
let humanoid_body = self.get_humanoid_body();
|
||||
let loadout = self.char_selection_ui.get_loadout();
|
||||
let client = self.client.borrow();
|
||||
let (humanoid_body, loadout) =
|
||||
Self::get_humanoid_body_loadout(&self.char_selection_ui, &client);
|
||||
|
||||
// Render the scene.
|
||||
self.scene.render(
|
||||
renderer,
|
||||
self.client.borrow().get_tick(),
|
||||
humanoid_body,
|
||||
loadout.as_ref(),
|
||||
);
|
||||
self.scene
|
||||
.render(renderer, client.get_tick(), humanoid_body, loadout);
|
||||
|
||||
// Draw the UI to the screen.
|
||||
self.char_selection_ui
|
||||
.render(renderer, self.scene.globals());
|
||||
self.char_selection_ui.render(renderer);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
1448
voxygen/src/menu/char_selection/ui/mod.rs
Normal file
1448
voxygen/src/menu/char_selection/ui/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -5,12 +5,15 @@ use super::char_selection::CharSelectionState;
|
||||
#[cfg(feature = "singleplayer")]
|
||||
use crate::singleplayer::Singleplayer;
|
||||
use crate::{
|
||||
render::Renderer, settings::Settings, window::Event, Direction, GlobalState, PlayState,
|
||||
PlayStateResult,
|
||||
i18n::{i18n_asset_key, Localization},
|
||||
render::Renderer,
|
||||
settings::Settings,
|
||||
window::Event,
|
||||
Direction, GlobalState, PlayState, PlayStateResult,
|
||||
};
|
||||
use client_init::{ClientInit, Error as InitError, Msg as InitMsg};
|
||||
use common::{assets::Asset, comp, span};
|
||||
use tracing::{error, warn};
|
||||
use tracing::error;
|
||||
use ui::{Event as MainMenuEvent, MainMenuUi};
|
||||
|
||||
pub struct MainMenuState {
|
||||
@ -47,7 +50,7 @@ impl PlayState for MainMenuState {
|
||||
|
||||
fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult {
|
||||
span!(_guard, "tick", "<MainMenuState as PlayState>::tick");
|
||||
let localized_strings = crate::i18n::VoxygenLocalization::load_expect(
|
||||
let mut localized_strings = crate::i18n::Localization::load_expect(
|
||||
&crate::i18n::i18n_asset_key(&global_state.settings.language.selected_language),
|
||||
);
|
||||
|
||||
@ -84,7 +87,7 @@ impl PlayState for MainMenuState {
|
||||
match event {
|
||||
Event::Close => return PlayStateResult::Shutdown,
|
||||
// Pass events to ui.
|
||||
Event::Ui(event) => {
|
||||
Event::IcedUi(event) => {
|
||||
self.main_menu_ui.handle_event(event);
|
||||
},
|
||||
// Ignore all other events.
|
||||
@ -219,6 +222,14 @@ impl PlayState for MainMenuState {
|
||||
password,
|
||||
server_address,
|
||||
} => {
|
||||
let mut net_settings = &mut global_state.settings.networking;
|
||||
net_settings.username = username.clone();
|
||||
net_settings.default_server = server_address.clone();
|
||||
if !net_settings.servers.contains(&server_address) {
|
||||
net_settings.servers.push(server_address.clone());
|
||||
}
|
||||
global_state.settings.save_to_file_warn();
|
||||
|
||||
attempt_login(
|
||||
&mut global_state.settings,
|
||||
&mut global_state.info_message,
|
||||
@ -240,15 +251,25 @@ impl PlayState for MainMenuState {
|
||||
self.client_init = None;
|
||||
self.main_menu_ui.cancel_connection();
|
||||
},
|
||||
MainMenuEvent::ChangeLanguage(new_language) => {
|
||||
global_state.settings.language.selected_language =
|
||||
new_language.language_identifier;
|
||||
localized_strings = Localization::load_expect(&i18n_asset_key(
|
||||
&global_state.settings.language.selected_language,
|
||||
));
|
||||
localized_strings.log_missing_entries();
|
||||
self.main_menu_ui
|
||||
.update_language(std::sync::Arc::clone(&localized_strings));
|
||||
},
|
||||
#[cfg(feature = "singleplayer")]
|
||||
MainMenuEvent::StartSingleplayer => {
|
||||
let singleplayer = Singleplayer::new(None); // TODO: Make client and server use the same thread pool
|
||||
|
||||
global_state.singleplayer = Some(singleplayer);
|
||||
},
|
||||
MainMenuEvent::Settings => {}, // TODO
|
||||
MainMenuEvent::Quit => return PlayStateResult::Shutdown,
|
||||
/*MainMenuEvent::DisclaimerClosed => {
|
||||
// Note: Keeping in case we re-add the disclaimer
|
||||
/*MainMenuEvent::DisclaimerAccepted => {
|
||||
global_state.settings.show_disclaimer = false
|
||||
},*/
|
||||
MainMenuEvent::AuthServerTrust(auth_server, trust) => {
|
||||
@ -291,15 +312,6 @@ fn attempt_login(
|
||||
server_port: u16,
|
||||
client_init: &mut Option<ClientInit>,
|
||||
) {
|
||||
let mut net_settings = &mut settings.networking;
|
||||
net_settings.username = username.clone();
|
||||
if !net_settings.servers.contains(&server_address) {
|
||||
net_settings.servers.push(server_address.clone());
|
||||
}
|
||||
if let Err(e) = settings.save_to_file() {
|
||||
warn!(?e, "Failed to save settings");
|
||||
}
|
||||
|
||||
if comp::Player::alias_is_valid(&username) {
|
||||
// Don't try to connect if there is already a connection in progress.
|
||||
if client_init.is_none() {
|
||||
|
@ -1,907 +0,0 @@
|
||||
use crate::{
|
||||
i18n::{i18n_asset_key, VoxygenLocalization},
|
||||
render::Renderer,
|
||||
ui::{
|
||||
self,
|
||||
fonts::ConrodVoxygenFonts,
|
||||
img_ids::{BlankGraphic, ImageGraphic, VoxelGraphic},
|
||||
Graphic, ImageFrame, Tooltip, Ui,
|
||||
},
|
||||
GlobalState,
|
||||
};
|
||||
use common::assets::Asset;
|
||||
use conrod_core::{
|
||||
color,
|
||||
color::TRANSPARENT,
|
||||
position::Relative,
|
||||
widget::{text_box::Event as TextBoxEvent, Button, Image, List, Rectangle, Text, TextBox},
|
||||
widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
|
||||
};
|
||||
use image::DynamicImage;
|
||||
use rand::{seq::SliceRandom, thread_rng, Rng};
|
||||
use std::time::Duration;
|
||||
|
||||
const COL1: Color = Color::Rgba(0.07, 0.1, 0.1, 0.9);
|
||||
|
||||
// UI Color-Theme
|
||||
/*const UI_MAIN: Color = Color::Rgba(0.61, 0.70, 0.70, 1.0); // Greenish Blue
|
||||
const UI_HIGHLIGHT_0: Color = Color::Rgba(0.79, 1.09, 1.09, 1.0);*/
|
||||
|
||||
widget_ids! {
|
||||
struct Ids {
|
||||
// Background and logo
|
||||
bg,
|
||||
v_logo,
|
||||
alpha_version,
|
||||
alpha_text,
|
||||
banner,
|
||||
banner_top,
|
||||
gears,
|
||||
// Disclaimer
|
||||
//disc_window,
|
||||
//disc_text_1,
|
||||
//disc_text_2,
|
||||
//disc_button,
|
||||
//disc_scrollbar,
|
||||
// Login, Singleplayer
|
||||
login_button,
|
||||
login_text,
|
||||
login_error,
|
||||
login_error_bg,
|
||||
address_text,
|
||||
address_bg,
|
||||
address_field,
|
||||
username_text,
|
||||
username_bg,
|
||||
username_field,
|
||||
password_text,
|
||||
password_bg,
|
||||
password_field,
|
||||
singleplayer_button,
|
||||
singleplayer_text,
|
||||
usrnm_bg,
|
||||
srvr_bg,
|
||||
passwd_bg,
|
||||
// Server list
|
||||
servers_button,
|
||||
servers_frame,
|
||||
servers_text,
|
||||
servers_close,
|
||||
// Buttons
|
||||
settings_button,
|
||||
quit_button,
|
||||
// Error
|
||||
error_frame,
|
||||
button_ok,
|
||||
version,
|
||||
// Info Window
|
||||
info_frame,
|
||||
info_text,
|
||||
info_bottom,
|
||||
// Auth Trust Prompt
|
||||
button_add_auth_trust,
|
||||
// Loading Screen Tips
|
||||
tip_txt_bg,
|
||||
tip_txt,
|
||||
// Loading Screen Artwork
|
||||
mid,
|
||||
left,
|
||||
right,
|
||||
}
|
||||
}
|
||||
|
||||
image_ids! {
|
||||
struct Imgs {
|
||||
<VoxelGraphic>
|
||||
v_logo: "voxygen.element.v_logo",
|
||||
|
||||
info_frame: "voxygen.element.frames.info_frame_2",
|
||||
|
||||
<ImageGraphic>
|
||||
bg: "voxygen.background.bg_main",
|
||||
banner_top: "voxygen.element.frames.banner_top",
|
||||
banner: "voxygen.element.frames.banner",
|
||||
banner_bottom: "voxygen.element.frames.banner_bottom",
|
||||
button: "voxygen.element.buttons.button",
|
||||
button_hover: "voxygen.element.buttons.button_hover",
|
||||
button_press: "voxygen.element.buttons.button_press",
|
||||
input_bg: "voxygen.element.misc_bg.textbox_mid",
|
||||
//disclaimer: "voxygen.element.frames.disclaimer",
|
||||
loading_art: "voxygen.element.frames.loading_screen.loading_bg",
|
||||
loading_art_l: "voxygen.element.frames.loading_screen.loading_bg_l",
|
||||
loading_art_r: "voxygen.element.frames.loading_screen.loading_bg_r",
|
||||
// Animation
|
||||
f1: "voxygen.element.animation.gears.1",
|
||||
f2: "voxygen.element.animation.gears.2",
|
||||
f3: "voxygen.element.animation.gears.3",
|
||||
f4: "voxygen.element.animation.gears.4",
|
||||
f5: "voxygen.element.animation.gears.5",
|
||||
|
||||
<BlankGraphic>
|
||||
nothing: (),
|
||||
}
|
||||
}
|
||||
|
||||
rotation_image_ids! {
|
||||
pub struct ImgsRot {
|
||||
<ImageGraphic>
|
||||
|
||||
// Tooltip Test
|
||||
tt_side: "voxygen/element/frames/tt_test_edge",
|
||||
tt_corner: "voxygen/element/frames/tt_test_corner_tr",
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Event {
|
||||
LoginAttempt {
|
||||
username: String,
|
||||
password: String,
|
||||
server_address: String,
|
||||
},
|
||||
CancelLoginAttempt,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
StartSingleplayer,
|
||||
Quit,
|
||||
Settings,
|
||||
//DisclaimerClosed,
|
||||
AuthServerTrust(String, bool),
|
||||
}
|
||||
|
||||
pub enum PopupType {
|
||||
Error,
|
||||
ConnectionInfo,
|
||||
AuthTrustPrompt(String),
|
||||
}
|
||||
|
||||
pub struct PopupData {
|
||||
msg: String,
|
||||
popup_type: PopupType,
|
||||
}
|
||||
|
||||
pub struct MainMenuUi {
|
||||
ui: Ui,
|
||||
ids: Ids,
|
||||
imgs: Imgs,
|
||||
rot_imgs: ImgsRot,
|
||||
username: String,
|
||||
password: String,
|
||||
server_address: String,
|
||||
popup: Option<PopupData>,
|
||||
connecting: Option<std::time::Instant>,
|
||||
connect: bool,
|
||||
show_servers: bool,
|
||||
//show_disclaimer: bool,
|
||||
time: f32,
|
||||
anim_timer: f32,
|
||||
bg_img_id: conrod_core::image::Id,
|
||||
voxygen_i18n: std::sync::Arc<VoxygenLocalization>,
|
||||
fonts: ConrodVoxygenFonts,
|
||||
tip_no: u16,
|
||||
}
|
||||
|
||||
impl<'a> MainMenuUi {
|
||||
pub fn new(global_state: &mut GlobalState) -> Self {
|
||||
let window = &mut global_state.window;
|
||||
let networking = &global_state.settings.networking;
|
||||
let gameplay = &global_state.settings.gameplay;
|
||||
// Randomly loaded background images
|
||||
let bg_imgs = [
|
||||
"voxygen.background.bg_1",
|
||||
"voxygen.background.bg_2",
|
||||
"voxygen.background.bg_3",
|
||||
"voxygen.background.bg_4",
|
||||
"voxygen.background.bg_5",
|
||||
"voxygen.background.bg_6",
|
||||
"voxygen.background.bg_7",
|
||||
"voxygen.background.bg_8",
|
||||
"voxygen.background.bg_9",
|
||||
//"voxygen.background.bg_10",
|
||||
"voxygen.background.bg_11",
|
||||
//"voxygen.background.bg_12",
|
||||
"voxygen.background.bg_13",
|
||||
//"voxygen.background.bg_14",
|
||||
"voxygen.background.bg_15",
|
||||
"voxygen.background.bg_16",
|
||||
];
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let mut ui = Ui::new(window).unwrap();
|
||||
ui.set_scaling_mode(gameplay.ui_scale);
|
||||
// Generate ids
|
||||
let ids = Ids::new(ui.id_generator());
|
||||
// Load images
|
||||
let imgs = Imgs::load(&mut ui).expect("Failed to load images");
|
||||
let rot_imgs = ImgsRot::load(&mut ui).expect("Failed to load images!");
|
||||
let bg_img_id = ui.add_graphic(Graphic::Image(
|
||||
DynamicImage::load_expect(bg_imgs.choose(&mut rng).unwrap()),
|
||||
None,
|
||||
));
|
||||
//let chosen_tip = *tips.choose(&mut rng).unwrap();
|
||||
// Load language
|
||||
let voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key(
|
||||
&global_state.settings.language.selected_language,
|
||||
));
|
||||
// Load fonts.
|
||||
let fonts = ConrodVoxygenFonts::load(&voxygen_i18n.fonts, &mut ui)
|
||||
.expect("Impossible to load fonts!");
|
||||
|
||||
Self {
|
||||
ui,
|
||||
ids,
|
||||
imgs,
|
||||
rot_imgs,
|
||||
username: networking.username.clone(),
|
||||
password: "".to_owned(),
|
||||
server_address: networking
|
||||
.servers
|
||||
.get(networking.default_server)
|
||||
.cloned()
|
||||
.unwrap_or_default(),
|
||||
popup: None,
|
||||
connecting: None,
|
||||
show_servers: false,
|
||||
connect: false,
|
||||
time: 0.0,
|
||||
anim_timer: 0.0,
|
||||
//show_disclaimer: global_state.settings.show_disclaimer,
|
||||
bg_img_id,
|
||||
voxygen_i18n,
|
||||
fonts,
|
||||
tip_no: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::assign_op_pattern)] // TODO: Pending review in #587
|
||||
#[allow(clippy::op_ref)] // TODO: Pending review in #587
|
||||
#[allow(clippy::toplevel_ref_arg)] // TODO: Pending review in #587
|
||||
fn update_layout(&mut self, global_state: &mut GlobalState, dt: Duration) -> Vec<Event> {
|
||||
let mut events = Vec::new();
|
||||
self.time = self.time + dt.as_secs_f32();
|
||||
let fade_msg = (self.time * 2.0).sin() * 0.5 + 0.51;
|
||||
let (ref mut ui_widgets, ref mut _tooltip_manager) = self.ui.set_widgets();
|
||||
let tip_msg = format!(
|
||||
"{} {}",
|
||||
&self.voxygen_i18n.get("main.tip"),
|
||||
&self.voxygen_i18n.get_variation("loading.tips", self.tip_no),
|
||||
);
|
||||
let tip_show = global_state.settings.gameplay.loading_tips;
|
||||
let mut rng = thread_rng();
|
||||
let version = common::util::DISPLAY_VERSION_LONG.clone();
|
||||
let scale = 0.8;
|
||||
const TEXT_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0);
|
||||
const TEXT_COLOR_2: Color = Color::Rgba(1.0, 1.0, 1.0, 0.2);
|
||||
const TEXT_BG: Color = Color::Rgba(0.0, 0.0, 0.0, 1.0);
|
||||
//const INACTIVE: Color = Color::Rgba(0.47, 0.47, 0.47, 0.47);
|
||||
|
||||
let intro_text = &self.voxygen_i18n.get("main.login_process");
|
||||
|
||||
// Tooltip
|
||||
let _tooltip = Tooltip::new({
|
||||
// Edge images [t, b, r, l]
|
||||
// Corner images [tr, tl, br, bl]
|
||||
let edge = &self.rot_imgs.tt_side;
|
||||
let corner = &self.rot_imgs.tt_corner;
|
||||
ImageFrame::new(
|
||||
[edge.cw180, edge.none, edge.cw270, edge.cw90],
|
||||
[corner.none, corner.cw270, corner.cw90, corner.cw180],
|
||||
Color::Rgba(0.08, 0.07, 0.04, 1.0),
|
||||
5.0,
|
||||
)
|
||||
})
|
||||
.title_font_size(self.fonts.cyri.scale(15))
|
||||
.desc_font_size(self.fonts.cyri.scale(10))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.desc_text_color(TEXT_COLOR_2);
|
||||
|
||||
// Background image, Veloren logo, Alpha-Version Label
|
||||
Image::new(if self.connect {
|
||||
self.bg_img_id
|
||||
} else {
|
||||
self.imgs.bg
|
||||
})
|
||||
.middle_of(ui_widgets.window)
|
||||
.set(self.ids.bg, ui_widgets);
|
||||
|
||||
if self.connect {
|
||||
// Artwork
|
||||
Image::new(self.imgs.loading_art)
|
||||
.h(100.0)
|
||||
.w_of(self.ids.bg)
|
||||
.mid_bottom_of(self.ids.bg)
|
||||
.set(self.ids.mid, ui_widgets);
|
||||
Image::new(self.imgs.loading_art_l)
|
||||
.w_h(12.0, 10.0)
|
||||
.top_left_with_margins_on(self.ids.mid, 2.0, 0.0)
|
||||
.set(self.ids.left, ui_widgets);
|
||||
Image::new(self.imgs.loading_art_r)
|
||||
.w_h(12.0, 10.0)
|
||||
.top_right_with_margins_on(self.ids.mid, 2.0, 0.0)
|
||||
.set(self.ids.right, ui_widgets);
|
||||
// Gears Animation
|
||||
self.anim_timer = (self.anim_timer + dt.as_secs_f32()) * 1.05; // Linear time function with Anim-Speed Factor
|
||||
if self.anim_timer >= 4.0 {
|
||||
self.anim_timer = 0.0 // Reset timer at last frame to loop
|
||||
};
|
||||
Image::new(match self.anim_timer.round() as i32 {
|
||||
0 => self.imgs.f1,
|
||||
1 => self.imgs.f2,
|
||||
2 => self.imgs.f3,
|
||||
3 => self.imgs.f4,
|
||||
_ => self.imgs.f5,
|
||||
})
|
||||
.w_h(74.0, 62.0)
|
||||
.bottom_right_with_margins_on(self.ids.mid, 10.0, 10.0)
|
||||
.set(self.ids.gears, ui_widgets);
|
||||
if tip_show {
|
||||
// Tips
|
||||
Text::new(&tip_msg)
|
||||
.color(TEXT_BG)
|
||||
.mid_bottom_with_margin_on(self.ids.mid, 60.0)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(self.fonts.cyri.scale(20))
|
||||
.set(self.ids.tip_txt_bg, ui_widgets);
|
||||
Text::new(&tip_msg)
|
||||
.color(TEXT_COLOR)
|
||||
.bottom_left_with_margins_on(self.ids.tip_txt_bg, 2.0, 2.0)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(self.fonts.cyri.scale(20))
|
||||
.set(self.ids.tip_txt, ui_widgets);
|
||||
};
|
||||
};
|
||||
|
||||
// Version displayed top right corner
|
||||
let pos = if self.connect { 5.0 } else { 98.0 };
|
||||
Text::new(&version)
|
||||
.color(TEXT_COLOR)
|
||||
.top_right_with_margins_on(ui_widgets.window, pos * scale, 10.0 * scale)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(self.fonts.cyri.scale(14))
|
||||
.set(self.ids.version, ui_widgets);
|
||||
// Alpha Disclaimer
|
||||
Text::new(&format!(
|
||||
"Veloren {}",
|
||||
common::util::DISPLAY_VERSION.as_str()
|
||||
))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(self.fonts.cyri.scale(10))
|
||||
.color(TEXT_COLOR)
|
||||
.mid_top_with_margin_on(ui_widgets.window, 2.0)
|
||||
.set(self.ids.alpha_text, ui_widgets);
|
||||
// Popup (Error/Info/AuthTrustPrompt)
|
||||
let mut change_popup = None;
|
||||
if let Some(PopupData { msg, popup_type }) = &self.popup {
|
||||
let text = Text::new(msg)
|
||||
.rgba(
|
||||
1.0,
|
||||
1.0,
|
||||
1.0,
|
||||
if let PopupType::ConnectionInfo = popup_type {
|
||||
fade_msg
|
||||
} else {
|
||||
1.0
|
||||
},
|
||||
)
|
||||
.font_id(self.fonts.cyri.conrod_id);
|
||||
let (frame_w, frame_h) = if let PopupType::AuthTrustPrompt(_) = popup_type {
|
||||
(65.0 * 8.0, 370.0)
|
||||
} else {
|
||||
(65.0 * 6.0, 140.0)
|
||||
};
|
||||
let error_bg = Rectangle::fill_with([frame_w, frame_h], color::TRANSPARENT)
|
||||
.rgba(0.1, 0.1, 0.1, if self.connect { 0.0 } else { 1.0 })
|
||||
.parent(ui_widgets.window);
|
||||
if let PopupType::AuthTrustPrompt(_) = popup_type {
|
||||
error_bg.middle_of(ui_widgets.window)
|
||||
} else {
|
||||
error_bg.up_from(self.ids.banner_top, 15.0)
|
||||
}
|
||||
.set(self.ids.login_error_bg, ui_widgets);
|
||||
Image::new(self.imgs.info_frame)
|
||||
.w_h(frame_w, frame_h)
|
||||
.color(Some(Color::Rgba(
|
||||
1.0,
|
||||
1.0,
|
||||
1.0,
|
||||
if let PopupType::ConnectionInfo = popup_type {
|
||||
0.0
|
||||
} else {
|
||||
1.0
|
||||
},
|
||||
)))
|
||||
.middle_of(self.ids.login_error_bg)
|
||||
.set(self.ids.error_frame, ui_widgets);
|
||||
if let PopupType::ConnectionInfo = popup_type {
|
||||
/*text.mid_top_with_margin_on(self.ids.error_frame, 10.0)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.bottom_left_with_margins_on(self.ids.bg, 30.0, 95.0)
|
||||
.font_size(self.fonts.cyri.scale(35))
|
||||
.set(self.ids.login_error, ui_widgets);*/
|
||||
} else {
|
||||
text.mid_top_with_margin_on(self.ids.error_frame, 10.0)
|
||||
.w(frame_w - 10.0 * 2.0)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(self.fonts.cyri.scale(20))
|
||||
.set(self.ids.login_error, ui_widgets);
|
||||
};
|
||||
if Button::image(self.imgs.button)
|
||||
.w_h(100.0, 30.0)
|
||||
.mid_bottom_with_margin_on(
|
||||
if let PopupType::ConnectionInfo = popup_type {
|
||||
ui_widgets.window
|
||||
} else {
|
||||
self.ids.login_error_bg
|
||||
},
|
||||
10.0,
|
||||
)
|
||||
.hover_image(self.imgs.button_hover)
|
||||
.press_image(self.imgs.button_press)
|
||||
.label_y(Relative::Scalar(2.0))
|
||||
.label(match popup_type {
|
||||
PopupType::Error => self.voxygen_i18n.get("common.okay"),
|
||||
PopupType::ConnectionInfo => self.voxygen_i18n.get("common.cancel"),
|
||||
PopupType::AuthTrustPrompt(_) => self.voxygen_i18n.get("common.cancel"),
|
||||
})
|
||||
.label_font_id(self.fonts.cyri.conrod_id)
|
||||
.label_font_size(self.fonts.cyri.scale(15))
|
||||
.label_color(TEXT_COLOR)
|
||||
.set(self.ids.button_ok, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
match &popup_type {
|
||||
PopupType::Error => (),
|
||||
PopupType::ConnectionInfo => {
|
||||
events.push(Event::CancelLoginAttempt);
|
||||
},
|
||||
PopupType::AuthTrustPrompt(auth_server) => {
|
||||
events.push(Event::AuthServerTrust(auth_server.clone(), false));
|
||||
},
|
||||
};
|
||||
change_popup = Some(None);
|
||||
}
|
||||
|
||||
if let PopupType::AuthTrustPrompt(auth_server) = popup_type {
|
||||
if Button::image(self.imgs.button)
|
||||
.w_h(100.0, 30.0)
|
||||
.right_from(self.ids.button_ok, 10.0)
|
||||
.hover_image(self.imgs.button_hover)
|
||||
.press_image(self.imgs.button_press)
|
||||
.label_y(Relative::Scalar(2.0))
|
||||
.label("Add") // TODO: localize
|
||||
.label_font_id(self.fonts.cyri.conrod_id)
|
||||
.label_font_size(self.fonts.cyri.scale(15))
|
||||
.label_color(TEXT_COLOR)
|
||||
.set(self.ids.button_add_auth_trust, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
events.push(Event::AuthServerTrust(auth_server.clone(), true));
|
||||
change_popup = Some(Some(PopupData {
|
||||
msg: self.voxygen_i18n.get("main.connecting").into(),
|
||||
popup_type: PopupType::ConnectionInfo,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(p) = change_popup {
|
||||
self.popup = p;
|
||||
}
|
||||
|
||||
if !self.connect {
|
||||
Image::new(self.imgs.banner)
|
||||
.w_h(65.0 * 6.0 * scale, 100.0 * 6.0 * scale)
|
||||
.middle_of(self.ids.bg)
|
||||
.color(Some(Color::Rgba(0.0, 0.0, 0.0, 0.0)))
|
||||
.set(self.ids.banner, ui_widgets);
|
||||
|
||||
Image::new(self.imgs.banner_top)
|
||||
.w_h(70.0 * 6.0 * scale, 34.0 * scale)
|
||||
.mid_top_with_margin_on(self.ids.banner, -34.0)
|
||||
.color(Some(Color::Rgba(0.0, 0.0, 0.0, 0.0)))
|
||||
.set(self.ids.banner_top, ui_widgets);
|
||||
|
||||
// Logo
|
||||
Image::new(self.imgs.v_logo)
|
||||
.w_h(123.0 * 2.5 * scale, 35.0 * 2.5 * scale)
|
||||
.top_right_with_margins_on(self.ids.bg, 10.0, 10.0)
|
||||
.color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.95)))
|
||||
.set(self.ids.v_logo, ui_widgets);
|
||||
|
||||
/*if self.show_disclaimer {
|
||||
Image::new(self.imgs.disclaimer)
|
||||
.w_h(1800.0, 800.0)
|
||||
.middle_of(ui_widgets.window)
|
||||
.scroll_kids()
|
||||
.scroll_kids_vertically()
|
||||
.set(self.ids.disc_window, ui_widgets);
|
||||
|
||||
Text::new(&self.voxygen_i18n.get("common.disclaimer"))
|
||||
.top_left_with_margins_on(self.ids.disc_window, 30.0, 40.0)
|
||||
.font_size(self.fonts.cyri.scale(35))
|
||||
.font_id(self.fonts.alkhemi.conrod_id)
|
||||
.color(TEXT_COLOR)
|
||||
.set(self.ids.disc_text_1, ui_widgets);
|
||||
Text::new(&self.voxygen_i18n.get("main.notice"))
|
||||
.top_left_with_margins_on(self.ids.disc_window, 110.0, 40.0)
|
||||
.font_size(self.fonts.cyri.scale(26))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(TEXT_COLOR)
|
||||
.set(self.ids.disc_text_2, ui_widgets);
|
||||
if Button::image(self.imgs.button)
|
||||
.w_h(300.0, 50.0)
|
||||
.mid_bottom_with_margin_on(self.ids.disc_window, 30.0)
|
||||
.hover_image(self.imgs.button_hover)
|
||||
.press_image(self.imgs.button_press)
|
||||
.label_y(Relative::Scalar(2.0))
|
||||
.label(&self.voxygen_i18n.get("common.accept"))
|
||||
.label_font_size(self.fonts.cyri.scale(22))
|
||||
.label_color(TEXT_COLOR)
|
||||
.label_font_id(self.fonts.cyri.conrod_id)
|
||||
.set(self.ids.disc_button, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.show_disclaimer = false;
|
||||
events.push(Event::DisclaimerClosed);
|
||||
}
|
||||
} else {*/
|
||||
// TODO: Don't use macros for this?
|
||||
// Input fields
|
||||
// Used when the login button is pressed, or enter is pressed within input field
|
||||
macro_rules! login {
|
||||
() => {
|
||||
self.connect = true;
|
||||
self.connecting = Some(std::time::Instant::now());
|
||||
self.popup = Some(PopupData {
|
||||
msg: [self.voxygen_i18n.get("main.connecting"), "..."].concat(),
|
||||
popup_type: PopupType::ConnectionInfo,
|
||||
});
|
||||
|
||||
events.push(Event::LoginAttempt {
|
||||
username: self.username.clone(),
|
||||
password: self.password.clone(),
|
||||
server_address: self.server_address.clone(),
|
||||
});
|
||||
};
|
||||
}
|
||||
// Info Window
|
||||
Rectangle::fill_with([550.0 * scale, 250.0 * scale], COL1)
|
||||
.top_left_with_margins_on(ui_widgets.window, 40.0 * scale, 40.0 * scale)
|
||||
.color(Color::Rgba(0.0, 0.0, 0.0, 0.80))
|
||||
.set(self.ids.info_frame, ui_widgets);
|
||||
Image::new(self.imgs.banner_bottom)
|
||||
.mid_bottom_with_margin_on(self.ids.info_frame, -50.0 * scale)
|
||||
.w_h(550.0 * scale, 50.0 * scale)
|
||||
.color(Some(Color::Rgba(0.0, 0.0, 0.0, 0.80)))
|
||||
.set(self.ids.info_bottom, ui_widgets);
|
||||
Text::new(intro_text)
|
||||
.top_left_with_margins_on(self.ids.info_frame, 15.0 * scale, 15.0 * scale)
|
||||
.font_size(self.fonts.cyri.scale(16))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(TEXT_COLOR)
|
||||
.set(self.ids.info_text, ui_widgets);
|
||||
|
||||
// Singleplayer
|
||||
// Used when the singleplayer button is pressed
|
||||
#[cfg(feature = "singleplayer")]
|
||||
macro_rules! singleplayer {
|
||||
() => {
|
||||
events.push(Event::StartSingleplayer);
|
||||
self.connect = true;
|
||||
self.connecting = Some(std::time::Instant::now());
|
||||
self.popup = Some(PopupData {
|
||||
msg: [self.voxygen_i18n.get(""), ""].concat(),
|
||||
popup_type: PopupType::ConnectionInfo,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// Username
|
||||
Rectangle::fill_with(
|
||||
[320.0 * scale, 50.0 * scale],
|
||||
color::rgba(0.0, 0.0, 0.0, 0.0),
|
||||
)
|
||||
.mid_top_with_margin_on(self.ids.banner_top, 150.0)
|
||||
.set(self.ids.usrnm_bg, ui_widgets);
|
||||
Image::new(self.imgs.input_bg)
|
||||
.w_h(338.0 * scale, 50.0 * scale)
|
||||
.middle_of(self.ids.usrnm_bg)
|
||||
.set(self.ids.username_bg, ui_widgets);
|
||||
for event in TextBox::new(&self.username)
|
||||
.w_h(290.0* scale, 30.0* scale)
|
||||
.mid_bottom_with_margin_on(self.ids.username_bg, 14.0* scale)
|
||||
.font_size(self.fonts.cyri.scale(18))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.text_color(TEXT_COLOR)
|
||||
// transparent background
|
||||
.color(TRANSPARENT)
|
||||
.border_color(TRANSPARENT)
|
||||
.set(self.ids.username_field, ui_widgets)
|
||||
{
|
||||
match event {
|
||||
TextBoxEvent::Update(username) => {
|
||||
// Note: TextBox limits the input string length to what fits in it
|
||||
self.username = username.to_string();
|
||||
},
|
||||
TextBoxEvent::Enter => {
|
||||
login!();
|
||||
},
|
||||
}
|
||||
}
|
||||
// Password
|
||||
Rectangle::fill_with(
|
||||
[320.0 * scale, 50.0 * scale],
|
||||
color::rgba(0.0, 0.0, 0.0, 0.0),
|
||||
)
|
||||
.down_from(self.ids.usrnm_bg, 10.0 * scale)
|
||||
.set(self.ids.passwd_bg, ui_widgets);
|
||||
Image::new(self.imgs.input_bg)
|
||||
.w_h(338.0 * scale, 50.0 * scale)
|
||||
.middle_of(self.ids.passwd_bg)
|
||||
.set(self.ids.password_bg, ui_widgets);
|
||||
for event in TextBox::new(&self.password)
|
||||
.w_h(290.0 * scale, 30.0* scale)
|
||||
.mid_bottom_with_margin_on(self.ids.password_bg, 10.0* scale)
|
||||
// The text is smaller to allow longer passwords, conrod limits text length
|
||||
// Basically the lower the scale of the font, the smaller and more characters we can fit
|
||||
// At the time of this commit change, scale of 10 should fit 34 characters
|
||||
.font_size(self.fonts.cyri.scale(10))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.text_color(TEXT_COLOR)
|
||||
// transparent background
|
||||
.color(TRANSPARENT)
|
||||
.border_color(TRANSPARENT)
|
||||
.hide_text("*")
|
||||
.set(self.ids.password_field, ui_widgets)
|
||||
{
|
||||
match event {
|
||||
TextBoxEvent::Update(password) => {
|
||||
// Note: TextBox limits the input string length to what fits in it
|
||||
self.password = password;
|
||||
},
|
||||
TextBoxEvent::Enter => {
|
||||
self.password.pop();
|
||||
login!();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if self.show_servers {
|
||||
Image::new(self.imgs.info_frame)
|
||||
.mid_top_with_margin_on(self.ids.username_bg, -320.0)
|
||||
.w_h(400.0, 300.0)
|
||||
.set(self.ids.servers_frame, ui_widgets);
|
||||
|
||||
let ref mut net_settings = global_state.settings.networking;
|
||||
|
||||
// TODO: Draw scroll bar or remove it.
|
||||
let (mut items, _scrollbar) = List::flow_down(net_settings.servers.len())
|
||||
.top_left_with_margins_on(self.ids.servers_frame, 0.0, 5.0)
|
||||
.w_h(400.0, 300.0)
|
||||
.scrollbar_next_to()
|
||||
.scrollbar_thickness(18.0)
|
||||
.scrollbar_color(TEXT_COLOR)
|
||||
.set(self.ids.servers_text, ui_widgets);
|
||||
|
||||
while let Some(item) = items.next(ui_widgets) {
|
||||
let mut text = "".to_string();
|
||||
if &net_settings.servers[item.i] == &self.server_address {
|
||||
text.push_str("-> ")
|
||||
} else {
|
||||
text.push_str(" ")
|
||||
}
|
||||
text.push_str(&net_settings.servers[item.i]);
|
||||
|
||||
if item
|
||||
.set(
|
||||
Button::image(self.imgs.nothing)
|
||||
.w_h(100.0, 50.0)
|
||||
.mid_top_with_margin_on(self.ids.servers_frame, 10.0)
|
||||
//.hover_image(self.imgs.button_hover)
|
||||
//.press_image(self.imgs.button_press)
|
||||
.label_y(Relative::Scalar(2.0))
|
||||
.label(&text)
|
||||
.label_font_size(self.fonts.cyri.scale(20))
|
||||
.label_font_id(self.fonts.cyri.conrod_id)
|
||||
.label_color(TEXT_COLOR),
|
||||
ui_widgets,
|
||||
)
|
||||
.was_clicked()
|
||||
{
|
||||
self.server_address = net_settings.servers[item.i].clone();
|
||||
net_settings.default_server = item.i;
|
||||
}
|
||||
}
|
||||
|
||||
if Button::image(self.imgs.button)
|
||||
.w_h(200.0, 53.0)
|
||||
.mid_bottom_with_margin_on(self.ids.servers_frame, 5.0)
|
||||
.hover_image(self.imgs.button_hover)
|
||||
.press_image(self.imgs.button_press)
|
||||
.label_y(Relative::Scalar(2.0))
|
||||
.label(&self.voxygen_i18n.get("common.close"))
|
||||
.label_font_size(self.fonts.cyri.scale(20))
|
||||
.label_font_id(self.fonts.cyri.conrod_id)
|
||||
.label_color(TEXT_COLOR)
|
||||
.set(self.ids.servers_close, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.show_servers = false
|
||||
};
|
||||
}
|
||||
// Server address
|
||||
Rectangle::fill_with(
|
||||
[320.0 * scale, 50.0 * scale],
|
||||
color::rgba(0.0, 0.0, 0.0, 0.0),
|
||||
)
|
||||
.down_from(self.ids.passwd_bg, 8.0 * scale)
|
||||
.set(self.ids.srvr_bg, ui_widgets);
|
||||
Image::new(self.imgs.input_bg)
|
||||
.w_h(338.0 * scale, 50.0 * scale)
|
||||
.middle_of(self.ids.srvr_bg)
|
||||
.set(self.ids.address_bg, ui_widgets);
|
||||
for event in TextBox::new(&self.server_address)
|
||||
.w_h(290.0*scale, 30.0*scale)
|
||||
.mid_top_with_margin_on(self.ids.address_bg, 8.0*scale)
|
||||
.font_size(self.fonts.cyri.scale(18))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.text_color(TEXT_COLOR)
|
||||
// transparent background
|
||||
.color(TRANSPARENT)
|
||||
.border_color(TRANSPARENT)
|
||||
.set(self.ids.address_field, ui_widgets)
|
||||
{
|
||||
match event {
|
||||
TextBoxEvent::Update(server_address) => {
|
||||
self.server_address = server_address.to_string();
|
||||
},
|
||||
TextBoxEvent::Enter => {
|
||||
login!();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Login button
|
||||
if Button::image(self.imgs.button)
|
||||
.hover_image(self.imgs.button_hover)
|
||||
.press_image(self.imgs.button_press)
|
||||
.w_h(258.0*scale, 55.0*scale)
|
||||
.down_from(self.ids.address_bg, 20.0*scale)
|
||||
.align_middle_x_of(self.ids.address_bg)
|
||||
.label(&self.voxygen_i18n.get("common.multiplayer"))
|
||||
.label_font_id(self.fonts.cyri.conrod_id)
|
||||
.label_color(TEXT_COLOR)
|
||||
.label_font_size(self.fonts.cyri.scale(18))
|
||||
.label_y(Relative::Scalar(4.0))
|
||||
/*.with_tooltip(
|
||||
tooltip_manager,
|
||||
"Login",
|
||||
"Click to login with the entered details",
|
||||
&tooltip,
|
||||
)
|
||||
.tooltip_image(self.imgs.v_logo)*/
|
||||
.set(self.ids.login_button, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.tip_no = rng.gen();
|
||||
login!();
|
||||
}
|
||||
|
||||
// Singleplayer button
|
||||
#[cfg(feature = "singleplayer")]
|
||||
{
|
||||
if Button::image(self.imgs.button)
|
||||
.hover_image(self.imgs.button_hover)
|
||||
.press_image(self.imgs.button_press)
|
||||
.w_h(258.0 * scale, 55.0 * scale)
|
||||
.down_from(self.ids.login_button, 20.0 * scale)
|
||||
.align_middle_x_of(self.ids.address_bg)
|
||||
.label(&self.voxygen_i18n.get("common.singleplayer"))
|
||||
.label_font_id(self.fonts.cyri.conrod_id)
|
||||
.label_color(TEXT_COLOR)
|
||||
.label_font_size(self.fonts.cyri.scale(18))
|
||||
.label_y(Relative::Scalar(4.0))
|
||||
.label_x(Relative::Scalar(2.0))
|
||||
.set(self.ids.singleplayer_button, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.tip_no = rng.gen();
|
||||
singleplayer!();
|
||||
}
|
||||
}
|
||||
// Quit
|
||||
if Button::image(self.imgs.button)
|
||||
.w_h(190.0 * scale, 40.0 * scale)
|
||||
.bottom_left_with_margins_on(ui_widgets.window, 60.0 * scale, 30.0 * scale)
|
||||
.hover_image(self.imgs.button_hover)
|
||||
.press_image(self.imgs.button_press)
|
||||
.label(&self.voxygen_i18n.get("common.quit"))
|
||||
.label_font_id(self.fonts.cyri.conrod_id)
|
||||
.label_color(TEXT_COLOR)
|
||||
.label_font_size(self.fonts.cyri.scale(16))
|
||||
.label_y(Relative::Scalar(3.0))
|
||||
.set(self.ids.quit_button, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
events.push(Event::Quit);
|
||||
}
|
||||
|
||||
// Settings
|
||||
if Button::image(self.imgs.button)
|
||||
.w_h(190.0*scale, 40.0*scale)
|
||||
.up_from(self.ids.quit_button, 8.0*scale)
|
||||
//.hover_image(self.imgs.button_hover)
|
||||
//.press_image(self.imgs.button_press)
|
||||
.label(&self.voxygen_i18n.get("common.settings"))
|
||||
.label_font_id(self.fonts.cyri.conrod_id)
|
||||
.label_color(TEXT_COLOR_2)
|
||||
.label_font_size(self.fonts.cyri.scale(16))
|
||||
.label_y(Relative::Scalar(3.0))
|
||||
.set(self.ids.settings_button, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
events.push(Event::Settings);
|
||||
}
|
||||
|
||||
// Servers
|
||||
if Button::image(self.imgs.button)
|
||||
.w_h(190.0 * scale, 40.0 * scale)
|
||||
.up_from(self.ids.settings_button, 8.0 * scale)
|
||||
.hover_image(self.imgs.button_hover)
|
||||
.press_image(self.imgs.button_press)
|
||||
.label(&self.voxygen_i18n.get("common.servers"))
|
||||
.label_font_id(self.fonts.cyri.conrod_id)
|
||||
.label_color(TEXT_COLOR)
|
||||
.label_font_size(self.fonts.cyri.scale(16))
|
||||
.label_y(Relative::Scalar(3.0))
|
||||
.set(self.ids.servers_button, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.show_servers = !self.show_servers;
|
||||
};
|
||||
}
|
||||
|
||||
events
|
||||
}
|
||||
|
||||
pub fn auth_trust_prompt(&mut self, auth_server: String) {
|
||||
self.popup = Some(PopupData {
|
||||
msg: format!(
|
||||
"Warning: The server you are trying to connect to has provided this \
|
||||
authentication server address:\n\n{}\n\nbut it is not in your list of trusted \
|
||||
authentication servers.\n\nMake sure that you trust this site and owner to not \
|
||||
try and bruteforce your password!",
|
||||
&auth_server
|
||||
),
|
||||
popup_type: PopupType::AuthTrustPrompt(auth_server),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn show_info(&mut self, msg: String) {
|
||||
self.popup = Some(PopupData {
|
||||
msg,
|
||||
popup_type: PopupType::Error,
|
||||
});
|
||||
self.connecting = None;
|
||||
self.connect = false;
|
||||
}
|
||||
|
||||
pub fn connected(&mut self) {
|
||||
self.popup = None;
|
||||
self.connecting = None;
|
||||
self.connect = false;
|
||||
}
|
||||
|
||||
pub fn cancel_connection(&mut self) {
|
||||
self.popup = None;
|
||||
self.connecting = None;
|
||||
self.connect = false;
|
||||
}
|
||||
|
||||
pub fn handle_event(&mut self, event: ui::Event) { self.ui.handle_event(event); }
|
||||
|
||||
pub fn maintain(&mut self, global_state: &mut GlobalState, dt: Duration) -> Vec<Event> {
|
||||
let events = self.update_layout(global_state, dt);
|
||||
self.ui.maintain(global_state.window.renderer_mut(), None);
|
||||
events
|
||||
}
|
||||
|
||||
pub fn render(&self, renderer: &mut Renderer) { self.ui.render(renderer, None); }
|
||||
}
|
183
voxygen/src/menu/main/ui/connecting.rs
Normal file
183
voxygen/src/menu/main/ui/connecting.rs
Normal file
@ -0,0 +1,183 @@
|
||||
use super::{ConnectionState, Imgs, Message};
|
||||
use crate::{
|
||||
i18n::Localization,
|
||||
ui::{
|
||||
fonts::IcedFonts as Fonts,
|
||||
ice::{component::neat_button, style, widget::Image, Element},
|
||||
},
|
||||
};
|
||||
use iced::{button, Align, Column, Container, Length, Row, Space, Text};
|
||||
|
||||
const GEAR_ANIMATION_SPEED_FACTOR: f64 = 10.0;
|
||||
/// Connecting screen for the main menu
|
||||
pub struct Screen {
|
||||
cancel_button: button::State,
|
||||
add_button: button::State,
|
||||
tip_number: u16,
|
||||
}
|
||||
|
||||
impl Screen {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
cancel_button: Default::default(),
|
||||
add_button: Default::default(),
|
||||
tip_number: rand::random(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn view(
|
||||
&mut self,
|
||||
fonts: &Fonts,
|
||||
imgs: &Imgs,
|
||||
connection_state: &ConnectionState,
|
||||
time: f64,
|
||||
i18n: &Localization,
|
||||
button_style: style::button::Style,
|
||||
show_tip: bool,
|
||||
) -> Element<Message> {
|
||||
let gear_anim_time = time * GEAR_ANIMATION_SPEED_FACTOR;
|
||||
// TODO: add built in support for animated images
|
||||
let gear_anim_image = match (gear_anim_time % 5.0).trunc() as u8 {
|
||||
0 => imgs.f1,
|
||||
1 => imgs.f2,
|
||||
2 => imgs.f3,
|
||||
3 => imgs.f4,
|
||||
_ => imgs.f5,
|
||||
};
|
||||
|
||||
let children = match connection_state {
|
||||
ConnectionState::InProgress => {
|
||||
let tip = if show_tip {
|
||||
let tip = format!(
|
||||
"{} {}",
|
||||
&i18n.get("main.tip"),
|
||||
&i18n.get_variation("loading.tips", self.tip_number)
|
||||
);
|
||||
Container::new(Text::new(tip).size(fonts.cyri.scale(25)))
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.center_x()
|
||||
.align_y(Align::End)
|
||||
.into()
|
||||
} else {
|
||||
Space::new(Length::Fill, Length::Fill).into()
|
||||
};
|
||||
|
||||
let cancel = Container::new(neat_button(
|
||||
&mut self.cancel_button,
|
||||
i18n.get("common.cancel"),
|
||||
0.7,
|
||||
button_style,
|
||||
Some(Message::CancelConnect),
|
||||
))
|
||||
.width(Length::Fill)
|
||||
.height(Length::Units(fonts.cyri.scale(30)))
|
||||
.center_x()
|
||||
.padding(3);
|
||||
|
||||
let tip_cancel = Column::with_children(vec![tip, cancel.into()])
|
||||
.width(Length::FillPortion(3))
|
||||
.align_items(Align::Center)
|
||||
.spacing(5)
|
||||
.padding(5);
|
||||
|
||||
let gear = Container::new(
|
||||
Image::new(gear_anim_image)
|
||||
.width(Length::Units(74))
|
||||
.height(Length::Units(62)),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.padding(10)
|
||||
.align_x(Align::End);
|
||||
|
||||
let bottom_content = Row::with_children(vec![
|
||||
Space::new(Length::Fill, Length::Shrink).into(),
|
||||
tip_cancel.into(),
|
||||
gear.into(),
|
||||
])
|
||||
.align_items(Align::Center)
|
||||
.width(Length::Fill);
|
||||
|
||||
let left_art = Image::new(imgs.loading_art_l)
|
||||
.width(Length::Units(12))
|
||||
.height(Length::Units(12));
|
||||
let right_art = Image::new(imgs.loading_art_r)
|
||||
.width(Length::Units(12))
|
||||
.height(Length::Units(12));
|
||||
|
||||
let bottom_bar = Container::new(Row::with_children(vec![
|
||||
left_art.into(),
|
||||
bottom_content.into(),
|
||||
right_art.into(),
|
||||
]))
|
||||
.height(Length::Units(85))
|
||||
.style(style::container::Style::image(imgs.loading_art));
|
||||
|
||||
vec![
|
||||
Space::new(Length::Fill, Length::Fill).into(),
|
||||
bottom_bar.into(),
|
||||
]
|
||||
},
|
||||
ConnectionState::AuthTrustPrompt { msg, .. } => {
|
||||
let text = Text::new(msg).size(fonts.cyri.scale(25));
|
||||
|
||||
let cancel = neat_button(
|
||||
&mut self.cancel_button,
|
||||
i18n.get("common.cancel"),
|
||||
0.7,
|
||||
button_style,
|
||||
Some(Message::TrustPromptCancel),
|
||||
);
|
||||
let add = neat_button(
|
||||
&mut self.add_button,
|
||||
i18n.get("common.add"),
|
||||
0.7,
|
||||
button_style,
|
||||
Some(Message::TrustPromptAdd),
|
||||
);
|
||||
|
||||
let content = Column::with_children(vec![
|
||||
text.into(),
|
||||
Container::new(
|
||||
Row::with_children(vec![cancel, add])
|
||||
.spacing(20)
|
||||
.height(Length::Units(25)),
|
||||
)
|
||||
.align_x(Align::End)
|
||||
.width(Length::Fill)
|
||||
.into(),
|
||||
])
|
||||
.spacing(4)
|
||||
.max_width(520)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill);
|
||||
|
||||
let prompt_window = Container::new(content)
|
||||
.style(
|
||||
style::container::Style::color_with_double_cornerless_border(
|
||||
(22, 18, 16, 255).into(),
|
||||
(11, 11, 11, 255).into(),
|
||||
(54, 46, 38, 255).into(),
|
||||
),
|
||||
)
|
||||
.padding(20);
|
||||
|
||||
let container = Container::new(prompt_window)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.center_x()
|
||||
.center_y();
|
||||
|
||||
vec![
|
||||
container.into(),
|
||||
Space::new(Length::Fill, Length::Units(fonts.cyri.scale(15))).into(),
|
||||
]
|
||||
},
|
||||
};
|
||||
|
||||
Column::with_children(children)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
}
|
||||
}
|
82
voxygen/src/menu/main/ui/disclaimer.rs
Normal file
82
voxygen/src/menu/main/ui/disclaimer.rs
Normal file
@ -0,0 +1,82 @@
|
||||
use super::Message;
|
||||
use crate::{
|
||||
i18n::Localization,
|
||||
ui::{
|
||||
fonts::IcedFonts as Fonts,
|
||||
ice::{component::neat_button, style, Element},
|
||||
},
|
||||
};
|
||||
use iced::{button, scrollable, Column, Container, Length, Scrollable, Space};
|
||||
|
||||
/// Connecting screen for the main menu
|
||||
pub struct Screen {
|
||||
accept_button: button::State,
|
||||
scroll: scrollable::State,
|
||||
}
|
||||
|
||||
impl Screen {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
accept_button: Default::default(),
|
||||
scroll: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn view(
|
||||
&mut self,
|
||||
fonts: &Fonts,
|
||||
i18n: &Localization,
|
||||
button_style: style::button::Style,
|
||||
) -> Element<Message> {
|
||||
Container::new(
|
||||
Container::new(
|
||||
Column::with_children(vec![
|
||||
iced::Text::new(i18n.get("common.disclaimer"))
|
||||
.font(fonts.alkhemi.id)
|
||||
.size(fonts.alkhemi.scale(35))
|
||||
.into(),
|
||||
Space::new(Length::Fill, Length::Units(20)).into(),
|
||||
Scrollable::new(&mut self.scroll)
|
||||
.push(
|
||||
iced::Text::new(i18n.get("main.notice"))
|
||||
.font(fonts.cyri.id)
|
||||
.size(fonts.cyri.scale(23)),
|
||||
)
|
||||
.height(Length::FillPortion(1))
|
||||
.into(),
|
||||
Container::new(
|
||||
Container::new(neat_button(
|
||||
&mut self.accept_button,
|
||||
i18n.get("common.accept"),
|
||||
0.7,
|
||||
button_style,
|
||||
Some(Message::AcceptDisclaimer),
|
||||
))
|
||||
.height(Length::Units(fonts.cyri.scale(50))),
|
||||
)
|
||||
.center_x()
|
||||
.height(Length::Shrink)
|
||||
.width(Length::Fill)
|
||||
.into(),
|
||||
])
|
||||
.spacing(5)
|
||||
.padding(20)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill),
|
||||
)
|
||||
.style(
|
||||
style::container::Style::color_with_double_cornerless_border(
|
||||
(22, 19, 17, 255).into(),
|
||||
(11, 11, 11, 255).into(),
|
||||
(54, 46, 38, 255).into(),
|
||||
),
|
||||
),
|
||||
)
|
||||
.center_x()
|
||||
.center_y()
|
||||
.padding(70)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
}
|
||||
}
|
434
voxygen/src/menu/main/ui/login.rs
Normal file
434
voxygen/src/menu/main/ui/login.rs
Normal file
@ -0,0 +1,434 @@
|
||||
use super::{Imgs, LoginInfo, Message, FILL_FRAC_ONE, FILL_FRAC_TWO};
|
||||
use crate::{
|
||||
i18n::Localization,
|
||||
ui::{
|
||||
fonts::IcedFonts as Fonts,
|
||||
ice::{
|
||||
component::neat_button,
|
||||
style,
|
||||
widget::{
|
||||
compound_graphic::{CompoundGraphic, Graphic},
|
||||
BackgroundContainer, Image, Padding,
|
||||
},
|
||||
Element,
|
||||
},
|
||||
},
|
||||
};
|
||||
use iced::{
|
||||
button, scrollable, text_input, Align, Button, Column, Container, Length, Row, Scrollable,
|
||||
Space, Text, TextInput,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
const INPUT_WIDTH: u16 = 230;
|
||||
const INPUT_TEXT_SIZE: u16 = 20;
|
||||
|
||||
/// Login screen for the main menu
|
||||
pub struct Screen {
|
||||
quit_button: button::State,
|
||||
settings_button: button::State,
|
||||
servers_button: button::State,
|
||||
language_select_button: button::State,
|
||||
|
||||
error_okay_button: button::State,
|
||||
|
||||
pub banner: LoginBanner,
|
||||
language_selection: LanguageSelectBanner,
|
||||
}
|
||||
|
||||
impl Screen {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
servers_button: Default::default(),
|
||||
settings_button: Default::default(),
|
||||
quit_button: Default::default(),
|
||||
language_select_button: Default::default(),
|
||||
|
||||
error_okay_button: Default::default(),
|
||||
|
||||
banner: LoginBanner::new(),
|
||||
language_selection: LanguageSelectBanner::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(super) fn view(
|
||||
&mut self,
|
||||
fonts: &Fonts,
|
||||
imgs: &Imgs,
|
||||
login_info: &LoginInfo,
|
||||
error: Option<&str>,
|
||||
i18n: &Localization,
|
||||
is_selecting_language: bool,
|
||||
selected_language_index: Option<usize>,
|
||||
language_metadatas: &[crate::i18n::LanguageMetadata],
|
||||
button_style: style::button::Style,
|
||||
version: &str,
|
||||
) -> Element<Message> {
|
||||
let buttons = Column::with_children(vec![
|
||||
neat_button(
|
||||
&mut self.servers_button,
|
||||
i18n.get("common.servers"),
|
||||
FILL_FRAC_ONE,
|
||||
button_style,
|
||||
Some(Message::ShowServers),
|
||||
),
|
||||
neat_button(
|
||||
&mut self.settings_button,
|
||||
i18n.get("common.settings"),
|
||||
FILL_FRAC_ONE,
|
||||
button_style,
|
||||
None,
|
||||
),
|
||||
neat_button(
|
||||
&mut self.language_select_button,
|
||||
i18n.get("common.languages"),
|
||||
FILL_FRAC_ONE,
|
||||
button_style,
|
||||
Some(Message::OpenLanguageMenu),
|
||||
),
|
||||
neat_button(
|
||||
&mut self.quit_button,
|
||||
i18n.get("common.quit"),
|
||||
FILL_FRAC_ONE,
|
||||
button_style,
|
||||
Some(Message::Quit),
|
||||
),
|
||||
])
|
||||
.width(Length::Fill)
|
||||
.max_width(100)
|
||||
.spacing(5);
|
||||
|
||||
let buttons = Container::new(buttons)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.align_y(Align::End);
|
||||
|
||||
let intro_text = i18n.get("main.login_process");
|
||||
|
||||
let info_window = BackgroundContainer::new(
|
||||
CompoundGraphic::from_graphics(vec![
|
||||
Graphic::rect(Rgba::new(0, 0, 0, 240), [500, 300], [0, 0]),
|
||||
// Note: a way to tell it to keep the height of this one piece constant and
|
||||
// unstreched would be nice, I suppose we could just break this out into a
|
||||
// column and use Length::Units
|
||||
Graphic::image(imgs.banner_gradient_bottom, [500, 50], [0, 300])
|
||||
.color(Rgba::new(0, 0, 0, 240)),
|
||||
])
|
||||
.height(Length::Shrink),
|
||||
Text::new(intro_text).size(fonts.cyri.scale(18)),
|
||||
)
|
||||
.max_width(360)
|
||||
.padding(Padding::new().horizontal(20).top(10).bottom(60));
|
||||
|
||||
let left_column = Column::with_children(vec![info_window.into(), buttons.into()])
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.padding(27)
|
||||
.into();
|
||||
|
||||
let central_content = if let Some(error) = error {
|
||||
Container::new(
|
||||
Column::with_children(vec![
|
||||
Container::new(Text::new(error)).height(Length::Fill).into(),
|
||||
Container::new(neat_button(
|
||||
&mut self.error_okay_button,
|
||||
i18n.get("common.okay"),
|
||||
FILL_FRAC_ONE,
|
||||
button_style,
|
||||
Some(Message::CloseError),
|
||||
))
|
||||
.width(Length::Fill)
|
||||
.height(Length::Units(30))
|
||||
.center_x()
|
||||
.into(),
|
||||
])
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.style(
|
||||
style::container::Style::color_with_double_cornerless_border(
|
||||
(22, 18, 16, 255).into(),
|
||||
(11, 11, 11, 255).into(),
|
||||
(54, 46, 38, 255).into(),
|
||||
),
|
||||
)
|
||||
.width(Length::Units(400))
|
||||
.height(Length::Units(180))
|
||||
.padding(20)
|
||||
.into()
|
||||
} else if is_selecting_language {
|
||||
self.language_selection.view(
|
||||
fonts,
|
||||
imgs,
|
||||
i18n,
|
||||
language_metadatas,
|
||||
selected_language_index,
|
||||
button_style,
|
||||
)
|
||||
} else {
|
||||
self.banner
|
||||
.view(fonts, imgs, login_info, i18n, button_style)
|
||||
};
|
||||
|
||||
let central_column = Container::new(central_content)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.center_x()
|
||||
.center_y();
|
||||
|
||||
let v_logo = Container::new(Image::new(imgs.v_logo).fix_aspect_ratio())
|
||||
.padding(3)
|
||||
.width(Length::Units(230));
|
||||
|
||||
let version = iced::Text::new(version).size(fonts.cyri.scale(15));
|
||||
|
||||
let right_column = Container::new(
|
||||
Column::with_children(vec![v_logo.into(), version.into()]).align_items(Align::Center),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.align_x(Align::End);
|
||||
|
||||
Row::with_children(vec![
|
||||
left_column,
|
||||
central_column.into(),
|
||||
right_column.into(),
|
||||
])
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.spacing(10)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LanguageSelectBanner {
|
||||
okay_button: button::State,
|
||||
language_buttons: Vec<button::State>,
|
||||
|
||||
selection_list: scrollable::State,
|
||||
}
|
||||
|
||||
impl LanguageSelectBanner {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
okay_button: Default::default(),
|
||||
language_buttons: Default::default(),
|
||||
selection_list: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn view(
|
||||
&mut self,
|
||||
fonts: &Fonts,
|
||||
imgs: &Imgs,
|
||||
i18n: &Localization,
|
||||
language_metadatas: &[crate::i18n::LanguageMetadata],
|
||||
selected_language_index: Option<usize>,
|
||||
button_style: style::button::Style,
|
||||
) -> Element<Message> {
|
||||
// Reset button states if languages were added / removed
|
||||
if self.language_buttons.len() != language_metadatas.len() {
|
||||
self.language_buttons = vec![Default::default(); language_metadatas.len()];
|
||||
}
|
||||
|
||||
let title = Text::new(i18n.get("main.login.select_language"))
|
||||
.size(fonts.cyri.scale(35))
|
||||
.horizontal_alignment(iced::HorizontalAlignment::Center);
|
||||
|
||||
let mut list = Scrollable::new(&mut self.selection_list)
|
||||
.spacing(8)
|
||||
.height(Length::Fill)
|
||||
.align_items(Align::Start);
|
||||
|
||||
let list_items = self
|
||||
.language_buttons
|
||||
.iter_mut()
|
||||
.zip(language_metadatas)
|
||||
.enumerate()
|
||||
.map(|(i, (state, lang))| {
|
||||
let color = if Some(i) == selected_language_index {
|
||||
(97, 255, 18)
|
||||
} else {
|
||||
(97, 97, 25)
|
||||
};
|
||||
let button = Button::new(
|
||||
state,
|
||||
Row::with_children(vec![
|
||||
Space::new(Length::FillPortion(5), Length::Units(0)).into(),
|
||||
Text::new(lang.language_name.clone())
|
||||
.width(Length::FillPortion(95))
|
||||
.size(fonts.cyri.scale(25))
|
||||
.vertical_alignment(iced::VerticalAlignment::Center)
|
||||
.into(),
|
||||
]),
|
||||
)
|
||||
.style(
|
||||
style::button::Style::new(imgs.selection)
|
||||
.hover_image(imgs.selection_hover)
|
||||
.press_image(imgs.selection_press)
|
||||
.image_color(vek::Rgba::new(color.0, color.1, color.2, 192)),
|
||||
)
|
||||
.min_height(56)
|
||||
.on_press(Message::LanguageChanged(i));
|
||||
Row::with_children(vec![
|
||||
Space::new(Length::FillPortion(3), Length::Units(0)).into(),
|
||||
button.width(Length::FillPortion(92)).into(),
|
||||
Space::new(Length::FillPortion(5), Length::Units(0)).into(),
|
||||
])
|
||||
});
|
||||
|
||||
for item in list_items {
|
||||
list = list.push(item);
|
||||
}
|
||||
|
||||
let okay_button = Container::new(neat_button(
|
||||
&mut self.okay_button,
|
||||
i18n.get("common.okay"),
|
||||
FILL_FRAC_TWO,
|
||||
button_style,
|
||||
Some(Message::OpenLanguageMenu),
|
||||
))
|
||||
.center_x()
|
||||
.max_width(200);
|
||||
|
||||
let content = Column::with_children(vec![title.into(), list.into(), okay_button.into()])
|
||||
.spacing(8)
|
||||
.width(Length::Fill)
|
||||
.height(Length::FillPortion(38))
|
||||
.align_items(Align::Center);
|
||||
|
||||
let selection_menu = BackgroundContainer::new(
|
||||
CompoundGraphic::from_graphics(vec![
|
||||
Graphic::image(imgs.banner_top, [138, 17], [0, 0]),
|
||||
Graphic::rect(Rgba::new(0, 0, 0, 230), [130, 165], [4, 17]),
|
||||
// TODO: use non image gradient
|
||||
Graphic::gradient(Rgba::new(0, 0, 0, 230), Rgba::zero(), [130, 50], [4, 182]),
|
||||
])
|
||||
.fix_aspect_ratio()
|
||||
.height(Length::Fill),
|
||||
content,
|
||||
)
|
||||
.padding(Padding::new().horizontal(5).top(15).bottom(50))
|
||||
.max_width(350);
|
||||
|
||||
selection_menu.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LoginBanner {
|
||||
pub username: text_input::State,
|
||||
pub password: text_input::State,
|
||||
pub server: text_input::State,
|
||||
|
||||
multiplayer_button: button::State,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
singleplayer_button: button::State,
|
||||
}
|
||||
|
||||
impl LoginBanner {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
username: Default::default(),
|
||||
password: Default::default(),
|
||||
server: Default::default(),
|
||||
|
||||
multiplayer_button: Default::default(),
|
||||
#[cfg(feature = "singleplayer")]
|
||||
singleplayer_button: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn view(
|
||||
&mut self,
|
||||
fonts: &Fonts,
|
||||
imgs: &Imgs,
|
||||
login_info: &LoginInfo,
|
||||
i18n: &Localization,
|
||||
button_style: style::button::Style,
|
||||
) -> Element<Message> {
|
||||
let input_text_size = fonts.cyri.scale(INPUT_TEXT_SIZE);
|
||||
|
||||
let banner_content = Column::with_children(vec![
|
||||
Column::with_children(vec![
|
||||
BackgroundContainer::new(
|
||||
Image::new(imgs.input_bg)
|
||||
.width(Length::Units(INPUT_WIDTH))
|
||||
.fix_aspect_ratio(),
|
||||
TextInput::new(
|
||||
&mut self.username,
|
||||
i18n.get("main.username"),
|
||||
&login_info.username,
|
||||
Message::Username,
|
||||
)
|
||||
.size(input_text_size)
|
||||
.on_submit(Message::FocusPassword),
|
||||
)
|
||||
.padding(Padding::new().horizontal(7).top(5))
|
||||
.into(),
|
||||
BackgroundContainer::new(
|
||||
Image::new(imgs.input_bg)
|
||||
.width(Length::Units(INPUT_WIDTH))
|
||||
.fix_aspect_ratio(),
|
||||
TextInput::new(
|
||||
&mut self.password,
|
||||
i18n.get("main.password"),
|
||||
&login_info.password,
|
||||
Message::Password,
|
||||
)
|
||||
.size(input_text_size)
|
||||
.password()
|
||||
.on_submit(Message::Multiplayer),
|
||||
)
|
||||
.padding(Padding::new().horizontal(7).top(5))
|
||||
.into(),
|
||||
BackgroundContainer::new(
|
||||
Image::new(imgs.input_bg)
|
||||
.width(Length::Units(INPUT_WIDTH))
|
||||
.fix_aspect_ratio(),
|
||||
TextInput::new(
|
||||
&mut self.server,
|
||||
i18n.get("main.server"),
|
||||
&login_info.server,
|
||||
Message::Server,
|
||||
)
|
||||
.size(input_text_size)
|
||||
.on_submit(Message::Multiplayer),
|
||||
)
|
||||
.padding(Padding::new().horizontal(7).top(5))
|
||||
.into(),
|
||||
])
|
||||
.spacing(5)
|
||||
.into(),
|
||||
Space::new(Length::Fill, Length::Units(8)).into(),
|
||||
Column::with_children(vec![
|
||||
neat_button(
|
||||
&mut self.multiplayer_button,
|
||||
i18n.get("common.multiplayer"),
|
||||
FILL_FRAC_TWO,
|
||||
button_style,
|
||||
Some(Message::Multiplayer),
|
||||
),
|
||||
#[cfg(feature = "singleplayer")]
|
||||
neat_button(
|
||||
&mut self.singleplayer_button,
|
||||
i18n.get("common.singleplayer"),
|
||||
FILL_FRAC_TWO,
|
||||
button_style,
|
||||
Some(Message::Singleplayer),
|
||||
),
|
||||
])
|
||||
.max_width(170)
|
||||
.height(Length::Units(200))
|
||||
.spacing(8)
|
||||
.into(),
|
||||
])
|
||||
.width(Length::Fill)
|
||||
.align_items(Align::Center);
|
||||
|
||||
Container::new(banner_content)
|
||||
.height(Length::Fill)
|
||||
.center_y()
|
||||
.into()
|
||||
}
|
||||
}
|
574
voxygen/src/menu/main/ui/mod.rs
Normal file
574
voxygen/src/menu/main/ui/mod.rs
Normal file
@ -0,0 +1,574 @@
|
||||
mod connecting;
|
||||
// Note: Keeping in case we re-add the disclaimer
|
||||
//mod disclaimer;
|
||||
mod login;
|
||||
mod servers;
|
||||
|
||||
use crate::{
|
||||
i18n::{i18n_asset_key, LanguageMetadata, Localization},
|
||||
render::Renderer,
|
||||
ui::{
|
||||
self,
|
||||
fonts::IcedFonts as Fonts,
|
||||
ice::{style, widget, Element, Font, IcedUi as Ui},
|
||||
img_ids::{ImageGraphic, VoxelGraphic},
|
||||
Graphic,
|
||||
},
|
||||
GlobalState,
|
||||
};
|
||||
use iced::{text_input, Column, Container, HorizontalAlignment, Length, Row, Space};
|
||||
//ImageFrame, Tooltip,
|
||||
use crate::settings::Settings;
|
||||
use common::assets::Asset;
|
||||
use image::DynamicImage;
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
use std::time::Duration;
|
||||
|
||||
// TODO: what is this? (showed up in rebase)
|
||||
//const COL1: Color = Color::Rgba(0.07, 0.1, 0.1, 0.9);
|
||||
|
||||
pub const TEXT_COLOR: iced::Color = iced::Color::from_rgb(1.0, 1.0, 1.0);
|
||||
pub const DISABLED_TEXT_COLOR: iced::Color = iced::Color::from_rgba(1.0, 1.0, 1.0, 0.2);
|
||||
|
||||
pub const FILL_FRAC_ONE: f32 = 0.77;
|
||||
pub const FILL_FRAC_TWO: f32 = 0.53;
|
||||
|
||||
image_ids_ice! {
|
||||
struct Imgs {
|
||||
<VoxelGraphic>
|
||||
v_logo: "voxygen.element.v_logo",
|
||||
|
||||
<ImageGraphic>
|
||||
bg: "voxygen.background.bg_main",
|
||||
banner_top: "voxygen.element.frames.banner_top",
|
||||
banner_gradient_bottom: "voxygen.element.frames.banner_gradient_bottom",
|
||||
button: "voxygen.element.buttons.button",
|
||||
button_hover: "voxygen.element.buttons.button_hover",
|
||||
button_press: "voxygen.element.buttons.button_press",
|
||||
input_bg: "voxygen.element.misc_bg.textbox",
|
||||
loading_art: "voxygen.element.frames.loading_screen.loading_bg",
|
||||
loading_art_l: "voxygen.element.frames.loading_screen.loading_bg_l",
|
||||
loading_art_r: "voxygen.element.frames.loading_screen.loading_bg_r",
|
||||
selection: "voxygen.element.frames.selection",
|
||||
selection_hover: "voxygen.element.frames.selection_hover",
|
||||
selection_press: "voxygen.element.frames.selection_press",
|
||||
|
||||
// Animation
|
||||
f1: "voxygen.element.animation.gears.1",
|
||||
f2: "voxygen.element.animation.gears.2",
|
||||
f3: "voxygen.element.animation.gears.3",
|
||||
f4: "voxygen.element.animation.gears.4",
|
||||
f5: "voxygen.element.animation.gears.5",
|
||||
}
|
||||
}
|
||||
|
||||
// Randomly loaded background images
|
||||
const BG_IMGS: [&str; 13] = [
|
||||
"voxygen.background.bg_1",
|
||||
"voxygen.background.bg_2",
|
||||
"voxygen.background.bg_3",
|
||||
"voxygen.background.bg_4",
|
||||
"voxygen.background.bg_5",
|
||||
"voxygen.background.bg_6",
|
||||
"voxygen.background.bg_7",
|
||||
"voxygen.background.bg_8",
|
||||
"voxygen.background.bg_9",
|
||||
//"voxygen.background.bg_10",
|
||||
"voxygen.background.bg_11",
|
||||
//"voxygen.background.bg_12",
|
||||
"voxygen.background.bg_13",
|
||||
//"voxygen.background.bg_14",
|
||||
"voxygen.background.bg_15",
|
||||
"voxygen.background.bg_16",
|
||||
];
|
||||
|
||||
pub enum Event {
|
||||
LoginAttempt {
|
||||
username: String,
|
||||
password: String,
|
||||
server_address: String,
|
||||
},
|
||||
CancelLoginAttempt,
|
||||
ChangeLanguage(LanguageMetadata),
|
||||
#[cfg(feature = "singleplayer")]
|
||||
StartSingleplayer,
|
||||
Quit,
|
||||
// Note: Keeping in case we re-add the disclaimer
|
||||
//DisclaimerAccepted,
|
||||
AuthServerTrust(String, bool),
|
||||
}
|
||||
|
||||
pub struct LoginInfo {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
pub server: String,
|
||||
}
|
||||
|
||||
enum ConnectionState {
|
||||
InProgress,
|
||||
AuthTrustPrompt { auth_server: String, msg: String },
|
||||
}
|
||||
|
||||
enum Screen {
|
||||
// Note: Keeping in case we re-add the disclaimer
|
||||
/*Disclaimer {
|
||||
screen: disclaimer::Screen,
|
||||
},*/
|
||||
Login {
|
||||
screen: login::Screen,
|
||||
// Error to display in a box
|
||||
error: Option<String>,
|
||||
},
|
||||
Servers {
|
||||
screen: servers::Screen,
|
||||
},
|
||||
Connecting {
|
||||
screen: connecting::Screen,
|
||||
connection_state: ConnectionState,
|
||||
},
|
||||
}
|
||||
|
||||
struct Controls {
|
||||
fonts: Fonts,
|
||||
imgs: Imgs,
|
||||
bg_img: widget::image::Handle,
|
||||
i18n: std::sync::Arc<Localization>,
|
||||
// Voxygen version
|
||||
version: String,
|
||||
// Alpha disclaimer
|
||||
alpha: String,
|
||||
|
||||
selected_server_index: Option<usize>,
|
||||
login_info: LoginInfo,
|
||||
|
||||
is_selecting_language: bool,
|
||||
selected_language_index: Option<usize>,
|
||||
|
||||
time: f64,
|
||||
|
||||
screen: Screen,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Message {
|
||||
Quit,
|
||||
Back,
|
||||
ShowServers,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
Singleplayer,
|
||||
Multiplayer,
|
||||
LanguageChanged(usize),
|
||||
OpenLanguageMenu,
|
||||
Username(String),
|
||||
Password(String),
|
||||
Server(String),
|
||||
ServerChanged(usize),
|
||||
FocusPassword,
|
||||
CancelConnect,
|
||||
TrustPromptAdd,
|
||||
TrustPromptCancel,
|
||||
CloseError,
|
||||
/* Note: Keeping in case we re-add the disclaimer
|
||||
*AcceptDisclaimer, */
|
||||
}
|
||||
|
||||
impl Controls {
|
||||
fn new(
|
||||
fonts: Fonts,
|
||||
imgs: Imgs,
|
||||
bg_img: widget::image::Handle,
|
||||
i18n: std::sync::Arc<Localization>,
|
||||
settings: &Settings,
|
||||
) -> Self {
|
||||
let version = common::util::DISPLAY_VERSION_LONG.clone();
|
||||
let alpha = format!("Veloren {}", common::util::DISPLAY_VERSION.as_str());
|
||||
|
||||
// Note: Keeping in case we re-add the disclaimer
|
||||
let screen = /* if settings.show_disclaimer {
|
||||
Screen::Disclaimer {
|
||||
screen: disclaimer::Screen::new(),
|
||||
}
|
||||
} else { */
|
||||
Screen::Login {
|
||||
screen: login::Screen::new(),
|
||||
error: None,
|
||||
};
|
||||
//};
|
||||
|
||||
let login_info = LoginInfo {
|
||||
username: settings.networking.username.clone(),
|
||||
password: String::new(),
|
||||
server: settings.networking.default_server.clone(),
|
||||
};
|
||||
let selected_server_index = settings
|
||||
.networking
|
||||
.servers
|
||||
.iter()
|
||||
.position(|f| f == &login_info.server);
|
||||
|
||||
let language_metadatas = crate::i18n::list_localizations();
|
||||
let selected_language_index = language_metadatas
|
||||
.iter()
|
||||
.position(|f| f.language_identifier == settings.language.selected_language);
|
||||
|
||||
Self {
|
||||
fonts,
|
||||
imgs,
|
||||
bg_img,
|
||||
i18n,
|
||||
version,
|
||||
alpha,
|
||||
|
||||
selected_server_index,
|
||||
login_info,
|
||||
|
||||
is_selecting_language: false,
|
||||
selected_language_index,
|
||||
|
||||
time: 0.0,
|
||||
|
||||
screen,
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&mut self, settings: &Settings, dt: f32) -> Element<Message> {
|
||||
self.time += dt as f64;
|
||||
|
||||
// TODO: consider setting this as the default in the renderer
|
||||
let button_style = style::button::Style::new(self.imgs.button)
|
||||
.hover_image(self.imgs.button_hover)
|
||||
.press_image(self.imgs.button_press)
|
||||
.text_color(TEXT_COLOR)
|
||||
.disabled_text_color(DISABLED_TEXT_COLOR);
|
||||
|
||||
let alpha = iced::Text::new(&self.alpha)
|
||||
.size(self.fonts.cyri.scale(12))
|
||||
.width(Length::Fill)
|
||||
.horizontal_alignment(HorizontalAlignment::Center);
|
||||
|
||||
let top_text = Row::with_children(vec![
|
||||
Space::new(Length::Fill, Length::Shrink).into(),
|
||||
alpha.into(),
|
||||
if matches!(&self.screen, Screen::Login { .. }) {
|
||||
// Login screen shows the Velroen logo over the version
|
||||
Space::new(Length::Fill, Length::Shrink).into()
|
||||
} else {
|
||||
iced::Text::new(&self.version)
|
||||
.size(self.fonts.cyri.scale(15))
|
||||
.width(Length::Fill)
|
||||
.horizontal_alignment(HorizontalAlignment::Right)
|
||||
.into()
|
||||
},
|
||||
])
|
||||
.padding(3)
|
||||
.width(Length::Fill);
|
||||
|
||||
let bg_img = if matches!(&self.screen, Screen::Connecting {..}) {
|
||||
self.bg_img
|
||||
} else {
|
||||
self.imgs.bg
|
||||
};
|
||||
|
||||
let language_metadatas = crate::i18n::list_localizations();
|
||||
|
||||
// TODO: make any large text blocks scrollable so that if the area is to
|
||||
// small they can still be read
|
||||
let content = match &mut self.screen {
|
||||
// Note: Keeping in case we re-add the disclaimer
|
||||
//Screen::Disclaimer { screen } => screen.view(&self.fonts, &self.i18n, button_style),
|
||||
Screen::Login { screen, error } => screen.view(
|
||||
&self.fonts,
|
||||
&self.imgs,
|
||||
&self.login_info,
|
||||
error.as_deref(),
|
||||
&self.i18n,
|
||||
self.is_selecting_language,
|
||||
self.selected_language_index,
|
||||
&language_metadatas,
|
||||
button_style,
|
||||
&self.version,
|
||||
),
|
||||
Screen::Servers { screen } => screen.view(
|
||||
&self.fonts,
|
||||
&self.imgs,
|
||||
&settings.networking.servers,
|
||||
self.selected_server_index,
|
||||
&self.i18n,
|
||||
button_style,
|
||||
),
|
||||
Screen::Connecting {
|
||||
screen,
|
||||
connection_state,
|
||||
} => screen.view(
|
||||
&self.fonts,
|
||||
&self.imgs,
|
||||
&connection_state,
|
||||
self.time,
|
||||
&self.i18n,
|
||||
button_style,
|
||||
settings.gameplay.loading_tips,
|
||||
),
|
||||
};
|
||||
|
||||
Container::new(
|
||||
Column::with_children(vec![top_text.into(), content])
|
||||
.spacing(3)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill),
|
||||
)
|
||||
.style(style::container::Style::image(bg_img))
|
||||
.into()
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Message, events: &mut Vec<Event>, settings: &Settings) {
|
||||
let servers = &settings.networking.servers;
|
||||
let mut language_metadatas = crate::i18n::list_localizations();
|
||||
|
||||
match message {
|
||||
Message::Quit => events.push(Event::Quit),
|
||||
Message::Back => {
|
||||
self.screen = Screen::Login {
|
||||
screen: login::Screen::new(),
|
||||
error: None,
|
||||
};
|
||||
},
|
||||
Message::ShowServers => {
|
||||
if matches!(&self.screen, Screen::Login {..}) {
|
||||
self.selected_server_index =
|
||||
servers.iter().position(|f| f == &self.login_info.server);
|
||||
self.screen = Screen::Servers {
|
||||
screen: servers::Screen::new(),
|
||||
};
|
||||
}
|
||||
},
|
||||
#[cfg(feature = "singleplayer")]
|
||||
Message::Singleplayer => {
|
||||
self.screen = Screen::Connecting {
|
||||
screen: connecting::Screen::new(),
|
||||
connection_state: ConnectionState::InProgress,
|
||||
};
|
||||
events.push(Event::StartSingleplayer);
|
||||
},
|
||||
Message::Multiplayer => {
|
||||
self.screen = Screen::Connecting {
|
||||
screen: connecting::Screen::new(),
|
||||
connection_state: ConnectionState::InProgress,
|
||||
};
|
||||
|
||||
events.push(Event::LoginAttempt {
|
||||
username: self.login_info.username.clone(),
|
||||
password: self.login_info.password.clone(),
|
||||
server_address: self.login_info.server.clone(),
|
||||
});
|
||||
},
|
||||
Message::Username(new_value) => self.login_info.username = new_value,
|
||||
Message::LanguageChanged(new_value) => {
|
||||
self.selected_language_index = Some(new_value);
|
||||
events.push(Event::ChangeLanguage(language_metadatas.remove(new_value)));
|
||||
},
|
||||
Message::OpenLanguageMenu => self.is_selecting_language = !self.is_selecting_language,
|
||||
Message::Password(new_value) => self.login_info.password = new_value,
|
||||
Message::Server(new_value) => {
|
||||
self.login_info.server = new_value;
|
||||
},
|
||||
Message::ServerChanged(new_value) => {
|
||||
self.selected_server_index = Some(new_value);
|
||||
self.login_info.server = servers[new_value].clone();
|
||||
},
|
||||
Message::FocusPassword => {
|
||||
if let Screen::Login { screen, .. } = &mut self.screen {
|
||||
screen.banner.password = text_input::State::focused();
|
||||
screen.banner.username = text_input::State::new();
|
||||
}
|
||||
},
|
||||
Message::CancelConnect => {
|
||||
self.exit_connect_screen();
|
||||
events.push(Event::CancelLoginAttempt);
|
||||
},
|
||||
msg @ Message::TrustPromptAdd | msg @ Message::TrustPromptCancel => {
|
||||
if let Screen::Connecting {
|
||||
connection_state, ..
|
||||
} = &mut self.screen
|
||||
{
|
||||
if let ConnectionState::AuthTrustPrompt { auth_server, .. } = connection_state {
|
||||
let auth_server = std::mem::take(auth_server);
|
||||
let added = matches!(msg, Message::TrustPromptAdd);
|
||||
|
||||
*connection_state = ConnectionState::InProgress;
|
||||
events.push(Event::AuthServerTrust(auth_server, added));
|
||||
}
|
||||
}
|
||||
},
|
||||
Message::CloseError => {
|
||||
if let Screen::Login { error, .. } = &mut self.screen {
|
||||
*error = None;
|
||||
}
|
||||
},
|
||||
/* Note: Keeping in case we re-add the disclaimer */
|
||||
/*Message::AcceptDisclaimer => {
|
||||
if let Screen::Disclaimer { .. } = &self.screen {
|
||||
events.push(Event::DisclaimerAccepted);
|
||||
self.screen = Screen::Login {
|
||||
screen: login::Screen::new(),
|
||||
error: None,
|
||||
};
|
||||
}
|
||||
},*/
|
||||
}
|
||||
}
|
||||
|
||||
// Connection successful of failed
|
||||
fn exit_connect_screen(&mut self) {
|
||||
if matches!(&self.screen, Screen::Connecting {..}) {
|
||||
self.screen = Screen::Login {
|
||||
screen: login::Screen::new(),
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn auth_trust_prompt(&mut self, auth_server: String) {
|
||||
if let Screen::Connecting {
|
||||
connection_state, ..
|
||||
} = &mut self.screen
|
||||
{
|
||||
let msg = format!(
|
||||
"Warning: The server you are trying to connect to has provided this \
|
||||
authentication server address:\n\n{}\n\nbut it is not in your list of trusted \
|
||||
authentication servers.\n\nMake sure that you trust this site and owner to not \
|
||||
try and bruteforce your password!",
|
||||
&auth_server
|
||||
);
|
||||
|
||||
*connection_state = ConnectionState::AuthTrustPrompt { auth_server, msg };
|
||||
}
|
||||
}
|
||||
|
||||
fn connection_error(&mut self, error: String) {
|
||||
if matches!(&self.screen, Screen::Connecting {..}) {
|
||||
self.screen = Screen::Login {
|
||||
screen: login::Screen::new(),
|
||||
error: Some(error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tab(&mut self) {
|
||||
if let Screen::Login { screen, .. } = &mut self.screen {
|
||||
// TODO: add select all function in iced
|
||||
if screen.banner.username.is_focused() {
|
||||
screen.banner.username = iced::text_input::State::new();
|
||||
screen.banner.password = iced::text_input::State::focused();
|
||||
screen.banner.password.move_cursor_to_end();
|
||||
} else if screen.banner.password.is_focused() {
|
||||
screen.banner.password = iced::text_input::State::new();
|
||||
screen.banner.server = iced::text_input::State::focused();
|
||||
screen.banner.server.move_cursor_to_end();
|
||||
} else if screen.banner.server.is_focused() {
|
||||
screen.banner.server = iced::text_input::State::new();
|
||||
screen.banner.username = iced::text_input::State::focused();
|
||||
screen.banner.username.move_cursor_to_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MainMenuUi {
|
||||
ui: Ui,
|
||||
// TODO: re add this
|
||||
// tip_no: u16,
|
||||
controls: Controls,
|
||||
}
|
||||
|
||||
impl<'a> MainMenuUi {
|
||||
pub fn new(global_state: &mut GlobalState) -> Self {
|
||||
// Load language
|
||||
let i18n = Localization::load_expect(&i18n_asset_key(
|
||||
&global_state.settings.language.selected_language,
|
||||
));
|
||||
|
||||
// TODO: don't add default font twice
|
||||
let font = {
|
||||
use std::io::Read;
|
||||
let mut buf = Vec::new();
|
||||
common::assets::load_file("voxygen.font.haxrcorp_4089_cyrillic_altgr_extended", &[
|
||||
"ttf",
|
||||
])
|
||||
.unwrap()
|
||||
.read_to_end(&mut buf)
|
||||
.unwrap();
|
||||
Font::try_from_vec(buf).unwrap()
|
||||
};
|
||||
|
||||
let mut ui = Ui::new(
|
||||
&mut global_state.window,
|
||||
font,
|
||||
global_state.settings.gameplay.ui_scale,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let fonts = Fonts::load(&i18n.fonts, &mut ui).expect("Impossible to load fonts");
|
||||
|
||||
let bg_img_spec = BG_IMGS.choose(&mut thread_rng()).unwrap();
|
||||
|
||||
let controls = Controls::new(
|
||||
fonts,
|
||||
Imgs::load(&mut ui).expect("Failed to load images"),
|
||||
ui.add_graphic(Graphic::Image(DynamicImage::load_expect(bg_img_spec), None)),
|
||||
i18n,
|
||||
&global_state.settings,
|
||||
);
|
||||
|
||||
Self { ui, controls }
|
||||
}
|
||||
|
||||
pub fn update_language(&mut self, i18n: std::sync::Arc<Localization>) {
|
||||
self.controls.i18n = i18n;
|
||||
self.controls.fonts = Fonts::load(&self.controls.i18n.fonts, &mut self.ui)
|
||||
.expect("Impossible to load fonts!");
|
||||
}
|
||||
|
||||
pub fn auth_trust_prompt(&mut self, auth_server: String) {
|
||||
self.controls.auth_trust_prompt(auth_server);
|
||||
}
|
||||
|
||||
pub fn show_info(&mut self, msg: String) { self.controls.connection_error(msg); }
|
||||
|
||||
pub fn connected(&mut self) { self.controls.exit_connect_screen(); }
|
||||
|
||||
pub fn cancel_connection(&mut self) { self.controls.exit_connect_screen(); }
|
||||
|
||||
pub fn handle_event(&mut self, event: ui::ice::Event) {
|
||||
// Tab for input fields
|
||||
use iced::keyboard;
|
||||
if matches!(
|
||||
&event,
|
||||
iced::Event::Keyboard(keyboard::Event::KeyPressed {
|
||||
key_code: keyboard::KeyCode::Tab,
|
||||
..
|
||||
})
|
||||
) {
|
||||
self.controls.tab();
|
||||
}
|
||||
|
||||
self.ui.handle_event(event);
|
||||
}
|
||||
|
||||
pub fn maintain(&mut self, global_state: &mut GlobalState, dt: Duration) -> Vec<Event> {
|
||||
let mut events = Vec::new();
|
||||
|
||||
let (messages, _) = self.ui.maintain(
|
||||
self.controls.view(&global_state.settings, dt.as_secs_f32()),
|
||||
global_state.window.renderer_mut(),
|
||||
);
|
||||
|
||||
messages.into_iter().for_each(|message| {
|
||||
self.controls
|
||||
.update(message, &mut events, &global_state.settings)
|
||||
});
|
||||
|
||||
events
|
||||
}
|
||||
|
||||
pub fn render(&self, renderer: &mut Renderer) { self.ui.render(renderer); }
|
||||
}
|
129
voxygen/src/menu/main/ui/servers.rs
Normal file
129
voxygen/src/menu/main/ui/servers.rs
Normal file
@ -0,0 +1,129 @@
|
||||
use super::{Imgs, Message, FILL_FRAC_ONE};
|
||||
use crate::{
|
||||
i18n::Localization,
|
||||
ui::{
|
||||
fonts::IcedFonts as Fonts,
|
||||
ice::{component::neat_button, style, Element},
|
||||
},
|
||||
};
|
||||
use iced::{
|
||||
button, scrollable, Align, Button, Column, Container, Length, Row, Scrollable, Space, Text,
|
||||
};
|
||||
|
||||
pub struct Screen {
|
||||
back_button: button::State,
|
||||
server_buttons: Vec<button::State>,
|
||||
servers_list: scrollable::State,
|
||||
}
|
||||
|
||||
impl Screen {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
back_button: Default::default(),
|
||||
server_buttons: vec![],
|
||||
servers_list: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn view(
|
||||
&mut self,
|
||||
fonts: &Fonts,
|
||||
imgs: &Imgs,
|
||||
servers: &[impl AsRef<str>],
|
||||
selected_server_index: Option<usize>,
|
||||
i18n: &Localization,
|
||||
button_style: style::button::Style,
|
||||
) -> Element<Message> {
|
||||
let title = Text::new(i18n.get("main.servers.select_server"))
|
||||
.size(fonts.cyri.scale(35))
|
||||
.width(Length::Fill)
|
||||
.horizontal_alignment(iced::HorizontalAlignment::Center);
|
||||
|
||||
let back_button = Container::new(
|
||||
Container::new(neat_button(
|
||||
&mut self.back_button,
|
||||
i18n.get("common.back"),
|
||||
FILL_FRAC_ONE,
|
||||
button_style,
|
||||
Some(Message::Back),
|
||||
))
|
||||
.max_width(200),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.align_x(Align::Center);
|
||||
|
||||
let mut list = Scrollable::new(&mut self.servers_list)
|
||||
.spacing(8)
|
||||
.align_items(Align::Start)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill);
|
||||
|
||||
// Reset button states if servers were added / removed
|
||||
if self.server_buttons.len() != servers.len() {
|
||||
self.server_buttons = vec![Default::default(); servers.len()];
|
||||
}
|
||||
|
||||
let list_items =
|
||||
self.server_buttons
|
||||
.iter_mut()
|
||||
.zip(servers)
|
||||
.enumerate()
|
||||
.map(|(i, (state, server))| {
|
||||
let color = if Some(i) == selected_server_index {
|
||||
(97, 255, 18)
|
||||
} else {
|
||||
(97, 97, 25)
|
||||
};
|
||||
let button = Button::new(
|
||||
state,
|
||||
Row::with_children(vec![
|
||||
Space::new(Length::FillPortion(5), Length::Units(0)).into(),
|
||||
Text::new(server.as_ref())
|
||||
.size(fonts.cyri.scale(30))
|
||||
.width(Length::FillPortion(95))
|
||||
.vertical_alignment(iced::VerticalAlignment::Center)
|
||||
.into(),
|
||||
]),
|
||||
)
|
||||
.style(
|
||||
style::button::Style::new(imgs.selection)
|
||||
.hover_image(imgs.selection_hover)
|
||||
.press_image(imgs.selection_press)
|
||||
.image_color(vek::Rgba::new(color.0, color.1, color.2, 255)),
|
||||
)
|
||||
.min_height(100)
|
||||
.on_press(Message::ServerChanged(i));
|
||||
Row::with_children(vec![
|
||||
Space::new(Length::FillPortion(3), Length::Units(0)).into(),
|
||||
button.width(Length::FillPortion(92)).into(),
|
||||
Space::new(Length::FillPortion(5), Length::Units(0)).into(),
|
||||
])
|
||||
});
|
||||
|
||||
for item in list_items {
|
||||
list = list.push(item);
|
||||
}
|
||||
|
||||
Container::new(
|
||||
Container::new(
|
||||
Column::with_children(vec![title.into(), list.into(), back_button.into()])
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.spacing(10)
|
||||
.padding(20),
|
||||
)
|
||||
.style(
|
||||
style::container::Style::color_with_double_cornerless_border(
|
||||
(22, 18, 16, 255).into(),
|
||||
(11, 11, 11, 255).into(),
|
||||
(54, 46, 38, 255).into(),
|
||||
),
|
||||
)
|
||||
.max_width(500),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.align_x(Align::Center)
|
||||
.padding(80)
|
||||
.into()
|
||||
}
|
||||
}
|
@ -57,6 +57,21 @@ impl<P: Pipeline> Mesh<P> {
|
||||
self.verts.push(quad.a);
|
||||
}
|
||||
|
||||
/// Overwrite a quad
|
||||
pub fn replace_quad(&mut self, index: usize, quad: Quad<P>) {
|
||||
debug_assert!(index % 3 == 0);
|
||||
assert!(index + 5 < self.verts.len());
|
||||
// Tri 1
|
||||
self.verts[index] = quad.a.clone();
|
||||
self.verts[index + 1] = quad.b;
|
||||
self.verts[index + 2] = quad.c.clone();
|
||||
|
||||
// Tri 2
|
||||
self.verts[index + 3] = quad.c;
|
||||
self.verts[index + 4] = quad.d;
|
||||
self.verts[index + 5] = quad.a;
|
||||
}
|
||||
|
||||
/// Push the vertices of another mesh onto the end of this mesh.
|
||||
pub fn push_mesh(&mut self, other: &Mesh<P>) { self.verts.extend_from_slice(other.vertices()); }
|
||||
|
||||
|
@ -31,8 +31,9 @@ pub use self::{
|
||||
sprite::{Instance as SpriteInstance, Locals as SpriteLocals, SpritePipeline},
|
||||
terrain::{Locals as TerrainLocals, TerrainPipeline},
|
||||
ui::{
|
||||
create_quad as create_ui_quad, create_tri as create_ui_tri, Locals as UiLocals,
|
||||
Mode as UiMode, UiPipeline,
|
||||
create_quad as create_ui_quad,
|
||||
create_quad_vert_gradient as create_ui_quad_vert_gradient, create_tri as create_ui_tri,
|
||||
Locals as UiLocals, Mode as UiMode, UiPipeline,
|
||||
},
|
||||
GlobalModel, Globals, Light, Shadow,
|
||||
},
|
||||
|
@ -87,24 +87,37 @@ impl Mode {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
pub fn create_quad(
|
||||
rect: Aabr<f32>,
|
||||
uv_rect: Aabr<f32>,
|
||||
color: Rgba<f32>,
|
||||
mode: Mode,
|
||||
) -> Quad<UiPipeline> {
|
||||
create_quad_vert_gradient(rect, uv_rect, color, color, mode)
|
||||
}
|
||||
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
pub fn create_quad_vert_gradient(
|
||||
rect: Aabr<f32>,
|
||||
uv_rect: Aabr<f32>,
|
||||
top_color: Rgba<f32>,
|
||||
bottom_color: Rgba<f32>,
|
||||
mode: Mode,
|
||||
) -> Quad<UiPipeline> {
|
||||
let top_color = top_color.into_array();
|
||||
let bottom_color = bottom_color.into_array();
|
||||
|
||||
let center = if let Mode::ImageSourceNorth = mode {
|
||||
uv_rect.center().into_array()
|
||||
} else {
|
||||
rect.center().into_array()
|
||||
};
|
||||
let mode_val = mode.value();
|
||||
let v = |pos, uv| Vertex {
|
||||
let v = |pos, uv, color| Vertex {
|
||||
pos,
|
||||
uv,
|
||||
center,
|
||||
color: color.into_array(),
|
||||
color,
|
||||
mode: mode_val,
|
||||
};
|
||||
let aabr_to_lbrt = |aabr: Aabr<f32>| (aabr.min.x, aabr.min.y, aabr.max.x, aabr.max.y);
|
||||
@ -114,22 +127,22 @@ pub fn create_quad(
|
||||
|
||||
match (uv_b > uv_t, uv_l > uv_r) {
|
||||
(true, true) => Quad::new(
|
||||
v([r, t], [uv_l, uv_b]),
|
||||
v([l, t], [uv_l, uv_t]),
|
||||
v([l, b], [uv_r, uv_t]),
|
||||
v([r, b], [uv_r, uv_b]),
|
||||
v([r, t], [uv_l, uv_b], top_color),
|
||||
v([l, t], [uv_l, uv_t], top_color),
|
||||
v([l, b], [uv_r, uv_t], bottom_color),
|
||||
v([r, b], [uv_r, uv_b], bottom_color),
|
||||
),
|
||||
(false, false) => Quad::new(
|
||||
v([r, t], [uv_l, uv_b]),
|
||||
v([l, t], [uv_l, uv_t]),
|
||||
v([l, b], [uv_r, uv_t]),
|
||||
v([r, b], [uv_r, uv_b]),
|
||||
v([r, t], [uv_l, uv_b], top_color),
|
||||
v([l, t], [uv_l, uv_t], top_color),
|
||||
v([l, b], [uv_r, uv_t], bottom_color),
|
||||
v([r, b], [uv_r, uv_b], bottom_color),
|
||||
),
|
||||
_ => Quad::new(
|
||||
v([r, t], [uv_r, uv_t]),
|
||||
v([l, t], [uv_l, uv_t]),
|
||||
v([l, b], [uv_l, uv_b]),
|
||||
v([r, b], [uv_r, uv_b]),
|
||||
v([r, t], [uv_r, uv_t], top_color),
|
||||
v([l, t], [uv_l, uv_t], top_color),
|
||||
v([l, b], [uv_l, uv_b], bottom_color),
|
||||
v([r, b], [uv_r, uv_b], bottom_color),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,16 @@ pub fn run(mut global_state: GlobalState, event_loop: EventLoop) {
|
||||
if let Some(event) = ui::Event::try_from(&event, global_state.window.window()) {
|
||||
global_state.window.send_event(Event::Ui(event));
|
||||
}
|
||||
// iced ui events
|
||||
// TODO: no clone
|
||||
if let winit::event::Event::WindowEvent { event, .. } = &event {
|
||||
let window = &mut global_state.window;
|
||||
if let Some(event) =
|
||||
ui::ice::window_event(event, window.scale_factor(), window.modifiers())
|
||||
{
|
||||
window.send_event(Event::IcedUi(event));
|
||||
}
|
||||
}
|
||||
|
||||
match event {
|
||||
winit::event::Event::NewEvents(_) => {
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
audio::sfx::{SfxEvent, SfxEventItem},
|
||||
ecs::MyEntity,
|
||||
hud::{DebugInfo, Event as HudEvent, Hud, HudInfo, PressBehavior},
|
||||
i18n::{i18n_asset_key, VoxygenLocalization},
|
||||
i18n::{i18n_asset_key, Localization},
|
||||
key_state::KeyState,
|
||||
menu::char_selection::CharSelectionState,
|
||||
render::Renderer,
|
||||
@ -46,7 +46,7 @@ pub struct SessionState {
|
||||
key_state: KeyState,
|
||||
inputs: comp::ControllerInputs,
|
||||
selected_block: Block,
|
||||
voxygen_i18n: std::sync::Arc<VoxygenLocalization>,
|
||||
i18n: std::sync::Arc<Localization>,
|
||||
walk_forward_dir: Vec2<f32>,
|
||||
walk_right_dir: Vec2<f32>,
|
||||
freefly_vel: Vec3<f32>,
|
||||
@ -72,7 +72,7 @@ impl SessionState {
|
||||
.camera_mut()
|
||||
.set_fov_deg(global_state.settings.graphics.fov);
|
||||
let hud = Hud::new(global_state, &client.borrow());
|
||||
let voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key(
|
||||
let i18n = Localization::load_expect(&i18n_asset_key(
|
||||
&global_state.settings.language.selected_language,
|
||||
));
|
||||
|
||||
@ -86,7 +86,7 @@ impl SessionState {
|
||||
inputs: comp::ControllerInputs::default(),
|
||||
hud,
|
||||
selected_block: Block::new(BlockKind::Misc, Rgb::broadcast(255)),
|
||||
voxygen_i18n,
|
||||
i18n,
|
||||
walk_forward_dir,
|
||||
walk_right_dir,
|
||||
freefly_vel: Vec3::zero(),
|
||||
@ -131,14 +131,14 @@ impl SessionState {
|
||||
match inv_event {
|
||||
InventoryUpdateEvent::CollectFailed => {
|
||||
self.hud.new_message(ChatMsg {
|
||||
message: self.voxygen_i18n.get("hud.chat.loot_fail").to_string(),
|
||||
message: self.i18n.get("hud.chat.loot_fail").to_string(),
|
||||
chat_type: ChatType::CommandError,
|
||||
});
|
||||
},
|
||||
InventoryUpdateEvent::Collected(item) => {
|
||||
self.hud.new_message(ChatMsg {
|
||||
message: self
|
||||
.voxygen_i18n
|
||||
.i18n
|
||||
.get("hud.chat.loot_msg")
|
||||
.replace("{item}", item.name()),
|
||||
chat_type: ChatType::Loot,
|
||||
@ -150,9 +150,9 @@ impl SessionState {
|
||||
client::Event::Disconnect => return Ok(TickAction::Disconnect),
|
||||
client::Event::DisconnectionNotification(time) => {
|
||||
let message = match time {
|
||||
0 => String::from(self.voxygen_i18n.get("hud.chat.goodbye")),
|
||||
0 => String::from(self.i18n.get("hud.chat.goodbye")),
|
||||
_ => self
|
||||
.voxygen_i18n
|
||||
.i18n
|
||||
.get("hud.chat.connection_lost")
|
||||
.replace("{time}", time.to_string().as_str()),
|
||||
};
|
||||
@ -165,7 +165,7 @@ impl SessionState {
|
||||
client::Event::Kicked(reason) => {
|
||||
global_state.info_message = Some(format!(
|
||||
"{}: {}",
|
||||
self.voxygen_i18n.get("main.login.kicked").to_string(),
|
||||
self.i18n.get("main.login.kicked").to_string(),
|
||||
reason
|
||||
));
|
||||
return Ok(TickAction::Disconnect);
|
||||
@ -207,7 +207,7 @@ impl PlayState for SessionState {
|
||||
span!(_guard, "tick", "<Session as PlayState>::tick");
|
||||
// TODO: let mut client = self.client.borrow_mut();
|
||||
// NOTE: Not strictly necessary, but useful for hotloading translation changes.
|
||||
self.voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key(
|
||||
self.i18n = Localization::load_expect(&i18n_asset_key(
|
||||
&global_state.settings.language.selected_language,
|
||||
));
|
||||
|
||||
@ -673,7 +673,7 @@ impl PlayState for SessionState {
|
||||
Ok(TickAction::Disconnect) => return PlayStateResult::Pop, // Go to main menu
|
||||
Err(err) => {
|
||||
global_state.info_message =
|
||||
Some(self.voxygen_i18n.get("common.connection_lost").to_owned());
|
||||
Some(self.i18n.get("common.connection_lost").to_owned());
|
||||
error!("[session] Failed to tick the scene: {:?}", err);
|
||||
|
||||
return PlayStateResult::Pop;
|
||||
@ -752,7 +752,7 @@ impl PlayState for SessionState {
|
||||
// Look for changes in the localization files
|
||||
if global_state.localization_watcher.reloaded() {
|
||||
hud_events.push(HudEvent::ChangeLanguage(Box::new(
|
||||
self.voxygen_i18n.metadata.clone(),
|
||||
self.i18n.metadata.clone(),
|
||||
)));
|
||||
}
|
||||
|
||||
@ -980,13 +980,13 @@ impl PlayState for SessionState {
|
||||
HudEvent::ChangeLanguage(new_language) => {
|
||||
global_state.settings.language.selected_language =
|
||||
new_language.language_identifier;
|
||||
self.voxygen_i18n = VoxygenLocalization::load_watched(
|
||||
self.i18n = Localization::load_watched(
|
||||
&i18n_asset_key(&global_state.settings.language.selected_language),
|
||||
&mut global_state.localization_watcher,
|
||||
)
|
||||
.unwrap();
|
||||
self.voxygen_i18n.log_missing_entries();
|
||||
self.hud.update_language(Arc::clone(&self.voxygen_i18n));
|
||||
self.i18n.log_missing_entries();
|
||||
self.hud.update_language(Arc::clone(&self.i18n));
|
||||
},
|
||||
HudEvent::ChangeFullscreenMode(new_fullscreen_settings) => {
|
||||
global_state
|
||||
|
@ -558,16 +558,16 @@ impl Default for GameplaySettings {
|
||||
pub struct NetworkingSettings {
|
||||
pub username: String,
|
||||
pub servers: Vec<String>,
|
||||
pub default_server: usize,
|
||||
pub default_server: String,
|
||||
pub trusted_auth_servers: HashSet<String>,
|
||||
}
|
||||
|
||||
impl Default for NetworkingSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
username: "Username".to_string(),
|
||||
username: "".to_string(),
|
||||
servers: vec!["server.veloren.net".to_string()],
|
||||
default_server: 0,
|
||||
default_server: "server.veloren.net".to_string(),
|
||||
trusted_auth_servers: ["https://auth.veloren.net"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
|
@ -6,7 +6,7 @@ pub struct Event(pub Input);
|
||||
impl Event {
|
||||
pub fn try_from(
|
||||
event: &winit::event::Event<()>,
|
||||
window: &glutin::ContextWrapper<glutin::PossiblyCurrent, winit::window::Window>,
|
||||
window: &winit::window::Window,
|
||||
) -> Option<Self> {
|
||||
use conrod_winit::*;
|
||||
// A wrapper around the winit window that allows us to implement the trait
|
||||
@ -26,7 +26,7 @@ impl Event {
|
||||
|
||||
fn hidpi_factor(&self) -> f64 { winit::window::Window::scale_factor(&self.0) }
|
||||
}
|
||||
convert_event!(event, &WindowRef(window.window())).map(Self)
|
||||
convert_event!(event, &WindowRef(window)).map(Self)
|
||||
}
|
||||
|
||||
pub fn is_keyboard_or_mouse(&self) -> bool {
|
||||
|
@ -1,18 +1,18 @@
|
||||
use crate::i18n::{Font, VoxygenFonts};
|
||||
use crate::i18n;
|
||||
use common::assets::Asset;
|
||||
|
||||
pub struct ConrodVoxygenFont {
|
||||
metadata: Font,
|
||||
pub struct Font {
|
||||
metadata: i18n::Font,
|
||||
pub conrod_id: conrod_core::text::font::Id,
|
||||
}
|
||||
|
||||
impl ConrodVoxygenFont {
|
||||
impl Font {
|
||||
#[allow(clippy::needless_return)] // TODO: Pending review in #587
|
||||
pub fn new(font: &Font, ui: &mut crate::ui::Ui) -> ConrodVoxygenFont {
|
||||
return Self {
|
||||
pub fn new(font: &i18n::Font, ui: &mut crate::ui::Ui) -> Self {
|
||||
Self {
|
||||
metadata: font.clone(),
|
||||
conrod_id: ui.new_font(crate::ui::Font::load_expect(&font.asset_key)),
|
||||
};
|
||||
conrod_id: ui.new_font(crate::ui::ice::RawFont::load_expect(&font.asset_key)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Scale input size to final UI size
|
||||
@ -22,14 +22,14 @@ impl ConrodVoxygenFont {
|
||||
macro_rules! conrod_fonts {
|
||||
($([ $( $name:ident$(,)? )* ])*) => {
|
||||
$(
|
||||
pub struct ConrodVoxygenFonts {
|
||||
$(pub $name: ConrodVoxygenFont,)*
|
||||
pub struct Fonts {
|
||||
$(pub $name: Font,)*
|
||||
}
|
||||
|
||||
impl ConrodVoxygenFonts {
|
||||
pub fn load(voxygen_fonts: &VoxygenFonts, ui: &mut crate::ui::Ui) -> Result<Self, common::assets::Error> {
|
||||
impl Fonts {
|
||||
pub fn load(fonts: &i18n::Fonts, ui: &mut crate::ui::Ui) -> Result<Self, common::assets::Error> {
|
||||
Ok(Self {
|
||||
$( $name: ConrodVoxygenFont::new(voxygen_fonts.get(stringify!($name)).unwrap(), ui),)*
|
||||
$( $name: Font::new(fonts.get(stringify!($name)).unwrap(), ui),)*
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -40,3 +40,43 @@ macro_rules! conrod_fonts {
|
||||
conrod_fonts! {
|
||||
[opensans, metamorph, alkhemi, cyri, wizard]
|
||||
}
|
||||
|
||||
pub struct IcedFont {
|
||||
metadata: i18n::Font,
|
||||
pub id: crate::ui::ice::FontId,
|
||||
}
|
||||
|
||||
impl IcedFont {
|
||||
pub fn new(font: &i18n::Font, ui: &mut crate::ui::ice::IcedUi) -> Self {
|
||||
Self {
|
||||
metadata: font.clone(),
|
||||
id: ui.add_font((*crate::ui::ice::RawFont::load_expect(&font.asset_key)).clone()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Scale input size to final UI size
|
||||
/// TODO: change metadata to use u16
|
||||
pub fn scale(&self, value: u16) -> u16 { self.metadata.scale(value as u32) as u16 }
|
||||
}
|
||||
|
||||
macro_rules! iced_fonts {
|
||||
($([ $( $name:ident$(,)? )* ])*) => {
|
||||
$(
|
||||
pub struct IcedFonts {
|
||||
$(pub $name: IcedFont,)*
|
||||
}
|
||||
|
||||
impl IcedFonts {
|
||||
pub fn load(fonts: &i18n::Fonts, ui: &mut crate::ui::ice::IcedUi) -> Result<Self, common::assets::Error> {
|
||||
Ok(Self {
|
||||
$( $name: IcedFont::new(fonts.get(stringify!($name)).unwrap(), ui),)*
|
||||
})
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
iced_fonts! {
|
||||
[opensans, metamorph, alkhemi, cyri, wizard]
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ pub enum Graphic {
|
||||
Blank,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Rotation {
|
||||
None,
|
||||
Cw90,
|
||||
@ -58,6 +58,7 @@ pub struct Id(u32);
|
||||
pub struct TexId(usize);
|
||||
|
||||
type Parameters = (Id, Vec2<u16>);
|
||||
// TODO replace with slab/slotmap
|
||||
type GraphicMap = HashMap<Id, Graphic>;
|
||||
|
||||
enum CachedDetails {
|
||||
@ -187,6 +188,27 @@ impl GraphicCache {
|
||||
self.textures.get(id.0).expect("Invalid TexId used")
|
||||
}
|
||||
|
||||
pub fn get_graphic_dims(&self, (id, rot): (Id, Rotation)) -> Option<(u32, u32)> {
|
||||
use image::GenericImageView;
|
||||
self.get_graphic(id)
|
||||
.and_then(|graphic| match graphic {
|
||||
Graphic::Image(image, _) => Some(image.dimensions()),
|
||||
Graphic::Voxel(segment, _, _) => {
|
||||
use common::vol::SizedVol;
|
||||
let size = segment.size();
|
||||
// TODO: HACK because they can be rotated arbitrarily, remove
|
||||
Some((size.x, size.z))
|
||||
},
|
||||
Graphic::Blank => None,
|
||||
})
|
||||
.and_then(|(w, h)| match rot {
|
||||
Rotation::None | Rotation::Cw180 => Some((w, h)),
|
||||
Rotation::Cw90 | Rotation::Cw270 => Some((h, w)),
|
||||
// TODO: need dims for these?
|
||||
Rotation::SourceNorth | Rotation::TargetNorth => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn clear_cache(&mut self, renderer: &mut Renderer) {
|
||||
self.cache_map.clear();
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
use common::util::{linear_to_srgba, srgba_to_linear};
|
||||
use common::{
|
||||
span,
|
||||
util::{linear_to_srgba, srgba_to_linear},
|
||||
};
|
||||
/// Pixel art scaling
|
||||
/// Note: The current ui is locked to the pixel grid with little animation, if
|
||||
/// we want smoothly moving pixel art this should be done in the shaders
|
||||
@ -35,6 +38,7 @@ const EPSILON: f32 = 0.0001;
|
||||
// E9: c3 = (A1 * c1 * a1 + A2 * c2 * a2) / a3
|
||||
#[allow(clippy::manual_saturating_arithmetic)] // TODO: Pending review in #587
|
||||
pub fn resize_pixel_art(image: &RgbaImage, new_width: u32, new_height: u32) -> RgbaImage {
|
||||
span!(_guard, "resize_pixel_art");
|
||||
let (width, height) = image.dimensions();
|
||||
let mut new_image = RgbaImage::new(new_width, new_height);
|
||||
|
||||
|
121
voxygen/src/ui/ice/cache.rs
Normal file
121
voxygen/src/ui/ice/cache.rs
Normal file
@ -0,0 +1,121 @@
|
||||
use super::graphic::{Graphic, GraphicCache, Id as GraphicId};
|
||||
use crate::{
|
||||
render::{Renderer, Texture},
|
||||
Error,
|
||||
};
|
||||
use glyph_brush::GlyphBrushBuilder;
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use vek::*;
|
||||
|
||||
// Multiplied by current window size
|
||||
const GLYPH_CACHE_SIZE: u16 = 1;
|
||||
// Glyph cache tolerances
|
||||
// TODO: consider scaling based on dpi as well as providing as an option to the
|
||||
// user
|
||||
const SCALE_TOLERANCE: f32 = 0.5;
|
||||
const POSITION_TOLERANCE: f32 = 0.5;
|
||||
|
||||
type GlyphBrush = glyph_brush::GlyphBrush<(Aabr<f32>, Aabr<f32>), ()>;
|
||||
|
||||
// TODO: might not need pub
|
||||
pub type Font = glyph_brush::ab_glyph::FontArc;
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub struct FontId(pub(super) glyph_brush::FontId);
|
||||
|
||||
pub struct Cache {
|
||||
glyph_brush: RefCell<GlyphBrush>,
|
||||
glyph_cache_tex: Texture,
|
||||
graphic_cache: GraphicCache,
|
||||
}
|
||||
|
||||
// TODO: Should functions be returning UiError instead of Error?
|
||||
impl Cache {
|
||||
pub fn new(renderer: &mut Renderer, default_font: Font) -> Result<Self, Error> {
|
||||
let (w, h) = renderer.get_resolution().into_tuple();
|
||||
|
||||
let max_texture_size = renderer.max_texture_size();
|
||||
|
||||
let glyph_cache_dims =
|
||||
Vec2::new(w, h).map(|e| (e * GLYPH_CACHE_SIZE).min(max_texture_size as u16).max(512));
|
||||
|
||||
let glyph_brush = GlyphBrushBuilder::using_font(default_font)
|
||||
.initial_cache_size((glyph_cache_dims.x as u32, glyph_cache_dims.y as u32))
|
||||
.draw_cache_scale_tolerance(SCALE_TOLERANCE)
|
||||
.draw_cache_position_tolerance(POSITION_TOLERANCE)
|
||||
.build();
|
||||
|
||||
Ok(Self {
|
||||
glyph_brush: RefCell::new(glyph_brush),
|
||||
glyph_cache_tex: renderer.create_dynamic_texture(glyph_cache_dims.map(|e| e as u16))?,
|
||||
graphic_cache: GraphicCache::new(renderer),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn glyph_cache_tex(&self) -> &Texture { &self.glyph_cache_tex }
|
||||
|
||||
pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphBrush, &Texture) {
|
||||
(self.glyph_brush.get_mut(), &self.glyph_cache_tex)
|
||||
}
|
||||
|
||||
pub fn glyph_cache_mut(&mut self) -> &mut GlyphBrush { self.glyph_brush.get_mut() }
|
||||
|
||||
pub fn glyph_calculator(&self) -> RefMut<GlyphBrush> { self.glyph_brush.borrow_mut() }
|
||||
|
||||
// TODO: consider not re-adding default font
|
||||
pub fn add_font(&mut self, font: RawFont) -> FontId {
|
||||
let font = Font::try_from_vec(font.0).unwrap();
|
||||
let id = self.glyph_brush.get_mut().add_font(font);
|
||||
FontId(id)
|
||||
}
|
||||
|
||||
pub fn graphic_cache(&self) -> &GraphicCache { &self.graphic_cache }
|
||||
|
||||
pub fn graphic_cache_mut(&mut self) -> &mut GraphicCache { &mut self.graphic_cache }
|
||||
|
||||
pub fn add_graphic(&mut self, graphic: Graphic) -> GraphicId {
|
||||
self.graphic_cache.add_graphic(graphic)
|
||||
}
|
||||
|
||||
pub fn replace_graphic(&mut self, id: GraphicId, graphic: Graphic) {
|
||||
self.graphic_cache.replace_graphic(id, graphic)
|
||||
}
|
||||
|
||||
// Resizes and clears the GraphicCache
|
||||
pub fn resize_graphic_cache(&mut self, renderer: &mut Renderer) {
|
||||
self.graphic_cache.clear_cache(renderer);
|
||||
}
|
||||
|
||||
// Resizes and clears the GlyphCache
|
||||
pub fn resize_glyph_cache(&mut self, renderer: &mut Renderer) -> Result<(), Error> {
|
||||
let max_texture_size = renderer.max_texture_size();
|
||||
let cache_dims = renderer
|
||||
.get_resolution()
|
||||
.map(|e| (e * GLYPH_CACHE_SIZE).min(max_texture_size as u16).max(512));
|
||||
let glyph_brush = self.glyph_brush.get_mut();
|
||||
*glyph_brush = glyph_brush
|
||||
.to_builder()
|
||||
.initial_cache_size((cache_dims.x as u32, cache_dims.y as u32))
|
||||
.build();
|
||||
|
||||
self.glyph_cache_tex = renderer.create_dynamic_texture(cache_dims.map(|e| e as u16))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: use font type instead of raw vec once we convert to full iced
|
||||
#[derive(Clone)]
|
||||
pub struct RawFont(pub Vec<u8>);
|
||||
impl common::assets::Asset for RawFont {
|
||||
const ENDINGS: &'static [&'static str] = &["ttf"];
|
||||
|
||||
fn parse(
|
||||
mut buf_reader: std::io::BufReader<std::fs::File>,
|
||||
_specifier: &str,
|
||||
) -> Result<Self, common::assets::Error> {
|
||||
use std::io::Read;
|
||||
let mut buf = Vec::new();
|
||||
buf_reader.read_to_end(&mut buf)?;
|
||||
Ok(Self(buf))
|
||||
}
|
||||
}
|
6
voxygen/src/ui/ice/component/mod.rs
Normal file
6
voxygen/src/ui/ice/component/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
/// Various composable helpers for making iced ui's
|
||||
pub mod neat_button;
|
||||
pub mod tooltip;
|
||||
|
||||
pub use neat_button::neat_button;
|
||||
//pub use tooltip::WithTooltip;
|
32
voxygen/src/ui/ice/component/neat_button.rs
Normal file
32
voxygen/src/ui/ice/component/neat_button.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use crate::ui::ice as ui;
|
||||
use iced::{button::State, Button, Element, Length};
|
||||
use ui::{
|
||||
style::button::Style,
|
||||
widget::{AspectRatioContainer, FillText},
|
||||
};
|
||||
|
||||
pub fn neat_button<M: Clone + 'static>(
|
||||
state: &mut State,
|
||||
label: impl Into<String>,
|
||||
fill_fraction: f32,
|
||||
button_style: Style,
|
||||
message: Option<M>,
|
||||
) -> Element<M, ui::IcedRenderer> {
|
||||
let button = Button::new(state, FillText::new(label).fill_fraction(fill_fraction))
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fill)
|
||||
.style(button_style);
|
||||
|
||||
let button = match message {
|
||||
Some(message) => button.on_press(message),
|
||||
None => button,
|
||||
};
|
||||
|
||||
let container = AspectRatioContainer::new(button);
|
||||
let container = match button_style.active().0 {
|
||||
Some((img, _)) => container.ratio_of_image(img),
|
||||
None => container,
|
||||
};
|
||||
|
||||
container.into()
|
||||
}
|
44
voxygen/src/ui/ice/component/tooltip.rs
Normal file
44
voxygen/src/ui/ice/component/tooltip.rs
Normal file
@ -0,0 +1,44 @@
|
||||
use crate::ui::ice as ui;
|
||||
use iced::{Container, Element, Text};
|
||||
use ui::{
|
||||
style,
|
||||
widget::{Tooltip, TooltipManager},
|
||||
};
|
||||
|
||||
// :( all tooltips have to copy because this is needed outside the function
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Style {
|
||||
pub container: style::container::Style,
|
||||
pub text_color: iced::Color,
|
||||
pub text_size: u16,
|
||||
pub padding: u16,
|
||||
}
|
||||
|
||||
/// Tooltip that is just text
|
||||
pub fn text<'a, M: 'a>(text: &'a str, style: Style) -> Element<'a, M, ui::IcedRenderer> {
|
||||
Container::new(
|
||||
Text::new(text)
|
||||
.color(style.text_color)
|
||||
.size(style.text_size),
|
||||
)
|
||||
.style(style.container)
|
||||
.padding(style.padding)
|
||||
.into()
|
||||
}
|
||||
|
||||
pub trait WithTooltip<'a, M, R: ui::widget::tooltip::Renderer> {
|
||||
fn with_tooltip<H>(self, manager: &'a TooltipManager, hover_content: H) -> Tooltip<'a, M, R>
|
||||
where
|
||||
H: 'a + FnMut() -> Element<'a, M, R>;
|
||||
}
|
||||
|
||||
impl<'a, M, R: ui::widget::tooltip::Renderer, E: Into<Element<'a, M, R>>> WithTooltip<'a, M, R>
|
||||
for E
|
||||
{
|
||||
fn with_tooltip<H>(self, manager: &'a TooltipManager, hover_content: H) -> Tooltip<'a, M, R>
|
||||
where
|
||||
H: 'a + FnMut() -> Element<'a, M, R>,
|
||||
{
|
||||
Tooltip::new(self, hover_content, manager)
|
||||
}
|
||||
}
|
209
voxygen/src/ui/ice/mod.rs
Normal file
209
voxygen/src/ui/ice/mod.rs
Normal file
@ -0,0 +1,209 @@
|
||||
// tooltip_manager: TooltipManager,
|
||||
mod cache;
|
||||
pub mod component;
|
||||
mod renderer;
|
||||
pub mod widget;
|
||||
|
||||
pub use cache::{Font, FontId, RawFont};
|
||||
pub use graphic::{Id, Rotation};
|
||||
pub use iced::Event;
|
||||
pub use iced_winit::conversion::window_event;
|
||||
pub use renderer::{style, IcedRenderer};
|
||||
|
||||
use super::{
|
||||
graphic::{self, Graphic},
|
||||
scale::{Scale, ScaleMode},
|
||||
};
|
||||
use crate::{render::Renderer, window::Window, Error};
|
||||
use common::span;
|
||||
use iced::{mouse, Cache, Size, UserInterface};
|
||||
use iced_winit::Clipboard;
|
||||
use vek::*;
|
||||
|
||||
pub type Element<'a, M> = iced::Element<'a, M, IcedRenderer>;
|
||||
|
||||
pub struct IcedUi {
|
||||
renderer: IcedRenderer,
|
||||
cache: Option<Cache>,
|
||||
events: Vec<Event>,
|
||||
clipboard: Clipboard,
|
||||
cursor_position: Vec2<f32>,
|
||||
// Scaling of the ui
|
||||
scale: Scale,
|
||||
window_resized: Option<Vec2<u32>>,
|
||||
scale_mode_changed: bool,
|
||||
}
|
||||
impl IcedUi {
|
||||
pub fn new(
|
||||
window: &mut Window,
|
||||
default_font: Font,
|
||||
scale_mode: ScaleMode,
|
||||
) -> Result<Self, Error> {
|
||||
let scale = Scale::new(window, scale_mode, 1.2);
|
||||
let renderer = window.renderer_mut();
|
||||
|
||||
let scaled_dims = scale.scaled_window_size().map(|e| e as f32);
|
||||
|
||||
// TODO: examine how much mem fonts take up and reduce clones if significant
|
||||
Ok(Self {
|
||||
renderer: IcedRenderer::new(renderer, scaled_dims, default_font)?,
|
||||
cache: Some(Cache::new()),
|
||||
events: Vec::new(),
|
||||
// TODO: handle None
|
||||
clipboard: Clipboard::new(window.window()).unwrap(),
|
||||
cursor_position: Vec2::zero(),
|
||||
scale,
|
||||
window_resized: None,
|
||||
scale_mode_changed: false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Add a new font that is referncable via the returned Id
|
||||
pub fn add_font(&mut self, font: RawFont) -> FontId { self.renderer.add_font(font) }
|
||||
|
||||
/// Add a new graphic that is referencable via the returned Id
|
||||
pub fn add_graphic(&mut self, graphic: Graphic) -> graphic::Id {
|
||||
self.renderer.add_graphic(graphic)
|
||||
}
|
||||
|
||||
pub fn replace_graphic(&mut self, id: graphic::Id, graphic: Graphic) {
|
||||
self.renderer.replace_graphic(id, graphic);
|
||||
}
|
||||
|
||||
pub fn scale(&self) -> Scale { self.scale }
|
||||
|
||||
pub fn set_scaling_mode(&mut self, mode: ScaleMode) {
|
||||
self.scale.set_scaling_mode(mode);
|
||||
// Signal that change needs to be handled
|
||||
self.scale_mode_changed = true;
|
||||
}
|
||||
|
||||
pub fn handle_event(&mut self, event: Event) {
|
||||
use iced::window;
|
||||
match event {
|
||||
// Intercept resizing events
|
||||
// TODO: examine if we are handling dpi properly here
|
||||
// ideally these values should be the logical ones
|
||||
Event::Window(window::Event::Resized { width, height }) => {
|
||||
if width != 0 && height != 0 {
|
||||
self.window_resized = Some(Vec2::new(width, height));
|
||||
}
|
||||
},
|
||||
// Scale cursor movement events
|
||||
// Note: in some cases the scaling could be off if a resized event occured in the same
|
||||
// frame, in practice this shouldn't be an issue
|
||||
Event::Mouse(mouse::Event::CursorMoved { x, y }) => {
|
||||
// TODO: return f32 here
|
||||
let scale = self.scale.scale_factor_logical() as f32;
|
||||
// TODO: determine why iced moved cursor position out of the `Cache` and if we
|
||||
// may need to handle this in a different way to address
|
||||
// whatever issue iced was trying to address
|
||||
self.cursor_position = Vec2 {
|
||||
x: x / scale,
|
||||
y: y / scale,
|
||||
};
|
||||
self.events.push(Event::Mouse(mouse::Event::CursorMoved {
|
||||
x: x / scale,
|
||||
y: y / scale,
|
||||
}));
|
||||
},
|
||||
// Scale pixel scrolling events
|
||||
Event::Mouse(mouse::Event::WheelScrolled {
|
||||
delta: mouse::ScrollDelta::Pixels { x, y },
|
||||
}) => {
|
||||
// TODO: return f32 here
|
||||
let scale = self.scale.scale_factor_logical() as f32;
|
||||
self.events.push(Event::Mouse(mouse::Event::WheelScrolled {
|
||||
delta: mouse::ScrollDelta::Pixels {
|
||||
x: x / scale,
|
||||
y: y / scale,
|
||||
},
|
||||
}));
|
||||
},
|
||||
event => self.events.push(event),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: produce root internally???
|
||||
// TODO: closure/trait for sending messages back? (take a look at higher level
|
||||
// iced libs)
|
||||
pub fn maintain<'a, M, E: Into<Element<'a, M>>>(
|
||||
&mut self,
|
||||
root: E,
|
||||
renderer: &mut Renderer,
|
||||
) -> (Vec<M>, mouse::Interaction) {
|
||||
span!(_guard, "maintain", "IcedUi::maintain");
|
||||
// Handle window resizing and scale mode changing
|
||||
let scaled_dims = if let Some(new_dims) = self.window_resized.take() {
|
||||
let old_scaled_dims = self.scale.scaled_window_size();
|
||||
// TODO maybe use u32 in Scale to be consistent with iced
|
||||
self.scale
|
||||
.window_resized(new_dims.map(|e| e as f64), renderer);
|
||||
let scaled_dims = self.scale.scaled_window_size();
|
||||
|
||||
// Avoid resetting cache if window size didn't change
|
||||
(scaled_dims != old_scaled_dims).then_some(scaled_dims)
|
||||
} else if self.scale_mode_changed {
|
||||
Some(self.scale.scaled_window_size())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(scaled_dims) = scaled_dims {
|
||||
self.scale_mode_changed = false;
|
||||
self.events
|
||||
.push(Event::Window(iced::window::Event::Resized {
|
||||
width: scaled_dims.x as u32,
|
||||
height: scaled_dims.y as u32,
|
||||
}));
|
||||
// Avoid panic in graphic cache when minimizing.
|
||||
// Somewhat inefficient for elements that won't change size after a window
|
||||
// resize
|
||||
let res = renderer.get_resolution();
|
||||
if res.x > 0 && res.y > 0 {
|
||||
self.renderer
|
||||
.resize(scaled_dims.map(|e| e as f32), renderer);
|
||||
}
|
||||
}
|
||||
|
||||
let cursor_position = iced::Point {
|
||||
x: self.cursor_position.x,
|
||||
y: self.cursor_position.y,
|
||||
};
|
||||
|
||||
// TODO: convert to f32 at source
|
||||
let window_size = self.scale.scaled_window_size().map(|e| e as f32);
|
||||
|
||||
span!(guard, "build user_interface");
|
||||
let mut user_interface = UserInterface::build(
|
||||
root,
|
||||
Size::new(window_size.x, window_size.y),
|
||||
self.cache.take().unwrap(),
|
||||
&mut self.renderer,
|
||||
);
|
||||
drop(guard);
|
||||
|
||||
span!(guard, "update user_interface");
|
||||
let messages = user_interface.update(
|
||||
&self.events,
|
||||
cursor_position,
|
||||
Some(&self.clipboard),
|
||||
&self.renderer,
|
||||
);
|
||||
drop(guard);
|
||||
// Clear events
|
||||
self.events.clear();
|
||||
|
||||
span!(guard, "draw user_interface");
|
||||
let (primitive, mouse_interaction) =
|
||||
user_interface.draw(&mut self.renderer, cursor_position);
|
||||
drop(guard);
|
||||
|
||||
self.cache = Some(user_interface.into_cache());
|
||||
|
||||
self.renderer.draw(primitive, renderer);
|
||||
|
||||
(messages, mouse_interaction)
|
||||
}
|
||||
|
||||
pub fn render(&self, renderer: &mut Renderer) { self.renderer.render(renderer, None); }
|
||||
}
|
12
voxygen/src/ui/ice/renderer/defaults.rs
Normal file
12
voxygen/src/ui/ice/renderer/defaults.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// TODO: expose to user
|
||||
pub struct Defaults {
|
||||
pub text_color: iced::Color,
|
||||
}
|
||||
|
||||
impl Default for Defaults {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
text_color: iced::Color::WHITE,
|
||||
}
|
||||
}
|
||||
}
|
858
voxygen/src/ui/ice/renderer/mod.rs
Normal file
858
voxygen/src/ui/ice/renderer/mod.rs
Normal file
@ -0,0 +1,858 @@
|
||||
mod defaults;
|
||||
mod primitive;
|
||||
pub mod style;
|
||||
mod widget;
|
||||
|
||||
pub use defaults::Defaults;
|
||||
|
||||
pub(self) use primitive::Primitive;
|
||||
|
||||
use super::{
|
||||
super::graphic::{self, Graphic, TexId},
|
||||
cache::Cache,
|
||||
widget::image,
|
||||
Font, FontId, RawFont, Rotation,
|
||||
};
|
||||
use crate::{
|
||||
render::{
|
||||
create_ui_quad, create_ui_quad_vert_gradient, Consts, DynamicModel, Globals, Mesh,
|
||||
Renderer, UiLocals, UiMode, UiPipeline,
|
||||
},
|
||||
Error,
|
||||
};
|
||||
use common::{span, util::srgba_to_linear};
|
||||
use std::{convert::TryInto, ops::Range};
|
||||
use vek::*;
|
||||
|
||||
enum DrawKind {
|
||||
Image(TexId),
|
||||
// Text and non-textured geometry
|
||||
Plain,
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // TODO: remove once WorldPos is used
|
||||
enum DrawCommand {
|
||||
Draw { kind: DrawKind, verts: Range<u32> },
|
||||
Scissor(Aabr<u16>),
|
||||
WorldPos(Option<usize>),
|
||||
}
|
||||
impl DrawCommand {
|
||||
fn image(verts: Range<usize>, id: TexId) -> DrawCommand {
|
||||
DrawCommand::Draw {
|
||||
kind: DrawKind::Image(id),
|
||||
// TODO: move conversion into helper method so we don't have to write it out so many
|
||||
// times
|
||||
verts: verts
|
||||
.start
|
||||
.try_into()
|
||||
.expect("Vertex count for UI rendering does not fit in a u32!")
|
||||
..verts
|
||||
.end
|
||||
.try_into()
|
||||
.expect("Vertex count for UI rendering does not fit in a u32!"),
|
||||
}
|
||||
}
|
||||
|
||||
fn plain(verts: Range<usize>) -> DrawCommand {
|
||||
DrawCommand::Draw {
|
||||
kind: DrawKind::Plain,
|
||||
verts: verts
|
||||
.start
|
||||
.try_into()
|
||||
.expect("Vertex count for UI rendering does not fit in a u32!")
|
||||
..verts
|
||||
.end
|
||||
.try_into()
|
||||
.expect("Vertex count for UI rendering does not fit in a u32!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum State {
|
||||
Image(TexId),
|
||||
Plain,
|
||||
}
|
||||
|
||||
// Optimization idea inspired by what I think iced wgpu renderer may be doing:
|
||||
// Could have layers of things which don't intersect and thus can be reordered
|
||||
// arbitrarily
|
||||
|
||||
pub struct IcedRenderer {
|
||||
//image_map: Map<(Image, Rotation)>,
|
||||
cache: Cache,
|
||||
// Model for drawing the ui
|
||||
model: DynamicModel<UiPipeline>,
|
||||
// Consts to specify positions of ingame elements (e.g. Nametags)
|
||||
ingame_locals: Vec<Consts<UiLocals>>,
|
||||
// Consts for default ui drawing position (ie the interface)
|
||||
interface_locals: Consts<UiLocals>,
|
||||
default_globals: Consts<Globals>,
|
||||
|
||||
// Used to delay cache resizing until after current frame is drawn
|
||||
//need_cache_resize: bool,
|
||||
// Half of physical resolution
|
||||
half_res: Vec2<f32>,
|
||||
// Pixel perfection alignment
|
||||
align: Vec2<f32>,
|
||||
// Scale factor between physical and win dims
|
||||
p_scale: f32,
|
||||
// Pretend dims :) (i.e. scaled)
|
||||
win_dims: Vec2<f32>,
|
||||
// Scissor for the whole window
|
||||
window_scissor: Aabr<u16>,
|
||||
|
||||
// Per-frame/update
|
||||
current_state: State,
|
||||
mesh: Mesh<UiPipeline>,
|
||||
glyphs: Vec<(usize, usize, Rgba<f32>, Vec2<u32>)>,
|
||||
// Output from glyph_brush in the previous frame
|
||||
// It can sometimes ask you to redraw with these instead (idk if that is done with
|
||||
// pre-positioned glyphs)
|
||||
last_glyph_verts: Vec<(Aabr<f32>, Aabr<f32>)>,
|
||||
start: usize,
|
||||
// Draw commands for the next render
|
||||
draw_commands: Vec<DrawCommand>,
|
||||
}
|
||||
impl IcedRenderer {
|
||||
pub fn new(
|
||||
renderer: &mut Renderer,
|
||||
scaled_dims: Vec2<f32>,
|
||||
default_font: Font,
|
||||
) -> Result<Self, Error> {
|
||||
let (half_res, align, p_scale) =
|
||||
Self::calculate_resolution_dependents(renderer.get_resolution(), scaled_dims);
|
||||
|
||||
Ok(Self {
|
||||
cache: Cache::new(renderer, default_font)?,
|
||||
draw_commands: Vec::new(),
|
||||
model: renderer.create_dynamic_model(100)?,
|
||||
interface_locals: renderer.create_consts(&[UiLocals::default()])?,
|
||||
default_globals: renderer.create_consts(&[Globals::default()])?,
|
||||
ingame_locals: Vec::new(),
|
||||
mesh: Mesh::new(),
|
||||
glyphs: Vec::new(),
|
||||
last_glyph_verts: Vec::new(),
|
||||
current_state: State::Plain,
|
||||
half_res,
|
||||
align,
|
||||
p_scale,
|
||||
win_dims: scaled_dims,
|
||||
window_scissor: default_scissor(renderer),
|
||||
start: 0,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_font(&mut self, font: RawFont) -> FontId { self.cache.add_font(font) }
|
||||
|
||||
pub fn add_graphic(&mut self, graphic: Graphic) -> graphic::Id {
|
||||
self.cache.add_graphic(graphic)
|
||||
}
|
||||
|
||||
pub fn replace_graphic(&mut self, id: graphic::Id, graphic: Graphic) {
|
||||
self.cache.replace_graphic(id, graphic);
|
||||
}
|
||||
|
||||
fn image_dims(&self, handle: image::Handle) -> (u32, u32) {
|
||||
self
|
||||
.cache
|
||||
.graphic_cache()
|
||||
.get_graphic_dims((handle, Rotation::None))
|
||||
// TODO: don't unwrap
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, scaled_dims: Vec2<f32>, renderer: &mut Renderer) {
|
||||
self.win_dims = scaled_dims;
|
||||
self.window_scissor = default_scissor(renderer);
|
||||
|
||||
self.update_resolution_dependents(renderer.get_resolution());
|
||||
|
||||
// Resize graphic cache
|
||||
self.cache.resize_graphic_cache(renderer);
|
||||
// Resize glyph cache
|
||||
self.cache.resize_glyph_cache(renderer).unwrap();
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, primitive: Primitive, renderer: &mut Renderer) {
|
||||
span!(_guard, "draw", "IcedRenderer::draw");
|
||||
// Re-use memory
|
||||
self.draw_commands.clear();
|
||||
self.mesh.clear();
|
||||
self.glyphs.clear();
|
||||
|
||||
self.current_state = State::Plain;
|
||||
self.start = 0;
|
||||
|
||||
self.draw_primitive(primitive, Vec2::zero(), 1.0, renderer);
|
||||
|
||||
// Enter the final command.
|
||||
self.draw_commands.push(match self.current_state {
|
||||
State::Plain => DrawCommand::plain(self.start..self.mesh.vertices().len()),
|
||||
State::Image(id) => DrawCommand::image(self.start..self.mesh.vertices().len(), id),
|
||||
});
|
||||
|
||||
// Draw glyph cache (use for debugging).
|
||||
/*self.draw_commands
|
||||
.push(DrawCommand::Scissor(default_scissor(renderer)));
|
||||
self.start = self.mesh.vertices().len();
|
||||
self.mesh.push_quad(create_ui_quad(
|
||||
Aabr {
|
||||
min: (-1.0, -1.0).into(),
|
||||
max: (1.0, 1.0).into(),
|
||||
},
|
||||
Aabr {
|
||||
min: (0.0, 1.0).into(),
|
||||
max: (1.0, 0.0).into(),
|
||||
},
|
||||
Rgba::new(1.0, 1.0, 1.0, 0.3),
|
||||
UiMode::Text,
|
||||
));
|
||||
self.draw_commands
|
||||
.push(DrawCommand::plain(self.start..self.mesh.vertices().len()));*/
|
||||
|
||||
// Fill in placeholder glyph quads
|
||||
let (glyph_cache, cache_tex) = self.cache.glyph_cache_mut_and_tex();
|
||||
let half_res = self.half_res;
|
||||
|
||||
let brush_result = glyph_cache.process_queued(
|
||||
|rect, tex_data| {
|
||||
let offset = [rect.min[0] as u16, rect.min[1] as u16];
|
||||
let size = [rect.width() as u16, rect.height() as u16];
|
||||
|
||||
let new_data = tex_data
|
||||
.iter()
|
||||
.map(|x| [255, 255, 255, *x])
|
||||
.collect::<Vec<[u8; 4]>>();
|
||||
|
||||
if let Err(err) = renderer.update_texture(cache_tex, offset, size, &new_data) {
|
||||
tracing::warn!("Failed to update glyph cache texture: {:?}", err);
|
||||
}
|
||||
},
|
||||
// Urgh more allocation we don't need
|
||||
|vertex_data| {
|
||||
let uv_rect = vertex_data.tex_coords;
|
||||
let uv = Aabr {
|
||||
min: Vec2::new(uv_rect.min.x, uv_rect.max.y),
|
||||
max: Vec2::new(uv_rect.max.x, uv_rect.min.y),
|
||||
};
|
||||
let pixel_coords = vertex_data.pixel_coords;
|
||||
let rect = Aabr {
|
||||
min: Vec2::new(
|
||||
pixel_coords.min.x as f32 / half_res.x - 1.0,
|
||||
1.0 - pixel_coords.max.y as f32 / half_res.y,
|
||||
),
|
||||
max: Vec2::new(
|
||||
pixel_coords.max.x as f32 / half_res.x - 1.0,
|
||||
1.0 - pixel_coords.min.y as f32 / half_res.y,
|
||||
),
|
||||
};
|
||||
(uv, rect)
|
||||
},
|
||||
);
|
||||
|
||||
match brush_result {
|
||||
Ok(brush_action) => {
|
||||
match brush_action {
|
||||
glyph_brush::BrushAction::Draw(verts) => self.last_glyph_verts = verts,
|
||||
glyph_brush::BrushAction::ReDraw => {},
|
||||
}
|
||||
|
||||
let glyphs = &self.glyphs;
|
||||
let mesh = &mut self.mesh;
|
||||
let p_scale = self.p_scale;
|
||||
let half_res = self.half_res;
|
||||
|
||||
glyphs
|
||||
.iter()
|
||||
.flat_map(|(mesh_index, glyph_count, linear_color, offset)| {
|
||||
let mesh_index = *mesh_index;
|
||||
let linear_color = *linear_color;
|
||||
// Could potentially pass this in as part of the extras
|
||||
let offset =
|
||||
offset.map(|e| e as f32 * p_scale) / half_res * Vec2::new(-1.0, 1.0);
|
||||
(0..*glyph_count).map(move |i| (mesh_index + i * 6, linear_color, offset))
|
||||
})
|
||||
.zip(self.last_glyph_verts.iter())
|
||||
.for_each(|((mesh_index, linear_color, offset), (uv, rect))| {
|
||||
// TODO: add function to vek for this
|
||||
let rect = Aabr {
|
||||
min: rect.min + offset,
|
||||
max: rect.max + offset,
|
||||
};
|
||||
|
||||
mesh.replace_quad(
|
||||
mesh_index,
|
||||
create_ui_quad(rect, *uv, linear_color, UiMode::Text),
|
||||
)
|
||||
});
|
||||
},
|
||||
Err(glyph_brush::BrushError::TextureTooSmall { suggested: (x, y) }) => {
|
||||
tracing::error!(
|
||||
"Texture to small for all glyphs, would need one of the size: ({}, {})",
|
||||
x,
|
||||
y
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
// Create a larger dynamic model if the mesh is larger than the current model
|
||||
// size.
|
||||
if self.model.vbuf.len() < self.mesh.vertices().len() {
|
||||
self.model = renderer
|
||||
.create_dynamic_model(self.mesh.vertices().len() * 4 / 3)
|
||||
.unwrap();
|
||||
}
|
||||
// Update model with new mesh.
|
||||
renderer.update_model(&self.model, &self.mesh, 0).unwrap();
|
||||
}
|
||||
|
||||
// Returns (half_res, align)
|
||||
fn calculate_resolution_dependents(
|
||||
res: Vec2<u16>,
|
||||
win_dims: Vec2<f32>,
|
||||
) -> (Vec2<f32>, Vec2<f32>, f32) {
|
||||
let half_res = res.map(|e| e as f32 / 2.0);
|
||||
let align = align(res);
|
||||
// Assume to be the same in x and y for now...
|
||||
let p_scale = res.x as f32 / win_dims.x;
|
||||
|
||||
(half_res, align, p_scale)
|
||||
}
|
||||
|
||||
fn update_resolution_dependents(&mut self, res: Vec2<u16>) {
|
||||
let (half_res, align, p_scale) = Self::calculate_resolution_dependents(res, self.win_dims);
|
||||
self.half_res = half_res;
|
||||
self.align = align;
|
||||
self.p_scale = p_scale;
|
||||
}
|
||||
|
||||
fn gl_aabr(&self, bounds: iced::Rectangle) -> Aabr<f32> {
|
||||
let flipped_y = self.win_dims.y - bounds.y;
|
||||
let half_win_dims = self.win_dims.map(|e| e / 2.0);
|
||||
let half_res = self.half_res;
|
||||
let min = (((Vec2::new(bounds.x, flipped_y - bounds.height) - half_win_dims)
|
||||
/ half_win_dims
|
||||
* half_res
|
||||
+ self.align)
|
||||
.map(|e| e.round())
|
||||
- self.align)
|
||||
/ half_res;
|
||||
let max = (((Vec2::new(bounds.x + bounds.width, flipped_y) - half_win_dims)
|
||||
/ half_win_dims
|
||||
* half_res
|
||||
+ self.align)
|
||||
.map(|e| e.round())
|
||||
- self.align)
|
||||
/ half_res;
|
||||
Aabr { min, max }
|
||||
}
|
||||
|
||||
fn position_glyphs(
|
||||
&mut self,
|
||||
bounds: iced::Rectangle,
|
||||
horizontal_alignment: iced::HorizontalAlignment,
|
||||
vertical_alignment: iced::VerticalAlignment,
|
||||
text: &str,
|
||||
size: u16,
|
||||
font: FontId,
|
||||
) -> Vec<glyph_brush::SectionGlyph> {
|
||||
use glyph_brush::{GlyphCruncher, HorizontalAlign, VerticalAlign};
|
||||
// TODO: add option to align based on the geometry of the rendered glyphs
|
||||
// instead of all possible glyphs
|
||||
let (x, h_align) = match horizontal_alignment {
|
||||
iced::HorizontalAlignment::Left => (bounds.x, HorizontalAlign::Left),
|
||||
iced::HorizontalAlignment::Center => (bounds.center_x(), HorizontalAlign::Center),
|
||||
iced::HorizontalAlignment::Right => (bounds.x + bounds.width, HorizontalAlign::Right),
|
||||
};
|
||||
|
||||
let (y, v_align) = match vertical_alignment {
|
||||
iced::VerticalAlignment::Top => (bounds.y, VerticalAlign::Top),
|
||||
iced::VerticalAlignment::Center => (bounds.center_y(), VerticalAlign::Center),
|
||||
iced::VerticalAlignment::Bottom => (bounds.y + bounds.height, VerticalAlign::Bottom),
|
||||
};
|
||||
|
||||
let p_scale = self.p_scale;
|
||||
|
||||
let section = glyph_brush::Section {
|
||||
screen_position: (x * p_scale, y * p_scale),
|
||||
bounds: (bounds.width * p_scale, bounds.height * p_scale),
|
||||
layout: glyph_brush::Layout::Wrap {
|
||||
line_breaker: Default::default(),
|
||||
h_align,
|
||||
v_align,
|
||||
},
|
||||
text: vec![glyph_brush::Text {
|
||||
text,
|
||||
scale: (size as f32 * p_scale).into(),
|
||||
font_id: font.0,
|
||||
extra: (),
|
||||
}],
|
||||
};
|
||||
|
||||
self
|
||||
.cache
|
||||
.glyph_cache_mut()
|
||||
.glyphs(section)
|
||||
// We would still have to generate vertices for these even if they have no pixels
|
||||
// Note: this is somewhat hacky and could fail if there is a non-whitespace character
|
||||
// that is not visible (to solve this we could use the extra values in
|
||||
// queue_pre_positioned to keep track of which glyphs are actually returned by
|
||||
// proccess_queued)
|
||||
.filter(|g| {
|
||||
!text[g.byte_index..]
|
||||
.chars()
|
||||
.next()
|
||||
.unwrap()
|
||||
.is_whitespace()
|
||||
})
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn draw_primitive(
|
||||
&mut self,
|
||||
primitive: Primitive,
|
||||
offset: Vec2<u32>,
|
||||
alpha: f32,
|
||||
renderer: &mut Renderer,
|
||||
) {
|
||||
match primitive {
|
||||
Primitive::Group { primitives } => {
|
||||
primitives
|
||||
.into_iter()
|
||||
.for_each(|p| self.draw_primitive(p, offset, alpha, renderer));
|
||||
},
|
||||
Primitive::Image {
|
||||
handle,
|
||||
bounds,
|
||||
color,
|
||||
source_rect,
|
||||
} => {
|
||||
let color = srgba_to_linear(color.map(|e| e as f32 / 255.0));
|
||||
let color = apply_alpha(color, alpha);
|
||||
// Don't draw a transparent image.
|
||||
if color.a == 0.0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let (graphic_id, rotation) = handle;
|
||||
let gl_aabr = self.gl_aabr(iced::Rectangle {
|
||||
x: bounds.x - offset.x as f32,
|
||||
y: bounds.y - offset.y as f32,
|
||||
..bounds
|
||||
});
|
||||
|
||||
let graphic_cache = self.cache.graphic_cache_mut();
|
||||
let half_res = self.half_res; // Make borrow checker happy by avoiding self in closure
|
||||
let (source_aabr, gl_size) = {
|
||||
// Transform the source rectangle into uv coordinate.
|
||||
// TODO: Make sure this is right. Especially the conversions.
|
||||
let ((uv_l, uv_r, uv_b, uv_t), gl_size) = match graphic_cache
|
||||
.get_graphic(graphic_id)
|
||||
{
|
||||
Some(Graphic::Blank) | None => return,
|
||||
Some(Graphic::Image(image, ..)) => {
|
||||
source_rect.and_then(|src_rect| {
|
||||
#[rustfmt::skip] use ::image::GenericImageView;
|
||||
let (image_w, image_h) = image.dimensions();
|
||||
let (source_w, source_h) = src_rect.size().into_tuple();
|
||||
let gl_size = gl_aabr.size();
|
||||
if image_w == 0
|
||||
|| image_h == 0
|
||||
|| source_w < 1.0
|
||||
|| source_h < 1.0
|
||||
|| gl_size.reduce_partial_min() < f32::EPSILON
|
||||
{
|
||||
None
|
||||
} else {
|
||||
// TODO: do this earlier
|
||||
// Multiply drawn image size by ratio of original image
|
||||
// size to
|
||||
// source rectangle size (since as the proportion of the
|
||||
// image gets
|
||||
// smaller, the drawn size should get bigger), up to the
|
||||
// actual
|
||||
// size of the original image.
|
||||
let ratio_x = (image_w as f32 / source_w)
|
||||
.min((image_w as f32 / (gl_size.w * half_res.x)).max(1.0));
|
||||
let ratio_y = (image_h as f32 / source_h)
|
||||
.min((image_h as f32 / (gl_size.h * half_res.y)).max(1.0));
|
||||
let (l, b) = src_rect.min.into_tuple();
|
||||
let (r, t) = src_rect.max.into_tuple();
|
||||
Some((
|
||||
(
|
||||
l / image_w as f32, /* * ratio_x*/
|
||||
r / image_w as f32, /* * ratio_x*/
|
||||
b / image_h as f32, /* * ratio_y*/
|
||||
t / image_h as f32, /* * ratio_y*/
|
||||
),
|
||||
Extent2::new(
|
||||
gl_size.w as f32 * ratio_x,
|
||||
gl_size.h as f32 * ratio_y,
|
||||
),
|
||||
))
|
||||
/* ((l / image_w as f32),
|
||||
(r / image_w as f32),
|
||||
(b / image_h as f32),
|
||||
(t / image_h as f32)) */
|
||||
}
|
||||
})
|
||||
},
|
||||
// No easy way to interpret source_rect for voxels...
|
||||
Some(Graphic::Voxel(..)) => None,
|
||||
}
|
||||
.unwrap_or_else(|| ((0.0, 1.0, 0.0, 1.0), gl_aabr.size()));
|
||||
(
|
||||
Aabr {
|
||||
min: Vec2::new(uv_l, uv_b),
|
||||
max: Vec2::new(uv_r, uv_t),
|
||||
},
|
||||
gl_size,
|
||||
)
|
||||
};
|
||||
|
||||
let resolution = Vec2::new(
|
||||
(gl_size.w * self.half_res.x).round() as u16,
|
||||
(gl_size.h * self.half_res.y).round() as u16,
|
||||
);
|
||||
|
||||
// Don't do anything if resolution is zero
|
||||
if resolution.map(|e| e == 0).reduce_or() {
|
||||
return;
|
||||
// TODO: consider logging uneeded elements
|
||||
}
|
||||
|
||||
// Cache graphic at particular resolution.
|
||||
let (uv_aabr, tex_id) = match graphic_cache.cache_res(
|
||||
renderer,
|
||||
graphic_id,
|
||||
resolution,
|
||||
// TODO: take f32 here
|
||||
source_aabr.map(|e| e as f64),
|
||||
rotation,
|
||||
) {
|
||||
// TODO: get dims from graphic_cache (or have it return floats directly)
|
||||
Some((aabr, tex_id)) => {
|
||||
let cache_dims = graphic_cache
|
||||
.get_tex(tex_id)
|
||||
.get_dimensions()
|
||||
.map(|e| e as f32);
|
||||
let min = Vec2::new(aabr.min.x as f32, aabr.max.y as f32) / cache_dims;
|
||||
let max = Vec2::new(aabr.max.x as f32, aabr.min.y as f32) / cache_dims;
|
||||
(Aabr { min, max }, tex_id)
|
||||
},
|
||||
None => return,
|
||||
};
|
||||
|
||||
// Switch to the image state if we are not in it already or if a different
|
||||
// texture id was being used.
|
||||
self.switch_state(State::Image(tex_id));
|
||||
|
||||
self.mesh
|
||||
.push_quad(create_ui_quad(gl_aabr, uv_aabr, color, UiMode::Image));
|
||||
},
|
||||
Primitive::Gradient {
|
||||
bounds,
|
||||
top_linear_color,
|
||||
bottom_linear_color,
|
||||
} => {
|
||||
// Don't draw a transparent rectangle.
|
||||
let top_linear_color = apply_alpha(top_linear_color, alpha);
|
||||
let bottom_linear_color = apply_alpha(bottom_linear_color, alpha);
|
||||
if top_linear_color.a == 0.0 && bottom_linear_color.a == 0.0 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.switch_state(State::Plain);
|
||||
|
||||
let gl_aabr = self.gl_aabr(iced::Rectangle {
|
||||
x: bounds.x - offset.x as f32,
|
||||
y: bounds.y - offset.y as f32,
|
||||
..bounds
|
||||
});
|
||||
|
||||
self.mesh.push_quad(create_ui_quad_vert_gradient(
|
||||
gl_aabr,
|
||||
Aabr {
|
||||
min: Vec2::zero(),
|
||||
max: Vec2::zero(),
|
||||
},
|
||||
top_linear_color,
|
||||
bottom_linear_color,
|
||||
UiMode::Geometry,
|
||||
));
|
||||
},
|
||||
|
||||
Primitive::Rectangle {
|
||||
bounds,
|
||||
linear_color,
|
||||
} => {
|
||||
let linear_color = apply_alpha(linear_color, alpha);
|
||||
// Don't draw a transparent rectangle.
|
||||
if linear_color.a == 0.0 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.switch_state(State::Plain);
|
||||
|
||||
let gl_aabr = self.gl_aabr(iced::Rectangle {
|
||||
x: bounds.x - offset.x as f32,
|
||||
y: bounds.y - offset.y as f32,
|
||||
..bounds
|
||||
});
|
||||
|
||||
self.mesh.push_quad(create_ui_quad(
|
||||
gl_aabr,
|
||||
Aabr {
|
||||
min: Vec2::zero(),
|
||||
max: Vec2::zero(),
|
||||
},
|
||||
linear_color,
|
||||
UiMode::Geometry,
|
||||
));
|
||||
},
|
||||
Primitive::Text {
|
||||
glyphs,
|
||||
bounds: _, // iced::Rectangle
|
||||
linear_color,
|
||||
} => {
|
||||
let linear_color = apply_alpha(linear_color, alpha);
|
||||
self.switch_state(State::Plain);
|
||||
|
||||
// TODO: makes sure we are not doing all this work for hidden text
|
||||
// e.g. in chat
|
||||
let glyph_cache = self.cache.glyph_cache_mut();
|
||||
|
||||
// Count glyphs
|
||||
let glyph_count = glyphs.len();
|
||||
|
||||
// Queue the glyphs to be cached.
|
||||
glyph_cache.queue_pre_positioned(
|
||||
glyphs,
|
||||
// TODO: glyph_brush should document that these need to be the same length
|
||||
vec![(); glyph_count],
|
||||
// Since we already passed in `bounds` to position the glyphs some of this
|
||||
// seems redundant...
|
||||
// Note: we can't actually use this because dropping glyphs messeses up the
|
||||
// counting and there is not a method provided to drop out of bounds
|
||||
// glyphs while positioning them
|
||||
// Note: keeping commented code in case how we handle text changes
|
||||
glyph_brush::ab_glyph::Rect {
|
||||
min: glyph_brush::ab_glyph::point(
|
||||
-10000.0, //bounds.x * self.p_scale,
|
||||
-10000.0, //bounds.y * self.p_scale,
|
||||
),
|
||||
max: glyph_brush::ab_glyph::point(
|
||||
10000.0, //(bounds.x + bounds.width) * self.p_scale,
|
||||
10000.0, //(bounds.y + bounds.height) * self.p_scale,
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
// Leave ui and verts blank to fill in when processing cached glyphs
|
||||
let zero_aabr = Aabr {
|
||||
min: Vec2::broadcast(0.0),
|
||||
max: Vec2::broadcast(0.0),
|
||||
};
|
||||
self.glyphs.push((
|
||||
self.mesh.vertices().len(),
|
||||
glyph_count,
|
||||
linear_color,
|
||||
offset,
|
||||
));
|
||||
for _ in 0..glyph_count {
|
||||
// Push placeholder quad
|
||||
// Note: moving to some sort of layering / z based system would be an
|
||||
// alternative to this (and might help with reducing draw
|
||||
// calls)
|
||||
self.mesh.push_quad(create_ui_quad(
|
||||
zero_aabr,
|
||||
zero_aabr,
|
||||
linear_color,
|
||||
UiMode::Text,
|
||||
));
|
||||
}
|
||||
},
|
||||
Primitive::Clip {
|
||||
bounds,
|
||||
offset: clip_offset,
|
||||
content,
|
||||
} => {
|
||||
let new_scissor = {
|
||||
// TODO: incorporate current offset for nested Clips
|
||||
let intersection = Aabr {
|
||||
min: Vec2 {
|
||||
x: (bounds.x * self.p_scale) as u16,
|
||||
y: (bounds.y * self.p_scale) as u16,
|
||||
},
|
||||
max: Vec2 {
|
||||
x: ((bounds.x + bounds.width) * self.p_scale) as u16,
|
||||
y: ((bounds.y + bounds.height) * self.p_scale) as u16,
|
||||
},
|
||||
}
|
||||
.intersection(self.window_scissor);
|
||||
|
||||
if intersection.is_valid() {
|
||||
intersection
|
||||
} else {
|
||||
Aabr::new_empty(Vec2::zero())
|
||||
}
|
||||
};
|
||||
// Not expecting this case: new_scissor == current_scissor
|
||||
// So not optimizing for it
|
||||
|
||||
// Finish the current command.
|
||||
// TODO: ensure we never push empty commands
|
||||
self.draw_commands.push(match self.current_state {
|
||||
State::Plain => DrawCommand::plain(self.start..self.mesh.vertices().len()),
|
||||
State::Image(id) => {
|
||||
DrawCommand::image(self.start..self.mesh.vertices().len(), id)
|
||||
},
|
||||
});
|
||||
self.start = self.mesh.vertices().len();
|
||||
|
||||
self.draw_commands.push(DrawCommand::Scissor(new_scissor));
|
||||
|
||||
// TODO: support nested clips?
|
||||
// TODO: if last command is a clip changing back to the default replace it with
|
||||
// this
|
||||
// TODO: cull primitives outside the current scissor
|
||||
|
||||
// Renderer child
|
||||
self.draw_primitive(*content, offset + clip_offset, alpha, renderer);
|
||||
|
||||
// Reset scissor
|
||||
self.draw_commands.push(match self.current_state {
|
||||
State::Plain => DrawCommand::plain(self.start..self.mesh.vertices().len()),
|
||||
State::Image(id) => {
|
||||
DrawCommand::image(self.start..self.mesh.vertices().len(), id)
|
||||
},
|
||||
});
|
||||
self.start = self.mesh.vertices().len();
|
||||
|
||||
self.draw_commands
|
||||
.push(DrawCommand::Scissor(self.window_scissor));
|
||||
},
|
||||
Primitive::Opacity { alpha: a, content } => {
|
||||
self.draw_primitive(*content, offset, alpha * a, renderer);
|
||||
},
|
||||
Primitive::Nothing => {},
|
||||
}
|
||||
}
|
||||
|
||||
// Switches to the specified state if not already in it
|
||||
// If switch occurs current state is converted into a draw command
|
||||
fn switch_state(&mut self, state: State) {
|
||||
if self.current_state != state {
|
||||
let vert_range = self.start..self.mesh.vertices().len();
|
||||
let draw_command = match self.current_state {
|
||||
State::Plain => DrawCommand::plain(vert_range),
|
||||
State::Image(id) => DrawCommand::image(vert_range, id),
|
||||
};
|
||||
self.draw_commands.push(draw_command);
|
||||
self.start = self.mesh.vertices().len();
|
||||
self.current_state = state;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&self, renderer: &mut Renderer, maybe_globals: Option<&Consts<Globals>>) {
|
||||
span!(_guard, "render", "IcedRenderer::render");
|
||||
let mut scissor = default_scissor(renderer);
|
||||
let globals = maybe_globals.unwrap_or(&self.default_globals);
|
||||
let mut locals = &self.interface_locals;
|
||||
for draw_command in self.draw_commands.iter() {
|
||||
match draw_command {
|
||||
DrawCommand::Scissor(new_scissor) => {
|
||||
scissor = *new_scissor;
|
||||
},
|
||||
DrawCommand::WorldPos(index) => {
|
||||
locals = index.map_or(&self.interface_locals, |i| &self.ingame_locals[i]);
|
||||
},
|
||||
DrawCommand::Draw { kind, verts } => {
|
||||
let tex = match kind {
|
||||
DrawKind::Image(tex_id) => self.cache.graphic_cache().get_tex(*tex_id),
|
||||
DrawKind::Plain => self.cache.glyph_cache_tex(),
|
||||
};
|
||||
let model = self.model.submodel(verts.clone());
|
||||
renderer.render_ui_element(model, tex, scissor, globals, locals);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Given the the resolution determines the offset needed to align integer
|
||||
// offsets from the center of the sceen to pixels
|
||||
#[inline(always)]
|
||||
fn align(res: Vec2<u16>) -> Vec2<f32> {
|
||||
// TODO: does this logic still apply in iced's coordinate system?
|
||||
// If the resolution is odd then the center of the screen will be within the
|
||||
// middle of a pixel so we need to offset by 0.5 pixels to be on the edge of
|
||||
// a pixel
|
||||
res.map(|e| (e & 1) as f32 * 0.5)
|
||||
}
|
||||
|
||||
fn default_scissor(renderer: &Renderer) -> Aabr<u16> {
|
||||
let (screen_w, screen_h) = renderer.get_resolution().map(|e| e as u16).into_tuple();
|
||||
Aabr {
|
||||
min: Vec2 { x: 0, y: 0 },
|
||||
max: Vec2 {
|
||||
x: screen_w,
|
||||
y: screen_h,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl iced::Renderer for IcedRenderer {
|
||||
// Default styling
|
||||
type Defaults = Defaults;
|
||||
// TODO: use graph of primitives to enable diffing???
|
||||
type Output = (Primitive, iced::mouse::Interaction);
|
||||
|
||||
#[allow(clippy::let_and_return)]
|
||||
fn layout<'a, M>(
|
||||
&mut self,
|
||||
element: &iced::Element<'a, M, Self>,
|
||||
limits: &iced::layout::Limits,
|
||||
) -> iced::layout::Node {
|
||||
span!(_guard, "layout", "IcedRenderer::layout");
|
||||
let node = element.layout(self, limits);
|
||||
|
||||
// Trim text measurements cache?
|
||||
|
||||
node
|
||||
}
|
||||
|
||||
fn overlay(
|
||||
&mut self,
|
||||
(base_primitive, base_interaction): Self::Output,
|
||||
(overlay_primitive, overlay_interaction): Self::Output,
|
||||
overlay_bounds: iced::Rectangle,
|
||||
) -> Self::Output {
|
||||
span!(_guard, "overlay", "IcedRenderer::overlay");
|
||||
(
|
||||
Primitive::Group {
|
||||
primitives: vec![base_primitive, Primitive::Clip {
|
||||
bounds: iced::Rectangle {
|
||||
// TODO: do we need this + 0.5?
|
||||
width: overlay_bounds.width + 0.5,
|
||||
height: overlay_bounds.height + 0.5,
|
||||
..overlay_bounds
|
||||
},
|
||||
offset: Vec2::new(0, 0),
|
||||
content: Box::new(overlay_primitive),
|
||||
}],
|
||||
},
|
||||
base_interaction.max(overlay_interaction),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_alpha(color: Rgba<f32>, alpha: f32) -> Rgba<f32> {
|
||||
Rgba {
|
||||
a: alpha * color.a,
|
||||
..color
|
||||
}
|
||||
}
|
||||
// TODO: impl Debugger
|
42
voxygen/src/ui/ice/renderer/primitive.rs
Normal file
42
voxygen/src/ui/ice/renderer/primitive.rs
Normal file
@ -0,0 +1,42 @@
|
||||
use crate::ui::{graphic, ice::widget::image};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Primitive {
|
||||
// Allocation :(
|
||||
Group {
|
||||
primitives: Vec<Primitive>,
|
||||
},
|
||||
Image {
|
||||
handle: (image::Handle, graphic::Rotation),
|
||||
bounds: iced::Rectangle,
|
||||
color: vek::Rgba<u8>,
|
||||
source_rect: Option<vek::Aabr<f32>>,
|
||||
},
|
||||
// A vertical gradient
|
||||
// TODO: could be combined with rectangle
|
||||
Gradient {
|
||||
bounds: iced::Rectangle,
|
||||
top_linear_color: vek::Rgba<f32>,
|
||||
bottom_linear_color: vek::Rgba<f32>,
|
||||
},
|
||||
Rectangle {
|
||||
bounds: iced::Rectangle,
|
||||
linear_color: vek::Rgba<f32>,
|
||||
},
|
||||
Text {
|
||||
glyphs: Vec<glyph_brush::SectionGlyph>,
|
||||
bounds: iced::Rectangle,
|
||||
linear_color: vek::Rgba<f32>,
|
||||
},
|
||||
Clip {
|
||||
bounds: iced::Rectangle,
|
||||
offset: vek::Vec2<u32>,
|
||||
content: Box<Primitive>,
|
||||
},
|
||||
// Make content translucent
|
||||
Opacity {
|
||||
alpha: f32,
|
||||
content: Box<Primitive>,
|
||||
},
|
||||
Nothing,
|
||||
}
|
118
voxygen/src/ui/ice/renderer/style/button.rs
Normal file
118
voxygen/src/ui/ice/renderer/style/button.rs
Normal file
@ -0,0 +1,118 @@
|
||||
use super::super::super::widget::image;
|
||||
use iced::Color;
|
||||
use vek::Rgba;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct Background {
|
||||
default: image::Handle,
|
||||
hover: image::Handle,
|
||||
press: image::Handle,
|
||||
color: Rgba<u8>,
|
||||
}
|
||||
|
||||
impl Background {
|
||||
fn new(image: image::Handle) -> Self {
|
||||
Self {
|
||||
default: image,
|
||||
hover: image,
|
||||
press: image,
|
||||
color: Rgba::white(),
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: consider a different place for this
|
||||
// Note: for now all buttons have an image background
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Style {
|
||||
background: Option<Background>,
|
||||
enabled_text: Color,
|
||||
disabled_text: Color,
|
||||
}
|
||||
|
||||
impl Style {
|
||||
pub fn new(image: image::Handle) -> Self {
|
||||
Self {
|
||||
background: Some(Background::new(image)),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hover_image(mut self, image: image::Handle) -> Self {
|
||||
self.background = Some(match self.background {
|
||||
Some(mut background) => {
|
||||
background.hover = image;
|
||||
background
|
||||
},
|
||||
None => Background::new(image),
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
pub fn press_image(mut self, image: image::Handle) -> Self {
|
||||
self.background = Some(match self.background {
|
||||
Some(mut background) => {
|
||||
background.press = image;
|
||||
background
|
||||
},
|
||||
None => Background::new(image),
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
// TODO: this needs to be refactored since the color isn't used if there is no
|
||||
// background
|
||||
pub fn image_color(mut self, color: Rgba<u8>) -> Self {
|
||||
if let Some(background) = &mut self.background {
|
||||
background.color = color;
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn text_color(mut self, color: Color) -> Self {
|
||||
self.enabled_text = color;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn disabled_text_color(mut self, color: Color) -> Self {
|
||||
self.disabled_text = color;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn disabled(&self) -> (Option<(image::Handle, Rgba<u8>)>, Color) {
|
||||
(
|
||||
self.background.as_ref().map(|b| (b.default, b.color)),
|
||||
self.disabled_text,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn pressed(&self) -> (Option<(image::Handle, Rgba<u8>)>, Color) {
|
||||
(
|
||||
self.background.as_ref().map(|b| (b.press, b.color)),
|
||||
self.enabled_text,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn hovered(&self) -> (Option<(image::Handle, Rgba<u8>)>, Color) {
|
||||
(
|
||||
self.background.as_ref().map(|b| (b.hover, b.color)),
|
||||
self.enabled_text,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn active(&self) -> (Option<(image::Handle, Rgba<u8>)>, Color) {
|
||||
(
|
||||
self.background.as_ref().map(|b| (b.default, b.color)),
|
||||
self.enabled_text,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Style {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
background: None,
|
||||
enabled_text: Color::WHITE,
|
||||
disabled_text: Color::from_rgb(0.5, 0.5, 0.5),
|
||||
}
|
||||
}
|
||||
}
|
55
voxygen/src/ui/ice/renderer/style/container.rs
Normal file
55
voxygen/src/ui/ice/renderer/style/container.rs
Normal file
@ -0,0 +1,55 @@
|
||||
use super::super::super::widget::image;
|
||||
use vek::Rgba;
|
||||
|
||||
/// Container Border
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Border {
|
||||
DoubleCornerless {
|
||||
inner: Rgba<u8>,
|
||||
outer: Rgba<u8>,
|
||||
},
|
||||
Image {
|
||||
corner: image::Handle,
|
||||
edge: image::Handle,
|
||||
},
|
||||
None,
|
||||
}
|
||||
|
||||
/// Background of the container
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Style {
|
||||
Image(image::Handle, Rgba<u8>),
|
||||
Color(Rgba<u8>, Border),
|
||||
None,
|
||||
}
|
||||
|
||||
impl Style {
|
||||
/// Shorthand for common case where the color of the image is not modified
|
||||
pub fn image(image: image::Handle) -> Self { Self::Image(image, Rgba::broadcast(255)) }
|
||||
|
||||
/// Shorthand for a color background with no border
|
||||
pub fn color(color: Rgba<u8>) -> Self { Self::Color(color, Border::None) }
|
||||
|
||||
/// Shorthand for a color background with a cornerless border
|
||||
pub fn color_with_double_cornerless_border(
|
||||
color: Rgba<u8>,
|
||||
inner: Rgba<u8>,
|
||||
outer: Rgba<u8>,
|
||||
) -> Self {
|
||||
Self::Color(color, Border::DoubleCornerless { inner, outer })
|
||||
}
|
||||
|
||||
/// Shorthand for a color background with image borders where the corners
|
||||
/// are inset
|
||||
pub fn color_with_image_border(
|
||||
color: Rgba<u8>,
|
||||
corner: image::Handle,
|
||||
edge: image::Handle,
|
||||
) -> Self {
|
||||
Self::Color(color, Border::Image { corner, edge })
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Style {
|
||||
fn default() -> Self { Self::None }
|
||||
}
|
4
voxygen/src/ui/ice/renderer/style/mod.rs
Normal file
4
voxygen/src/ui/ice/renderer/style/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub mod button;
|
||||
pub mod container;
|
||||
pub mod scrollable;
|
||||
pub mod slider;
|
33
voxygen/src/ui/ice/renderer/style/scrollable.rs
Normal file
33
voxygen/src/ui/ice/renderer/style/scrollable.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use super::super::super::widget::image;
|
||||
use vek::Rgba;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Style {
|
||||
pub track: Option<Track>,
|
||||
pub scroller: Scroller,
|
||||
}
|
||||
|
||||
impl Default for Style {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
track: None,
|
||||
scroller: Scroller::Color(Rgba::new(128, 128, 128, 255)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Track {
|
||||
Color(Rgba<u8>),
|
||||
Image(image::Handle, Rgba<u8>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Scroller {
|
||||
Color(Rgba<u8>),
|
||||
Image {
|
||||
ends: image::Handle,
|
||||
mid: image::Handle,
|
||||
color: Rgba<u8>,
|
||||
},
|
||||
}
|
53
voxygen/src/ui/ice/renderer/style/slider.rs
Normal file
53
voxygen/src/ui/ice/renderer/style/slider.rs
Normal file
@ -0,0 +1,53 @@
|
||||
use super::super::super::widget::image;
|
||||
use vek::Rgba;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Style {
|
||||
pub cursor: Cursor,
|
||||
pub bar: Bar,
|
||||
pub labels: bool,
|
||||
pub cursor_size: (u16, u16),
|
||||
pub bar_height: u16,
|
||||
}
|
||||
|
||||
impl Default for Style {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
cursor: Cursor::Color(Rgba::new(0.5, 0.5, 0.5, 1.0)),
|
||||
bar: Bar::Color(Rgba::new(0.5, 0.5, 0.5, 1.0)),
|
||||
labels: false,
|
||||
cursor_size: (8, 16),
|
||||
bar_height: 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Cursor {
|
||||
Color(Rgba<f32>),
|
||||
Image(image::Handle, Rgba<u8>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Bar {
|
||||
Color(Rgba<f32>),
|
||||
Image(image::Handle, Rgba<u8>, u16),
|
||||
}
|
||||
|
||||
impl Style {
|
||||
pub fn images(
|
||||
cursor: image::Handle,
|
||||
bar: image::Handle,
|
||||
bar_pad: u16,
|
||||
cursor_size: (u16, u16),
|
||||
bar_height: u16,
|
||||
) -> Self {
|
||||
Self {
|
||||
cursor: Cursor::Image(cursor, Rgba::white()),
|
||||
bar: Bar::Image(bar, Rgba::white(), bar_pad),
|
||||
labels: false,
|
||||
cursor_size,
|
||||
bar_height,
|
||||
}
|
||||
}
|
||||
}
|
23
voxygen/src/ui/ice/renderer/widget/aspect_ratio_container.rs
Normal file
23
voxygen/src/ui/ice/renderer/widget/aspect_ratio_container.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use super::super::{
|
||||
super::widget::{aspect_ratio_container, image},
|
||||
IcedRenderer,
|
||||
};
|
||||
use iced::{Element, Layout, Point, Rectangle};
|
||||
|
||||
impl aspect_ratio_container::Renderer for IcedRenderer {
|
||||
type ImageHandle = image::Handle;
|
||||
|
||||
fn dimensions(&self, handle: &Self::ImageHandle) -> (u32, u32) { self.image_dims(*handle) }
|
||||
|
||||
fn draw<M>(
|
||||
&mut self,
|
||||
defaults: &Self::Defaults,
|
||||
_bounds: Rectangle,
|
||||
cursor_position: Point,
|
||||
viewport: &Rectangle,
|
||||
content: &Element<'_, M, Self>,
|
||||
content_layout: Layout<'_>,
|
||||
) -> Self::Output {
|
||||
content.draw(self, defaults, content_layout, cursor_position, viewport)
|
||||
}
|
||||
}
|
30
voxygen/src/ui/ice/renderer/widget/background_container.rs
Normal file
30
voxygen/src/ui/ice/renderer/widget/background_container.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use super::super::{super::widget::background_container, IcedRenderer, Primitive};
|
||||
use iced::{Element, Layout, Point, Rectangle};
|
||||
|
||||
impl background_container::Renderer for IcedRenderer {
|
||||
fn draw<M, B>(
|
||||
&mut self,
|
||||
defaults: &Self::Defaults,
|
||||
background: &B,
|
||||
background_layout: Layout<'_>,
|
||||
viewport: &Rectangle,
|
||||
content: &Element<'_, M, Self>,
|
||||
content_layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Self::Output
|
||||
where
|
||||
B: background_container::Background<Self>,
|
||||
{
|
||||
let back_primitive = background
|
||||
.draw(self, defaults, background_layout, cursor_position, viewport)
|
||||
.0;
|
||||
let (content_primitive, mouse_interaction) =
|
||||
content.draw(self, defaults, content_layout, cursor_position, viewport);
|
||||
(
|
||||
Primitive::Group {
|
||||
primitives: vec![back_primitive, content_primitive],
|
||||
},
|
||||
mouse_interaction,
|
||||
)
|
||||
}
|
||||
}
|
66
voxygen/src/ui/ice/renderer/widget/button.rs
Normal file
66
voxygen/src/ui/ice/renderer/widget/button.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use super::super::{super::Rotation, style, Defaults, IcedRenderer, Primitive};
|
||||
use iced::{button, mouse, Element, Layout, Point, Rectangle};
|
||||
|
||||
impl button::Renderer for IcedRenderer {
|
||||
// TODO: what if this gets large enough to not be copied around?
|
||||
type Style = style::button::Style;
|
||||
|
||||
const DEFAULT_PADDING: u16 = 0;
|
||||
|
||||
fn draw<M>(
|
||||
&mut self,
|
||||
_defaults: &Self::Defaults,
|
||||
bounds: Rectangle,
|
||||
cursor_position: Point,
|
||||
is_disabled: bool,
|
||||
is_pressed: bool,
|
||||
style: &Self::Style,
|
||||
content: &Element<'_, M, Self>,
|
||||
content_layout: Layout<'_>,
|
||||
) -> Self::Output {
|
||||
let is_mouse_over = bounds.contains(cursor_position);
|
||||
|
||||
let (maybe_image, text_color) = if is_disabled {
|
||||
style.disabled()
|
||||
} else if is_mouse_over {
|
||||
if is_pressed {
|
||||
style.pressed()
|
||||
} else {
|
||||
style.hovered()
|
||||
}
|
||||
} else {
|
||||
style.active()
|
||||
};
|
||||
|
||||
let (content, _) = content.draw(
|
||||
self,
|
||||
&Defaults { text_color },
|
||||
content_layout,
|
||||
cursor_position,
|
||||
&bounds,
|
||||
);
|
||||
|
||||
let primitive = if let Some((handle, color)) = maybe_image {
|
||||
let background = Primitive::Image {
|
||||
handle: (handle, Rotation::None),
|
||||
bounds,
|
||||
color,
|
||||
source_rect: None,
|
||||
};
|
||||
|
||||
Primitive::Group {
|
||||
primitives: vec![background, content],
|
||||
}
|
||||
} else {
|
||||
content
|
||||
};
|
||||
|
||||
let mouse_interaction = if is_mouse_over {
|
||||
mouse::Interaction::Pointer
|
||||
} else {
|
||||
mouse::Interaction::default()
|
||||
};
|
||||
|
||||
(primitive, mouse_interaction)
|
||||
}
|
||||
}
|
35
voxygen/src/ui/ice/renderer/widget/column.rs
Normal file
35
voxygen/src/ui/ice/renderer/widget/column.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use super::super::{IcedRenderer, Primitive};
|
||||
use iced::{column, mouse, Element, Layout, Point, Rectangle};
|
||||
|
||||
impl column::Renderer for IcedRenderer {
|
||||
fn draw<M>(
|
||||
&mut self,
|
||||
defaults: &Self::Defaults,
|
||||
content: &[Element<'_, M, Self>],
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
viewport: &Rectangle,
|
||||
) -> Self::Output {
|
||||
let mut mouse_interaction = mouse::Interaction::default();
|
||||
|
||||
(
|
||||
Primitive::Group {
|
||||
primitives: content
|
||||
.iter()
|
||||
.zip(layout.children())
|
||||
.map(|(child, layout)| {
|
||||
let (primitive, new_mouse_interaction) =
|
||||
child.draw(self, defaults, layout, cursor_position, viewport);
|
||||
|
||||
if new_mouse_interaction > mouse_interaction {
|
||||
mouse_interaction = new_mouse_interaction;
|
||||
}
|
||||
|
||||
primitive
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
mouse_interaction,
|
||||
)
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user