diff --git a/Cargo.lock b/Cargo.lock
index 7144e09..8a20562 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -20,15 +20,15 @@ checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
 
 [[package]]
 name = "accesskit"
-version = "0.16.3"
+version = "0.17.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99b76d84ee70e30a4a7e39ab9018e2b17a6a09e31084176cc7c0b2dec036ba45"
+checksum = "d3d3b8f9bae46a948369bc4a03e815d4ed6d616bd00de4051133a5019dc31c5a"
 
 [[package]]
 name = "accesskit_atspi_common"
-version = "0.9.3"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5393c75d4666f580f4cac0a968bc97c36076bb536a129f28210dac54ee127ed"
+checksum = "7c5dd55e6e94949498698daf4d48fb5659e824d7abec0d394089656ceaf99d4f"
 dependencies = [
  "accesskit",
  "accesskit_consumer",
@@ -40,33 +40,34 @@ dependencies = [
 
 [[package]]
 name = "accesskit_consumer"
-version = "0.24.3"
+version = "0.26.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a12dc159d52233c43d9fe5415969433cbdd52c3d6e0df51bda7d447427b9986"
+checksum = "f47983a1084940ba9a39c077a8c63e55c619388be5476ac04c804cfbd1e63459"
 dependencies = [
  "accesskit",
+ "hashbrown 0.15.2",
  "immutable-chunkmap",
 ]
 
 [[package]]
 name = "accesskit_macos"
-version = "0.17.4"
+version = "0.18.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfc6c1ecd82053d127961ad80a8beaa6004fb851a3a5b96506d7a6bd462403f6"
+checksum = "7329821f3bd1101e03a7d2e03bd339e3ac0dc64c70b4c9f9ae1949e3ba8dece1"
 dependencies = [
  "accesskit",
  "accesskit_consumer",
+ "hashbrown 0.15.2",
  "objc2",
  "objc2-app-kit",
  "objc2-foundation",
- "once_cell",
 ]
 
 [[package]]
 name = "accesskit_unix"
-version = "0.12.3"
+version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be7f5cf6165be10a54b2655fa2e0e12b2509f38ed6fc43e11c31fdb7ee6230bb"
+checksum = "fcee751cc20d88678c33edaf9c07e8b693cd02819fe89053776f5313492273f5"
 dependencies = [
  "accesskit",
  "accesskit_atspi_common",
@@ -82,12 +83,13 @@ dependencies = [
 
 [[package]]
 name = "accesskit_windows"
-version = "0.23.2"
+version = "0.24.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "974e96c347384d9133427167fb8a58c340cb0496988dacceebdc1ed27071023b"
+checksum = "24fcd5d23d70670992b823e735e859374d694a3d12bfd8dd32bd3bd8bedb5d81"
 dependencies = [
  "accesskit",
  "accesskit_consumer",
+ "hashbrown 0.15.2",
  "paste",
  "static_assertions",
  "windows 0.58.0",
@@ -96,9 +98,9 @@ dependencies = [
 
 [[package]]
 name = "accesskit_winit"
-version = "0.22.4"
+version = "0.23.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aea3522719f1c44564d03e9469a8e2f3a98b3a8a880bd66d0789c6b9c4a669dd"
+checksum = "6a6a48dad5530b6deb9fc7a52cc6c3bf72cdd9eb8157ac9d32d69f2427a5e879"
 dependencies = [
  "accesskit",
  "accesskit_macos",
@@ -164,9 +166,9 @@ checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1"
 
 [[package]]
 name = "allocator-api2"
-version = "0.2.20"
+version = "0.2.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
 
 [[package]]
 name = "android-activity"
@@ -261,9 +263,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.93"
+version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
+checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
 
 [[package]]
 name = "arbitrary"
@@ -297,7 +299,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -465,7 +467,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -500,7 +502,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -646,18 +648,18 @@ dependencies = [
 
 [[package]]
 name = "bit-set"
-version = "0.6.0"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0481a0e032742109b1133a095184ee93d88f3dc9e0d28a5d033dc77a073f44f"
+checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
 dependencies = [
  "bit-vec",
 ]
 
 [[package]]
 name = "bit-vec"
-version = "0.7.0"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22"
+checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
 
 [[package]]
 name = "bit_field"
@@ -740,9 +742,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
 
 [[package]]
 name = "bytemuck"
-version = "1.19.0"
+version = "1.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d"
+checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a"
 dependencies = [
  "bytemuck_derive",
 ]
@@ -755,7 +757,7 @@ checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -772,9 +774,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
 
 [[package]]
 name = "bytes"
-version = "1.8.0"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
+checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
 
 [[package]]
 name = "bzip2"
@@ -834,9 +836,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.2.1"
+version = "1.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
+checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d"
 dependencies = [
  "jobserver",
  "libc",
@@ -888,9 +890,9 @@ dependencies = [
 
 [[package]]
 name = "chrono"
-version = "0.4.38"
+version = "0.4.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
+checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
@@ -912,9 +914,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.21"
+version = "4.5.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
+checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -922,9 +924,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.21"
+version = "4.5.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
+checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
 dependencies = [
  "anstream",
  "anstyle",
@@ -941,14 +943,14 @@ dependencies = [
  "heck",
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
 name = "clap_lex"
-version = "0.7.3"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
+checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
 
 [[package]]
 name = "clipboard-win"
@@ -981,37 +983,6 @@ version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
 
-[[package]]
-name = "com"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6"
-dependencies = [
- "com_macros",
-]
-
-[[package]]
-name = "com_macros"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5"
-dependencies = [
- "com_macros_support",
- "proc-macro2",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "com_macros_support"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
 [[package]]
 name = "combine"
 version = "4.6.7"
@@ -1110,9 +1081,9 @@ dependencies = [
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.15"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6"
+checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
 dependencies = [
  "libc",
 ]
@@ -1188,17 +1159,6 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
 
-[[package]]
-name = "d3d12"
-version = "22.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdbd1f579714e3c809ebd822c81ef148b1ceaeb3d535352afc73fd0c4c6a0017"
-dependencies = [
- "bitflags 2.6.0",
- "libloading",
- "winapi",
-]
-
 [[package]]
 name = "deflate64"
 version = "0.1.9"
@@ -1222,7 +1182,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -1235,7 +1195,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "rustc_version",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -1255,7 +1215,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
  "unicode-xid",
 ]
 
@@ -1305,7 +1265,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -1341,8 +1301,7 @@ checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53"
 [[package]]
 name = "ecolor"
 version = "0.29.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "775cfde491852059e386c4e1deb4aef381c617dc364184c6f6afee99b87c402b"
+source = "git+https://github.com/emilk/egui#36a70e12c3a8a70308a4faa15799d557a5c0a064"
 dependencies = [
  "bytemuck",
  "emath",
@@ -1351,8 +1310,7 @@ dependencies = [
 [[package]]
 name = "eframe"
 version = "0.29.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ac2645a9bf4826eb4e91488b1f17b8eaddeef09396706b2f14066461338e24f"
+source = "git+https://github.com/emilk/egui#36a70e12c3a8a70308a4faa15799d557a5c0a064"
 dependencies = [
  "ahash",
  "bytemuck",
@@ -1361,7 +1319,7 @@ dependencies = [
  "egui-wgpu",
  "egui-winit",
  "egui_glow",
- "glow 0.14.2",
+ "glow 0.16.0",
  "glutin",
  "glutin-winit",
  "image",
@@ -1372,7 +1330,7 @@ dependencies = [
  "objc2-foundation",
  "parking_lot 0.12.3",
  "percent-encoding",
- "pollster",
+ "pollster 0.4.0",
  "raw-window-handle",
  "static_assertions",
  "wasm-bindgen",
@@ -1381,15 +1339,14 @@ dependencies = [
  "web-time",
  "wgpu",
  "winapi",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
  "winit",
 ]
 
 [[package]]
 name = "egui"
 version = "0.29.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53eafabcce0cb2325a59a98736efe0bf060585b437763f8c476957fb274bb974"
+source = "git+https://github.com/emilk/egui#36a70e12c3a8a70308a4faa15799d557a5c0a064"
 dependencies = [
  "accesskit",
  "ahash",
@@ -1403,8 +1360,7 @@ dependencies = [
 [[package]]
 name = "egui-wgpu"
 version = "0.29.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d00fd5d06d8405397e64a928fa0ef3934b3c30273ea7603e3dc4627b1f7a1a82"
+source = "git+https://github.com/emilk/egui#36a70e12c3a8a70308a4faa15799d557a5c0a064"
 dependencies = [
  "ahash",
  "bytemuck",
@@ -1422,8 +1378,7 @@ dependencies = [
 [[package]]
 name = "egui-winit"
 version = "0.29.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a9c430f4f816340e8e8c1b20eec274186b1be6bc4c7dfc467ed50d57abc36c6"
+source = "git+https://github.com/emilk/egui#36a70e12c3a8a70308a4faa15799d557a5c0a064"
 dependencies = [
  "accesskit_winit",
  "ahash",
@@ -1440,8 +1395,7 @@ dependencies = [
 [[package]]
 name = "egui_extras"
 version = "0.29.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf3c1f5cd8dfe2ade470a218696c66cf556fcfd701e7830fa2e9f4428292a2a1"
+source = "git+https://github.com/emilk/egui#36a70e12c3a8a70308a4faa15799d557a5c0a064"
 dependencies = [
  "ahash",
  "egui",
@@ -1454,13 +1408,12 @@ dependencies = [
 [[package]]
 name = "egui_glow"
 version = "0.29.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e39bccc683cd43adab530d8f21a13eb91e80de10bcc38c3f1c16601b6f62b26"
+source = "git+https://github.com/emilk/egui#36a70e12c3a8a70308a4faa15799d557a5c0a064"
 dependencies = [
  "ahash",
  "bytemuck",
  "egui",
- "glow 0.14.2",
+ "glow 0.16.0",
  "log",
  "memoffset 0.9.1",
  "wasm-bindgen",
@@ -1477,8 +1430,7 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
 [[package]]
 name = "emath"
 version = "0.29.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1fe0049ce51d0fb414d029e668dd72eb30bc2b739bf34296ed97bd33df544f3"
+source = "git+https://github.com/emilk/egui#36a70e12c3a8a70308a4faa15799d557a5c0a064"
 dependencies = [
  "bytemuck",
 ]
@@ -1513,7 +1465,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -1534,7 +1486,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -1563,8 +1515,7 @@ dependencies = [
 [[package]]
 name = "epaint"
 version = "0.29.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a32af8da821bd4f43f2c137e295459ee2e1661d87ca8779dfa0eaf45d870e20f"
+source = "git+https://github.com/emilk/egui#36a70e12c3a8a70308a4faa15799d557a5c0a064"
 dependencies = [
  "ab_glyph",
  "ahash",
@@ -1580,8 +1531,7 @@ dependencies = [
 [[package]]
 name = "epaint_default_fonts"
 version = "0.29.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "483440db0b7993cf77a20314f08311dbe95675092405518c0677aa08c151a3ea"
+source = "git+https://github.com/emilk/egui#36a70e12c3a8a70308a4faa15799d557a5c0a064"
 
 [[package]]
 name = "equivalent"
@@ -1591,12 +1541,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
 [[package]]
 name = "errno"
-version = "0.3.9"
+version = "0.3.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
 dependencies = [
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1618,9 +1568,9 @@ dependencies = [
 
 [[package]]
 name = "event-listener-strategy"
-version = "0.5.2"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
+checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2"
 dependencies = [
  "event-listener",
  "pin-project-lite",
@@ -1643,15 +1593,15 @@ dependencies = [
 
 [[package]]
 name = "fastrand"
-version = "2.2.0"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "fdeflate"
-version = "0.3.6"
+version = "0.3.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07c6f4c64c1d33a3111c4466f7365ebdcc37c5bd1ea0d62aae2e3d722aacbedb"
+checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
 dependencies = [
  "simd-adler32",
 ]
@@ -1704,15 +1654,15 @@ dependencies = [
 
 [[package]]
 name = "flexi_logger"
-version = "0.29.6"
+version = "0.29.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d26948e37cfcb1f2c2cd38e0602d3a8ab6b9472c0c6eff4516fc8def9a3124d7"
+checksum = "4613c3fa90ebf91dff72ff383a9324329c017819711bda86142be81368ac6fad"
 dependencies = [
  "chrono",
  "log",
  "nu-ansi-term",
  "regex",
- "thiserror 1.0.69",
+ "thiserror 2.0.6",
 ]
 
 [[package]]
@@ -1721,6 +1671,12 @@ version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
+[[package]]
+name = "foldhash"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
+
 [[package]]
 name = "foreign-types"
 version = "0.5.0"
@@ -1739,7 +1695,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -1826,7 +1782,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -1921,9 +1877,9 @@ dependencies = [
 
 [[package]]
 name = "glow"
-version = "0.13.1"
+version = "0.14.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1"
+checksum = "d51fa363f025f5c111e03f13eda21162faeacb6911fe8caa0c0349f9cf0c4483"
 dependencies = [
  "js-sys",
  "slotmap",
@@ -1933,9 +1889,9 @@ dependencies = [
 
 [[package]]
 name = "glow"
-version = "0.14.2"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d51fa363f025f5c111e03f13eda21162faeacb6911fe8caa0c0349f9cf0c4483"
+checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08"
 dependencies = [
  "js-sys",
  "slotmap",
@@ -2030,15 +1986,14 @@ dependencies = [
 
 [[package]]
 name = "gpu-allocator"
-version = "0.26.0"
+version = "0.27.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdd4240fc91d3433d5e5b0fc5b67672d771850dc19bbee03c1381e19322803d7"
+checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd"
 dependencies = [
  "log",
  "presser",
  "thiserror 1.0.69",
- "winapi",
- "windows 0.52.0",
+ "windows 0.58.0",
 ]
 
 [[package]]
@@ -2137,23 +2092,11 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.15.1"
+version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
-
-[[package]]
-name = "hassle-rs"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
 dependencies = [
- "bitflags 2.6.0",
- "com",
- "libc",
- "libloading",
- "thiserror 1.0.69",
- "widestring",
- "winapi",
+ "foldhash",
 ]
 
 [[package]]
@@ -2162,12 +2105,6 @@ version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
-[[package]]
-name = "hermit-abi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
-
 [[package]]
 name = "hermit-abi"
 version = "0.4.0"
@@ -2206,9 +2143,9 @@ dependencies = [
 
 [[package]]
 name = "http"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
+checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
 dependencies = [
  "bytes",
  "fnv",
@@ -2252,9 +2189,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
 [[package]]
 name = "hyper"
-version = "1.5.0"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a"
+checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -2444,7 +2381,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -2518,12 +2455,12 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.6.0"
+version = "2.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
+checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
 dependencies = [
  "equivalent",
- "hashbrown 0.15.1",
+ "hashbrown 0.15.2",
 ]
 
 [[package]]
@@ -2555,7 +2492,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -2599,9 +2536,9 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "1.0.11"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
 
 [[package]]
 name = "jni"
@@ -2642,10 +2579,11 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
 
 [[package]]
 name = "js-sys"
-version = "0.3.72"
+version = "0.3.76"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
+checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
 dependencies = [
+ "once_cell",
  "wasm-bindgen",
 ]
 
@@ -2680,9 +2618,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
 
 [[package]]
 name = "libc"
-version = "0.2.164"
+version = "0.2.168"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
+checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
 
 [[package]]
 name = "libfuzzer-sys"
@@ -2696,9 +2634,9 @@ dependencies = [
 
 [[package]]
 name = "libloading"
-version = "0.8.5"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
+checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
 dependencies = [
  "cfg-if",
  "windows-targets 0.52.6",
@@ -2712,7 +2650,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
 dependencies = [
  "bitflags 2.6.0",
  "libc",
- "redox_syscall 0.5.7",
+ "redox_syscall 0.5.8",
 ]
 
 [[package]]
@@ -2723,9 +2661,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
 
 [[package]]
 name = "litemap"
-version = "0.7.3"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704"
+checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
 
 [[package]]
 name = "litrs"
@@ -2886,11 +2824,10 @@ dependencies = [
 
 [[package]]
 name = "mio"
-version = "1.0.2"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
+checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
 dependencies = [
- "hermit-abi 0.3.9",
  "libc",
  "wasi",
  "windows-sys 0.52.0",
@@ -2898,9 +2835,9 @@ dependencies = [
 
 [[package]]
 name = "naga"
-version = "22.1.0"
+version = "23.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bd5a652b6faf21496f2cfd88fc49989c8db0825d1f6746b1a71a6ede24a63ad"
+checksum = "3d5941e45a15b53aad4375eedf02033adb7a28931eedc31117faffa52e6a857e"
 dependencies = [
  "arrayvec",
  "bit-set",
@@ -3066,7 +3003,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -3126,7 +3063,7 @@ dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -3439,7 +3376,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall 0.5.7",
+ "redox_syscall 0.5.8",
  "smallvec",
  "windows-targets 0.52.6",
 ]
@@ -3483,7 +3420,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -3517,9 +3454,9 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
 
 [[package]]
 name = "png"
-version = "0.17.14"
+version = "0.17.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0"
+checksum = "b67582bd5b65bdff614270e2ea89a1cf15bef71245cc1e5f7ea126977144211d"
 dependencies = [
  "bitflags 1.3.2",
  "crc32fast",
@@ -3536,7 +3473,7 @@ checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f"
 dependencies = [
  "cfg-if",
  "concurrent-queue",
- "hermit-abi 0.4.0",
+ "hermit-abi",
  "pin-project-lite",
  "rustix",
  "tracing",
@@ -3549,6 +3486,12 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2"
 
+[[package]]
+name = "pollster"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3"
+
 [[package]]
 name = "portable-pty"
 version = "0.8.1"
@@ -3602,9 +3545,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.89"
+version = "1.0.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
 dependencies = [
  "unicode-ident",
 ]
@@ -3625,7 +3568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30"
 dependencies = [
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -3672,10 +3615,10 @@ dependencies = [
  "pin-project-lite",
  "quinn-proto",
  "quinn-udp",
- "rustc-hash 2.0.0",
+ "rustc-hash 2.1.0",
  "rustls",
  "socket2",
- "thiserror 2.0.3",
+ "thiserror 2.0.6",
  "tokio",
  "tracing",
 ]
@@ -3690,11 +3633,11 @@ dependencies = [
  "getrandom",
  "rand",
  "ring",
- "rustc-hash 2.0.0",
+ "rustc-hash 2.1.0",
  "rustls",
  "rustls-pki-types",
  "slab",
- "thiserror 2.0.3",
+ "thiserror 2.0.6",
  "tinyvec",
  "tracing",
  "web-time",
@@ -3702,9 +3645,9 @@ dependencies = [
 
 [[package]]
 name = "quinn-udp"
-version = "0.5.7"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da"
+checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527"
 dependencies = [
  "cfg_aliases 0.2.1",
  "libc",
@@ -3872,9 +3815,9 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.7"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
+checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
 dependencies = [
  "bitflags 2.6.0",
 ]
@@ -4026,7 +3969,7 @@ dependencies = [
  "objc2",
  "objc2-app-kit",
  "objc2-foundation",
- "pollster",
+ "pollster 0.3.0",
  "raw-window-handle",
  "urlencoding",
  "wasm-bindgen",
@@ -4070,9 +4013,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 
 [[package]]
 name = "rustc-hash"
-version = "2.0.0"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
+checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
 
 [[package]]
 name = "rustc_version"
@@ -4085,22 +4028,22 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.38.41"
+version = "0.38.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6"
+checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
 dependencies = [
  "bitflags 2.6.0",
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "rustls"
-version = "0.23.17"
+version = "0.23.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f1a745511c54ba6d4465e8d5dfbd81b45791756de28d4981af70d6dca128f1e"
+checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b"
 dependencies = [
  "once_cell",
  "ring",
@@ -4199,9 +4142,9 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4"
 
 [[package]]
 name = "serde"
-version = "1.0.215"
+version = "1.0.216"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
+checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
 dependencies = [
  "serde_derive",
 ]
@@ -4217,13 +4160,13 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.215"
+version = "1.0.216"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
+checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -4246,7 +4189,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -4440,9 +4383,9 @@ dependencies = [
 
 [[package]]
 name = "socket2"
-version = "0.5.7"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
+checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
 dependencies = [
  "libc",
  "windows-sys 0.52.0",
@@ -4521,7 +4464,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "rustversion",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -4542,20 +4485,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.109"
+version = "2.0.90"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.87"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
+checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4564,9 +4496,9 @@ dependencies = [
 
 [[package]]
 name = "sync_wrapper"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
 dependencies = [
  "futures-core",
 ]
@@ -4579,14 +4511,14 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
 name = "sysinfo"
-version = "0.32.0"
+version = "0.32.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3b5ae3f4f7d64646c46c4cae4e3f01d1c5d255c7406fdd7c7f999a94e488791"
+checksum = "4c33cd241af0f2e9e3b5c32163b873b29956890b5342e6745b917ce9d490f4af"
 dependencies = [
  "core-foundation-sys",
  "libc",
@@ -4667,11 +4599,11 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "2.0.3"
+version = "2.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa"
+checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47"
 dependencies = [
- "thiserror-impl 2.0.3",
+ "thiserror-impl 2.0.6",
 ]
 
 [[package]]
@@ -4682,18 +4614,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "2.0.3"
+version = "2.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
+checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -4709,9 +4641,9 @@ dependencies = [
 
 [[package]]
 name = "time"
-version = "0.3.36"
+version = "0.3.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
+checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
 dependencies = [
  "deranged",
  "num-conv",
@@ -4778,9 +4710,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.41.1"
+version = "1.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33"
+checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
 dependencies = [
  "backtrace",
  "bytes",
@@ -4801,17 +4733,16 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
 name = "tokio-rustls"
-version = "0.26.0"
+version = "0.26.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
+checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37"
 dependencies = [
  "rustls",
- "rustls-pki-types",
  "tokio",
 ]
 
@@ -4867,9 +4798,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
 
 [[package]]
 name = "tracing"
-version = "0.1.40"
+version = "0.1.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
 dependencies = [
  "pin-project-lite",
  "tracing-attributes",
@@ -4878,20 +4809,20 @@ dependencies = [
 
 [[package]]
 name = "tracing-attributes"
-version = "0.1.27"
+version = "0.1.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
+checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
 name = "tracing-core"
-version = "0.1.32"
+version = "0.1.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
 dependencies = [
  "once_cell",
 ]
@@ -4904,9 +4835,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
 
 [[package]]
 name = "ttf-parser"
-version = "0.25.0"
+version = "0.25.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5902c5d130972a0000f60860bfbf46f7ca3db5391eddfedd1b8728bd9dc96c0e"
+checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
 
 [[package]]
 name = "type-map"
@@ -4951,9 +4882,9 @@ checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.13"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
 
 [[package]]
 name = "unicode-segmentation"
@@ -4981,9 +4912,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
 
 [[package]]
 name = "url"
-version = "2.5.3"
+version = "2.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada"
+checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
 dependencies = [
  "form_urlencoded",
  "idna",
@@ -5091,9 +5022,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.95"
+version = "0.2.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
+checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
 dependencies = [
  "cfg-if",
  "once_cell",
@@ -5102,36 +5033,36 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.95"
+version = "0.2.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
+checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
 dependencies = [
  "bumpalo",
  "log",
- "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.45"
+version = "0.4.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b"
+checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2"
 dependencies = [
  "cfg-if",
  "js-sys",
+ "once_cell",
  "wasm-bindgen",
  "web-sys",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.95"
+version = "0.2.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
+checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -5139,22 +5070,22 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.95"
+version = "0.2.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
+checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.95"
+version = "0.2.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
+checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
 
 [[package]]
 name = "wasm-timer"
@@ -5282,9 +5213,9 @@ dependencies = [
 
 [[package]]
 name = "web-sys"
-version = "0.3.72"
+version = "0.3.76"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
+checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -5302,9 +5233,9 @@ dependencies = [
 
 [[package]]
 name = "webbrowser"
-version = "1.0.2"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e5f07fb9bc8de2ddfe6b24a71a75430673fd679e568c48b52716cef1cfae923"
+checksum = "ea9fe1ebb156110ff855242c1101df158b822487e4957b0556d9ffce9db0f535"
 dependencies = [
  "block2",
  "core-foundation 0.10.0",
@@ -5320,9 +5251,9 @@ dependencies = [
 
 [[package]]
 name = "webpki-roots"
-version = "0.26.6"
+version = "0.26.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958"
+checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e"
 dependencies = [
  "rustls-pki-types",
 ]
@@ -5335,9 +5266,9 @@ checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
 
 [[package]]
 name = "wgpu"
-version = "22.1.0"
+version = "23.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1d1c4ba43f80542cf63a0a6ed3134629ae73e8ab51e4b765a67f3aa062eb433"
+checksum = "80f70000db37c469ea9d67defdc13024ddf9a5f1b89cb2941b812ad7cde1735a"
 dependencies = [
  "arrayvec",
  "cfg_aliases 0.1.1",
@@ -5360,9 +5291,9 @@ dependencies = [
 
 [[package]]
 name = "wgpu-core"
-version = "22.1.0"
+version = "23.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0348c840d1051b8e86c3bcd31206080c5e71e5933dabd79be1ce732b0b2f089a"
+checksum = "d63c3c478de8e7e01786479919c8769f62a22eec16788d8c2ac77ce2c132778a"
 dependencies = [
  "arrayvec",
  "bit-vec",
@@ -5385,9 +5316,9 @@ dependencies = [
 
 [[package]]
 name = "wgpu-hal"
-version = "22.0.0"
+version = "23.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6bbf4b4de8b2a83c0401d9e5ae0080a2792055f25859a02bf9be97952bbed4f"
+checksum = "89364b8a0b211adc7b16aeaf1bd5ad4a919c1154b44c9ce27838213ba05fd821"
 dependencies = [
  "android_system_properties",
  "arrayvec",
@@ -5395,15 +5326,14 @@ dependencies = [
  "bit-set",
  "bitflags 2.6.0",
  "block",
+ "bytemuck",
  "cfg_aliases 0.1.1",
  "core-graphics-types",
- "d3d12",
- "glow 0.13.1",
+ "glow 0.14.2",
  "glutin_wgl_sys",
  "gpu-alloc",
  "gpu-allocator",
  "gpu-descriptor",
- "hassle-rs",
  "js-sys",
  "khronos-egl",
  "libc",
@@ -5425,26 +5355,21 @@ dependencies = [
  "wasm-bindgen",
  "web-sys",
  "wgpu-types",
- "winapi",
+ "windows 0.58.0",
+ "windows-core 0.58.0",
 ]
 
 [[package]]
 name = "wgpu-types"
-version = "22.0.0"
+version = "23.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc9d91f0e2c4b51434dfa6db77846f2793149d8e73f800fa2e41f52b8eac3c5d"
+checksum = "610f6ff27778148c31093f3b03abc4840f9636d58d597ca2f5977433acfe0068"
 dependencies = [
  "bitflags 2.6.0",
  "js-sys",
  "web-sys",
 ]
 
-[[package]]
-name = "widestring"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
-
 [[package]]
 name = "winapi"
 version = "0.3.9"
@@ -5476,16 +5401,6 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
-[[package]]
-name = "windows"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
-dependencies = [
- "windows-core 0.52.0",
- "windows-targets 0.52.6",
-]
-
 [[package]]
 name = "windows"
 version = "0.57.0"
@@ -5548,7 +5463,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -5559,7 +5474,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -5570,7 +5485,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -5581,7 +5496,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -6008,15 +5923,15 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
 
 [[package]]
 name = "xml-rs"
-version = "0.8.23"
+version = "0.8.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af310deaae937e48a26602b730250b4949e125f468f11e6990be3e5304ddd96f"
+checksum = "ea8b391c9a790b496184c29f7f93b9ed5b16abb306c05415b68bcc16e4d06432"
 
 [[package]]
 name = "yoke"
-version = "0.7.4"
+version = "0.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5"
+checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
 dependencies = [
  "serde",
  "stable_deref_trait",
@@ -6026,13 +5941,13 @@ dependencies = [
 
 [[package]]
 name = "yoke-derive"
-version = "0.7.4"
+version = "0.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95"
+checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
  "synstructure",
 ]
 
@@ -6128,7 +6043,7 @@ checksum = "709ab20fc57cb22af85be7b360239563209258430bccf38d8b979c5a2ae3ecce"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
  "zbus-lockstep",
  "zbus_xml",
  "zvariant 4.2.0",
@@ -6143,7 +6058,7 @@ dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
  "zvariant_utils 2.1.0",
 ]
 
@@ -6156,7 +6071,7 @@ dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
  "zbus_names 4.1.0",
  "zvariant 5.1.0",
  "zvariant_utils 3.0.2",
@@ -6216,27 +6131,27 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
 name = "zerofrom"
-version = "0.1.4"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55"
+checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
 dependencies = [
  "zerofrom-derive",
 ]
 
 [[package]]
 name = "zerofrom-derive"
-version = "0.1.4"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5"
+checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
  "synstructure",
 ]
 
@@ -6257,7 +6172,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -6279,14 +6194,14 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
 name = "zip"
-version = "2.2.0"
+version = "2.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc5e4288ea4057ae23afc69a4472434a87a2495cafce6632fd1c4ec9f5cf3494"
+checksum = "99d52293fc86ea7cf13971b3bb81eb21683636e7ae24c729cdaf1b7c4157a352"
 dependencies = [
  "aes",
  "arbitrary",
@@ -6304,7 +6219,7 @@ dependencies = [
  "pbkdf2",
  "rand",
  "sha1",
- "thiserror 1.0.69",
+ "thiserror 2.0.6",
  "time",
  "zeroize",
  "zopfli",
@@ -6415,7 +6330,7 @@ dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
  "zvariant_utils 2.1.0",
 ]
 
@@ -6428,7 +6343,7 @@ dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
  "zvariant_utils 3.0.2",
 ]
 
@@ -6440,7 +6355,7 @@ checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn",
 ]
 
 [[package]]
@@ -6453,6 +6368,6 @@ dependencies = [
  "quote",
  "serde",
  "static_assertions",
- "syn 2.0.87",
+ "syn",
  "winnow",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index 77daf58..f02d0f9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -31,8 +31,11 @@ benri = "0.1.12"
 bytes = "1.8.0"
 dirs = "5.0.1"
 #--------------------------------------------------------------------------------
-egui = "0.29.1"
-egui_extras = {version="0.29.1", features = ["image"] }
+# egui = "0.29.1"
+egui = {git="https://github.com/emilk/egui"}
+# egui_extras = {version="0.29.1", features = ["image"] }
+egui_extras = {git="https://github.com/emilk/egui", features = ["image"] }
+
 ## 2023-12-28: https://github.com/hinto-janai/gupax/issues/68
 ##
 ## 2024-03-18: Both `glow` and `wgpu` seem to crash:
@@ -75,7 +78,8 @@ enclose = "1.2.0"
 bounded-vec-deque = {version="0.1.1", default-features=false}
 cfg-if = "1.0"
 flexi_logger = "0.29"
-eframe = {version="0.29.1", features=["wgpu"]}
+# eframe = {version="0.29.1", features=["wgpu"]}
+eframe = {git="https://github.com/emilk/egui", features=["wgpu"]}
 strum = {version="0.26", features=["derive"]}
 # Unix dependencies
 [target.'cfg(unix)'.dependencies]
@@ -97,7 +101,8 @@ sudo = "0.6.0"
 # linked as well which causes problems, so statically link it.
 lzma-sys = { version = "0.1", features = ["static"] }
 [dev-dependencies]
-egui = {version="0.29.1", features=["callstack"]}
+# egui = {version="0.29.1", features=["callstack"]}
+egui = {git="https://github.com/emilk/egui", features=["callstack"]}
 
 # [target.'cfg(not(target_os = "macos"))'.dependencies]
 # tls-api-native-tls = "0.9.0"
@@ -107,7 +112,7 @@ egui = {version="0.29.1", features=["callstack"]}
 # glow start on windows but not wgpu
 # need the same version that eframe is using with egui_wgpu
 # feature angle to enable support for old cpu on Windows
-wgpu = {version = "22.1", features=["angle"]}
+wgpu = {version = "23.0", features=["angle"]}
 zip = "2.2.0"
 is_elevated = "0.1.2"
 
diff --git a/src/app/mod.rs b/src/app/mod.rs
index ec33e39..ffeccfa 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -1,5 +1,13 @@
 use crate::APP_DEFAULT_HEIGHT;
 use crate::APP_DEFAULT_WIDTH;
+use crate::GUPAX_TAB_ABOUT;
+use crate::GUPAX_TAB_GUPAX;
+use crate::GUPAX_TAB_NODE;
+use crate::GUPAX_TAB_P2POOL;
+use crate::GUPAX_TAB_STATUS;
+use crate::GUPAX_TAB_XMRIG;
+use crate::GUPAX_TAB_XMRIG_PROXY;
+use crate::GUPAX_TAB_XVB;
 use crate::GUPAX_VERSION;
 use crate::OS;
 use crate::cli::Cli;
@@ -47,6 +55,7 @@ use log::debug;
 use log::error;
 use log::info;
 use log::warn;
+use panels::middle::common::list_poolnode::PoolNode;
 use serde::Deserialize;
 use serde::Serialize;
 use std::path::PathBuf;
@@ -87,10 +96,10 @@ pub struct App {
     pub update: Arc<Mutex<Update>>, // State for update data [update.rs]
     pub file_window: Arc<Mutex<FileWindow>>, // State for the path selector in [Gupax]
     pub ping: Arc<Mutex<Ping>>,     // Ping data found in [node.rs]
-    pub og_node_vec: Vec<(String, Node)>, // Manual Node database
-    pub node_vec: Vec<(String, Node)>, // Manual Node database
-    pub og_pool_vec: Vec<(String, Pool)>, // Manual Pool database
-    pub pool_vec: Vec<(String, Pool)>, // Manual Pool database
+    pub og_node_vec: Vec<(String, PoolNode)>, // Manual Node database
+    pub node_vec: Vec<(String, PoolNode)>, // Manual Node database
+    pub og_pool_vec: Vec<(String, PoolNode)>, // Manual Pool database
+    pub pool_vec: Vec<(String, PoolNode)>, // Manual Pool database
     pub diff: bool,                 // This bool indicates state changes
     // Restart state:
     // If Gupax updated itself, this represents that the
@@ -136,7 +145,7 @@ pub struct App {
     // Static stuff
     pub benchmarks: Vec<Benchmark>,     // XMRig CPU benchmarks
     pub pid: sysinfo::Pid,              // Gupax's PID
-    pub max_threads: usize,             // Max amount of detected system threads
+    pub max_threads: u16,               // Max amount of detected system threads
     pub now: Instant,                   // Internal timer
     pub exe: String,                    // Path for [Gupax] binary
     pub dir: String,                    // Directory [Gupax] binary is in
@@ -311,7 +320,7 @@ impl App {
             pub_sys,
             benchmarks,
             pid,
-            max_threads: benri::threads!(),
+            max_threads: benri::threads!() as u16,
             now,
             admin: false,
             exe: String::new(),
@@ -511,65 +520,83 @@ impl App {
         }
         // Handle [node_vec] overflow
         info!("App Init | Handling [node_vec] overflow");
-        if og.p2pool.selected_index > app.og_node_vec.len() {
+        if og.p2pool.selected_node.index > app.og_node_vec.len() {
             warn!(
                 "App | Overflowing manual node index [{} > {}]",
-                og.p2pool.selected_index,
+                og.p2pool.selected_node.index,
                 app.og_node_vec.len()
             );
             let (name, node) = match app.og_node_vec.first() {
                 Some(zero) => zero.clone(),
                 None => Node::new_tuple(),
             };
-            og.p2pool.selected_index = 0;
-            og.p2pool.selected_name.clone_from(&name);
-            og.p2pool.selected_ip.clone_from(&node.ip);
-            og.p2pool.selected_rpc.clone_from(&node.rpc);
-            og.p2pool.selected_zmq.clone_from(&node.zmq);
-            app.state.p2pool.selected_index = 0;
-            app.state.p2pool.selected_name = name;
-            app.state.p2pool.selected_ip = node.ip;
-            app.state.p2pool.selected_rpc = node.rpc;
-            app.state.p2pool.selected_zmq = node.zmq;
+            og.p2pool.selected_node.index = 0;
+            og.p2pool.selected_node.name.clone_from(&name);
+            og.p2pool
+                .selected_node
+                .ip
+                .clone_from(&node.ip().to_string());
+            og.p2pool
+                .selected_node
+                .rpc
+                .clone_from(&node.port().to_string());
+            og.p2pool
+                .selected_node
+                .zmq_rig
+                .clone_from(&node.custom().to_string());
+            app.state.p2pool.selected_node.index = 0;
+            app.state.p2pool.selected_node.name = name;
+            app.state.p2pool.selected_node.ip = node.ip().to_string();
+            app.state.p2pool.selected_node.rpc = node.port().to_string();
+            app.state.p2pool.selected_node.zmq_rig = node.custom().to_string();
         }
         // Handle [pool_vec] overflow
         info!("App Init | Handling [pool_vec] overflow...");
-        if og.xmrig.selected_index > app.og_pool_vec.len() {
+        if og.xmrig.selected_pool.index > app.og_pool_vec.len() {
             warn!(
                 "App | Overflowing manual pool index [{} > {}], resetting to 1",
-                og.xmrig.selected_index,
+                og.xmrig.selected_pool.index,
                 app.og_pool_vec.len()
             );
             let (name, pool) = match app.og_pool_vec.first() {
                 Some(zero) => zero.clone(),
                 None => Pool::new_tuple(),
             };
-            og.xmrig.selected_index = 0;
-            og.xmrig.selected_name.clone_from(&name);
-            og.xmrig.selected_ip.clone_from(&pool.ip);
-            og.xmrig.selected_port.clone_from(&pool.port);
-            app.state.xmrig.selected_index = 0;
-            app.state.xmrig.selected_name = name;
-            app.state.xmrig.selected_ip = pool.ip;
-            app.state.xmrig.selected_port = pool.port;
-            if og.xmrig_proxy.selected_index > app.og_pool_vec.len() {
+            og.xmrig.selected_pool.index = 0;
+            og.xmrig.selected_pool.name.clone_from(&name);
+            og.xmrig.selected_pool.ip.clone_from(&pool.ip().to_string());
+            og.xmrig
+                .selected_pool
+                .rpc
+                .clone_from(&pool.port().to_string());
+            app.state.xmrig.selected_pool.index = 0;
+            app.state.xmrig.selected_pool.name = name;
+            app.state.xmrig.selected_pool.ip = pool.ip().to_string();
+            app.state.xmrig.selected_pool.rpc = pool.port().to_string();
+            if og.xmrig_proxy.selected_pool.index > app.og_pool_vec.len() {
                 warn!(
                     "App | Overflowing manual pool index [{} > {}], resetting to 1",
-                    og.xmrig_proxy.selected_index,
+                    og.xmrig_proxy.selected_pool.index,
                     app.og_pool_vec.len()
                 );
                 let (name, pool) = match app.og_pool_vec.first() {
                     Some(zero) => zero.clone(),
                     None => Pool::new_tuple(),
                 };
-                og.xmrig_proxy.selected_index = 0;
-                og.xmrig_proxy.selected_name.clone_from(&name);
-                og.xmrig_proxy.selected_ip.clone_from(&pool.ip);
-                og.xmrig_proxy.selected_port.clone_from(&pool.port);
-                app.state.xmrig_proxy.selected_index = 0;
-                app.state.xmrig_proxy.selected_name = name;
-                app.state.xmrig_proxy.selected_ip = pool.ip;
-                app.state.xmrig_proxy.selected_port = pool.port;
+                og.xmrig_proxy.selected_pool.index = 0;
+                og.xmrig_proxy.selected_pool.name.clone_from(&name);
+                og.xmrig_proxy
+                    .selected_pool
+                    .ip
+                    .clone_from(&pool.ip().to_string());
+                og.xmrig_proxy
+                    .selected_pool
+                    .rpc
+                    .clone_from(&pool.port().to_string());
+                app.state.xmrig_proxy.selected_pool.index = 0;
+                app.state.xmrig_proxy.selected_pool.name = name;
+                app.state.xmrig_proxy.selected_pool.ip = pool.ip().to_string();
+                app.state.xmrig_proxy.selected_pool.rpc = pool.port().to_string();
             }
         }
 
@@ -648,7 +675,7 @@ impl App {
 
     #[cold]
     #[inline(never)]
-    pub fn gather_backup_hosts(&self) -> Option<Vec<Node>> {
+    pub fn gather_backup_hosts(&self) -> Option<Vec<PoolNode>> {
         if !self.state.p2pool.backup_host {
             return None;
         }
@@ -695,7 +722,7 @@ impl App {
                     zmq: zmq.into(),
                 };
 
-                vec.push(node);
+                vec.push(PoolNode::Node(node));
             }
 
             if vec.is_empty() {
@@ -747,6 +774,18 @@ impl Tab {
             Tab::Xvb => Some(ProcessName::Xvb),
         }
     }
+    pub fn msg_default_tab(&self) -> &str {
+        match self {
+            Tab::About => GUPAX_TAB_ABOUT,
+            Tab::Status => GUPAX_TAB_STATUS,
+            Tab::Gupax => GUPAX_TAB_GUPAX,
+            Tab::Node => GUPAX_TAB_NODE,
+            Tab::P2pool => GUPAX_TAB_P2POOL,
+            Tab::Xmrig => GUPAX_TAB_XMRIG,
+            Tab::XmrigProxy => GUPAX_TAB_XMRIG_PROXY,
+            Tab::Xvb => GUPAX_TAB_XVB,
+        }
+    }
 }
 //---------------------------------------------------------------------------------------------------- [Restart] Enum
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
diff --git a/src/app/panels/bottom.rs b/src/app/panels/bottom.rs
index b634d1a..826b19d 100644
--- a/src/app/panels/bottom.rs
+++ b/src/app/panels/bottom.rs
@@ -207,16 +207,30 @@ impl crate::app::App {
             let restart_msg = format!("Restart {}", name);
             if process.waiting {
                 ui.add_enabled_ui(false, |ui| {
-                    ui.add_sized(size, Button::new("⟲"))
+                    ui.add_sized(size, Button::new("▶"))
                         .on_disabled_hover_text(process.run_middle_msg());
                     ui.add(Separator::default().grow(0.0));
                     ui.add_sized(size, Button::new("⏹"))
                         .on_disabled_hover_text(process.run_middle_msg());
                     ui.add(Separator::default().grow(0.0));
-                    ui.add_sized(size, Button::new("▶"))
+                    ui.add_sized(size, Button::new("⟲"))
                         .on_disabled_hover_text(process.run_middle_msg());
                 });
             } else if process.alive {
+                ui.add_enabled_ui(false, |ui| {
+                    ui.add_sized(size, Button::new("▶"))
+                        .on_disabled_hover_text(start_msg)
+                });
+                ui.add(Separator::default().grow(0.0));
+                if key.is_down() && !wants_input
+                    || ui
+                        .add_sized(size, Button::new("⏹"))
+                        .on_hover_text(stop_msg)
+                        .clicked()
+                {
+                    process.stop(&self.helper);
+                }
+                ui.add(Separator::default().grow(0.0));
                 if key.is_up() && !wants_input
                     || ui
                         .add_sized(size, Button::new("⟲"))
@@ -274,29 +288,7 @@ impl crate::app::App {
                         }
                     }
                 }
-                ui.add(Separator::default().grow(0.0));
-                if key.is_down() && !wants_input
-                    || ui
-                        .add_sized(size, Button::new("⏹"))
-                        .on_hover_text(stop_msg)
-                        .clicked()
-                {
-                    process.stop(&self.helper);
-                }
-                ui.add(Separator::default().grow(0.0));
-                ui.add_enabled_ui(false, |ui| {
-                    ui.add_sized(size, Button::new("▶"))
-                        .on_disabled_hover_text(start_msg)
-                });
             } else {
-                ui.add_enabled_ui(false, |ui| {
-                    ui.add_sized(size, Button::new("⟲"))
-                        .on_disabled_hover_text(restart_msg);
-                    ui.add(Separator::default().grow(0.0));
-                    ui.add_sized(size, Button::new("⏹"))
-                        .on_disabled_hover_text(stop_msg);
-                    ui.add(Separator::default().grow(0.0));
-                });
                 let text_err = self.start_ready(process).err().unwrap_or_default();
                 let ui_enabled = text_err.is_empty();
                 ui.add_enabled_ui(ui_enabled, |ui| {
@@ -354,6 +346,14 @@ impl crate::app::App {
                         }
                     }
                 });
+                ui.add_enabled_ui(false, |ui| {
+                    ui.add_sized(size, Button::new("⏹"))
+                        .on_disabled_hover_text(stop_msg);
+                    ui.add(Separator::default().grow(0.0));
+                    ui.add_sized(size, Button::new("⟲"))
+                        .on_disabled_hover_text(restart_msg);
+                    ui.add(Separator::default().grow(0.0));
+                });
             }
         });
     }
diff --git a/src/app/panels/middle/common/console.rs b/src/app/panels/middle/common/console.rs
new file mode 100644
index 0000000..48218e2
--- /dev/null
+++ b/src/app/panels/middle/common/console.rs
@@ -0,0 +1,73 @@
+use std::sync::{Arc, Mutex};
+
+use egui::{Label, TextEdit, TextStyle, Ui};
+
+use crate::{DARK_GRAY, helper::Process, miscs::height_txt_before_button, regex::num_lines};
+
+pub fn console(ui: &mut Ui, text: &str) {
+    let nb_lines = num_lines(text);
+    let height = ui.available_height() / 2.8;
+    egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
+        ui.style_mut().override_text_style = Some(TextStyle::Small);
+        egui::ScrollArea::vertical()
+            .stick_to_bottom(true)
+            .max_width(ui.available_width())
+            .max_height(height)
+            .auto_shrink([false; 2])
+            // .show_viewport(ui, |ui, _| {
+            .show_rows(
+                ui,
+                ui.text_style_height(&TextStyle::Small),
+                nb_lines,
+                |ui, row_range| {
+                    for i in row_range {
+                        if let Some(line) = text.lines().nth(i) {
+                            ui.label(line);
+                        }
+                    }
+                },
+            );
+    });
+}
+
+// input args
+pub fn input_args_field(
+    ui: &mut Ui,
+    buffer: &mut String,
+    process: &Arc<Mutex<Process>>,
+    hint: &str,
+    hover: &str,
+) {
+    ui.style_mut().spacing.text_edit_width = ui.available_width();
+    let response = ui
+        .add(TextEdit::hint_text(TextEdit::singleline(buffer), hint))
+        .on_hover_text(hover);
+    // If the user pressed enter, dump buffer contents into the process STDIN
+    if response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
+        response.request_focus(); // Get focus back
+        let buffer = std::mem::take(buffer); // Take buffer
+        let mut process = process.lock().unwrap();
+        if process.is_alive() {
+            process.input.push(buffer);
+        } // Push only if alive
+    }
+}
+
+// Command arguments
+pub fn start_options_field(ui: &mut Ui, arguments: &mut String, hint: &str, hover: &str) {
+    ui.group(|ui| {
+        ui.horizontal(|ui| {
+            ui.add_sized(
+                [0.0, height_txt_before_button(ui, &TextStyle::Body)],
+                Label::new("Command arguments:"),
+            );
+            ui.style_mut().spacing.text_edit_width = ui.available_width();
+            ui.add(TextEdit::hint_text(TextEdit::singleline(arguments), hint))
+                .on_hover_text(hover);
+            arguments.truncate(1024);
+        })
+    });
+    if !arguments.is_empty() {
+        ui.disable();
+    }
+}
diff --git a/src/app/panels/middle/common/header_tab.rs b/src/app/panels/middle/common/header_tab.rs
new file mode 100644
index 0000000..f287ce1
--- /dev/null
+++ b/src/app/panels/middle/common/header_tab.rs
@@ -0,0 +1,83 @@
+use egui::{Hyperlink, Image, Separator, TextStyle, TextWrapMode, Ui};
+use log::debug;
+
+use crate::SPACE;
+/// logo first, first hyperlink will be the header, description under.
+/// will take care of centering widgets if boerder weight is more than 0.
+#[allow(clippy::needless_range_loop)]
+pub fn header_tab(
+    ui: &mut Ui,
+    logo: Option<Image>,
+    // text, link, hover text
+    links: &[(&str, &str, &str)],
+    subtitle: Option<String>,
+    one_line_center: bool,
+) {
+    // width - logo and links and separators divided by double the size of logo (can't know width of links).
+    ui.style_mut().wrap_mode = Some(TextWrapMode::Extend);
+    ui.style_mut().override_text_style = Some(TextStyle::Heading);
+    ui.add_space(SPACE);
+    if one_line_center {
+        let height = 64.0;
+        let nb_links = links.len();
+        let border_weight = ((ui.available_width()
+            - ((height * 4.0 * nb_links as f32) + if logo.is_some() { height * 2.0 } else { 0.0 }))
+            / (height * 2.0))
+            .max(0.0) as usize;
+        // nb_columns add logo if exist plus number of links with separator for each + number of column for border space
+        let nb_columns = if logo.is_some() { 1 } else { 0 } + (links.len() * 2) + border_weight * 2;
+        ui.columns(nb_columns, |col| {
+            // first column for left border
+            for n in 0..(border_weight) {
+                col[n].vertical_centered(|ui| ui.add_space(0.0));
+                debug!("left side space: {}", n);
+            }
+            // jump first column, stop less 2, because begin at 0 and end with space column.
+            let mut nb_col = border_weight;
+            if let Some(logo) = logo {
+                debug!("logo: {}", nb_col);
+                col[nb_col].vertical_centered(|ui| ui.add_sized([height, height], logo));
+                nb_col += 1;
+            }
+            for link in links {
+                debug!("separator: {}", nb_col);
+                col[nb_col].vertical_centered(|ui| {
+                    ui.add_sized(
+                        [height / 8.0, height],
+                        Separator::default().vertical().spacing(height / 8.0),
+                    )
+                });
+                nb_col += 1;
+
+                debug!("link: {}", nb_col);
+                col[nb_col].vertical_centered(|ui| {
+                    ui.add_sized(
+                        [ui.available_width(), height],
+                        Hyperlink::from_label_and_url(link.0, link.1),
+                    );
+                });
+                nb_col += 1;
+            }
+
+            for n in nb_col..(nb_col + border_weight) {
+                debug!("right side border space: {}", n);
+                col[n].vertical_centered(|ui| ui.add_space(0.0));
+            }
+        });
+    } else {
+        // top down
+        ui.vertical_centered(|ui| {
+            if let Some(source) = logo {
+                ui.add(source);
+            }
+            for link in links {
+                ui.hyperlink_to(link.0, link.1);
+            }
+            ui.style_mut().override_text_style = Some(TextStyle::Body);
+        });
+    }
+    if let Some(desc) = subtitle {
+        ui.label(desc);
+    }
+    ui.add_space(SPACE);
+}
diff --git a/src/app/panels/middle/common/list_poolnode.rs b/src/app/panels/middle/common/list_poolnode.rs
new file mode 100644
index 0000000..93cd16c
--- /dev/null
+++ b/src/app/panels/middle/common/list_poolnode.rs
@@ -0,0 +1,330 @@
+use egui::{Button, ComboBox, RichText, SelectableLabel, Ui};
+use log::{debug, info};
+
+use crate::{
+    LIST_ADD, LIST_CLEAR, LIST_DELETE, LIST_SAVE,
+    disk::{node::Node, pool::Pool, state::SelectedPoolNode},
+};
+#[derive(Clone, Debug, PartialEq)]
+pub enum PoolNode {
+    Node(Node),
+    Pool(Pool),
+}
+
+impl PoolNode {
+    pub fn ip(&self) -> &str {
+        match &self {
+            PoolNode::Node(n) => &n.ip,
+            PoolNode::Pool(p) => &p.ip,
+        }
+    }
+    pub fn port(&self) -> &str {
+        match &self {
+            PoolNode::Node(n) => &n.rpc,
+            PoolNode::Pool(p) => &p.port,
+        }
+    }
+    pub fn custom(&self) -> &str {
+        match &self {
+            PoolNode::Node(n) => &n.zmq,
+            PoolNode::Pool(p) => &p.rig,
+        }
+    }
+    pub fn custom_name(&self) -> &str {
+        match &self {
+            PoolNode::Node(_) => "ZMQ",
+            PoolNode::Pool(_) => "rig",
+        }
+    }
+    fn set_ip(&mut self, new_ip: String) {
+        match self {
+            PoolNode::Node(n) => n.ip = new_ip,
+            PoolNode::Pool(p) => p.ip = new_ip,
+        }
+    }
+    fn set_port(&mut self, new_port: String) {
+        match self {
+            PoolNode::Node(n) => n.rpc = new_port,
+            PoolNode::Pool(p) => p.port = new_port,
+        }
+    }
+    fn set_custom(&mut self, new_custom: String) {
+        match self {
+            PoolNode::Node(n) => n.zmq = new_custom,
+            PoolNode::Pool(p) => p.rig = new_custom,
+        }
+    }
+    // pub fn from_vec_node(vec_node: Vec<(String, Node)>) -> Vec<(String, Self)> {
+    //     vec_node
+    //         .into_iter()
+    //         .map(|(name, node)| (name, PoolNode::Node(node)))
+    //         .collect()
+    // }
+    // pub fn from_vec_pool(vec_node: Vec<(String, Pool)>) -> Vec<(String, Self)> {
+    //     vec_node
+    //         .into_iter()
+    //         .map(|(name, pool)| (name, PoolNode::Pool(pool)))
+    //         .collect()
+    // }
+}
+/// compatible for P2Pool and Xmrig/Proxy
+/// current is (name, ip, port, zmq/rig)
+pub fn list_poolnode(
+    ui: &mut Ui,
+    current: &mut (&mut String, &mut String, &mut String, &mut String),
+    selected: &mut SelectedPoolNode,
+    node_vec: &mut Vec<(String, PoolNode)>,
+    incorrect_input: bool,
+) {
+    ui.vertical(|ui| {
+        ui.spacing_mut().item_spacing.y = 0.0;
+        // ui.spacing_mut().button_padding.x = ui.available_width() / 2.0;
+        let width = ui.available_width();
+        // [Manual node selection]
+        // [Ping List]
+        debug!("P2Pool Tab | Rendering [Node List]");
+        // [Menu]
+        menu_list_node(ui, node_vec, width, selected, current);
+        let node_vec_len = node_vec.len();
+        // [Add/Save]
+        ui.horizontal(|ui| {
+            add_save_node(
+                ui,
+                selected,
+                node_vec,
+                current,
+                node_vec_len,
+                incorrect_input,
+            );
+        });
+        // [Delete]
+        ui.horizontal(|ui| {
+            delete_node(ui, selected, node_vec, current, node_vec_len);
+        });
+        // [Clear]
+        ui.horizontal(|ui| {
+            clear_node(ui, current);
+        });
+    });
+}
+// slider H/s
+
+fn clear_node(ui: &mut Ui, current: &mut (&mut String, &mut String, &mut String, &mut String)) {
+    ui.add_enabled_ui(
+        !current.0.is_empty()
+            || !current.1.is_empty()
+            || !current.2.is_empty()
+            || !current.3.is_empty(),
+        |ui| {
+            if ui
+                .add_sized([ui.available_width(), 0.0], Button::new("Clear"))
+                .on_hover_text(LIST_CLEAR)
+                .clicked()
+            {
+                current.0.clear();
+                current.1.clear();
+                current.2.clear();
+                current.3.clear();
+            }
+        },
+    );
+}
+fn menu_list_node(
+    ui: &mut Ui,
+    node_vec: &mut [(String, PoolNode)],
+    width: f32,
+    selected: &mut SelectedPoolNode,
+    current: &mut (&mut String, &mut String, &mut String, &mut String),
+) {
+    let text = RichText::new(format!("{}. {}", selected.index + 1, selected.name));
+    ComboBox::from_id_salt("manual_nodes")
+        .selected_text(text)
+        .width(width)
+        .show_ui(ui, |ui| {
+            for (n, (name, node)) in node_vec.iter().enumerate() {
+                let text = RichText::new(format!(
+                    "{}. {}\n     IP: {}\n    RPC: {}\n    {}: {}",
+                    n + 1,
+                    name,
+                    node.ip(),
+                    node.port(),
+                    node.custom_name(),
+                    node.custom()
+                ));
+                if ui
+                    .add(SelectableLabel::new(selected.name == **name, text))
+                    .clicked()
+                {
+                    selected.index = n;
+                    let node = node.clone();
+                    selected.name.clone_from(name);
+                    selected.ip.clone_from(&node.ip().to_string());
+                    selected.rpc.clone_from(&node.port().to_string());
+                    selected.zmq_rig.clone_from(&node.custom().to_string());
+                    current.0.clone_from(name);
+                    *current.1 = node.ip().to_string();
+                    *current.2 = node.port().to_string();
+                    *current.3 = node.custom().to_string();
+                }
+            }
+        });
+}
+fn add_save_node(
+    ui: &mut Ui,
+    selected: &mut SelectedPoolNode,
+    node_vec: &mut Vec<(String, PoolNode)>,
+    current: &mut (&mut String, &mut String, &mut String, &mut String),
+    node_vec_len: usize,
+    incorrect_input: bool,
+) {
+    // list should never be empty unless state edited by hand.
+    let is_node = matches!(node_vec[0].1, PoolNode::Node(_));
+    // [Add/Save]
+    let mut exists = false;
+    let mut save_diff = true;
+    let mut existing_index = 0;
+    for (name, node) in node_vec.iter() {
+        if *name == *current.0 {
+            exists = true;
+            if *current.1 == node.ip() && *current.2 == node.port() && *current.3 == node.custom() {
+                save_diff = false;
+            }
+            break;
+        }
+        existing_index += 1;
+    }
+    let text = if exists { LIST_SAVE } else { LIST_ADD };
+    let text = format!(
+        "{}\n    Currently selected node: {}. {}\n    Current amount of {}: {}/1000",
+        text,
+        selected.index + 1,
+        selected.name,
+        if is_node { "nodes" } else { "pools" },
+        node_vec_len
+    );
+    // If the node already exists, show [Save] and mutate the already existing node
+    if exists {
+        ui.add_enabled_ui(!incorrect_input && save_diff, |ui| {
+            if ui
+                .add_sized([ui.available_width(), 0.0], Button::new("Save"))
+                .on_hover_text(text)
+                .clicked()
+            {
+                let ip = current.1.clone();
+                let rpc = current.2.clone();
+                // zmq can be rig in case of Pool
+                let zmq = current.3.clone();
+                let poolnode = &mut node_vec[existing_index].1;
+                poolnode.set_ip(ip);
+                poolnode.set_port(rpc);
+                poolnode.set_custom(zmq);
+                info!(
+                    "Node | S | [index: {}, name: \"{}\", ip: \"{}\", rpc: {}, {}: {}]",
+                    existing_index + 1,
+                    current.0,
+                    current.1,
+                    current.2,
+                    poolnode.custom_name(),
+                    current.3
+                );
+                selected.index = existing_index;
+                selected.ip.clone_from(current.1);
+                selected.rpc.clone_from(current.2);
+                selected.zmq_rig.clone_from(current.3);
+            }
+        });
+    // Else, add to the list
+    } else {
+        ui.add_enabled_ui(!incorrect_input && node_vec_len < 1000, |ui| {
+            if ui
+                .add_sized([ui.available_width(), 0.0], Button::new("Add"))
+                .on_hover_text(text)
+                .clicked()
+            {
+                let ip = current.1.clone();
+                let rpc = current.2.clone();
+                // zmq can be rig in case of Pool
+                let zmq = current.3.clone();
+                let poolnode = match node_vec[existing_index].1 {
+                    PoolNode::Node(_) => PoolNode::Node(Node { ip, rpc, zmq }),
+                    PoolNode::Pool(_) => PoolNode::Pool(Pool {
+                        rig: zmq,
+                        ip,
+                        port: rpc,
+                    }),
+                };
+                info!(
+                    "Node | A | [index: {}, name: \"{}\", ip: \"{}\", rpc: {}, {}: {}]",
+                    node_vec_len,
+                    current.0,
+                    current.1,
+                    current.2,
+                    poolnode.custom_name(),
+                    current.3
+                );
+                node_vec.push((current.0.clone(), poolnode));
+                selected.index = node_vec_len;
+                selected.name.clone_from(current.0);
+                selected.ip.clone_from(current.1);
+                selected.rpc.clone_from(current.2);
+                selected.zmq_rig.clone_from(current.3);
+            }
+        });
+    }
+}
+
+fn delete_node(
+    ui: &mut Ui,
+    selected: &mut SelectedPoolNode,
+    node_vec: &mut Vec<(String, PoolNode)>,
+    current: &mut (&mut String, &mut String, &mut String, &mut String),
+    node_vec_len: usize,
+) {
+    ui.add_enabled_ui(node_vec_len > 1, |ui| {
+        let text = format!(
+            "{}\n    Currently selected node: {}. {}\n    Current amount of nodes: {}/1000",
+            LIST_DELETE,
+            selected.index + 1,
+            selected.name,
+            node_vec_len
+        );
+        if ui
+            .add_sized([ui.available_width(), 0.0], Button::new("Delete"))
+            .on_hover_text(text)
+            .clicked()
+        {
+            let new_name;
+            let new_node;
+            match selected.index {
+                0 => {
+                    new_name = node_vec[1].0.clone();
+                    new_node = node_vec[1].1.clone();
+                    node_vec.remove(0);
+                }
+                _ => {
+                    node_vec.remove(selected.index);
+                    selected.index -= 1;
+                    new_name = node_vec[selected.index].0.clone();
+                    new_node = node_vec[selected.index].1.clone();
+                }
+            };
+            selected.name.clone_from(&new_name);
+            selected.ip = new_node.ip().to_string();
+            selected.rpc = new_node.port().to_string();
+            selected.zmq_rig = new_node.custom().to_string();
+            *current.0 = new_name;
+            *current.1 = new_node.ip().to_string();
+            *current.2 = new_node.port().to_string();
+            *current.3 = new_node.custom().to_string();
+            info!(
+                "Node | D | [index: {}, name: \"{}\", ip: \"{}\", port: {}, {}: {}]",
+                selected.index,
+                selected.name,
+                selected.ip,
+                selected.rpc,
+                new_node.custom_name(),
+                selected.zmq_rig
+            );
+        }
+    });
+}
diff --git a/src/app/panels/middle/common/mod.rs b/src/app/panels/middle/common/mod.rs
new file mode 100644
index 0000000..05d780b
--- /dev/null
+++ b/src/app/panels/middle/common/mod.rs
@@ -0,0 +1,4 @@
+pub mod console;
+pub mod header_tab;
+pub mod list_poolnode;
+pub mod state_edit_field;
diff --git a/src/app/panels/middle/common/state_edit_field.rs b/src/app/panels/middle/common/state_edit_field.rs
new file mode 100644
index 0000000..a5f0670
--- /dev/null
+++ b/src/app/panels/middle/common/state_edit_field.rs
@@ -0,0 +1,212 @@
+use std::ops::RangeInclusive;
+use std::sync::{Arc, Mutex};
+
+use egui::{Color32, Label, RichText, Slider, TextEdit};
+use egui::{TextStyle, Ui};
+
+use crate::components::gupax::{FileType, FileWindow};
+use crate::disk::state::Gupax;
+use crate::miscs::height_txt_before_button;
+use crate::regex::Regexes;
+use crate::{
+    GREEN, GUPAX_SELECT, LIGHT_GRAY, NODE_DB_DIR, NODE_DB_PATH_EMPTY, NODE_PATH_OK, RED, SPACE,
+};
+
+pub fn slider_state_field(
+    ui: &mut Ui,
+    description: &str,
+    hover_msg: &str,
+    field: &mut u16,
+    range: RangeInclusive<u16>,
+) {
+    ui.horizontal(|ui| {
+        ui.add_sized(
+            [0.0, height_txt_before_button(ui, &TextStyle::Body)],
+            Label::new(description),
+        );
+        // not sure what's the right calculation to make
+        ui.style_mut().spacing.slider_width = (ui.available_width()
+            - ui.spacing().item_spacing.x * 4.0
+            - ui.spacing().scroll.bar_width
+            - SPACE * 2.0
+            + 2.0)
+            .max(80.0);
+        ui.add_sized(
+            [0.0, height_txt_before_button(ui, &TextStyle::Body)],
+            Slider::new(field, range),
+        )
+        .on_hover_text(hover_msg);
+    });
+}
+
+pub struct StateTextEdit<'a> {
+    description: &'a str,
+    max_ch: u8,
+    help_msg: &'a str,
+    validations: &'a [fn(&str) -> bool],
+    text_edit_width: f32,
+    text_style: TextStyle,
+}
+#[allow(unused)]
+impl<'a> StateTextEdit<'a> {
+    pub fn new(ui: &Ui) -> Self {
+        StateTextEdit {
+            description: "",
+            max_ch: 30,
+            help_msg: "",
+            validations: &[],
+            text_edit_width: ui.text_style_height(&TextStyle::Body) * 18.0,
+            text_style: TextStyle::Body,
+        }
+    }
+    pub fn build(self, ui: &mut Ui, state_field: &mut String) -> bool {
+        let mut valid = false;
+        ui.horizontal_centered(|ui| {
+            let color;
+            let symbol;
+            let mut input_validated = true;
+            let len;
+            let inside_space;
+            for v in self.validations {
+                if !v(state_field) {
+                    input_validated = false;
+                }
+            }
+            if state_field.is_empty() {
+                symbol = "➖";
+                color = Color32::LIGHT_GRAY;
+            } else if input_validated {
+                symbol = "✔";
+                color = Color32::from_rgb(100, 230, 100);
+                valid = true;
+            } else {
+                symbol = "❌";
+                color = Color32::from_rgb(230, 50, 50);
+            }
+            match self.max_ch {
+                x if x >= 100 => {
+                    len = format!("{:03}", state_field.len());
+                    inside_space = "";
+                }
+                10..99 => {
+                    len = format!("{:02}", state_field.len());
+                    inside_space = " ";
+                }
+                _ => {
+                    len = format!("{}", state_field.len());
+                    inside_space = "  ";
+                }
+            }
+            let text = format!(
+                "{}[{}{}/{}{}]{}",
+                self.description, inside_space, len, self.max_ch, inside_space, symbol
+            );
+            ui.add_sized(
+                [0.0, height_txt_before_button(ui, &self.text_style)],
+                Label::new(RichText::new(text).color(color)),
+            );
+            // allocate the size to leave half of the total width free.
+            ui.spacing_mut().text_edit_width = self.text_edit_width;
+            ui.text_edit_singleline(state_field)
+                .on_hover_text(self.help_msg);
+            state_field.truncate(self.max_ch.into());
+        });
+        valid
+    }
+    pub fn description(mut self, description: &'a str) -> Self {
+        self.description = description;
+        self
+    }
+    pub fn max_ch(mut self, max_ch: u8) -> Self {
+        self.max_ch = max_ch;
+        self
+    }
+    pub fn help_msg(mut self, help_msg: &'a str) -> Self {
+        self.help_msg = help_msg;
+        self
+    }
+    pub fn validations(mut self, validations: &'a [fn(&str) -> bool]) -> Self {
+        self.validations = validations;
+        self
+    }
+    pub fn text_style(mut self, text_style: TextStyle) -> Self {
+        self.text_style = text_style;
+        self
+    }
+    pub fn text_edit_width(mut self, text_edit_width: f32) -> Self {
+        self.text_edit_width = text_edit_width;
+        self
+    }
+    pub fn text_edit_width_half_left(mut self, ui: &Ui) -> Self {
+        self.text_edit_width = ui.available_width() / 2.0;
+        self
+    }
+    pub fn text_edit_width_same_as_max_ch(mut self, ui: &Ui) -> Self {
+        self.text_edit_width = ui.text_style_height(&self.text_style) * self.max_ch as f32;
+        self
+    }
+}
+
+// path to choose
+pub fn path_db_field(ui: &mut Ui, path: &mut String, file_window: &Arc<Mutex<FileWindow>>) {
+    ui.horizontal(|ui| {
+        let symbol;
+        let color;
+        let hover;
+        if path.is_empty() {
+            symbol = "➖";
+            color = LIGHT_GRAY;
+            hover = NODE_DB_PATH_EMPTY;
+        } else if !Gupax::path_is_dir(path) {
+            symbol = "❌";
+            color = RED;
+            hover = NODE_DB_DIR;
+        } else {
+            symbol = "✔";
+            color = GREEN;
+            hover = NODE_PATH_OK;
+        }
+        let text = ["Node Database Directory ", symbol].concat();
+        ui.add_sized(
+            [0.0, height_txt_before_button(ui, &TextStyle::Body)],
+            Label::new(RichText::new(text).color(color)),
+        );
+        let window_busy = file_window.lock().unwrap().thread;
+        ui.add_enabled_ui(!window_busy, |ui| {
+            if ui.button("Open").on_hover_text(GUPAX_SELECT).clicked() {
+                Gupax::spawn_file_window_thread(file_window, FileType::NodeDB);
+            }
+            ui.spacing_mut().text_edit_width = ui.available_width();
+            ui.text_edit_singleline(path).on_hover_text(hover);
+        });
+    });
+}
+pub fn monero_address_field(address: &mut String, ui: &mut Ui, hover: &str) {
+    ui.group(|ui| {
+        let text;
+        let color;
+        let len = format!("{:02}", address.len());
+        if address.is_empty() {
+            text = format!("Monero Address [{}/95] ➖", len);
+            color = Color32::LIGHT_GRAY;
+        } else if Regexes::addr_ok(address) {
+            text = format!("Monero Address [{}/95] ✔", len);
+            color = Color32::from_rgb(100, 230, 100);
+        } else {
+            text = format!("Monero Address [{}/95] ❌", len);
+            color = Color32::from_rgb(230, 50, 50);
+        }
+        ui.style_mut().spacing.text_edit_width = ui.available_width();
+        ui.vertical_centered(|ui| {
+            ui.label(RichText::new(text).color(color));
+            // ui.set_max_width(95.0 * 3.0);
+            ui.add_space(SPACE);
+            ui.add(
+                TextEdit::hint_text(TextEdit::singleline(address), "4...")
+                    .horizontal_align(egui::Align::Center),
+            )
+            .on_hover_text(hover);
+            address.truncate(95);
+        });
+    });
+}
diff --git a/src/app/panels/middle/gupax.rs b/src/app/panels/middle/gupax.rs
index 31915e4..874f2a9 100644
--- a/src/app/panels/middle/gupax.rs
+++ b/src/app/panels/middle/gupax.rs
@@ -5,10 +5,13 @@ use crate::components::gupax::*;
 use crate::components::update::Update;
 use crate::components::update::check_binary_path;
 use crate::disk::state::*;
+use crate::miscs::height_txt_before_button;
 use log::debug;
 use std::path::Path;
 use std::sync::Arc;
 use std::sync::Mutex;
+use strum::EnumCount;
+use strum::IntoEnumIterator;
 impl Gupax {
     #[inline(always)] // called once
     #[allow(clippy::too_many_arguments)]
@@ -20,7 +23,6 @@ impl Gupax {
         file_window: &Arc<Mutex<FileWindow>>,
         error_state: &mut ErrorState,
         restart: &Arc<Mutex<Restart>>,
-        size: Vec2,
         _frame: &mut eframe::Frame,
         _ctx: &egui::Context,
         ui: &mut egui::Ui,
@@ -28,33 +30,30 @@ impl Gupax {
     ) {
         // Update button + Progress bar
         debug!("Gupaxx Tab | Rendering [Update] button + progress bar");
+        let height_font = ui.text_style_height(&TextStyle::Body);
         egui::ScrollArea::vertical().show(ui, |ui| {
+            ui.style_mut().spacing.item_spacing = [height_font, height_font].into();
             ui.group(|ui| {
-                let button = if self.simple {
-                    size.y / 5.0
-                } else {
-                    size.y / 15.0
-                };
-                let height = if self.simple {
-                    size.y / 5.0
-                } else {
-                    size.y / 10.0
-                };
-                let width = size.x - SPACE;
                 let updating = *update.lock().unwrap().updating.lock().unwrap();
-                ui.vertical(|ui| {
+                ui.vertical_centered(|ui| {
+                    ui.add_space(height_font);
+                    ui.style_mut().spacing.button_padding = ui.style().spacing.button_padding * 3.0;
                     // If [Gupax] is being built for a Linux distro,
                     // disable built-in updating completely.
                     #[cfg(feature = "distro")]
                     ui.disable();
                     #[cfg(feature = "distro")]
-                    ui.add_sized([width, button], Button::new("Updates are disabled"))
+                    // ui.add_sized([width, button], Button::new("Updates are disabled"))
+                    // .on_disabled_hover_text(DISTRO_NO_UPDATE);
+                    ui.button("Updates are disabled")
                         .on_disabled_hover_text(DISTRO_NO_UPDATE);
                     #[cfg(not(feature = "distro"))]
                     ui.add_enabled_ui(!updating && *restart.lock().unwrap() == Restart::No, |ui| {
                         #[cfg(not(feature = "distro"))]
+                        // if ui
+                        //     .add_sized([width, button], Button::new("Check for updates"))
                         if ui
-                            .add_sized([width, button], Button::new("Check for updates"))
+                            .button("Check for updates")
                             .on_hover_text(GUPAX_UPDATE)
                             .clicked()
                         {
@@ -68,8 +67,6 @@ impl Gupax {
                             );
                         }
                     });
-                });
-                ui.vertical(|ui| {
                     ui.add_enabled_ui(updating, |ui| {
                         let prog = *update.lock().unwrap().prog.lock().unwrap();
                         let msg = format!(
@@ -78,479 +75,346 @@ impl Gupax {
                             prog,
                             "%"
                         );
-                        ui.add_sized([width, height * 1.4], Label::new(RichText::new(msg)));
-                        let height = height / 2.0;
-                        let size = vec2(width, height);
+                        ui.label(msg);
                         if updating {
-                            ui.add_sized(size, Spinner::new().size(height));
+                            ui.spinner();
                         } else {
-                            ui.add_sized(size, Label::new("..."));
+                            ui.label("...");
                         }
-                        ui.add_sized(
-                            size,
-                            ProgressBar::new(
-                                update.lock().unwrap().prog.lock().unwrap().round() / 100.0,
-                            ),
-                        );
+                        ui.add(ProgressBar::new(
+                            update.lock().unwrap().prog.lock().unwrap().round() / 100.0,
+                        ));
                     });
                 });
             });
 
-            debug!("Gupaxx Tab | Rendering bool buttons");
-            ui.horizontal(|ui| {
-                ui.group(|ui| {
-                    egui::ScrollArea::horizontal().show(ui, |ui| {
-                        let width = (size.x - SPACE * 17.0) / 8.0;
-                        let height = if self.simple {
-                            size.y / 10.0
-                        } else {
-                            size.y / 15.0
-                        };
-                        let size = vec2(width, height);
-                        ui.style_mut().override_text_style = Some(egui::TextStyle::Small);
-                        ui.add_sized(size, Checkbox::new(&mut self.auto_update, "Auto-Update"))
-                            .on_hover_text(GUPAX_AUTO_UPDATE);
-                        ui.separator();
-                        ui.add_sized(size, Checkbox::new(&mut self.bundled, "Bundle"))
-                            .on_hover_text(GUPAX_BUNDLED_UPDATE);
-                        ui.separator();
-                        ui.add_sized(size, Checkbox::new(&mut self.auto_node, "Auto-Node"))
-                            .on_hover_text(GUPAX_AUTO_NODE);
-                        ui.separator();
-                        ui.add_sized(size, Checkbox::new(&mut self.auto_p2pool, "Auto-P2Pool"))
-                            .on_hover_text(GUPAX_AUTO_P2POOL);
-                        ui.separator();
-                        ui.add_sized(size, Checkbox::new(&mut self.auto_xmrig, "Auto-XMRig"))
-                            .on_hover_text(GUPAX_AUTO_XMRIG);
-                        ui.separator();
-                        ui.add_sized(size, Checkbox::new(&mut self.auto_xp, "Auto-Proxy"))
-                            .on_hover_text(GUPAX_AUTO_XMRIG_PROXY);
-                        ui.separator();
-                        ui.add_sized(size, Checkbox::new(&mut self.auto_xvb, "Auto-XvB"))
-                            .on_hover_text(GUPAX_AUTO_XVB);
-                        ui.separator();
-                        ui.add_sized(
-                            size,
-                            Checkbox::new(&mut self.ask_before_quit, "Confirm quit"),
-                        )
-                        .on_hover_text(GUPAX_ASK_BEFORE_QUIT);
-                        ui.separator();
-                        ui.add_sized(
-                            size,
-                            Checkbox::new(&mut self.save_before_quit, "Save on quit"),
-                        )
-                        .on_hover_text(GUPAX_SAVE_BEFORE_QUIT);
-                    });
+            // debug!("Gupaxx Tab | Rendering bool buttons");
+            ui.group(|ui| {
+                ui.vertical_centered(|ui| {
+                    ui.add(Label::new(
+                        RichText::new("Default Behaviour")
+                            .underline()
+                            .color(LIGHT_GRAY),
+                    ))
                 });
+                ui.separator();
+                self.horizontal_flex_auto_start(ui, AutoStart::ALL);
             });
-
             if self.simple {
                 return;
             }
 
-            debug!("Gupaxx Tab | Rendering P2Pool/XMRig path selection");
-            // P2Pool/XMRig binary path selection
+            debug!("Gupaxx Tab | Rendering Node/P2Pool/XMRig/XMRig-Proxy path selection");
             // need to clone bool so file_window is not locked across a thread
             let window_busy = file_window.lock().unwrap().thread.to_owned();
-            let height = size.y / 28.0;
-            let text_edit = (ui.available_width() / 10.0) - SPACE;
             ui.group(|ui| {
-                ui.add_sized(
-                    [ui.available_width(), height / 2.0],
-                    Label::new(
-                        RichText::new("Node/P2Pool/XMRig/XMRig-Proxy PATHs")
-                            .underline()
-                            .color(LIGHT_GRAY),
-                    ),
-                )
-                .on_hover_text("Gupaxx is online");
-                ui.separator();
-                ui.horizontal(|ui| {
-                    if self.node_path.is_empty() {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("Node Binary Path ➖").color(LIGHT_GRAY)),
-                        )
-                        .on_hover_text(NODE_PATH_EMPTY);
-                    } else if !Self::path_is_file(&self.node_path) {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("Node Binary Path ❌").color(RED)),
-                        )
-                        .on_hover_text(NODE_PATH_NOT_FILE);
-                    } else if !check_binary_path(&self.node_path, ProcessName::Node) {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("Node Binary Path ❌").color(RED)),
-                        )
-                        .on_hover_text(NODE_PATH_NOT_VALID);
-                    } else {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("Node Binary Path ✔").color(GREEN)),
-                        )
-                        .on_hover_text(NODE_PATH_OK);
-                    }
-                    ui.spacing_mut().text_edit_width = ui.available_width() - SPACE;
-                    ui.add_enabled_ui(!window_busy, |ui| {
-                        if ui.button("Open").on_hover_text(GUPAX_SELECT).clicked() {
-                            Self::spawn_file_window_thread(file_window, FileType::Node);
-                        }
-                        ui.add_sized(
-                            [ui.available_width(), height],
-                            TextEdit::singleline(&mut self.node_path),
-                        )
-                        .on_hover_text(GUPAX_PATH_NODE);
-                    });
-                });
-                ui.horizontal(|ui| {
-                    if self.p2pool_path.is_empty() {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("P2Pool Binary Path ➖").color(LIGHT_GRAY)),
-                        )
-                        .on_hover_text(P2POOL_PATH_EMPTY);
-                    } else if !Self::path_is_file(&self.p2pool_path) {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("P2Pool Binary Path ❌").color(RED)),
-                        )
-                        .on_hover_text(P2POOL_PATH_NOT_FILE);
-                    } else if !check_binary_path(&self.p2pool_path, ProcessName::P2pool) {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("P2Pool Binary Path ❌").color(RED)),
-                        )
-                        .on_hover_text(P2POOL_PATH_NOT_VALID);
-                    } else {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("P2Pool Binary Path ✔").color(GREEN)),
-                        )
-                        .on_hover_text(P2POOL_PATH_OK);
-                    }
-                    ui.spacing_mut().text_edit_width = ui.available_width() - SPACE;
-                    ui.add_enabled_ui(!window_busy, |ui| {
-                        if ui.button("Open").on_hover_text(GUPAX_SELECT).clicked() {
-                            Self::spawn_file_window_thread(file_window, FileType::P2pool);
-                        }
-                        ui.add_sized(
-                            [ui.available_width(), height],
-                            TextEdit::singleline(&mut self.p2pool_path),
-                        )
-                        .on_hover_text(GUPAX_PATH_P2POOL);
-                    });
-                });
-                ui.horizontal(|ui| {
-                    if self.xmrig_path.is_empty() {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("XMRig Binary Path ➖").color(LIGHT_GRAY)),
-                        )
-                        .on_hover_text(XMRIG_PATH_EMPTY);
-                    } else if !Self::path_is_file(&self.xmrig_path) {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("XMRig Binary Path ❌").color(RED)),
-                        )
-                        .on_hover_text(XMRIG_PATH_NOT_FILE);
-                    } else if !check_binary_path(&self.xmrig_path, ProcessName::Xmrig) {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("XMRig Binary Path ❌").color(RED)),
-                        )
-                        .on_hover_text(XMRIG_PATH_NOT_VALID);
-                    } else {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("XMRig Binary Path ✔").color(GREEN)),
-                        )
-                        .on_hover_text(XMRIG_PATH_OK);
-                    }
-                    ui.spacing_mut().text_edit_width = ui.available_width() - SPACE;
-                    ui.add_enabled_ui(!window_busy, |ui| {
-                        if ui.button("Open").on_hover_text(GUPAX_SELECT).clicked() {
-                            Self::spawn_file_window_thread(file_window, FileType::Xmrig);
-                        }
-                        ui.add_sized(
-                            [ui.available_width(), height],
-                            TextEdit::singleline(&mut self.xmrig_path),
-                        )
-                        .on_hover_text(GUPAX_PATH_XMRIG);
-                    });
-                });
-                ui.horizontal(|ui| {
-                    if self.xmrig_proxy_path.is_empty() {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(
-                                RichText::new("XMRig-Proxy Binary Path ➖").color(LIGHT_GRAY),
-                            ),
-                        )
-                        .on_hover_text(XMRIG_PROXY_PATH_EMPTY);
-                    } else if !Self::path_is_file(&self.xmrig_proxy_path) {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("XMRig-Proxy Binary Path ❌").color(RED)),
-                        )
-                        .on_hover_text(XMRIG_PROXY_PATH_NOT_FILE);
-                    } else if !crate::components::update::check_binary_path(
-                        &self.xmrig_proxy_path,
-                        ProcessName::XmrigProxy,
-                    ) {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("XMRig-Proxy Binary Path ❌").color(RED)),
-                        )
-                        .on_hover_text(XMRIG_PROXY_PATH_NOT_VALID);
-                    } else {
-                        ui.add_sized(
-                            [text_edit, height],
-                            Label::new(RichText::new("XMRig-Proxy Binary Path ✔").color(GREEN)),
-                        )
-                        .on_hover_text(XMRIG_PROXY_PATH_OK);
-                    }
-                    ui.spacing_mut().text_edit_width = ui.available_width() - SPACE;
-                    ui.add_enabled_ui(!window_busy, |ui| {
-                        if ui.button("Open").on_hover_text(GUPAX_SELECT).clicked() {
-                            Self::spawn_file_window_thread(file_window, FileType::XmrigProxy);
-                        }
-                        ui.add_sized(
-                            [ui.available_width(), height],
-                            TextEdit::singleline(&mut self.xmrig_proxy_path),
-                        )
-                        .on_hover_text(GUPAX_PATH_XMRIG_PROXY);
+                ui.push_id(2, |ui| {
+                    ui.vertical_centered(|ui| {
+                        ui.add(Label::new(
+                            RichText::new("Node/P2Pool/XMRig/XMRig-Proxy PATHs")
+                                .underline()
+                                .color(LIGHT_GRAY),
+                        ))
+                        .on_hover_text("Gupaxx is online");
+                    });
+                    ui.separator();
+                    ScrollArea::horizontal().show(ui, |ui| {
+                        ui.vertical(|ui| {
+                            BundledProcess::iter().for_each(|name| {
+                                path_binary(
+                                    self.path_binary(&name),
+                                    name.process_name(),
+                                    ui,
+                                    window_busy,
+                                    file_window,
+                                )
+                            });
+                        });
                     });
                 });
+                let mut guard = file_window.lock().unwrap();
+                if guard.picked_p2pool {
+                    self.p2pool_path.clone_from(&guard.p2pool_path);
+                    guard.picked_p2pool = false;
+                }
+                if guard.picked_xmrig {
+                    self.xmrig_path.clone_from(&guard.xmrig_path);
+                    guard.picked_xmrig = false;
+                }
+                if guard.picked_xp {
+                    self.xmrig_proxy_path.clone_from(&guard.xmrig_proxy_path);
+                    guard.picked_xp = false;
+                }
+                if guard.picked_node {
+                    self.node_path.clone_from(&guard.node_path);
+                    guard.picked_node = false;
+                }
+                drop(guard);
             });
-            let mut guard = file_window.lock().unwrap();
-            if guard.picked_p2pool {
-                self.p2pool_path.clone_from(&guard.p2pool_path);
-                guard.picked_p2pool = false;
-            }
-            if guard.picked_xmrig {
-                self.xmrig_path.clone_from(&guard.xmrig_path);
-                guard.picked_xmrig = false;
-            }
-            if guard.picked_xp {
-                self.xmrig_proxy_path.clone_from(&guard.xmrig_proxy_path);
-                guard.picked_xp = false;
-            }
-            if guard.picked_node {
-                self.node_path.clone_from(&guard.node_path);
-                guard.picked_node = false;
-            }
-            drop(guard);
-
-            let height = ui.available_height() / 6.0;
-
             // Saved [Tab]
             debug!("Gupaxx Tab | Rendering [Tab] selector");
             ui.group(|ui| {
-                let width = (size.x / 7.0) - (SPACE * 1.93);
-                let size = vec2(width, height);
-                ui.add_sized(
-                    [ui.available_width(), height / 2.0],
-                    Label::new(RichText::new("Default Tab").underline().color(LIGHT_GRAY)),
-                )
-                .on_hover_text(GUPAX_TAB);
+                ui.vertical_centered(|ui| {
+                    ui.add(Label::new(
+                        RichText::new("Default Tab").underline().color(LIGHT_GRAY),
+                    ))
+                    .on_hover_text(GUPAX_TAB);
+                });
                 ui.separator();
-                ui.horizontal(|ui| {
-                    if ui
-                        .add_sized(size, SelectableLabel::new(self.tab == Tab::About, "About"))
-                        .on_hover_text(GUPAX_TAB_ABOUT)
-                        .clicked()
-                    {
-                        self.tab = Tab::About;
-                    }
-                    ui.separator();
-                    if ui
-                        .add_sized(
-                            size,
-                            SelectableLabel::new(self.tab == Tab::Status, "Status"),
-                        )
-                        .on_hover_text(GUPAX_TAB_STATUS)
-                        .clicked()
-                    {
-                        self.tab = Tab::Status;
-                    }
-                    ui.separator();
-                    if ui
-                        .add_sized(size, SelectableLabel::new(self.tab == Tab::Gupax, "Gupaxx"))
-                        .on_hover_text(GUPAX_TAB_GUPAX)
-                        .clicked()
-                    {
-                        self.tab = Tab::Gupax;
-                    }
-                    ui.separator();
-                    if ui
-                        .add_sized(size, SelectableLabel::new(self.tab == Tab::Node, "Node"))
-                        .on_hover_text(GUPAX_TAB_NODE)
-                        .clicked()
-                    {
-                        self.tab = Tab::Node;
-                    }
-                    ui.separator();
-                    if ui
-                        .add_sized(
-                            size,
-                            SelectableLabel::new(self.tab == Tab::P2pool, "P2Pool"),
-                        )
-                        .on_hover_text(GUPAX_TAB_P2POOL)
-                        .clicked()
-                    {
-                        self.tab = Tab::P2pool;
-                    }
-                    ui.separator();
-                    if ui
-                        .add_sized(size, SelectableLabel::new(self.tab == Tab::Xmrig, "XMRig"))
-                        .on_hover_text(GUPAX_TAB_XMRIG)
-                        .clicked()
-                    {
-                        self.tab = Tab::Xmrig;
-                    }
-                    if ui
-                        .add_sized(size, SelectableLabel::new(self.tab == Tab::Xvb, "XvB"))
-                        .on_hover_text(GUPAX_TAB_XVB)
-                        .clicked()
-                    {
-                        self.tab = Tab::Xvb;
-                    }
-                })
+                ui.push_id(1, |ui| {
+                    ScrollArea::horizontal().show(ui, |ui| {
+                        ui.horizontal(|ui| {
+                            let width = (ui.available_width() / Tab::COUNT as f32)
+                                - (ui.spacing().button_padding.y * 2.0
+                                    + ui.spacing().item_spacing.x)
+                                - SPACE;
+                            Tab::iter().enumerate().for_each(|(count, tab)| {
+                                if ui
+                                    .add_sized(
+                                        [width, height_txt_before_button(ui, &TextStyle::Button)],
+                                        SelectableLabel::new(self.tab == tab, tab.to_string()),
+                                    )
+                                    .on_hover_text(tab.msg_default_tab())
+                                    .clicked()
+                                {
+                                    self.tab = tab;
+                                }
+
+                                if count + 1 != Tab::COUNT {
+                                    ui.separator();
+                                }
+                            })
+                        });
+                    });
+                });
             });
 
             // Gupax App resolution sliders
             debug!("Gupaxx Tab | Rendering resolution sliders");
             ui.group(|ui| {
-                ui.add_sized(
-                    [ui.available_width(), height / 2.0],
-                    Label::new(
-                        RichText::new("Width/Height Adjust")
+                ui.vertical_centered(|ui| {
+                    ui.add(Label::new(
+                        RichText::new("Width/Height/Scaling Adjustment")
                             .underline()
                             .color(LIGHT_GRAY),
-                    ),
-                )
-                .on_hover_text(GUPAX_ADJUST);
-                ui.separator();
-                ui.vertical(|ui| {
-                    let width = size.x / 10.0;
-                    ui.spacing_mut().icon_width = width / 25.0;
-                    ui.spacing_mut().slider_width = width * 7.6;
-                    match self.ratio {
-                        Ratio::None => (),
-                        Ratio::Width => {
-                            let width = self.selected_width as f64;
-                            let height = (width / 1.333).round();
-                            self.selected_height = height as u16;
-                        }
-                        Ratio::Height => {
-                            let height = self.selected_height as f64;
-                            let width = (height * 1.333).round();
-                            self.selected_width = width as u16;
-                        }
-                    }
-                    let height = height / 3.5;
-                    let size = vec2(width, height);
-                    ui.horizontal(|ui| {
-                        ui.add_enabled_ui(self.ratio != Ratio::Height, |ui| {
-                            ui.add_sized(
-                                size,
-                                Label::new(format!(
-                                    " Width [{}-{}]:",
-                                    APP_MIN_WIDTH as u16, APP_MAX_WIDTH as u16
-                                )),
-                            );
-                            ui.add_sized(
-                                size,
-                                Slider::new(
-                                    &mut self.selected_width,
-                                    APP_MIN_WIDTH as u16..=APP_MAX_WIDTH as u16,
-                                ),
-                            )
-                            .on_hover_text(GUPAX_WIDTH);
-                        });
-                    });
-                    ui.horizontal(|ui| {
-                        ui.add_enabled_ui(self.ratio != Ratio::Width, |ui| {
-                            ui.add_sized(
-                                size,
-                                Label::new(format!(
-                                    "Height [{}-{}]:",
-                                    APP_MIN_HEIGHT as u16, APP_MAX_HEIGHT as u16
-                                )),
-                            );
-                            ui.add_sized(
-                                size,
-                                Slider::new(
-                                    &mut self.selected_height,
-                                    APP_MIN_HEIGHT as u16..=APP_MAX_HEIGHT as u16,
-                                ),
-                            )
-                            .on_hover_text(GUPAX_HEIGHT);
-                        });
-                    });
-                    ui.horizontal(|ui| {
-                        ui.add_sized(
-                            size,
-                            Label::new(format!("Scaling [{APP_MIN_SCALE}..{APP_MAX_SCALE}]:")),
-                        );
-                        ui.add_sized(
-                            size,
-                            Slider::new(&mut self.selected_scale, APP_MIN_SCALE..=APP_MAX_SCALE)
-                                .step_by(0.1),
-                        )
-                        .on_hover_text(GUPAX_SCALE);
-                    });
+                    ))
+                    .on_hover_text(GUPAX_ADJUST);
+                    ui.separator();
                 });
-                ui.style_mut().override_text_style = Some(egui::TextStyle::Button);
-                ui.separator();
-                // Width/Height locks
                 ui.horizontal(|ui| {
-                    use Ratio::*;
-                    let width = (size.x / 4.0) - (SPACE * 1.5);
-                    let size = vec2(width, height);
-                    if ui
-                        .add_sized(
-                            size,
-                            SelectableLabel::new(self.ratio == Width, "Lock to width"),
-                        )
-                        .on_hover_text(GUPAX_LOCK_WIDTH)
-                        .clicked()
-                    {
-                        self.ratio = Width;
-                    }
-                    ui.separator();
-                    if ui
-                        .add_sized(
-                            size,
-                            SelectableLabel::new(self.ratio == Height, "Lock to height"),
-                        )
-                        .on_hover_text(GUPAX_LOCK_HEIGHT)
-                        .clicked()
-                    {
-                        self.ratio = Height;
-                    }
-                    ui.separator();
-                    if ui
-                        .add_sized(size, SelectableLabel::new(self.ratio == None, "No lock"))
-                        .on_hover_text(GUPAX_NO_LOCK)
-                        .clicked()
-                    {
-                        self.ratio = None;
-                    }
-                    if ui
-                        .add_sized(size, Button::new("Set"))
-                        .on_hover_text(GUPAX_SET)
-                        .clicked()
-                    {
-                        let size =
-                            Vec2::new(self.selected_width as f32, self.selected_height as f32);
-                        ui.ctx()
-                            .send_viewport_cmd(egui::viewport::ViewportCommand::InnerSize(size));
-                        *must_resize = true;
-                    }
-                })
+                    ScrollArea::horizontal().show(ui, |ui| {
+                        ui.vertical(|ui| {
+                            match self.ratio {
+                                Ratio::None => (),
+                                Ratio::Width => {
+                                    let width = self.selected_width as f64;
+                                    let height = (width / 1.333).round();
+                                    self.selected_height = height as u16;
+                                }
+                                Ratio::Height => {
+                                    let height = self.selected_height as f64;
+                                    let width = (height * 1.333).round();
+                                    self.selected_width = width as u16;
+                                }
+                            }
+                            // let height = height / 3.5;
+                            // let size = vec2(width, height);
+                            ui.horizontal(|ui| {
+                                ui.add_enabled_ui(self.ratio != Ratio::Height, |ui| {
+                                    ui.label(format!(
+                                        " Width   [{}-{}]:",
+                                        APP_MIN_WIDTH as u16, APP_MAX_WIDTH as u16
+                                    ));
+                                    ui.add(Slider::new(
+                                        &mut self.selected_width,
+                                        APP_MIN_WIDTH as u16..=APP_MAX_WIDTH as u16,
+                                    ))
+                                    .on_hover_text(GUPAX_WIDTH);
+                                });
+                            });
+                            ui.horizontal(|ui| {
+                                ui.add_enabled_ui(self.ratio != Ratio::Width, |ui| {
+                                    ui.label(format!(
+                                        " Height  [{}-{}]:",
+                                        APP_MIN_HEIGHT as u16, APP_MAX_HEIGHT as u16
+                                    ));
+                                    ui.add(Slider::new(
+                                        &mut self.selected_height,
+                                        APP_MIN_HEIGHT as u16..=APP_MAX_HEIGHT as u16,
+                                    ))
+                                    .on_hover_text(GUPAX_HEIGHT);
+                                });
+                            });
+                            ui.horizontal(|ui| {
+                                ui.label(format!(" Scaling   [{APP_MIN_SCALE}..{APP_MAX_SCALE}]:"));
+                                ui.add(
+                                    Slider::new(
+                                        &mut self.selected_scale,
+                                        APP_MIN_SCALE..=APP_MAX_SCALE,
+                                    )
+                                    .step_by(0.1),
+                                )
+                                .on_hover_text(GUPAX_SCALE);
+                            });
+                        });
+                        ui.style_mut().override_text_style = Some(egui::TextStyle::Button);
+                        ui.separator();
+                        // Width/Height locks
+                        ui.vertical(|ui| {
+                            use Ratio::*;
+                            ui.horizontal(|ui| {
+                                if ui
+                                    .selectable_label(self.ratio == Width, "Lock to width")
+                                    .on_hover_text(GUPAX_LOCK_WIDTH)
+                                    .clicked()
+                                {
+                                    self.ratio = Width;
+                                }
+                                ui.separator();
+                                if ui
+                                    .selectable_label(self.ratio == Height, "Lock to height")
+                                    .on_hover_text(GUPAX_LOCK_HEIGHT)
+                                    .clicked()
+                                {
+                                    self.ratio = Height;
+                                }
+                                ui.separator();
+                                if ui
+                                    .selectable_label(self.ratio == None, "No lock")
+                                    .on_hover_text(GUPAX_NO_LOCK)
+                                    .clicked()
+                                {
+                                    self.ratio = None;
+                                }
+                                ui.separator();
+                                if ui.button("Set").on_hover_text(GUPAX_SET).clicked() {
+                                    let size = Vec2::new(
+                                        self.selected_width as f32,
+                                        self.selected_height as f32,
+                                    );
+                                    ui.ctx().send_viewport_cmd(
+                                        egui::viewport::ViewportCommand::InnerSize(size),
+                                    );
+                                    *must_resize = true;
+                                }
+                            });
+                        });
+                    })
+                });
+            });
+        });
+    }
+    /// widget: AutoStart variant and selectable label (true) or checkbox (false)
+    pub fn horizontal_flex_auto_start(&mut self, ui: &mut Ui, auto_starts: &[AutoStart]) {
+        let text_style = TextStyle::Button;
+        // let height = ui.style().text_styles.get(&text_style).unwrap().size;
+        ui.style_mut().override_text_style = Some(text_style);
+        // width = (width - / number of tab) - (space between widget * 2.0 + space of separator / 2.0)
+        // ui.style_mut().spacing.item_spacing.x = 4.0;
+        let spacing = 2.0;
+        // ui.with_layout(egui::Layout::left_to_right(egui::Align::Center), |ui| {
+        // ui.horizontal(|ui| {
+        ScrollArea::horizontal().show(ui, |ui| {
+            ui.with_layout(egui::Layout::left_to_right(egui::Align::Min), |ui| {
+                let width = (((ui.available_width()) / auto_starts.len() as f32)
+                    - ((ui.style().spacing.item_spacing.x * 2.0) + (spacing / 2.0)))
+                    .max(0.0);
+                // TODO: calculate minimum width needed, if ui.available width is less, show items on two lines, then on 3 etc..
+                // checkbox padding + item spacing + text + separator
+                let size = [width, 0.0];
+                let len = auto_starts.iter().len();
+                for (count, auto) in auto_starts.iter().enumerate() {
+                    ui.horizontal(|ui| {
+                        ui.vertical(|ui| {
+                            ui.horizontal(|ui| {
+                                let mut is_checked = self.auto.is_enabled(auto);
+                                let widget = Checkbox::new(&mut is_checked, auto.to_string());
+
+                                if ui
+                                    .add_sized(size, widget)
+                                    .on_hover_text(auto.help_msg())
+                                    .clicked()
+                                {
+                                    self.auto.enable(auto, is_checked);
+                                }
+                            });
+                            // add a space to prevent selectable button to be at the same line as the end of the top bar. Make it the same spacing as separators.
+                            ui.add_space(spacing * 4.0);
+                        });
+                        if count + 1 != len {
+                            ui.add(Separator::default().spacing(spacing).vertical());
+                        }
+                    });
+                }
             });
         });
     }
 }
+fn path_binary(
+    path: &mut String,
+    name: ProcessName,
+    ui: &mut Ui,
+    window_busy: bool,
+    file_window: &Arc<Mutex<FileWindow>>,
+) {
+    // align correctly even with different length of name by adapting the space just after.
+    let flex_space = " ".repeat(
+        ProcessName::iter()
+            .enumerate()
+            .max_by(|(_, a), (_, b)| {
+                a.to_string()
+                    .len()
+                    .partial_cmp(&b.to_string().len())
+                    .expect("ProcessName should have values")
+            })
+            .expect("Iterator cant' be empty")
+            .1
+            .to_string()
+            .len()
+            - name.to_string().len()
+            + 1,
+    );
+    let msg = format!(" {name}{flex_space}Binary Path");
+    // need to precise the height of text or there will be an misalignment with the button if it's bigger than the text.
+    let height =
+        (ui.style().spacing.button_padding.y * 2.0) + ui.text_style_height(&TextStyle::Body);
+    ui.horizontal(|ui| {
+        if path.is_empty() {
+            ui.add_sized(
+                [0.0, height],
+                Label::new(RichText::new(msg + " ➖").color(LIGHT_GRAY)),
+            )
+            .on_hover_text(name.msg_binary_path_empty());
+        } else if !Gupax::path_is_file(path) {
+            ui.add_sized(
+                [0.0, height],
+                Label::new(RichText::new(msg + " ❌").color(RED)),
+            )
+            .on_hover_text(name.msg_binary_path_not_file());
+        } else if !check_binary_path(path, name) {
+            ui.add_sized(
+                [0.0, height],
+                Label::new(RichText::new(msg + " ❌").color(RED)),
+            )
+            .on_hover_text(name.msg_binary_path_invalid());
+        } else {
+            ui.add_sized(
+                [0.0, height],
+                Label::new(RichText::new(msg + " ✔").color(GREEN)),
+            )
+            .on_hover_text(name.msg_binary_path_ok());
+        }
+        ui.spacing_mut().text_edit_width = (ui.available_width() - SPACE).max(0.0);
+        ui.add_enabled_ui(!window_busy, |ui| {
+            if ui.button("Open").on_hover_text(GUPAX_SELECT).clicked() {
+                Gupax::spawn_file_window_thread(
+                    file_window,
+                    name.file_type()
+                        .expect("XvB process should not be called in a function related to path"),
+                );
+            }
+            ui.text_edit_singleline(path)
+                .on_hover_text(name.msg_path_edit());
+        });
+    });
+}
diff --git a/src/app/panels/middle/mod.rs b/src/app/panels/middle/mod.rs
index 36654fd..720a8a0 100644
--- a/src/app/panels/middle/mod.rs
+++ b/src/app/panels/middle/mod.rs
@@ -1,11 +1,15 @@
 use crate::app::Tab;
 use crate::app::eframe_impl::ProcessStatesGui;
 use crate::app::keys::KeyPressed;
+use crate::components::gupax::FileWindow;
 use crate::helper::ProcessName;
+use crate::regex::REGEXES;
 use crate::utils::constants::*;
+use common::state_edit_field::StateTextEdit;
 use egui::*;
 use log::debug;
 mod about;
+pub mod common;
 mod gupax;
 mod node;
 mod p2pool;
@@ -47,7 +51,6 @@ impl crate::app::App {
                         self.max_threads,
                         &self.gupax_p2pool_api,
                         &self.benchmarks,
-                        self.size,
                         ctx,
                         ui,
                     );
@@ -62,7 +65,6 @@ impl crate::app::App {
                         &self.file_window,
                         &mut self.error_state,
                         &self.restart,
-                        self.size,
                         frame,
                         ctx,
                         ui,
@@ -76,7 +78,6 @@ impl crate::app::App {
                         &self.node,
                         &self.node_api,
                         &mut self.node_stdin,
-                        self.size,
                         &self.file_window,
                         ui,
                     );
@@ -91,7 +92,6 @@ impl crate::app::App {
                         &self.p2pool,
                         &self.p2pool_api,
                         &mut self.p2pool_stdin,
-                        self.size,
                         ctx,
                         ui,
                     );
@@ -104,7 +104,6 @@ impl crate::app::App {
                         &self.xmrig,
                         &self.xmrig_api,
                         &mut self.xmrig_stdin,
-                        self.size,
                         ctx,
                         ui,
                     );
@@ -117,7 +116,6 @@ impl crate::app::App {
                         &mut self.pool_vec,
                         &self.xmrig_proxy_api,
                         &mut self.xmrig_proxy_stdin,
-                        self.size,
                         ui,
                     );
                 }
@@ -125,7 +123,6 @@ impl crate::app::App {
                     debug!("App | Entering [XvB] Tab");
                     crate::disk::state::Xvb::show(
                         &mut self.state.xvb,
-                        self.size,
                         &self.state.p2pool.address,
                         ctx,
                         ui,
@@ -139,3 +136,49 @@ impl crate::app::App {
         });
     }
 }
+
+// Common widgets that will appears on multiple panels.
+
+// header
+
+// console
+
+// sliders in/out peers/log
+
+// menu node
+
+// premade state edit field
+// return boolean to know if the field input is validated.
+fn rpc_port_field(field: &mut String, ui: &mut Ui) -> bool {
+    StateTextEdit::new(ui)
+        .description("   RPC PORT ")
+        .max_ch(5)
+        .help_msg(NODE_API_PORT)
+        .validations(&[|x| REGEXES.port.is_match(x)])
+        .build(ui, field)
+}
+fn zmq_port_field(field: &mut String, ui: &mut Ui) -> bool {
+    StateTextEdit::new(ui)
+        .description("   ZMQ PORT ")
+        .max_ch(5)
+        .help_msg(NODE_ZMQ_PORT)
+        .validations(&[|x| REGEXES.port.is_match(x)])
+        .build(ui, field)
+}
+fn rpc_bind_field(field: &mut String, ui: &mut Ui) -> bool {
+    StateTextEdit::new(ui)
+        .description("RPC BIND IP ")
+        .max_ch(255)
+        .help_msg(NODE_API_BIND)
+        .validations(&[|x| REGEXES.ipv4.is_match(x), |x| REGEXES.domain.is_match(x)])
+        .build(ui, field)
+}
+
+fn zmq_bind_field(field: &mut String, ui: &mut Ui) -> bool {
+    StateTextEdit::new(ui)
+        .description("API BIND IP ")
+        .max_ch(255)
+        .help_msg(NODE_ZMQ_BIND)
+        .validations(&[|x| REGEXES.ipv4.is_match(x), |x| REGEXES.domain.is_match(x)])
+        .build(ui, field)
+}
diff --git a/src/app/panels/middle/node.rs b/src/app/panels/middle/node.rs
index 2ab6dfb..b282dd2 100644
--- a/src/app/panels/middle/node.rs
+++ b/src/app/panels/middle/node.rs
@@ -1,21 +1,19 @@
+use crate::app::panels::middle::common::console::{console, input_args_field, start_options_field};
+use crate::app::panels::middle::common::state_edit_field::{path_db_field, slider_state_field};
+use crate::app::panels::middle::{rpc_bind_field, rpc_port_field, zmq_bind_field, zmq_port_field};
 use crate::{
-    GUPAX_SELECT, NODE_API_BIND, NODE_API_PORT, NODE_ARGUMENTS, NODE_DB_DIR, NODE_DB_PATH_EMPTY,
-    NODE_DNS_BLOCKLIST, NODE_DNS_CHECKPOINT, NODE_INPUT, NODE_PATH_OK, NODE_PRUNNING, NODE_URL,
-    NODE_ZMQ_BIND, NODE_ZMQ_PORT,
+    NODE_ARGUMENTS, NODE_DNS_BLOCKLIST, NODE_DNS_CHECKPOINT, NODE_INPUT, NODE_PRUNNING, NODE_URL,
 };
-use egui::{Color32, Label, RichText, Slider, TextEdit, TextStyle, Ui, Vec2};
-use regex::Regex;
+use egui::{Label, TextStyle};
 use std::sync::{Arc, Mutex};
 
 use log::debug;
 
-use crate::components::gupax::{FileType, FileWindow};
-use crate::disk::state::{Gupax, Node};
+use crate::components::gupax::FileWindow;
+use crate::disk::state::Node;
 use crate::helper::Process;
 use crate::helper::node::PubNodeApi;
-use crate::regex::{REGEXES, num_lines};
-use crate::utils::constants::DARK_GRAY;
-use crate::{GREEN, LIGHT_GRAY, P2POOL_IN, P2POOL_LOG, P2POOL_OUT, RED, SPACE};
+use crate::{P2POOL_IN, P2POOL_LOG, P2POOL_OUT, SPACE};
 
 impl Node {
     #[inline(always)] // called once
@@ -24,102 +22,47 @@ impl Node {
         process: &Arc<Mutex<Process>>,
         api: &Arc<Mutex<PubNodeApi>>,
         buffer: &mut String,
-        size: Vec2,
         file_window: &Arc<Mutex<FileWindow>>,
         ui: &mut egui::Ui,
     ) {
-        let width = size.x;
-        let height = size.y;
-        let space_h = height / 48.0;
-        let text_height = size.y / 25.0;
-        let txt_description_width = size.x * 0.1;
+        ui.style_mut().override_text_style = Some(TextStyle::Body);
+        ui.vertical_centered(|ui| {
+            ui.add_space(SPACE);
+            ui.style_mut().override_text_style = Some(TextStyle::Heading);
+            ui.hyperlink_to("Monerod", NODE_URL);
+            ui.style_mut().override_text_style = None;
+            ui.add(Label::new("C++ Monero Node"));
+            ui.add_space(SPACE);
+        });
+        // console output for log
+        debug!("Node Tab | Rendering [Console]");
         egui::ScrollArea::vertical().show(ui, |ui| {
-            ui.vertical_centered(|ui| {
-                ui.add_space(space_h);
-                ui.style_mut().override_text_style = Some(TextStyle::Heading);
-                ui.hyperlink_to("Monerod", NODE_URL);
-                ui.style_mut().override_text_style = Some(TextStyle::Body);
-                ui.add(Label::new("C++ Monero Node"));
-                ui.add_space(space_h);
-            });
-            // console output for log
-            debug!("Node Tab | Rendering [Console]");
+            let text = &api.lock().unwrap().output;
             ui.group(|ui| {
-                let text = &api.lock().unwrap().output;
-                let nb_lines = num_lines(text);
-                let height = size.y / 2.8;
-                let width = (size.x - (space_h / 2.0)).max(0.0);
-                egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
-                    ui.style_mut().override_text_style = Some(TextStyle::Small);
-                    egui::ScrollArea::vertical()
-                        .stick_to_bottom(true)
-                        .max_width(width)
-                        .max_height(height)
-                        .auto_shrink([false; 2])
-                        // .show_viewport(ui, |ui, _| {
-                        .show_rows(
-                            ui,
-                            ui.text_style_height(&TextStyle::Small),
-                            nb_lines,
-                            |ui, row_range| {
-                                for i in row_range {
-                                    if let Some(line) = text.lines().nth(i) {
-                                        ui.label(line);
-                                    }
-                                }
-                            },
-                        );
-                });
+                console(ui, text);
+                if !self.simple {
+                    ui.separator();
+                    input_args_field(
+                        ui,
+                        buffer,
+                        process,
+                        r#"Commands: help, status, set_log <level>, diff"#,
+                        NODE_INPUT,
+                    );
+                }
             });
             //---------------------------------------------------------------------------------------------------- [Advanced] Console
             if !self.simple {
-                ui.separator();
-                let response = ui
-                    .add_sized(
-                        [width, text_height],
-                        TextEdit::hint_text(
-                            TextEdit::singleline(buffer),
-                            r#"Commands: help, status, set_log <level>, diff"#,
-                        ),
-                    )
-                    .on_hover_text(NODE_INPUT);
-                // If the user pressed enter, dump buffer contents into the process STDIN
-                if response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
-                    response.request_focus(); // Get focus back
-                    let buffer = std::mem::take(buffer); // Take buffer
-                    let mut process = process.lock().unwrap(); // Lock
-                    if process.is_alive() {
-                        process.input.push(buffer);
-                    } // Push only if alive
-                }
-
                 //---------------------------------------------------------------------------------------------------- Arguments
                 debug!("Node Tab | Rendering [Arguments]");
-                ui.group(|ui| {
-                    ui.horizontal(|ui| {
-                        ui.add_sized(
-                            [txt_description_width, text_height],
-                            Label::new("Command arguments:"),
-                        );
-                        ui.add_sized(
-                            [ui.available_width(), text_height],
-                            TextEdit::hint_text(
-                                TextEdit::singleline(&mut self.arguments),
-                                r#"--zmq-pub tcp://127.0.0.1:18081"#,
-                            ),
-                        )
-                        .on_hover_text(NODE_ARGUMENTS);
-                        self.arguments.truncate(1024);
-                    })
-                });
-                if !self.arguments.is_empty() {
-                    ui.disable();
-                }
+                start_options_field(
+                    ui,
+                    &mut self.arguments,
+                    r#"--zmq-pub tcp://127.0.0.1:18081"#,
+                    NODE_ARGUMENTS,
+                );
                 //---------------------------------------------------------------------------------------------------- Prunned checkbox
-                ui.add_space(space_h);
-                ui.style_mut().spacing.icon_width_inner = width / 45.0;
-                ui.style_mut().spacing.icon_width = width / 35.0;
-                ui.style_mut().spacing.icon_spacing = space_h;
+                ui.add_space(SPACE);
                 debug!("Node Tab | Rendering DNS  and Prunning buttons");
                 ui.horizontal(|ui| {
                     ui.group(|ui| {
@@ -134,276 +77,69 @@ impl Node {
                     });
                 });
 
-                ui.add_space(space_h);
-                // idea
-                // need to warn the user if local firewall is blocking port
-                // need to warn the user if NAT is blocking port
-                // need to show local ip address
-                // need to show public ip
-                // text edit width is 4x bigger than description. Which makes half of the total width on screen less a space.
-
-                // (width - (width - ui.available_width()) - (ui.spacing().item_spacing.x * 4.5))
-                // / 2.0;
+                ui.add_space(SPACE);
+                //         // idea
+                //         // need to warn the user if local firewall is blocking port
+                //         // need to warn the user if NAT is blocking port
+                //         // need to show local ip address
+                //         // need to show public ip
                 ui.horizontal(|ui| {
-                    ui.group(|ui| {
-                        ui.vertical(|ui| {
-                            rpc_bind_field(self, ui, txt_description_width, text_height, width);
-                            rpc_port_field(self, ui, txt_description_width, text_height, width);
-                            ui.add_space(space_h);
-                            zmq_bind_field(self, ui, txt_description_width, text_height, width);
-                            zmq_port_field(self, ui, txt_description_width, text_height, width);
-                        });
-                    });
-
-                    //---------------------------------------------------------------------------------------------------- In/Out peers
-                    debug!("Node Tab | Rendering sliders elements");
-                    ui.vertical(|ui| {
+                    egui::ScrollArea::horizontal().show(ui, |ui| {
                         ui.group(|ui| {
-                            ui.style_mut().override_text_style = Some(TextStyle::Small);
-                            ui.horizontal(|ui| {
-                                // ui.label("Out peers [10-450]:");
-                                ui.add_sized(
-                                    [txt_description_width, text_height],
-                                    Label::new("Out peers [2-450]:"),
-                                );
-                                // not sure what's the right calculation to make
-                                ui.style_mut().spacing.slider_width = (ui.available_width()
-                                    - ui.spacing().item_spacing.x * 4.0
-                                    - ui.spacing().scroll.bar_width
-                                    - (SPACE * 2.0))
-                                    .max(0.0);
-                                ui.add(Slider::new(&mut self.out_peers, 2..=450))
-                                    .on_hover_text(P2POOL_OUT);
-                                // ui.add_space(ui.available_width() - 4.0);
+                            ui.vertical(|ui| {
+                                rpc_bind_field(&mut self.api_ip, ui);
+                                rpc_port_field(&mut self.api_port, ui);
+                                ui.add_space(SPACE);
+                                zmq_bind_field(&mut self.zmq_ip, ui);
+                                zmq_port_field(&mut self.zmq_port, ui);
                             });
-                            ui.horizontal(|ui| {
-                                // ui.label("In peers  [10-450]:");
-                                ui.add_sized(
-                                    [txt_description_width, text_height],
-                                    Label::new("In peers  [2-450]:"),
+                        });
+
+                        //---------------------------------------------------------------------------------------------------- In/Out peers
+                        debug!("Node Tab | Rendering sliders elements");
+                        ui.vertical(|ui| {
+                            ui.group(|ui| {
+                                ui.add_space(SPACE);
+                                slider_state_field(
+                                    ui,
+                                    "Out peers [2-450]:",
+                                    P2POOL_OUT,
+                                    &mut self.out_peers,
+                                    2..=450,
                                 );
-                                ui.style_mut().spacing.slider_width = (ui.available_width()
-                                    - ui.spacing().item_spacing.x * 4.0
-                                    - ui.spacing().scroll.bar_width
-                                    - (SPACE * 2.0))
-                                    .max(0.0);
-                                ui.add(Slider::new(&mut self.in_peers, 2..=450))
-                                    .on_hover_text(P2POOL_IN);
-                            });
-                            ui.horizontal(|ui| {
-                                // ui.label("Log level  [ 0-4 ]:");
-                                ui.add_sized(
-                                    [txt_description_width, text_height],
-                                    Label::new("Log level [ 0-4 ] :"),
+                                ui.add_space(SPACE);
+                                slider_state_field(
+                                    ui,
+                                    "In peers  [2-450]:",
+                                    P2POOL_IN,
+                                    &mut self.in_peers,
+                                    2..=450,
                                 );
-                                ui.style_mut().spacing.slider_width = (ui.available_width()
-                                    - ui.spacing().item_spacing.x * 4.0
-                                    - ui.spacing().scroll.bar_width
-                                    - (SPACE * 2.0))
-                                    .max(0.0);
-                                ui.add(Slider::new(&mut self.log_level, 0..=4))
-                                    .on_hover_text(P2POOL_LOG);
+                                ui.add_space(SPACE);
+                                slider_state_field(
+                                    ui,
+                                    "Log level [ 0-4 ]:",
+                                    P2POOL_LOG,
+                                    &mut self.log_level,
+                                    0..=6,
+                                );
+                                ui.add_space(SPACE);
                             });
                         });
                     });
                 });
                 //---------------------------------------------------------------------------------------------------- DB path
-                ui.add_space(space_h);
+                ui.add_space(SPACE);
                 ui.group(|ui| {
-                    path_db_field(self, ui, txt_description_width, text_height, file_window);
+                    path_db_field(ui, &mut self.path_db, file_window);
+                    let mut guard = file_window.lock().unwrap();
+                    if guard.picked_nodedb {
+                        self.path_db.clone_from(&guard.nodedb_path);
+                        guard.picked_nodedb = false;
+                    }
                 });
-                ui.add_space(space_h);
+                ui.add_space(SPACE);
             }
         });
     }
 }
-
-fn rpc_bind_field(
-    state: &mut Node,
-    ui: &mut Ui,
-    txt_description_width: f32,
-    text_height: f32,
-    width: f32,
-) {
-    state_edit_field(
-        &mut state.api_ip,
-        ui,
-        txt_description_width,
-        text_height,
-        width,
-        "RPC BIND IP ",
-        255,
-        NODE_API_BIND,
-        vec![&REGEXES.ipv4, &REGEXES.domain],
-    );
-}
-
-fn rpc_port_field(
-    state: &mut Node,
-    ui: &mut Ui,
-    txt_description_width: f32,
-    text_height: f32,
-    width: f32,
-) {
-    state_edit_field(
-        &mut state.api_port,
-        ui,
-        txt_description_width,
-        text_height,
-        width,
-        "   RPC PORT ",
-        5,
-        NODE_API_PORT,
-        vec![&REGEXES.port],
-    );
-}
-fn zmq_bind_field(
-    state: &mut Node,
-    ui: &mut Ui,
-    txt_description_width: f32,
-    text_height: f32,
-    width: f32,
-) {
-    state_edit_field(
-        &mut state.zmq_ip,
-        ui,
-        txt_description_width,
-        text_height,
-        width,
-        "API BIND IP ",
-        255,
-        NODE_ZMQ_BIND,
-        vec![&REGEXES.ipv4, &REGEXES.domain],
-    );
-}
-fn zmq_port_field(
-    state: &mut Node,
-    ui: &mut Ui,
-    txt_description_width: f32,
-    text_height: f32,
-    width: f32,
-) {
-    state_edit_field(
-        &mut state.zmq_port,
-        ui,
-        txt_description_width,
-        text_height,
-        width,
-        "   ZMQ PORT ",
-        5,
-        NODE_ZMQ_PORT,
-        vec![&REGEXES.port],
-    );
-}
-
-fn path_db_field(
-    state: &mut Node,
-    ui: &mut Ui,
-    txt_description_width: f32,
-    text_height: f32,
-    file_window: &Arc<Mutex<FileWindow>>,
-) {
-    ui.horizontal(|ui| {
-        let symbol;
-        let color;
-        let hover;
-        if state.path_db.is_empty() {
-            symbol = "➖";
-            color = LIGHT_GRAY;
-            hover = NODE_DB_PATH_EMPTY;
-        } else if !Gupax::path_is_dir(&state.path_db) {
-            symbol = "❌";
-            color = RED;
-            hover = NODE_DB_DIR;
-        } else {
-            symbol = "✔";
-            color = GREEN;
-            hover = NODE_PATH_OK;
-        }
-        let text = ["Node Database Directory ", symbol].concat();
-        ui.add_sized(
-            [txt_description_width, text_height],
-            Label::new(RichText::new(text).color(color)),
-        );
-        ui.spacing_mut().text_edit_width =
-            (ui.available_width() - (ui.spacing().item_spacing.x * 8.0) - SPACE * 2.0).max(0.0);
-        let window_busy = file_window.lock().unwrap().thread;
-        ui.add_enabled_ui(!window_busy, |ui| {
-            if ui.button("Open").on_hover_text(GUPAX_SELECT).clicked() {
-                Gupax::spawn_file_window_thread(file_window, FileType::NodeDB);
-            }
-            ui.text_edit_singleline(&mut state.path_db)
-                .on_hover_text(hover);
-        });
-    });
-
-    let mut guard = file_window.lock().unwrap();
-    if guard.picked_nodedb {
-        state.path_db.clone_from(&guard.nodedb_path);
-        guard.picked_nodedb = false;
-    }
-}
-#[allow(clippy::too_many_arguments)]
-fn state_edit_field(
-    state_field: &mut String,
-    ui: &mut Ui,
-    txt_description_width: f32,
-    text_height: f32,
-    width: f32,
-    description: &str,
-    max_ch: u8,
-    help_msg: &str,
-    validations: Vec<&Regex>,
-) {
-    ui.horizontal(|ui| {
-        let color;
-        let symbol;
-        let mut input_validated = true;
-        let len;
-        let inside_space;
-        for v in validations {
-            if !v.is_match(state_field) {
-                input_validated = false;
-            }
-        }
-        if state_field.is_empty() {
-            symbol = "➖";
-            color = Color32::LIGHT_GRAY;
-        } else if input_validated {
-            symbol = "✔";
-            color = Color32::from_rgb(100, 230, 100);
-        } else {
-            symbol = "❌";
-            color = Color32::from_rgb(230, 50, 50);
-        }
-        match max_ch {
-            x if x >= 100 => {
-                len = format!("{:03}", state_field.len());
-                inside_space = "";
-            }
-            10..99 => {
-                len = format!("{:02}", state_field.len());
-                inside_space = " ";
-            }
-            _ => {
-                len = format!("{}", state_field.len());
-                inside_space = "  ";
-            }
-        }
-        let text = format!(
-            "{}[{}{}/{}{}]{}",
-            description, inside_space, len, max_ch, inside_space, symbol
-        );
-        ui.add_sized(
-            [txt_description_width, text_height],
-            Label::new(RichText::new(text).color(color)),
-        );
-        // allocate the size to leave half of the total width free.
-        ui.spacing_mut().text_edit_width = ((width / 2.0)
-            - (width - ui.available_width() - ui.spacing().scroll.bar_width)
-            - ui.spacing().item_spacing.x * 2.5)
-            .max(0.0);
-        ui.text_edit_singleline(state_field).on_hover_text(help_msg);
-        state_field.truncate(max_ch.into());
-    });
-}
diff --git a/src/app/panels/middle/p2pool/advanced.rs b/src/app/panels/middle/p2pool/advanced.rs
index 3219b9e..33728cd 100644
--- a/src/app/panels/middle/p2pool/advanced.rs
+++ b/src/app/panels/middle/p2pool/advanced.rs
@@ -1,313 +1,154 @@
-use crate::disk::node::Node;
+use crate::app::panels::middle::common::list_poolnode::{PoolNode, list_poolnode};
+use crate::app::panels::middle::common::state_edit_field::{StateTextEdit, slider_state_field};
+use crate::miscs::height_txt_before_button;
 use crate::{disk::state::P2pool, utils::regex::REGEXES};
-use egui::Checkbox;
-use egui::Slider;
-use egui::{Button, Vec2};
 
 use crate::constants::*;
-use egui::{Color32, ComboBox, Label, RichText, SelectableLabel, Ui};
+use egui::{Checkbox, SelectableLabel, Ui};
 use log::*;
 
 impl P2pool {
-    pub(super) fn advanced(
-        &mut self,
-        ui: &mut Ui,
-        size: Vec2,
-        text_edit: f32,
-        node_vec: &mut Vec<(String, Node)>,
-    ) {
-        let height = size.y / 16.0;
-        let space_h = size.y / 128.0;
+    pub(super) fn advanced(&mut self, ui: &mut Ui, node_vec: &mut Vec<(String, PoolNode)>) {
+        // let height = size.y / 16.0;
+        // let space_h = size.y / 128.0;
         debug!("P2Pool Tab | Rendering [Node List] elements");
         let mut incorrect_input = false; // This will disable [Add/Delete] on bad input
         // [Monero node IP/RPC/ZMQ]
         ui.horizontal(|ui| {
-		    ui.group(|ui| {
-			let width = size.x/10.0;
-			ui.vertical(|ui| {
-			ui.spacing_mut().text_edit_width = width*3.32;
-			ui.horizontal(|ui| {
-				let text;
-				let color;
-				let len = format!("{:02}", self.name.len());
-				if self.name.is_empty() {
-					text = format!("Name [ {}/30 ]➖", len);
-					color = Color32::LIGHT_GRAY;
-					incorrect_input = true;
-				} else if REGEXES.name.is_match(&self.name) {
-					text = format!("Name [ {}/30 ]✔", len);
-					color = Color32::from_rgb(100, 230, 100);
-				} else {
-					text = format!("Name [ {}/30 ]❌", len);
-					color = Color32::from_rgb(230, 50, 50);
-					incorrect_input = true;
-				}
-				ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
-				ui.text_edit_singleline(&mut self.name).on_hover_text(P2POOL_NAME);
-				self.name.truncate(30);
-			});
-			ui.horizontal(|ui| {
-				let text;
-				let color;
-				let len = format!("{:03}", self.ip.len());
-				if self.ip.is_empty() {
-					text = format!("  IP [{}/255]➖", len);
-					color = Color32::LIGHT_GRAY;
-					incorrect_input = true;
-				} else if self.ip == "localhost" || REGEXES.ipv4.is_match(&self.ip) || REGEXES.domain.is_match(&self.ip) {
-					text = format!("  IP [{}/255]✔", len);
-					color = Color32::from_rgb(100, 230, 100);
-				} else {
-					text = format!("  IP [{}/255]❌", len);
-					color = Color32::from_rgb(230, 50, 50);
-					incorrect_input = true;
-				}
-				ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
-				ui.text_edit_singleline(&mut self.ip).on_hover_text(P2POOL_NODE_IP);
-				self.ip.truncate(255);
-			});
-			ui.horizontal(|ui| {
-				let text;
-				let color;
-				let len = self.rpc.len();
-				if self.rpc.is_empty() {
-					text = format!(" RPC [  {}/5  ]➖", len);
-					color = Color32::LIGHT_GRAY;
-					incorrect_input = true;
-				} else if REGEXES.port.is_match(&self.rpc) {
-					text = format!(" RPC [  {}/5  ]✔", len);
-					color = Color32::from_rgb(100, 230, 100);
-				} else {
-					text = format!(" RPC [  {}/5  ]❌", len);
-					color = Color32::from_rgb(230, 50, 50);
-					incorrect_input = true;
-				}
-				ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
-				ui.text_edit_singleline(&mut self.rpc).on_hover_text(P2POOL_RPC_PORT);
-				self.rpc.truncate(5);
-			});
-			ui.horizontal(|ui| {
-				let text;
-				let color;
-				let len = self.zmq.len();
-				if self.zmq.is_empty() {
-					text = format!(" ZMQ [  {}/5  ]➖", len);
-					color = Color32::LIGHT_GRAY;
-					incorrect_input = true;
-				} else if REGEXES.port.is_match(&self.zmq) {
-					text = format!(" ZMQ [  {}/5  ]✔", len);
-					color = Color32::from_rgb(100, 230, 100);
-				} else {
-					text = format!(" ZMQ [  {}/5  ]❌", len);
-					color = Color32::from_rgb(230, 50, 50);
-					incorrect_input = true;
-				}
-				ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
-				ui.text_edit_singleline(&mut self.zmq).on_hover_text(P2POOL_ZMQ_PORT);
-				self.zmq.truncate(5);
-			});
-		});
-
-		ui.vertical(|ui| {
-			let width = ui.available_width();
-			ui.add_space(1.0);
-			// [Manual node selection]
-			ui.spacing_mut().slider_width = width - 8.0;
-			ui.spacing_mut().icon_width = width / 25.0;
-			// [Ping List]
-			debug!("P2Pool Tab | Rendering [Node List]");
-			let text = RichText::new(format!("{}. {}", self.selected_index+1, self.selected_name));
-			ComboBox::from_id_salt("manual_nodes").selected_text(text).width(width).show_ui(ui, |ui| {
-				for (n, (name, node)) in node_vec.iter().enumerate() {
-					let text = RichText::new(format!("{}. {}\n     IP: {}\n    RPC: {}\n    ZMQ: {}", n+1, name, node.ip, node.rpc, node.zmq));
-					if ui.add(SelectableLabel::new(self.selected_name == *name, text)).clicked() {
-						self.selected_index = n;
-						let node = node.clone();
-						self.selected_name.clone_from(name);
-						self.selected_ip.clone_from(&node.ip);
-						self.selected_rpc.clone_from(&node.rpc);
-						self.selected_zmq.clone_from(&node.zmq);
-						self.name.clone_from(name);
-						self.ip = node.ip;
-						self.rpc = node.rpc;
-						self.zmq = node.zmq;
-					}
-				}
-			});
-			// [Add/Save]
-			let node_vec_len = node_vec.len();
-			let mut exists = false;
-			let mut save_diff = true;
-			let mut existing_index = 0;
-			for (name, node) in node_vec.iter() {
-				if *name == self.name {
-					exists = true;
-					if self.ip == node.ip && self.rpc == node.rpc && self.zmq == node.zmq {
-						save_diff = false;
-					}
-					break
-				}
-				existing_index += 1;
-			}
-			ui.horizontal(|ui| {
-				let text = if exists { LIST_SAVE } else { LIST_ADD };
-				let text = format!("{}\n    Currently selected node: {}. {}\n    Current amount of nodes: {}/1000", text, self.selected_index+1, self.selected_name, node_vec_len);
-				// If the node already exists, show [Save] and mutate the already existing node
-				if exists {
-					ui.add_enabled_ui(!incorrect_input && save_diff, |ui|{
-					if ui.add_sized([width, text_edit], Button::new("Save")).on_hover_text(text).clicked() {
-						let node = Node {
-							ip: self.ip.clone(),
-							rpc: self.rpc.clone(),
-							zmq: self.zmq.clone(),
-						};
-						node_vec[existing_index].1 = node;
-						self.selected_index = existing_index;
-						self.selected_ip.clone_from(&self.ip);
-						self.selected_rpc.clone_from(&self.rpc);
-						self.selected_zmq.clone_from(&self.zmq);
-						info!("Node | S | [index: {}, name: \"{}\", ip: \"{}\", rpc: {}, zmq: {}]", existing_index+1, self.name, self.ip, self.rpc, self.zmq);
-					}
-					});
-				// Else, add to the list
-				} else {
-					ui.add_enabled_ui(!incorrect_input && node_vec_len < 1000, |ui| {
-					if ui.add_sized([width, text_edit], Button::new("Add")).on_hover_text(text).clicked() {
-						let node = Node {
-							ip: self.ip.clone(),
-							rpc: self.rpc.clone(),
-							zmq: self.zmq.clone(),
-						};
-						node_vec.push((self.name.clone(), node));
-						self.selected_index = node_vec_len;
-						self.selected_name.clone_from(&self.name);
-						self.selected_ip.clone_from(&self.ip);
-						self.selected_rpc.clone_from(&self.rpc);
-						self.selected_zmq.clone_from(&self.zmq);
-						info!("Node | A | [index: {}, name: \"{}\", ip: \"{}\", rpc: {}, zmq: {}]", node_vec_len, self.name, self.ip, self.rpc, self.zmq);
-					}
-					});
-				}
-			});
-			// [Delete]
-			ui.horizontal(|ui| {
-				ui.add_enabled_ui(node_vec_len > 1, |ui|{
-				let text = format!("{}\n    Currently selected node: {}. {}\n    Current amount of nodes: {}/1000", LIST_DELETE, self.selected_index+1, self.selected_name, node_vec_len);
-				if ui.add_sized([width, text_edit], Button::new("Delete")).on_hover_text(text).clicked() {
-					let new_name;
-					let new_node;
-					match self.selected_index {
-						0 => {
-							new_name = node_vec[1].0.clone();
-							new_node = node_vec[1].1.clone();
-							node_vec.remove(0);
-						}
-						_ => {
-							node_vec.remove(self.selected_index);
-							self.selected_index -= 1;
-							new_name = node_vec[self.selected_index].0.clone();
-							new_node = node_vec[self.selected_index].1.clone();
-						}
-					};
-					self.selected_name.clone_from(&new_name);
-					self.selected_ip.clone_from(&new_node.ip);
-					self.selected_rpc.clone_from(&new_node.rpc);
-					self.selected_zmq.clone_from(&new_node.zmq);
-					self.name = new_name;
-					self.ip = new_node.ip;
-					self.rpc = new_node.rpc;
-					self.zmq = new_node.zmq;
-					info!("Node | D | [index: {}, name: \"{}\", ip: \"{}\", rpc: {}, zmq: {}]", self.selected_index, self.selected_name, self.selected_ip, self.selected_rpc, self.selected_zmq);
-				}
-				});
-			});
-			ui.horizontal(|ui| {
-				ui.add_enabled_ui(!self.name.is_empty() || !self.ip.is_empty() || !self.rpc.is_empty() || !self.zmq.is_empty(), |ui|{
-				if ui.add_sized([width, text_edit], Button::new("Clear")).on_hover_text(LIST_CLEAR).clicked() {
-					self.name.clear();
-					self.ip.clear();
-					self.rpc.clear();
-					self.zmq.clear();
-				}
-
-				});
-			});
-		});
-		});
-		});
+            ui.group(|ui| {
+                // let width = size.x/10.0;
+                ui.vertical(|ui| {
+                    if !self.name_field(ui) {
+                        incorrect_input = false;
+                    }
+                    if !self.ip_field(ui) {
+                        incorrect_input = false;
+                    }
+                    if !self.rpc_port_field(ui) {
+                        incorrect_input = false;
+                    }
+                    if !self.zmq_port_field(ui) {
+                        incorrect_input = false;
+                    }
+                });
+                list_poolnode(
+                    ui,
+                    &mut (&mut self.name, &mut self.ip, &mut self.rpc, &mut self.zmq),
+                    &mut self.selected_node,
+                    node_vec,
+                    incorrect_input,
+                );
+            });
+        });
         // ui.add_space(space_h);
 
         debug!("P2Pool Tab | Rendering [Main/Mini/Peers/Log] elements");
         // [Main/Mini]
         ui.horizontal(|ui| {
-            let height = height / 4.0;
+            // let height = height / 4.0;
             ui.group(|ui| {
-                ui.horizontal(|ui| {
-                    let width = (size.x / 4.0) - SPACE;
-                    let height = height + space_h;
-                    if ui
-                        .add_sized(
-                            [width, height],
-                            SelectableLabel::new(!self.mini, "P2Pool Main"),
+                ui.vertical(|ui| {
+                    let height = height_txt_before_button(ui, &egui::TextStyle::Button) * 1.9;
+                    ui.horizontal(|ui| {
+                        let width = (ui.available_width() / 4.0) - SPACE;
+                        if ui
+                            // if ui.add_sized(, )
+                            // .selectable_label(!self.mini, "P2Pool Main")
+                            .add_sized(
+                                [width, height],
+                                SelectableLabel::new(!self.mini, "P2Pool Main"),
+                            )
+                            .on_hover_text(P2POOL_MAIN)
+                            .clicked()
+                        {
+                            self.mini = false;
+                        }
+                        if ui
+                            // .selectable_label(!self.mini, "P2Pool Mini")
+                            // if ui
+                            .add_sized(
+                                [width, height],
+                                SelectableLabel::new(self.mini, "P2Pool Mini"),
+                            )
+                            .on_hover_text(P2POOL_MINI)
+                            .clicked()
+                        {
+                            self.mini = true;
+                        }
+                    });
+                    debug!("P2Pool Tab | Rendering Backup host button");
+                    ui.group(|ui| {
+                        // [Backup host]
+                        ui.add_sized(
+                            [(ui.available_width() / 2.0) - (SPACE * 2.0), height],
+                            Checkbox::new(&mut self.backup_host, "Backup host"),
                         )
-                        .on_hover_text(P2POOL_MAIN)
-                        .clicked()
-                    {
-                        self.mini = false;
-                    }
-                    if ui
-                        .add_sized(
-                            [width, height],
-                            SelectableLabel::new(self.mini, "P2Pool Mini"),
-                        )
-                        .on_hover_text(P2POOL_MINI)
-                        .clicked()
-                    {
-                        self.mini = true;
-                    }
-                })
+                        // ui.checkbox(&mut self.backup_host, "Backup host")
+                        .on_hover_text(P2POOL_BACKUP_HOST_ADVANCED);
+                    });
+                });
             });
             // [Out/In Peers] + [Log Level]
             ui.group(|ui| {
                 ui.vertical(|ui| {
-                    let text = (ui.available_width() / 10.0) - SPACE;
-                    let width = (text * 8.0) - SPACE;
-                    let height = height / 3.0;
-                    ui.style_mut().spacing.slider_width = width / 1.1;
-                    ui.style_mut().spacing.interact_size.y = height;
-                    ui.style_mut().override_text_style = Some(egui::TextStyle::Small);
-                    ui.horizontal(|ui| {
-                        ui.add_sized([text, height], Label::new("Out peers [10-450]:"));
-                        ui.add_sized([width, height], Slider::new(&mut self.out_peers, 10..=450))
-                            .on_hover_text(P2POOL_OUT);
-                        ui.add_space(ui.available_width() - 4.0);
-                    });
-                    ui.horizontal(|ui| {
-                        ui.add_sized([text, height], Label::new(" In peers [10-450]:"));
-                        ui.add_sized([width, height], Slider::new(&mut self.in_peers, 10..=450))
-                            .on_hover_text(P2POOL_IN);
-                    });
-                    ui.horizontal(|ui| {
-                        ui.add_sized([text, height], Label::new("   Log level [0-6]:"));
-                        ui.add_sized([width, height], Slider::new(&mut self.log_level, 0..=6))
-                            .on_hover_text(P2POOL_LOG);
-                    });
+                    ui.add_space(SPACE);
+                    slider_state_field(
+                        ui,
+                        "Out peers [2-450]:",
+                        P2POOL_OUT,
+                        &mut self.out_peers,
+                        2..=450,
+                    );
+                    ui.add_space(SPACE);
+                    slider_state_field(
+                        ui,
+                        "In peers  [2-450]:",
+                        P2POOL_IN,
+                        &mut self.in_peers,
+                        2..=450,
+                    );
+                    ui.add_space(SPACE);
+                    slider_state_field(
+                        ui,
+                        "Log level [ 0-6 ]:",
+                        P2POOL_LOG,
+                        &mut self.log_level,
+                        0..=6,
+                    );
                 })
             });
         });
-
-        debug!("P2Pool Tab | Rendering Backup host button");
-        ui.group(|ui| {
-            let width = size.x - SPACE;
-            let height = ui.available_height();
-            ui.style_mut().spacing.icon_width = height;
-            ui.style_mut().spacing.icon_width_inner = height * 0.9;
-            // [Backup host]
-            ui.add_sized(
-                [width, height],
-                Checkbox::new(&mut self.backup_host, "Backup host"),
-            )
-            .on_hover_text(P2POOL_BACKUP_HOST_ADVANCED);
-        });
+    }
+    fn name_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description("   Name     ")
+            .max_ch(30)
+            .help_msg(P2POOL_NAME)
+            .validations(&[|x| REGEXES.name.is_match(x)])
+            .build(ui, &mut self.name)
+    }
+    fn rpc_port_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description("   RPC PORT ")
+            .max_ch(5)
+            .help_msg(P2POOL_RPC_PORT)
+            .validations(&[|x| REGEXES.port.is_match(x)])
+            .build(ui, &mut self.rpc)
+    }
+    fn zmq_port_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description("   ZMQ PORT ")
+            .max_ch(5)
+            .help_msg(P2POOL_ZMQ_PORT)
+            .validations(&[|x| REGEXES.port.is_match(x)])
+            .build(ui, &mut self.zmq)
+    }
+    fn ip_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description("   IP       ")
+            .max_ch(255)
+            .help_msg(P2POOL_NODE_IP)
+            .validations(&[|x| REGEXES.ipv4.is_match(x), |x| REGEXES.domain.is_match(x)])
+            .build(ui, &mut self.ip)
     }
 }
diff --git a/src/app/panels/middle/p2pool/mod.rs b/src/app/panels/middle/p2pool/mod.rs
index 1fdda52..c5a709b 100644
--- a/src/app/panels/middle/p2pool/mod.rs
+++ b/src/app/panels/middle/p2pool/mod.rs
@@ -1,7 +1,6 @@
-use crate::disk::node::Node;
+use crate::app::panels::middle::common::console::{console, input_args_field, start_options_field};
 use crate::disk::state::{P2pool, State};
 use crate::helper::p2pool::PubP2poolApi;
-use crate::regex::num_lines;
 // Gupax - GUI Uniting P2Pool And XMRig
 //
 // Copyright (c) 2022-2023 hinto-janai
@@ -18,12 +17,13 @@ use crate::regex::num_lines;
 //
 // You should have received a copy of the GNU General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
-use crate::{components::node::*, constants::*, helper::*, utils::regex::Regexes};
-use egui::{Color32, Label, RichText, TextEdit, TextStyle, Vec2, vec2};
+use crate::{components::node::*, constants::*, helper::*};
 use log::*;
 
 use std::sync::{Arc, Mutex};
 
+use super::common::list_poolnode::PoolNode;
+
 mod advanced;
 mod simple;
 
@@ -32,143 +32,51 @@ impl P2pool {
     #[allow(clippy::too_many_arguments)]
     pub fn show(
         &mut self,
-        node_vec: &mut Vec<(String, Node)>,
+        node_vec: &mut Vec<(String, PoolNode)>,
         _og: &Arc<Mutex<State>>,
         ping: &Arc<Mutex<Ping>>,
         process: &Arc<Mutex<Process>>,
         api: &Arc<Mutex<PubP2poolApi>>,
         buffer: &mut String,
-        size: Vec2,
         _ctx: &egui::Context,
         ui: &mut egui::Ui,
     ) {
-        let height = size.y;
-        let width = size.x;
-        let text_edit = size.y / 25.0;
         //---------------------------------------------------------------------------------------------------- [Simple] Console
         // debug!("P2Pool Tab | Rendering [Console]");
         egui::ScrollArea::vertical().show(ui, |ui| {
+            let text = &api.lock().unwrap().output;
             ui.group(|ui| {
-                let text = &api.lock().unwrap().output;
-                let nb_lines = num_lines(text);
-                let (height, width) = if self.simple {
-                    ((size.y * 0.38) - SPACE, size.x - SPACE)
-                } else {
-                    (
-                        if size.y < 600.0 {
-                            size.y * 0.22 - SPACE
-                        } else {
-                            size.y * 0.36 - SPACE
-                        },
-                        width - SPACE,
-                    )
-                };
-                egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
-                    ui.style_mut().override_text_style = Some(egui::TextStyle::Small);
-                    egui::ScrollArea::vertical()
-                        .stick_to_bottom(true)
-                        .max_width(width)
-                        .max_height(height)
-                        .auto_shrink([false; 2])
-                        // .show_viewport(ui, |ui, _| {
-                        .show_rows(
-                            ui,
-                            ui.text_style_height(&TextStyle::Small),
-                            nb_lines,
-                            |ui, row_range| {
-                                for i in row_range {
-                                    if let Some(line) = text.lines().nth(i) {
-                                        ui.label(line);
-                                    }
-                                }
-                            },
-                        );
-                });
+                console(ui, text);
                 if !self.simple {
-                    //---------------------------------------------------------------------------------------------------- [Advanced] Console
                     ui.separator();
-                    let response = ui
-                        .add_sized(
-                            [width, text_edit],
-                            TextEdit::hint_text(
-                                TextEdit::singleline(buffer),
-                                r#"Type a command (e.g "help" or "status") and press Enter"#,
-                            ),
-                        )
-                        .on_hover_text(P2POOL_INPUT);
-                    // If the user pressed enter, dump buffer contents into the process STDIN
-                    if response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
-                        response.request_focus(); // Get focus back
-                        let buffer = std::mem::take(buffer); // Take buffer
-                        let mut process = process.lock().unwrap(); // Lock
-                        if process.is_alive() {
-                            process.input.push(buffer);
-                        } // Push only if alive
-                    }
+                    input_args_field(
+                        ui,
+                        buffer,
+                        process,
+                        r#"Type a command (e.g "help" or "status") and press Enter"#,
+                        P2POOL_INPUT,
+                    );
                 }
             });
-
-            //---------------------------------------------------------------------------------------------------- Args
             if !self.simple {
-                debug!("P2Pool Tab | Rendering [Arguments]");
-                ui.group(|ui| {
-                    ui.horizontal(|ui| {
-                        let width = (width / 10.0) - SPACE;
-                        ui.add_sized([width, text_edit], Label::new("Command arguments:"));
-                        ui.add_sized(
-                            [ui.available_width(), text_edit],
-                            TextEdit::hint_text(
-                                TextEdit::singleline(&mut self.arguments),
-                                r#"--wallet <...> --host <...>"#,
-                            ),
-                        )
-                        .on_hover_text(P2POOL_ARGUMENTS);
-                        self.arguments.truncate(1024);
-                    })
-                });
-                if !self.arguments.is_empty() {
-                    ui.disable()
-                }
-            }
-
-            //---------------------------------------------------------------------------------------------------- Address
-            debug!("P2Pool Tab | Rendering [Address]");
-            ui.group(|ui| {
-                let width = width - SPACE;
-                ui.spacing_mut().text_edit_width = (width) - (SPACE * 3.0);
-                let text;
-                let color;
-                let len = format!("{:02}", self.address.len());
-                if self.address.is_empty() {
-                    text = format!("Monero Address [{}/95] ➖", len);
-                    color = Color32::LIGHT_GRAY;
-                } else if Regexes::addr_ok(&self.address) {
-                    text = format!("Monero Address [{}/95] ✔", len);
-                    color = Color32::from_rgb(100, 230, 100);
-                } else {
-                    text = format!("Monero Address [{}/95] ❌", len);
-                    color = Color32::from_rgb(230, 50, 50);
-                }
-                ui.add_sized(
-                    [width, text_edit],
-                    Label::new(RichText::new(text).color(color)),
+                start_options_field(
+                    ui,
+                    &mut self.arguments,
+                    r#"--wallet <...> --host <...>"#,
+                    P2POOL_ARGUMENTS,
                 );
-                ui.add_sized(
-                    [width, text_edit],
-                    TextEdit::hint_text(TextEdit::singleline(&mut self.address), "4..."),
-                )
-                .on_hover_text(P2POOL_ADDRESS);
-                self.address.truncate(95);
-            });
+            }
+            debug!("P2Pool Tab | Rendering [Address]");
+            crate::app::panels::middle::common::state_edit_field::monero_address_field(
+                &mut self.address,
+                ui,
+                P2POOL_ADDRESS,
+            );
 
-            // let height = ui.available_height();
-            let size = vec2(width, height);
             if self.simple {
-                //---------------------------------------------------------------------------------------------------- Simple
-                self.simple(ui, size, ping);
-            //---------------------------------------------------------------------------------------------------- Advanced
+                self.simple(ui, ping);
             } else {
-                self.advanced(ui, size, text_edit, node_vec);
+                self.advanced(ui, node_vec);
             }
         });
     }
diff --git a/src/app/panels/middle/p2pool/simple.rs b/src/app/panels/middle/p2pool/simple.rs
index 9316c2c..2242ded 100644
--- a/src/app/panels/middle/p2pool/simple.rs
+++ b/src/app/panels/middle/p2pool/simple.rs
@@ -1,47 +1,32 @@
 use std::sync::Arc;
 use std::sync::Mutex;
 
-use crate::app::panels::middle::Hyperlink;
 use crate::app::panels::middle::ProgressBar;
-use crate::app::panels::middle::Spinner;
 use crate::components::node::Ping;
 use crate::components::node::RemoteNode;
 use crate::components::node::format_ip_location;
 use crate::components::node::format_ms;
 use crate::disk::state::P2pool;
+use crate::miscs::height_txt_before_button;
 use egui::Button;
 use egui::Checkbox;
-use egui::Vec2;
+use egui::ScrollArea;
+use egui::TextStyle;
+use egui::TextWrapMode;
 use egui::vec2;
 
 use crate::constants::*;
-use egui::{Color32, ComboBox, Label, RichText, Ui};
+use egui::{Color32, ComboBox, RichText, Ui};
 use log::*;
 impl P2pool {
-    pub(super) fn simple(&mut self, ui: &mut Ui, size: Vec2, ping: &Arc<Mutex<Ping>>) {
-        // [Node]
-        let height = size.y / 13.0;
-        let space_h = size.y / 96.0;
-        ui.spacing_mut().slider_width = (size.x - 16.0).max(0.0);
-        ui.spacing_mut().icon_width = size.x / 25.0;
-
-        // [Auto-select] if we haven't already.
-        // Using [Arc<Mutex<Ping>>] as an intermediary here
-        // saves me the hassle of wrapping [state: State] completely
-        // and [.lock().unwrap()]ing it everywhere.
-        // Two atomic bools = enough to represent this data
-
-        // local or remote
-        // button bool
+    pub(super) fn simple(&mut self, ui: &mut Ui, ping: &Arc<Mutex<Ping>>) {
         ui.vertical_centered(|ui|{
-            ui.add_space(space_h);
+            ui.add_space(SPACE);
             ui.checkbox(&mut self.local_node, "Use a local node").on_hover_text("If checked (recommended), p2pool will automatically use the local node.\nCheck the Node tab to start a local node.\nIf unchecked, p2pool will attempt to use a remote node.");
         });
-        ui.add_space(space_h * 2.0);
-
+        ui.add_space(SPACE * 2.0);
         // if checked, use only local node
         // if unchecked, show remote nodes.
-
         // disable remote if local is checked.
         let visible = !self.local_node;
         debug!("P2Pool Tab | Running [auto-select] check");
@@ -54,7 +39,6 @@ impl P2pool {
             }
             drop(ping);
         }
-
         ui.add_enabled_ui(visible, |ui| {
             ui.vertical(|ui| {
                 ui.horizontal(|ui| {
@@ -74,9 +58,11 @@ impl P2pool {
                     debug!("P2Pool Tab | Rendering [ComboBox] of Remote Nodes");
                     let ip_location = format_ip_location(&self.node, false);
                     let text = RichText::new(format!(" ⏺ {}ms | {}", ms, ip_location)).color(color);
+                    ui.style_mut().override_text_style = Some(egui::TextStyle::Small);
+                    ui.spacing_mut().item_spacing.y = 0.0;
                     ComboBox::from_id_salt("remote_nodes")
                         .selected_text(text)
-                        .width(size.x)
+                        .width(ui.available_width())
                         .show_ui(ui, |ui| {
                             for data in ping.lock().unwrap().nodes.iter() {
                                 let ms = format_ms(data.ms);
@@ -87,123 +73,151 @@ impl P2pool {
                             }
                         });
                 });
-
-                ui.add_space(space_h);
-
+                ui.add_space(SPACE);
                 debug!("P2Pool Tab | Rendering [Select fastest ... Ping] buttons");
-                ui.horizontal(|ui| {
-                    let width = ((size.x / 5.0) - 6.0).max(0.0);
-                    let size = vec2(width, height);
-                    // [Select random node]
-                    if ui
-                        .add_sized(size, Button::new("Select random node"))
-                        .on_hover_text(P2POOL_SELECT_RANDOM)
-                        .clicked()
-                    {
-                        self.node = RemoteNode::get_random(&self.node);
-                    }
-                    // [Select fastest node]
-                    if ui
-                        .add_sized(size, Button::new("Select fastest node"))
-                        .on_hover_text(P2POOL_SELECT_FASTEST)
-                        .clicked()
-                        && ping.lock().unwrap().pinged
-                    {
-                        self.node = ping.lock().unwrap().fastest.to_string();
-                    }
-                    // [Ping Button]
-                    ui.add_enabled_ui(!ping.lock().unwrap().pinging, |ui| {
-                        if ui
-                            .add_sized(size, Button::new("Ping remote nodes"))
-                            .on_hover_text(P2POOL_PING)
-                            .clicked()
-                        {
-                            Ping::spawn_thread(ping);
-                        }
-                    });
-                    // [Last <-]
-                    if ui
-                        .add_sized(size, Button::new("⬅ Last"))
-                        .on_hover_text(P2POOL_SELECT_LAST)
-                        .clicked()
-                    {
-                        let ping = ping.lock().unwrap();
-                        match ping.pinged {
-                            true => {
-                                self.node = RemoteNode::get_last_from_ping(&self.node, &ping.nodes)
+                ScrollArea::horizontal()
+                    .scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysHidden)
+                    .id_salt("horizontal")
+                    .show(ui, |ui| {
+                        ui.style_mut().override_text_style = Some(egui::TextStyle::Button);
+                        ui.horizontal(|ui| {
+                            ui.style_mut().wrap_mode = Some(TextWrapMode::Extend);
+                            // ui.columns_const(|[col1, col2, col3, col4, col5]| {
+                            let width = ((ui.available_width() / 5.0)
+                                - (ui.spacing().item_spacing.x * (4.0 / 5.0)))
+                                .max(20.0);
+                            let height = height_txt_before_button(ui, &TextStyle::Button) * 2.0;
+                            // [Select random node]
+                            ui.style_mut().override_text_valign = Some(egui::Align::Center);
+                            if ui
+                                .add_sized([width, height], Button::new("Select random node"))
+                                .on_hover_text(P2POOL_SELECT_RANDOM)
+                                .clicked()
+                            {
+                                self.node = RemoteNode::get_random(&self.node);
                             }
-                            false => self.node = RemoteNode::get_last(&self.node),
-                        }
-                        drop(ping);
-                    }
-                    // [Next ->]
-                    if ui
-                        .add_sized(size, Button::new("Next ➡"))
-                        .on_hover_text(P2POOL_SELECT_NEXT)
-                        .clicked()
-                    {
-                        let ping = ping.lock().unwrap();
-                        match ping.pinged {
-                            true => {
-                                self.node = RemoteNode::get_next_from_ping(&self.node, &ping.nodes)
+                            // [Select fastest node]
+                            if ui
+                                .add_sized([width, height], Button::new("Select fastest node"))
+                                .on_hover_text(P2POOL_SELECT_FASTEST)
+                                .clicked()
+                                && ping.lock().unwrap().pinged
+                            {
+                                self.node = ping.lock().unwrap().fastest.to_string();
                             }
-                            false => self.node = RemoteNode::get_next(&self.node),
-                        }
-                        drop(ping);
-                    }
-                });
+                            // [Ping Button]
+                            ui.add_enabled_ui(!ping.lock().unwrap().pinging, |ui| {
+                                if ui
+                                    .add_sized([width, height], Button::new("Ping remote nodes"))
+                                    .on_hover_text(P2POOL_PING)
+                                    .clicked()
+                                {
+                                    Ping::spawn_thread(ping);
+                                }
+                            });
+                            // [Last <-]
+                            if ui
+                                .add_sized([width, height], Button::new("⬅ Last"))
+                                .on_hover_text(P2POOL_SELECT_LAST)
+                                .clicked()
+                            {
+                                let ping = ping.lock().unwrap();
+                                match ping.pinged {
+                                    true => {
+                                        self.node =
+                                            RemoteNode::get_last_from_ping(&self.node, &ping.nodes)
+                                    }
+                                    false => self.node = RemoteNode::get_last(&self.node),
+                                }
+                                drop(ping);
+                            }
+                            // [Next ->]
+                            if ui
+                                .add_sized([width, height], Button::new("Next ➡"))
+                                .on_hover_text(P2POOL_SELECT_NEXT)
+                                .clicked()
+                            {
+                                let ping = ping.lock().unwrap();
+                                match ping.pinged {
+                                    true => {
+                                        self.node =
+                                            RemoteNode::get_next_from_ping(&self.node, &ping.nodes)
+                                    }
+                                    false => self.node = RemoteNode::get_next(&self.node),
+                                }
+                                drop(ping);
+                            }
+                        });
 
-                ui.vertical(|ui| {
-                    let height = height / 2.0;
-                    let pinging = ping.lock().unwrap().pinging;
-                    ui.add_enabled_ui(pinging, |ui| {
-                        let prog = ping.lock().unwrap().prog.round();
-                        let msg =
-                            RichText::new(format!("{} ... {}%", ping.lock().unwrap().msg, prog));
-                        let height = height / 1.25;
-                        let size = vec2(size.x, height);
-                        ui.add_space(space_h);
-                        ui.add_sized(size, Label::new(msg));
-                        ui.add_space(space_h);
-                        if pinging {
-                            ui.add_sized(size, Spinner::new().size(height));
-                        } else {
-                            ui.add_sized(size, Label::new("..."));
-                        }
-                        ui.add_sized(size, ProgressBar::new(prog.round() / 100.0));
-                        ui.add_space(space_h);
+                        ui.vertical_centered(|ui| {
+                            // let height = height / 2.0;
+                            let pinging = ping.lock().unwrap().pinging;
+                            ui.add_enabled_ui(pinging, |ui| {
+                                let prog = ping.lock().unwrap().prog.round();
+                                let msg = RichText::new(format!(
+                                    "{} ... {}%",
+                                    ping.lock().unwrap().msg,
+                                    prog
+                                ));
+                                // let height = height / 1.25;
+                                // let size = vec2(size.x, height);
+                                ui.add_space(SPACE);
+                                ui.label(msg);
+                                ui.add_space(SPACE);
+                                if pinging {
+                                    ui.spinner();
+                                } else {
+                                    ui.label("...");
+                                }
+                                ui.add(ProgressBar::new(prog.round() / 100.0));
+                                ui.add_space(SPACE);
+                            });
+                        });
+
+                        debug!("P2Pool Tab | Rendering [Auto-*] buttons");
+                        ui.group(|ui| {
+                            ui.horizontal(|ui| {
+                                let width =
+                                    (((ui.available_width() - ui.spacing().item_spacing.x) / 3.0)
+                                        - SPACE * 1.5)
+                                        .max(ui.text_style_height(&TextStyle::Button) * 7.0);
+                                let size = vec2(
+                                    width,
+                                    height_txt_before_button(ui, &TextStyle::Button) * 2.0,
+                                );
+                                // [Auto-node]
+                                ui.add_sized(
+                                    size,
+                                    Checkbox::new(&mut self.auto_select, "Auto-select"),
+                                )
+                                // ui.checkbox(&mut self.auto_select, "Auto-select")
+                                .on_hover_text(P2POOL_AUTO_SELECT);
+                                ui.separator();
+                                // [Auto-node]
+                                ui.add_sized(size, Checkbox::new(&mut self.auto_ping, "Auto-ping"))
+                                    // ui.checkbox(&mut self.auto_ping, "Auto-ping")
+                                    .on_hover_text(P2POOL_AUTO_NODE);
+                                ui.separator();
+                                // [Backup host]
+                                ui.add_sized(
+                                    size,
+                                    Checkbox::new(&mut self.backup_host, "Backup host"),
+                                )
+                                // ui.checkbox(&mut self.backup_host, "Backup host")
+                                .on_hover_text(P2POOL_BACKUP_HOST_SIMPLE);
+                            })
+                        });
                     });
-                });
             });
-
-            debug!("P2Pool Tab | Rendering [Auto-*] buttons");
-            ui.group(|ui| {
-                ui.horizontal(|ui| {
-                    let width = ((size.x / 3.0) - (SPACE * 1.75)).max(0.0);
-                    let size = vec2(width, height);
-                    // [Auto-node]
-                    ui.add_sized(size, Checkbox::new(&mut self.auto_select, "Auto-select"))
-                        .on_hover_text(P2POOL_AUTO_SELECT);
-                    ui.separator();
-                    // [Auto-node]
-                    ui.add_sized(size, Checkbox::new(&mut self.auto_ping, "Auto-ping"))
-                        .on_hover_text(P2POOL_AUTO_NODE);
-                    ui.separator();
-                    // [Backup host]
-                    ui.add_sized(size, Checkbox::new(&mut self.backup_host, "Backup host"))
-                        .on_hover_text(P2POOL_BACKUP_HOST_SIMPLE);
-                })
-            });
-
             debug!("P2Pool Tab | Rendering warning text");
-            ui.add_sized(
-            [size.x, height / 2.0],
-            Hyperlink::from_label_and_url(
+            ui.add_space(SPACE);
+            ui.vertical_centered(|ui| {
+                ui.hyperlink_to(
                 "WARNING: It is recommended to run/use your own Monero Node (hover for details)",
                 "https://github.com/Cyrix126/gupaxx#running-a-local-monero-node",
-            ),
-        )
-        .on_hover_text(P2POOL_COMMUNITY_NODE_WARNING);
+            )
+            .on_hover_text(P2POOL_COMMUNITY_NODE_WARNING);
+            });
         });
     }
 }
diff --git a/src/app/panels/middle/status/benchmarks.rs b/src/app/panels/middle/status/benchmarks.rs
index 77e4da0..bcbecef 100644
--- a/src/app/panels/middle/status/benchmarks.rs
+++ b/src/app/panels/middle/status/benchmarks.rs
@@ -1,7 +1,7 @@
 use std::sync::{Arc, Mutex};
 
 use crate::{app::Benchmark, disk::state::Status, helper::xrig::xmrig::PubXmrigApi};
-use egui::{Hyperlink, ProgressBar, ScrollArea, Spinner, Vec2};
+use egui::{ProgressBar, ScrollArea, TextWrapMode};
 use egui_extras::{Column, TableBuilder};
 use readable::num::{Float, Percent, Unsigned};
 
@@ -11,85 +11,56 @@ use log::*;
 impl Status {
     pub(super) fn benchmarks(
         &mut self,
-        size: Vec2,
         ui: &mut egui::Ui,
         benchmarks: &[Benchmark],
         xmrig_alive: bool,
         xmrig_api: &Arc<Mutex<PubXmrigApi>>,
     ) {
         debug!("Status Tab | Rendering [Benchmarks]");
-        let text = size.y / 20.0;
+        let text = ui.text_style_height(&egui::TextStyle::Body);
         let double = text * 2.0;
-        let log = size.y / 3.0;
 
-        let width = size.x;
+        let width = ui.available_width();
         // [0], The user's CPU (most likely).
         let cpu = &benchmarks[0];
         ui.horizontal(|ui| {
-            let width = (width / 2.0) - (SPACE * 1.666);
-            let min_height = log;
             ui.group(|ui| {
-                ui.vertical(|ui| {
-                    ui.set_min_height(min_height);
-                    ui.add_sized(
-                        [width, text],
-                        Label::new(RichText::new("Your CPU").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_SUBMENU_YOUR_CPU);
-                    ui.add_sized([width, text], Label::new(cpu.cpu.as_str()));
-                    ui.add_sized(
-                        [width, text],
-                        Label::new(RichText::new("Total Benchmarks").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_SUBMENU_YOUR_BENCHMARKS);
-                    ui.add_sized([width, text], Label::new(format!("{}", cpu.benchmarks)));
-                    ui.add_sized(
-                        [width, text],
-                        Label::new(RichText::new("Rank").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_SUBMENU_YOUR_RANK);
-                    ui.add_sized(
-                        [width, text],
-                        Label::new(format!("{}/{}", cpu.rank, &benchmarks.len())),
-                    );
+                ui.set_max_width(ui.available_width() / 2.0);
+                ui.vertical_centered(|ui| {
+                    ui.label(RichText::new("Your CPU").underline().color(BONE))
+                        .on_hover_text(STATUS_SUBMENU_YOUR_CPU);
+                    ui.label(cpu.cpu.as_str());
+                    ui.label(RichText::new("Total Banchmarks").underline().color(BONE))
+                        .on_hover_text(STATUS_SUBMENU_YOUR_BENCHMARKS);
+                    ui.label(format!("{}", cpu.benchmarks));
+                    // ui.add_sized([width, text], Label::new(format!("{}", cpu.benchmarks)));
+                    ui.label(RichText::new("Rank").underline().color(BONE))
+                        .on_hover_text(STATUS_SUBMENU_YOUR_RANK);
+                    ui.label(format!("{}/{}", cpu.rank, &benchmarks.len()));
                 })
             });
             ui.group(|ui| {
-                ui.vertical(|ui| {
-                    ui.set_min_height(min_height);
-                    ui.add_sized(
-                        [width, text],
-                        Label::new(RichText::new("High Hashrate").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_SUBMENU_YOUR_HIGH);
-                    ui.add_sized(
-                        [width, text],
-                        Label::new(format!("{} H/s", Float::from_0(cpu.high.into()))),
-                    );
-                    ui.add_sized(
-                        [width, text],
-                        Label::new(RichText::new("Average Hashrate").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_SUBMENU_YOUR_AVERAGE);
-                    ui.add_sized(
-                        [width, text],
-                        Label::new(format!("{} H/s", Float::from_0(cpu.average.into()))),
-                    );
-                    ui.add_sized(
-                        [width, text],
-                        Label::new(RichText::new("Low Hashrate").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_SUBMENU_YOUR_LOW);
-                    ui.add_sized(
-                        [width, text],
-                        Label::new(format!("{} H/s", Float::from_0(cpu.low.into()))),
-                    );
+                ui.vertical_centered(|ui| {
+                    ui.label(RichText::new("High Hashrate").underline().color(BONE))
+                        .on_hover_text(STATUS_SUBMENU_YOUR_HIGH);
+                    ui.label(format!("{} H/s", Float::from_0(cpu.high.into())));
+                    ui.label(RichText::new("Average Hashrate").underline().color(BONE))
+                        .on_hover_text(STATUS_SUBMENU_YOUR_AVERAGE);
+                    ui.label(format!("{} H/s", Float::from_0(cpu.average.into())));
+                    ui.label(RichText::new("Low Hashrate").underline().color(BONE))
+                        .on_hover_text(STATUS_SUBMENU_YOUR_LOW);
+                    ui.label(RichText::new(format!(
+                        "{} H/s",
+                        Float::from_0(cpu.low.into())
+                    )));
                 })
             })
         });
 
         // User's CPU hashrate comparison (if XMRig is alive).
-        ui.scope(|ui| {
+        // User's CPU hashrate comparison (if XMRig is alive).
+        ui.vertical_centered(|ui| {
+            ui.add_space(SPACE);
             if xmrig_alive {
                 let api = xmrig_api.lock().unwrap();
                 let percent = (api.hashrate_raw / cpu.high) * 100.0;
@@ -102,11 +73,11 @@ impl Status {
                         human, api.hashrate
                     )),
                     );
-                    ui.add_sized([width, text], ProgressBar::new(1.0));
+                    ui.add(ProgressBar::new(1.0));
                 } else if api.hashrate_raw == 0.0 {
-                    ui.add_sized([width, text], Label::new("Measuring hashrate..."));
-                    ui.add_sized([width, text], Spinner::new().size(text));
-                    ui.add_sized([width, text], ProgressBar::new(0.0));
+                    ui.label("Measuring hashrate...");
+                    ui.spinner();
+                    ui.add(ProgressBar::new(0.0));
                 } else {
                     ui.add_sized(
                         [width, double],
@@ -115,7 +86,7 @@ impl Status {
                             human, api.hashrate
                         )),
                     );
-                    ui.add_sized([width, text], ProgressBar::new(percent / 100.0));
+                    ui.add(ProgressBar::new(percent / 100.0));
                 }
             } else {
                 ui.add_enabled_ui(xmrig_alive, |ui| {
@@ -123,22 +94,21 @@ impl Status {
                         [width, double],
                         Label::new("XMRig is offline. Hashrate cannot be determined."),
                     );
-                    ui.add_sized([width, text], ProgressBar::new(0.0));
+                    ui.add(ProgressBar::new(0.0));
                 });
             }
+            ui.add_space(SPACE);
+            // Comparison
+            ui.group(|ui| {
+                ui.hyperlink_to("Other CPUs", "https://xmrig.com/benchmark")
+                    .on_hover_text(STATUS_SUBMENU_OTHER_CPUS);
+            });
         });
 
         // Comparison
-        ui.group(|ui| {
-            ui.add_sized(
-                [width, text],
-                Hyperlink::from_label_and_url("Other CPUs", "https://xmrig.com/benchmark"),
-            )
-            .on_hover_text(STATUS_SUBMENU_OTHER_CPUS);
-        });
         let width_column = width / 20.0;
         let (cpu, bar, high, average, low, rank, bench) = (
-            width_column * 10.0,
+            width_column * 6.0,
             width_column * 3.0,
             width_column * 2.0,
             width_column * 2.0,
@@ -146,6 +116,7 @@ impl Status {
             width_column,
             width_column * 2.0,
         );
+        ui.style_mut().wrap_mode = Some(TextWrapMode::Extend);
         ScrollArea::horizontal().show(ui, |ui| {
             TableBuilder::new(ui)
                 .columns(Column::auto(), 7)
diff --git a/src/app/panels/middle/status/mod.rs b/src/app/panels/middle/status/mod.rs
index 0debc47..7a4405e 100644
--- a/src/app/panels/middle/status/mod.rs
+++ b/src/app/panels/middle/status/mod.rs
@@ -15,8 +15,6 @@
 // You should have received a copy of the GNU General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-use egui::Vec2;
-
 use crate::{
     app::{Benchmark, eframe_impl::ProcessStatesGui},
     disk::{gupax_p2pool_api::GupaxP2poolApi, state::Status, status::*},
@@ -51,10 +49,9 @@ impl Status {
         p2pool_img: &Arc<Mutex<ImgP2pool>>,
         xmrig_img: &Arc<Mutex<ImgXmrig>>,
         states: &ProcessStatesGui,
-        max_threads: usize,
+        max_threads: u16,
         gupax_p2pool_api: &Arc<Mutex<GupaxP2poolApi>>,
         benchmarks: &[Benchmark],
-        size: Vec2,
         _ctx: &egui::Context,
         ui: &mut egui::Ui,
     ) {
@@ -62,7 +59,6 @@ impl Status {
         if self.submenu == Submenu::Processes {
             self.processes(
                 sys,
-                size,
                 ui,
                 node_api,
                 p2pool_api,
@@ -77,7 +73,6 @@ impl Status {
         //---------------------------------------------------------------------------------------------------- [P2Pool]
         } else if self.submenu == Submenu::P2pool {
             self.p2pool(
-                size,
                 ui,
                 gupax_p2pool_api,
                 states.is_alive(ProcessName::P2pool),
@@ -86,7 +81,6 @@ impl Status {
         //---------------------------------------------------------------------------------------------------- [Benchmarks]
         } else if self.submenu == Submenu::Benchmarks {
             self.benchmarks(
-                size,
                 ui,
                 benchmarks,
                 states.is_alive(ProcessName::Xmrig),
diff --git a/src/app/panels/middle/status/p2pool.rs b/src/app/panels/middle/status/p2pool.rs
index 3373b6a..49f7f1b 100644
--- a/src/app/panels/middle/status/p2pool.rs
+++ b/src/app/panels/middle/status/p2pool.rs
@@ -1,7 +1,8 @@
 use std::sync::{Arc, Mutex};
 
-use egui::{Label, RichText, SelectableLabel, Slider, TextEdit, Vec2};
+use egui::{Label, RichText, ScrollArea, SelectableLabel, Separator, Slider, TextStyle};
 use readable::num::Unsigned;
+use strum::{EnumCount, IntoEnumIterator};
 
 use crate::{
     disk::{
@@ -16,445 +17,345 @@ use crate::{
 impl Status {
     pub fn p2pool(
         &mut self,
-        size: Vec2,
         ui: &mut egui::Ui,
         gupax_p2pool_api: &Arc<Mutex<GupaxP2poolApi>>,
         p2pool_alive: bool,
         p2pool_api: &Arc<Mutex<PubP2poolApi>>,
     ) {
         let api = gupax_p2pool_api.lock().unwrap();
-        let height = size.y;
-        let width = size.x;
-        let text = height / 25.0;
-        let log = height / 2.8;
+        // let height = size.y;
+        // let width = size.x;
+        // let text = height / 25.0;
+        // let log = height / 2.8;
         // Payout Text + PayoutView buttons
-        ui.group(|ui| {
-            ui.horizontal(|ui| {
-                let width = (width / 3.0) - (SPACE * 4.0);
-                ui.add_sized(
-                    [width, text],
-                    Label::new(
-                        RichText::new(format!("Total Payouts: {}", api.payout))
-                            .underline()
-                            .color(LIGHT_GRAY),
-                    ),
-                )
-                .on_hover_text(STATUS_SUBMENU_PAYOUT);
-                ui.separator();
-                ui.add_sized(
-                    [width, text],
-                    Label::new(
-                        RichText::new(format!("Total XMR: {}", api.xmr))
-                            .underline()
-                            .color(LIGHT_GRAY),
-                    ),
-                )
-                .on_hover_text(STATUS_SUBMENU_XMR);
-                let width = width / 4.0;
-                ui.separator();
-                if ui
-                    .add_sized(
-                        [width, text],
-                        SelectableLabel::new(self.payout_view == PayoutView::Latest, "Latest"),
-                    )
-                    .on_hover_text(STATUS_SUBMENU_LATEST)
-                    .clicked()
-                {
-                    self.payout_view = PayoutView::Latest;
-                }
-                ui.separator();
-                if ui
-                    .add_sized(
-                        [width, text],
-                        SelectableLabel::new(self.payout_view == PayoutView::Oldest, "Oldest"),
-                    )
-                    .on_hover_text(STATUS_SUBMENU_OLDEST)
-                    .clicked()
-                {
-                    self.payout_view = PayoutView::Oldest;
-                }
-                ui.separator();
-                if ui
-                    .add_sized(
-                        [width, text],
-                        SelectableLabel::new(self.payout_view == PayoutView::Biggest, "Biggest"),
-                    )
-                    .on_hover_text(STATUS_SUBMENU_BIGGEST)
-                    .clicked()
-                {
-                    self.payout_view = PayoutView::Biggest;
-                }
-                ui.separator();
-                if ui
-                    .add_sized(
-                        [width, text],
-                        SelectableLabel::new(self.payout_view == PayoutView::Smallest, "Smallest"),
-                    )
-                    .on_hover_text(STATUS_SUBMENU_SMALLEST)
-                    .clicked()
-                {
-                    self.payout_view = PayoutView::Smallest;
-                }
-            });
-            ui.separator();
-            // Actual logs
-            egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
-                egui::ScrollArea::vertical()
-                    .stick_to_bottom(self.payout_view == PayoutView::Oldest)
-                    .max_width(width)
-                    .max_height(log)
-                    .auto_shrink([false; 2])
-                    .show_viewport(ui, |ui, _| {
-                        ui.style_mut().override_text_style = Some(egui::TextStyle::Body);
-                        match self.payout_view {
-                            PayoutView::Latest => ui.add_sized(
-                                [width, log],
-                                TextEdit::multiline(&mut api.log_rev.as_str()),
+        ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
+        ui.style_mut().override_text_style = Some(TextStyle::Body);
+        let size_text = ui.text_style_height(&TextStyle::Body);
+        let height = (ui.style().spacing.button_padding.y * 2.0) + size_text;
+        ScrollArea::vertical().show(ui, |ui| {
+            ui.group(|ui| {
+                ScrollArea::horizontal().show(ui, |ui| {
+                    ui.horizontal(|ui| {
+                        let width =
+                            ((ui.available_width() / 3.0) - (SPACE * 4.0)).max(size_text * 9.0);
+                        let width_button =
+                            ((ui.available_width() / 3.0 / 4.0) - SPACE).max(size_text * 4.0);
+                        ui.add_sized(
+                            [width, height],
+                            Label::new(
+                                RichText::new(format!("Total Payouts: {}", api.payout))
+                                    .underline()
+                                    .color(LIGHT_GRAY),
                             ),
-                            PayoutView::Oldest => ui.add_sized(
-                                [width, log],
-                                TextEdit::multiline(&mut api.log.as_str()),
+                        )
+                        .on_hover_text(STATUS_SUBMENU_PAYOUT);
+                        ui.add(Separator::default().vertical());
+                        ui.add_sized(
+                            [width, height],
+                            Label::new(
+                                RichText::new(format!("Total XMR: {}", api.xmr))
+                                    .underline()
+                                    .color(LIGHT_GRAY),
                             ),
-                            PayoutView::Biggest => ui.add_sized(
-                                [width, log],
-                                TextEdit::multiline(&mut api.payout_high.as_str()),
-                            ),
-                            PayoutView::Smallest => ui.add_sized(
-                                [width, log],
-                                TextEdit::multiline(&mut api.payout_low.as_str()),
-                            ),
-                        };
+                        )
+                        .on_hover_text(STATUS_SUBMENU_XMR);
+                        // });
+                        ui.add(Separator::default().vertical());
+                        PayoutView::iter().enumerate().for_each(|(count, p)| {
+                            if ui
+                                .add_sized(
+                                    [width_button, height],
+                                    SelectableLabel::new(self.payout_view == p, p.to_string()),
+                                )
+                                .on_hover_text(p.msg_help())
+                                .clicked()
+                            {
+                                self.payout_view = p;
+                            }
+                            if count + 1 < PayoutView::COUNT {
+                                ui.add(Separator::default().vertical());
+                            }
+                        });
                     });
-            });
-        });
-        drop(api);
-        // Payout/Share Calculator
-        let button = (width / 20.0) - (SPACE * 1.666);
-        ui.group(|ui| {
-            ui.horizontal(|ui| {
-                ui.set_min_width(width - SPACE);
-                if ui
-                    .add_sized(
-                        [button * 2.0, text],
-                        SelectableLabel::new(!self.manual_hash, "Automatic"),
-                    )
-                    .on_hover_text(STATUS_SUBMENU_AUTOMATIC)
-                    .clicked()
-                {
-                    self.manual_hash = false;
-                }
-                ui.separator();
-                if ui
-                    .add_sized(
-                        [button * 2.0, text],
-                        SelectableLabel::new(self.manual_hash, "Manual"),
-                    )
-                    .on_hover_text(STATUS_SUBMENU_MANUAL)
-                    .clicked()
-                {
-                    self.manual_hash = true;
-                }
-                ui.separator();
-                ui.add_enabled_ui(self.manual_hash, |ui| {
-                    if ui
-                        .add_sized(
-                            [button, text],
-                            SelectableLabel::new(self.hash_metric == Hash::Hash, "Hash"),
-                        )
-                        .on_hover_text(STATUS_SUBMENU_HASH)
-                        .clicked()
-                    {
-                        self.hash_metric = Hash::Hash;
-                    }
-                    ui.separator();
-                    if ui
-                        .add_sized(
-                            [button, text],
-                            SelectableLabel::new(self.hash_metric == Hash::Kilo, "Kilo"),
-                        )
-                        .on_hover_text(STATUS_SUBMENU_KILO)
-                        .clicked()
-                    {
-                        self.hash_metric = Hash::Kilo;
-                    }
-                    ui.separator();
-                    if ui
-                        .add_sized(
-                            [button, text],
-                            SelectableLabel::new(self.hash_metric == Hash::Mega, "Mega"),
-                        )
-                        .on_hover_text(STATUS_SUBMENU_MEGA)
-                        .clicked()
-                    {
-                        self.hash_metric = Hash::Mega;
-                    }
-                    ui.separator();
-                    if ui
-                        .add_sized(
-                            [button, text],
-                            SelectableLabel::new(self.hash_metric == Hash::Giga, "Giga"),
-                        )
-                        .on_hover_text(STATUS_SUBMENU_GIGA)
-                        .clicked()
-                    {
-                        self.hash_metric = Hash::Giga;
-                    }
-                    ui.separator();
-                    ui.spacing_mut().slider_width = button * 11.5;
-                    ui.add_sized(
-                        [button * 14.0, text],
-                        Slider::new(&mut self.hashrate, 1.0..=1_000.0),
-                    );
                 });
-            })
-        });
-        // Actual stats
-        ui.add_enabled_ui(p2pool_alive, |ui| {
-            let text = height / 25.0;
-            let width = (width / 3.0) - (SPACE * 1.666);
-            let min_height = ui.available_height() / 1.3;
-            let api = p2pool_api.lock().unwrap();
-            ui.horizontal(|ui| {
-                ui.group(|ui| {
-                    ui.vertical(|ui| {
-                        ui.set_min_height(min_height);
-                        ui.add_sized(
-                            [width, text],
-                            Label::new(RichText::new("Monero Difficulty").underline().color(BONE)),
-                        )
-                        .on_hover_text(STATUS_SUBMENU_MONERO_DIFFICULTY);
-                        ui.add_sized([width, text], Label::new(api.monero_difficulty.as_str()));
-                        ui.add_sized(
-                            [width, text],
-                            Label::new(RichText::new("Monero Hashrate").underline().color(BONE)),
-                        )
-                        .on_hover_text(STATUS_SUBMENU_MONERO_HASHRATE);
-                        ui.add_sized([width, text], Label::new(api.monero_hashrate.as_str()));
-                        ui.add_sized(
-                            [width, text],
-                            Label::new(RichText::new("P2Pool Difficulty").underline().color(BONE)),
-                        )
-                        .on_hover_text(STATUS_SUBMENU_P2POOL_DIFFICULTY);
-                        ui.add_sized([width, text], Label::new(api.p2pool_difficulty.as_str()));
-                        ui.add_sized(
-                            [width, text],
-                            Label::new(RichText::new("P2Pool Hashrate").underline().color(BONE)),
-                        )
-                        .on_hover_text(STATUS_SUBMENU_P2POOL_HASHRATE);
-                        ui.add_sized([width, text], Label::new(api.p2pool_hashrate.as_str()));
-                    })
-                });
-                ui.group(|ui| {
-                    ui.vertical(|ui| {
-                        ui.set_min_height(min_height);
-                        if self.manual_hash {
-                            let hashrate =
-                                Hash::convert_to_hash(self.hashrate, self.hash_metric) as u64;
-                            let p2pool_share_mean = PubP2poolApi::calculate_share_or_block_time(
-                                hashrate,
-                                api.p2pool_difficulty_u64,
-                            );
-                            let solo_block_mean = PubP2poolApi::calculate_share_or_block_time(
-                                hashrate,
-                                api.monero_difficulty_u64,
-                            );
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(
-                                    RichText::new("Manually Inputted Hashrate")
-                                        .underline()
-                                        .color(BONE),
-                                ),
-                            );
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(format!("{} H/s", Unsigned::from(hashrate))),
-                            );
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(
-                                    RichText::new("P2Pool Block Mean").underline().color(BONE),
-                                ),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_P2POOL_BLOCK_MEAN);
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(api.p2pool_block_mean.to_string()),
-                            );
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(
-                                    RichText::new("Your P2Pool Share Mean")
-                                        .underline()
-                                        .color(BONE),
-                                ),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_P2POOL_SHARE_MEAN);
-                            ui.add_sized([width, text], Label::new(p2pool_share_mean.to_string()));
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(
-                                    RichText::new("Your Solo Block Mean")
-                                        .underline()
-                                        .color(BONE),
-                                ),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_SOLO_BLOCK_MEAN);
-                            ui.add_sized([width, text], Label::new(solo_block_mean.to_string()));
-                        } else {
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(
-                                    RichText::new("Your P2Pool Hashrate")
-                                        .underline()
-                                        .color(BONE),
-                                ),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_HASHRATE);
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(format!("{} H/s", api.hashrate_1h)),
-                            );
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(
-                                    RichText::new("P2Pool Block Mean").underline().color(BONE),
-                                ),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_P2POOL_BLOCK_MEAN);
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(api.p2pool_block_mean.to_string()),
-                            );
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(
-                                    RichText::new("Your P2Pool Share Mean")
-                                        .underline()
-                                        .color(BONE),
-                                ),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_P2POOL_SHARE_MEAN);
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(api.p2pool_share_mean.to_string()),
-                            );
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(
-                                    RichText::new("Your Solo Block Mean")
-                                        .underline()
-                                        .color(BONE),
-                                ),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_SOLO_BLOCK_MEAN);
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(api.solo_block_mean.to_string()),
-                            );
-                        }
-                    })
-                });
-                ui.group(|ui| {
-                    ui.vertical(|ui| {
-                        ui.set_min_height(min_height);
-                        if self.manual_hash {
-                            let hashrate =
-                                Hash::convert_to_hash(self.hashrate, self.hash_metric) as u64;
-                            let user_p2pool_percent = PubP2poolApi::calculate_dominance(
-                                hashrate,
-                                api.p2pool_hashrate_u64,
-                            );
-                            let user_monero_percent = PubP2poolApi::calculate_dominance(
-                                hashrate,
-                                api.monero_hashrate_u64,
-                            );
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(RichText::new("P2Pool Miners").underline().color(BONE)),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_P2POOL_MINERS);
-                            ui.add_sized([width, text], Label::new(api.miners.as_str()));
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(
-                                    RichText::new("P2Pool Dominance").underline().color(BONE),
-                                ),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_P2POOL_DOMINANCE);
-                            ui.add_sized([width, text], Label::new(api.p2pool_percent.as_str()));
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(
-                                    RichText::new("Your P2Pool Dominance")
-                                        .underline()
-                                        .color(BONE),
-                                ),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_DOMINANCE);
-                            ui.add_sized([width, text], Label::new(user_p2pool_percent.as_str()));
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(
-                                    RichText::new("Your Monero Dominance")
-                                        .underline()
-                                        .color(BONE),
-                                ),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_YOUR_MONERO_DOMINANCE);
-                            ui.add_sized([width, text], Label::new(user_monero_percent.as_str()));
-                        } else {
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(RichText::new("P2Pool Miners").underline().color(BONE)),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_P2POOL_MINERS);
-                            ui.add_sized([width, text], Label::new(api.miners.as_str()));
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(
-                                    RichText::new("P2Pool Dominance").underline().color(BONE),
-                                ),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_P2POOL_DOMINANCE);
-                            ui.add_sized([width, text], Label::new(api.p2pool_percent.as_str()));
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(
-                                    RichText::new("Your P2Pool Dominance")
-                                        .underline()
-                                        .color(BONE),
-                                ),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_DOMINANCE);
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(api.user_p2pool_percent.as_str()),
-                            );
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(
-                                    RichText::new("Your Monero Dominance")
-                                        .underline()
-                                        .color(BONE),
-                                ),
-                            )
-                            .on_hover_text(STATUS_SUBMENU_YOUR_MONERO_DOMINANCE);
-                            ui.add_sized(
-                                [width, text],
-                                Label::new(api.user_monero_percent.as_str()),
-                            );
-                        }
-                    })
+                // ui.separator();
+                // Actual logs
+                egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
+                    egui::ScrollArea::vertical()
+                        .stick_to_bottom(self.payout_view == PayoutView::Oldest)
+                        .max_width(ui.available_width())
+                        .max_height(ui.available_height() / 2.8)
+                        .auto_shrink([false; 2])
+                        .show_viewport(ui, |ui, _| {
+                            ui.style_mut().override_text_style = Some(egui::TextStyle::Body);
+                            ui.style_mut().spacing.text_edit_width = ui.available_width();
+                            match self.payout_view {
+                                PayoutView::Latest => {
+                                    ui.text_edit_multiline(&mut api.log_rev.as_str())
+                                }
+                                PayoutView::Oldest => ui.text_edit_multiline(&mut api.log.as_str()),
+                                PayoutView::Biggest => {
+                                    ui.text_edit_multiline(&mut api.payout_high.as_str())
+                                }
+                                PayoutView::Smallest => {
+                                    ui.text_edit_multiline(&mut api.payout_low.as_str())
+                                }
+                            };
+                        });
                 });
             });
-            // Tick bar
-            ui.add_sized(
-                [ui.available_width(), text],
-                Label::new(api.calculate_tick_bar()),
-            )
-            .on_hover_text(STATUS_SUBMENU_PROGRESS_BAR);
+            // });
             drop(api);
+            // Payout/Share Calculator
+            // let button = (width / 20.0) - (SPACE * 1.666);
+            ui.group(|ui| {
+                ui.set_width(ui.available_width());
+                ui.horizontal(|ui| {
+                    // ui.set_min_width(width - SPACE);
+                    let width = ui.available_width() / 10.0;
+                    if ui
+                        .add_sized(
+                            [width, height],
+                            SelectableLabel::new(!self.manual_hash, "Automatic"),
+                        )
+                        .on_hover_text(STATUS_SUBMENU_AUTOMATIC)
+                        .clicked()
+                    {
+                        self.manual_hash = false;
+                    }
+                    ui.separator();
+                    if ui
+                        .add_sized(
+                            [width, height],
+                            SelectableLabel::new(self.manual_hash, "Manual"),
+                        )
+                        .on_hover_text(STATUS_SUBMENU_MANUAL)
+                        .clicked()
+                    {
+                        self.manual_hash = true;
+                    }
+                    ui.separator();
+                    ui.add_enabled_ui(self.manual_hash, |ui| {
+                        if ui
+                            .selectable_label(self.hash_metric == Hash::Hash, "Hash")
+                            .on_hover_text(STATUS_SUBMENU_HASH)
+                            .clicked()
+                        {
+                            self.hash_metric = Hash::Hash;
+                        }
+                        ui.separator();
+                        if ui
+                            .selectable_label(self.hash_metric == Hash::Kilo, "Kilo")
+                            .on_hover_text(STATUS_SUBMENU_KILO)
+                            .clicked()
+                        {
+                            self.hash_metric = Hash::Kilo;
+                        }
+                        ui.separator();
+                        if ui
+                            .selectable_label(self.hash_metric == Hash::Mega, "Mega")
+                            .on_hover_text(STATUS_SUBMENU_MEGA)
+                            .clicked()
+                        {
+                            self.hash_metric = Hash::Mega;
+                        }
+                        ui.separator();
+                        if ui
+                            .selectable_label(self.hash_metric == Hash::Giga, "Giga")
+                            .on_hover_text(STATUS_SUBMENU_GIGA)
+                            .clicked()
+                        {
+                            self.hash_metric = Hash::Giga;
+                        }
+                        ui.separator();
+                        ui.spacing_mut().slider_width = (ui.available_width() / 1.2).max(0.0);
+                        ui.add_sized(
+                            [0.0, height],
+                            Slider::new(&mut self.hashrate, 1.0..=1_000.0)
+                                .suffix(format!(" {}", self.hash_metric)),
+                        );
+                    });
+                })
+            });
+            // Actual stats
+            ui.add_space(height / 2.0);
+            ui.add_enabled_ui(p2pool_alive, |ui| {
+                let min_height = ui.available_height() / 1.5;
+                let api = p2pool_api.lock().unwrap();
+                ui.horizontal(|ui| {
+                    ui.columns_const(|[col1, col2, col3]| {
+                        col1.group(|ui| {
+                            ui.vertical_centered(|ui| {
+                                ui.add_space(height * 2.0);
+                                ui.set_min_height(min_height);
+                                ui.label(
+                                    RichText::new("Monero Difficulty").underline().color(BONE),
+                                )
+                                .on_hover_text(STATUS_SUBMENU_MONERO_DIFFICULTY);
+                                ui.label(api.monero_difficulty.as_str());
+                                ui.label(RichText::new("Monero Hashrate").underline().color(BONE))
+                                    .on_hover_text(STATUS_SUBMENU_MONERO_HASHRATE);
+                                ui.label(api.monero_hashrate.as_str());
+                                ui.label(
+                                    RichText::new("P2Pool Difficulty").underline().color(BONE),
+                                )
+                                .on_hover_text(STATUS_SUBMENU_P2POOL_DIFFICULTY);
+                                ui.label(api.p2pool_difficulty.as_str());
+                                ui.label(RichText::new("P2Pool Hashrate").underline().color(BONE))
+                                    .on_hover_text(STATUS_SUBMENU_P2POOL_HASHRATE);
+                                ui.label(api.p2pool_hashrate.as_str());
+                            })
+                        });
+                        col2.group(|ui| {
+                            ui.vertical_centered(|ui| {
+                                ui.add_space(height * 2.0);
+                                ui.set_min_height(min_height);
+                                if self.manual_hash {
+                                    let hashrate =
+                                        Hash::convert_to_hash(self.hashrate, self.hash_metric)
+                                            as u64;
+                                    let p2pool_share_mean =
+                                        PubP2poolApi::calculate_share_or_block_time(
+                                            hashrate,
+                                            api.p2pool_difficulty_u64,
+                                        );
+                                    let solo_block_mean =
+                                        PubP2poolApi::calculate_share_or_block_time(
+                                            hashrate,
+                                            api.monero_difficulty_u64,
+                                        );
+                                    ui.label(
+                                        RichText::new("Manually Inputted Hashrate")
+                                            .underline()
+                                            .color(BONE),
+                                    );
+                                    ui.label(format!("{} H/s", Unsigned::from(hashrate)));
+                                    ui.label(
+                                        RichText::new("P2Pool Block Mean").underline().color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_P2POOL_BLOCK_MEAN);
+                                    ui.label(api.p2pool_block_mean.to_string());
+                                    ui.label(
+                                        RichText::new("Your P2Pool Share Mean")
+                                            .underline()
+                                            .color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_P2POOL_SHARE_MEAN);
+                                    ui.label(p2pool_share_mean.to_string());
+                                    ui.label(
+                                        RichText::new("Your Solo Block Mean")
+                                            .underline()
+                                            .color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_SOLO_BLOCK_MEAN);
+                                    ui.label(solo_block_mean.to_string());
+                                } else {
+                                    ui.label(
+                                        RichText::new("Your P2Pool Hashrate")
+                                            .underline()
+                                            .color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_HASHRATE);
+                                    ui.label(format!("{} H/s", api.hashrate_1h));
+                                    ui.label(
+                                        RichText::new("P2Pool Block Mean").underline().color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_P2POOL_BLOCK_MEAN);
+                                    ui.label(api.p2pool_block_mean.to_string());
+                                    ui.label(
+                                        RichText::new("Your P2Pool Share Mean")
+                                            .underline()
+                                            .color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_P2POOL_SHARE_MEAN);
+                                    ui.label(api.p2pool_share_mean.to_string());
+                                    ui.label(
+                                        RichText::new("Your Solo Block Mean")
+                                            .underline()
+                                            .color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_SOLO_BLOCK_MEAN);
+                                    ui.label(api.solo_block_mean.to_string());
+                                }
+                            })
+                        });
+                        col3.group(|ui| {
+                            ui.vertical_centered(|ui| {
+                                ui.add_space(height * 2.0);
+                                ui.set_min_height(min_height);
+                                if self.manual_hash {
+                                    let hashrate =
+                                        Hash::convert_to_hash(self.hashrate, self.hash_metric)
+                                            as u64;
+                                    let user_p2pool_percent = PubP2poolApi::calculate_dominance(
+                                        hashrate,
+                                        api.p2pool_hashrate_u64,
+                                    );
+                                    let user_monero_percent = PubP2poolApi::calculate_dominance(
+                                        hashrate,
+                                        api.monero_hashrate_u64,
+                                    );
+                                    ui.label(
+                                        RichText::new("P2Pool Miners").underline().color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_P2POOL_MINERS);
+                                    ui.label(api.miners.as_str());
+                                    ui.label(
+                                        RichText::new("P2Pool Dominance").underline().color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_P2POOL_DOMINANCE);
+                                    ui.label(api.p2pool_percent.as_str());
+                                    ui.label(
+                                        RichText::new("Your P2Pool Dominance")
+                                            .underline()
+                                            .color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_DOMINANCE);
+                                    ui.label(user_p2pool_percent.as_str());
+                                    ui.label(
+                                        RichText::new("Your Monero Dominance")
+                                            .underline()
+                                            .color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_YOUR_MONERO_DOMINANCE);
+                                    ui.label(user_monero_percent.as_str());
+                                } else {
+                                    ui.label(
+                                        RichText::new("P2Pool Miners").underline().color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_P2POOL_MINERS);
+                                    ui.label(api.miners.as_str());
+                                    ui.label(
+                                        RichText::new("P2Pool Dominance").underline().color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_P2POOL_DOMINANCE);
+                                    ui.label(api.p2pool_percent.as_str());
+                                    ui.label(
+                                        RichText::new("Your P2Pool Dominance")
+                                            .underline()
+                                            .color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_DOMINANCE);
+                                    ui.label(api.user_p2pool_percent.as_str());
+                                    ui.label(
+                                        RichText::new("Your Monero Dominance")
+                                            .underline()
+                                            .color(BONE),
+                                    )
+                                    .on_hover_text(STATUS_SUBMENU_YOUR_MONERO_DOMINANCE);
+                                    ui.label(api.user_monero_percent.as_str());
+                                }
+                            })
+                        });
+                    });
+                });
+                // Tick bar
+                ui.vertical_centered(|ui| {
+                    ui.label(api.calculate_tick_bar())
+                        .on_hover_text(STATUS_SUBMENU_PROGRESS_BAR);
+                });
+                drop(api);
+            });
         });
     }
 }
diff --git a/src/app/panels/middle/status/processes.rs b/src/app/panels/middle/status/processes.rs
index 4e7d17f..a49e70d 100644
--- a/src/app/panels/middle/status/processes.rs
+++ b/src/app/panels/middle/status/processes.rs
@@ -1,4 +1,4 @@
-use egui::{ScrollArea, Ui, Vec2};
+use egui::{ScrollArea, Ui};
 use readable::up::UptimeFull;
 use std::sync::{Arc, Mutex};
 
@@ -12,14 +12,13 @@ use crate::helper::xvb::{PubXvbApi, rounds::XvbRound};
 use crate::helper::{ProcessName, Sys};
 
 use crate::constants::*;
-use egui::{Label, RichText, TextStyle};
+use egui::{RichText, TextStyle};
 use log::*;
 impl Status {
     #[allow(clippy::too_many_arguments)]
     pub(super) fn processes(
         &mut self,
         sys: &Arc<Mutex<Sys>>,
-        size: Vec2,
         ui: &mut egui::Ui,
         node_api: &Arc<Mutex<PubNodeApi>>,
         p2pool_api: &Arc<Mutex<PubP2poolApi>>,
@@ -28,642 +27,417 @@ impl Status {
         xmrig_proxy_api: &Arc<Mutex<PubXmrigProxyApi>>,
         xmrig_img: &Arc<Mutex<ImgXmrig>>,
         xvb_api: &Arc<Mutex<PubXvbApi>>,
-        max_threads: usize,
+        max_threads: u16,
         states: &ProcessStatesGui,
     ) {
-        // set fixed text size, temporary solution before refactoring text/widget size.
-        let width = ((size.x / 5.0) - (SPACE * 1.7500)).max(0.0);
-        let height = size.y / 25.0;
-        // height must be height - top - bottom - space * 2 - space of text
-        let size: Vec2 = [width, height].into();
-        let min_height = (size.y - SPACE).max(0.0);
-        // min width must allow to display text without wrapping.
-        let size_text = ui.text_style_height(&TextStyle::Body);
-        // ui.spacing_mut().item_spacing = Vec2::new(2.0, 2.0);
-        let min_width = size_text * 14.0;
-        let min_size: Vec2 = [min_width, min_height].into();
-        ui.horizontal(|ui| {
-            ScrollArea::horizontal().show(ui, |ui| {
-                ui.set_min_height(min_height * 34.2);
-                gupax(ui, min_size, size, sys);
-                node(
-                    ui,
-                    min_size,
-                    size,
-                    states.is_alive(ProcessName::Node),
-                    node_api,
-                );
-                p2pool(
-                    ui,
-                    min_size,
-                    size,
-                    states.is_alive(ProcessName::P2pool),
-                    p2pool_api,
-                    p2pool_img,
-                );
-                xmrig(
-                    ui,
-                    min_size,
-                    size,
-                    states.is_alive(ProcessName::Xmrig),
-                    xmrig_api,
-                    xmrig_img,
-                    max_threads,
-                );
-                xmrig_proxy(
-                    ui,
-                    min_size,
-                    size,
-                    states.is_alive(ProcessName::XmrigProxy),
-                    xmrig_proxy_api,
-                );
-                xvb(
-                    ui,
-                    min_size,
-                    size,
-                    states.is_alive(ProcessName::Xvb),
-                    xvb_api,
-                );
-            })
+        let width_column = ui.text_style_height(&TextStyle::Body) * 16.0;
+        let height_column = width_column * 2.4;
+        ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
+        // let width = ((ui.available_width() / 5.0) - (SPACE * 1.7500)).max(0.0);
+        ScrollArea::vertical().show(ui, |ui| {
+            ui.horizontal(|ui| {
+                ScrollArea::horizontal().show(ui, |ui| {
+                    ui.vertical(|ui| {
+                        ui.group(|ui| {
+                            ui.set_width(width_column);
+                            ui.set_height(height_column);
+                            ui.vertical_centered(|ui| {
+                                // ui.set_min_width(ui.text_style_height(&TextStyle::Body) * 2.0);
+                                gupax(ui, sys);
+                            });
+                        });
+                    });
+                    ui.vertical(|ui| {
+                        ui.group(|ui| {
+                            ui.set_width(width_column);
+                            ui.set_height(height_column);
+                            ui.vertical_centered(|ui| {
+                                node(ui, states.is_alive(ProcessName::Node), node_api);
+                            });
+                        });
+                    });
+                    ui.vertical(|ui| {
+                        ui.group(|ui| {
+                            ui.set_width(width_column);
+                            ui.set_height(height_column);
+                            ui.vertical_centered(|ui| {
+                                p2pool(
+                                    ui,
+                                    states.is_alive(ProcessName::P2pool),
+                                    p2pool_api,
+                                    p2pool_img,
+                                );
+                            });
+                        });
+                    });
+                    ui.vertical(|ui| {
+                        ui.group(|ui| {
+                            ui.set_width(width_column);
+                            ui.set_height(height_column);
+                            ui.vertical_centered(|ui| {
+                                xmrig(
+                                    ui,
+                                    states.is_alive(ProcessName::Xmrig),
+                                    xmrig_api,
+                                    xmrig_img,
+                                    max_threads,
+                                );
+                            });
+                        });
+                    });
+                    ui.vertical(|ui| {
+                        ui.group(|ui| {
+                            ui.set_width(width_column);
+                            ui.set_height(height_column);
+                            ui.vertical_centered(|ui| {
+                                xmrig_proxy(
+                                    ui,
+                                    states.is_alive(ProcessName::XmrigProxy),
+                                    xmrig_proxy_api,
+                                );
+                            });
+                        });
+                    });
+                    ui.vertical(|ui| {
+                        ui.group(|ui| {
+                            ui.set_width(width_column);
+                            ui.set_height(height_column);
+                            ui.vertical_centered(|ui| {
+                                xvb(ui, states.is_alive(ProcessName::Xvb), xvb_api);
+                            });
+                        });
+                    });
+                });
+            });
         });
     }
 }
-fn gupax(ui: &mut Ui, min_size: Vec2, size: Vec2, sys: &Arc<Mutex<Sys>>) {
-    ui.group(|ui| {
-        ui.vertical(|ui| {
-            ui.set_min_size(min_size);
-            ui.set_min_height(min_size.y * 34.0);
-            debug!("Status Tab | Rendering [Gupaxx]");
-            // ui.set_min_size([min_size.x, min_size.y / 2.0].into());
-            ui.add_sized(
-                size,
-                Label::new(
-                    RichText::new("[Gupaxx]")
-                        .color(LIGHT_GRAY)
-                        .text_style(TextStyle::Heading),
-                ),
-            )
-            .on_hover_text("Gupaxx is online");
-            let sys = sys.lock().unwrap();
-            ui.add_sized(
-                size,
-                Label::new(RichText::new("Uptime").underline().color(BONE)),
-            )
-            .on_hover_text(STATUS_GUPAX_UPTIME);
-            ui.add_sized(size, Label::new(sys.gupax_uptime.to_string()));
-            ui.add_sized(
-                size,
-                Label::new(RichText::new("Gupaxx CPU").underline().color(BONE)),
-            )
-            .on_hover_text(STATUS_GUPAX_CPU_USAGE);
-            ui.add_sized(size, Label::new(sys.gupax_cpu_usage.to_string()));
-            ui.add_sized(
-                size,
-                Label::new(RichText::new("Gupaxx Memory").underline().color(BONE)),
-            )
-            .on_hover_text(STATUS_GUPAX_MEMORY_USAGE);
-            ui.add_sized(size, Label::new(sys.gupax_memory_used_mb.to_string()));
-            ui.add_sized(
-                size,
-                Label::new(RichText::new("System CPU").underline().color(BONE)),
-            )
-            .on_hover_text(STATUS_GUPAX_SYSTEM_CPU_USAGE);
-            ui.add_sized(size, Label::new(sys.system_cpu_usage.to_string()));
-            ui.add_sized(
-                size,
-                Label::new(RichText::new("System Memory").underline().color(BONE)),
-            )
-            .on_hover_text(STATUS_GUPAX_SYSTEM_MEMORY);
-            ui.add_sized(size, Label::new(sys.system_memory.to_string()));
-            ui.add_sized(
-                size,
-                Label::new(RichText::new("System CPU Model").underline().color(BONE)),
-            )
-            .on_hover_text(STATUS_GUPAX_SYSTEM_CPU_MODEL);
-            ui.add_sized(size, Label::new(sys.system_cpu_model.to_string()));
-            drop(sys);
-        })
-    });
+
+fn gupax(ui: &mut Ui, sys: &Arc<Mutex<Sys>>) {
+    ui.label(
+        RichText::new("[Gupaxx]")
+            .color(LIGHT_GRAY)
+            .text_style(TextStyle::Heading),
+    )
+    .on_hover_text("Gupaxx is online");
+    let sys = sys.lock().unwrap();
+    ui.label(RichText::new("Uptime").underline().color(BONE))
+        .on_hover_text(STATUS_GUPAX_UPTIME);
+    ui.label(sys.gupax_uptime.to_string());
+    ui.label(RichText::new("Gupaxx CPU").underline().color(BONE))
+        .on_hover_text(STATUS_GUPAX_CPU_USAGE);
+    ui.label(sys.gupax_cpu_usage.to_string());
+    ui.label(RichText::new("Gupaxx Memory").underline().color(BONE))
+        .on_hover_text(STATUS_GUPAX_MEMORY_USAGE);
+    ui.label(sys.gupax_memory_used_mb.to_string());
+    ui.label(RichText::new("System CPU").underline().color(BONE))
+        .on_hover_text(STATUS_GUPAX_SYSTEM_CPU_USAGE);
+    ui.label(sys.system_cpu_usage.to_string());
+    ui.label(RichText::new("System Memory").underline().color(BONE))
+        .on_hover_text(STATUS_GUPAX_SYSTEM_MEMORY);
+    ui.label(sys.system_memory.to_string());
+    ui.label(RichText::new("System CPU Model").underline().color(BONE))
+        .on_hover_text(STATUS_GUPAX_SYSTEM_CPU_MODEL);
+    ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Wrap);
+    ui.label(sys.system_cpu_model.to_string());
+    drop(sys);
 }
 
 fn p2pool(
     ui: &mut Ui,
-    min_size: Vec2,
-    size: Vec2,
     p2pool_alive: bool,
     p2pool_api: &Arc<Mutex<PubP2poolApi>>,
     p2pool_img: &Arc<Mutex<ImgP2pool>>,
 ) {
-    ui.group(|ui| {
-        ui.vertical(|ui| {
-            ScrollArea::vertical().show(ui, |ui| {
-                ui.set_min_height(min_size.y * 34.0);
-                ui.set_min_size(min_size);
-                debug!("Status Tab | Rendering [P2Pool]");
-                ui.add_enabled_ui(p2pool_alive, |ui| {
-                    ui.add_sized(
-                        size,
-                        Label::new(
-                            RichText::new("[P2Pool]")
-                                .color(LIGHT_GRAY)
-                                .text_style(TextStyle::Heading),
-                        ),
-                    )
-                    .on_hover_text("P2Pool is online")
-                    .on_disabled_hover_text("P2Pool is offline");
-                    ui.style_mut().override_text_style = Some(TextStyle::Small);
-                    let size = [size.x, size.y / 1.4];
-                    let api = p2pool_api.lock().unwrap();
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Uptime").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_P2POOL_UPTIME);
-                    ui.add_sized(size, Label::new(format!("{}", api.uptime)));
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Current Shares").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_P2POOL_CURRENT_SHARES);
-                    ui.add_sized(size, Label::new(api.sidechain_shares.to_string()));
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Shares Found").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_P2POOL_SHARES);
-                    ui.add_sized(
-                        size,
-                        Label::new(
-                            (if let Some(s) = api.shares_found {
-                                s.to_string()
-                            } else {
-                                UNKNOWN_DATA.to_string()
-                            })
-                            .to_string(),
-                        ),
-                    );
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Payouts").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_P2POOL_PAYOUTS);
-                    ui.add_sized(size, Label::new(format!("Total: {}", api.payouts)));
-                    ui.add_sized(
-                        size,
-                        Label::new(format!(
-                            "[{:.7}/hour]\n[{:.7}/day]\n[{:.7}/month]",
-                            api.payouts_hour, api.payouts_day, api.payouts_month
-                        )),
-                    );
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("XMR Mined").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_P2POOL_XMR);
-                    ui.add_sized(size, Label::new(format!("Total: {:.13} XMR", api.xmr)));
-                    ui.add_sized(
-                        size,
-                        Label::new(format!(
-                            "[{:.7}/hour]\n[{:.7}/day]\n[{:.7}/month]",
-                            api.xmr_hour, api.xmr_day, api.xmr_month
-                        )),
-                    );
-                    ui.add_sized(
-                        size,
-                        Label::new(
-                            RichText::new("Hashrate (15m/1h/24h)")
-                                .underline()
-                                .color(BONE),
-                        ),
-                    )
-                    .on_hover_text(STATUS_P2POOL_HASHRATE);
-                    ui.add_sized(
-                        size,
-                        Label::new(format!(
-                            "[{} H/s] [{} H/s] [{} H/s]",
-                            api.hashrate_15m, api.hashrate_1h, api.hashrate_24h
-                        )),
-                    );
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Miners Connected").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_P2POOL_CONNECTIONS);
-                    ui.add_sized(size, Label::new(format!("{}", api.connections)));
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Effort").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_P2POOL_EFFORT);
-                    ui.add_sized(
-                        size,
-                        Label::new(format!(
-                            "[Average: {}] [Current: {}]",
-                            api.average_effort, api.current_effort
-                        )),
-                    );
-                    let img = p2pool_img.lock().unwrap();
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Monero Node").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_P2POOL_MONERO_NODE);
-                    ui.add_sized(
-                        size,
-                        Label::new(format!(
-                            "[IP: {}]\n[RPC: {}] [ZMQ: {}]",
-                            &img.host, &img.rpc, &img.zmq
-                        )),
-                    );
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Sidechain").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_P2POOL_POOL);
-                    ui.add_sized(size, Label::new(&img.mini));
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Address").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_P2POOL_ADDRESS);
-                    ui.add_sized(size, Label::new(&img.address));
-                    drop(img);
-                    drop(api);
-                });
+    ui.add_enabled_ui(p2pool_alive, |ui| {
+        ui.label(
+            RichText::new("[P2Pool]")
+                .color(LIGHT_GRAY)
+                .text_style(TextStyle::Heading),
+        )
+        .on_hover_text("P2Pool is online")
+        .on_disabled_hover_text("P2Pool is offline");
+        ui.style_mut().override_text_style = Some(TextStyle::Small);
+        let api = p2pool_api.lock().unwrap();
+        ui.label(RichText::new("Uptime").underline().color(BONE))
+            .on_hover_text(STATUS_P2POOL_UPTIME);
+        ui.label(format!("{}", api.uptime));
+        ui.label(RichText::new("Current Shares").underline().color(BONE))
+            .on_hover_text(STATUS_P2POOL_CURRENT_SHARES);
+        ui.label(api.sidechain_shares.to_string());
+        ui.label(RichText::new("Shares Found").underline().color(BONE))
+            .on_hover_text(STATUS_P2POOL_SHARES);
+        ui.label(
+            (if let Some(s) = api.shares_found {
+                s.to_string()
+            } else {
+                UNKNOWN_DATA.to_string()
             })
-        })
+            .to_string(),
+        );
+        ui.label(RichText::new("Payouts").underline().color(BONE))
+            .on_hover_text(STATUS_P2POOL_PAYOUTS);
+        ui.label(format!("Total: {}", api.payouts));
+        ui.label(format!(
+            "[{:.7}/hour]\n[{:.7}/day]\n[{:.7}/month]",
+            api.payouts_hour, api.payouts_day, api.payouts_month
+        ));
+        ui.label(RichText::new("XMR Mined").underline().color(BONE))
+            .on_hover_text(STATUS_P2POOL_XMR);
+        ui.label(format!("Total: {:.13} XMR", api.xmr));
+        ui.label(format!(
+            "[{:.7}/hour]\n[{:.7}/day]\n[{:.7}/month]",
+            api.xmr_hour, api.xmr_day, api.xmr_month
+        ));
+        ui.label(
+            RichText::new("Hashrate (15m/1h/24h)")
+                .underline()
+                .color(BONE),
+        )
+        .on_hover_text(STATUS_P2POOL_HASHRATE);
+        ui.label(format!(
+            "[{} H/s]\n[{} H/s]\n[{} H/s]",
+            api.hashrate_15m, api.hashrate_1h, api.hashrate_24h
+        ));
+        ui.label(RichText::new("Miners Connected").underline().color(BONE))
+            .on_hover_text(STATUS_P2POOL_CONNECTIONS);
+        ui.label(format!("{}", api.connections));
+        ui.label(RichText::new("Effort").underline().color(BONE))
+            .on_hover_text(STATUS_P2POOL_EFFORT);
+        ui.label(format!(
+            "[Average: {}] [Current: {}]",
+            api.average_effort, api.current_effort
+        ));
+        let img = p2pool_img.lock().unwrap();
+        ui.label(RichText::new("Monero Node").underline().color(BONE))
+            .on_hover_text(STATUS_P2POOL_MONERO_NODE);
+        ui.label(format!(
+            "IP: {}]\n[RPC: {}] [ZMQ: {}]",
+            &img.host, &img.rpc, &img.zmq
+        ));
+        ui.label(RichText::new("Sidechain").underline().color(BONE))
+            .on_hover_text(STATUS_P2POOL_POOL);
+        ui.label(&img.mini);
+        ui.label(RichText::new("Address").underline().color(BONE))
+            .on_hover_text(STATUS_P2POOL_ADDRESS);
+        ui.label(&img.address);
+        drop(img);
+        drop(api);
     });
 }
 #[allow(clippy::too_many_arguments)]
 fn xmrig_proxy(
     ui: &mut Ui,
-    min_size: Vec2,
-    size: Vec2,
     xmrig_proxy_alive: bool,
     xmrig_proxy_api: &Arc<Mutex<PubXmrigProxyApi>>,
 ) {
-    ui.group(|ui| {
-        ui.vertical(|ui| {
-            ui.set_min_height(min_size.y * 34.0);
-            debug!("Status Tab | Rendering [XMRig-Proxy]");
-            ui.add_enabled_ui(xmrig_proxy_alive, |ui| {
-                ui.set_min_size(min_size);
-                ui.add_sized(
-                    size,
-                    Label::new(
-                        RichText::new("[XMRig-Proxy]")
-                            .color(LIGHT_GRAY)
-                            .text_style(TextStyle::Heading),
-                    ),
-                )
-                .on_hover_text("XMRig-Proxy is online")
-                .on_disabled_hover_text("XMRig-Proxy is offline");
-                let api = xmrig_proxy_api.lock().unwrap();
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Uptime").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_XMRIG_PROXY_UPTIME);
-                ui.add_sized(size, Label::new(UptimeFull::from(api.uptime).as_str()));
-                ui.add_sized(
-                    size,
-                    Label::new(
-                        RichText::new("Hashrate\n(1m/10m/1h/12h/24h)")
-                            .underline()
-                            .color(BONE),
-                    ),
-                )
-                .on_hover_text(STATUS_XMRIG_PROXY_HASHRATE);
-                ui.add_sized(
-                    size,
-                    Label::new(format!(
-                        "[{} H/s] [{} H/s]\n[{} H/s] [{} H/s] [{} H/s]",
-                        api.hashrate_1m,
-                        api.hashrate_10m,
-                        api.hashrate_1h,
-                        api.hashrate_12h,
-                        api.hashrate_24h
-                    )),
-                );
-                ui.add_sized(
-                    size,
-                    Label::new(format!(
-                        "[Accepted: {}]\n[Rejected: {}]",
-                        api.accepted, api.rejected
-                    )),
-                );
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Pool").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_XMRIG_PROXY_POOL);
-                ui.add_sized(size, Label::new(api.node.to_string()));
-                drop(api);
-            });
-        })
+    ui.add_enabled_ui(xmrig_proxy_alive, |ui| {
+        ui.label(
+            RichText::new("[XMRig-Proxy]")
+                .color(LIGHT_GRAY)
+                .text_style(TextStyle::Heading),
+        )
+        .on_hover_text("XMRig-Proxy is online")
+        .on_disabled_hover_text("XMRig-Proxy is offline");
+        let api = xmrig_proxy_api.lock().unwrap();
+        ui.label(RichText::new("Uptime").underline().color(BONE))
+            .on_hover_text(STATUS_XMRIG_PROXY_UPTIME);
+        ui.label(UptimeFull::from(api.uptime).as_str());
+        ui.label(
+            RichText::new("Hashrate\n(1m/10m/1h/12h/24h)")
+                .underline()
+                .color(BONE),
+        )
+        .on_hover_text(STATUS_XMRIG_PROXY_HASHRATE);
+        ui.label(format!(
+            "[{} H/s]\n[{} H/s]\n[{} H/s]\n[{} H/s]\n[{} H/s]",
+            api.hashrate_1m, api.hashrate_10m, api.hashrate_1h, api.hashrate_12h, api.hashrate_24h
+        ));
+        ui.label(format!(
+            "[Accepted: {}]\n[Rejected: {}]",
+            api.accepted, api.rejected
+        ));
+        ui.label(RichText::new("Pool").underline().color(BONE))
+            .on_hover_text(STATUS_XMRIG_PROXY_POOL);
+        ui.label(api.node.to_string());
+        drop(api);
     });
 }
 #[allow(clippy::too_many_arguments)]
 fn xmrig(
     ui: &mut Ui,
-    min_size: Vec2,
-    size: Vec2,
     xmrig_alive: bool,
     xmrig_api: &Arc<Mutex<PubXmrigApi>>,
     xmrig_img: &Arc<Mutex<ImgXmrig>>,
-    max_threads: usize,
+    max_threads: u16,
 ) {
-    ui.group(|ui| {
-        // ScrollArea::vertical().show(ui, |ui| {
-        ui.vertical(|ui| {
-            ui.set_min_height(min_size.y * 34.0);
-            ui.spacing_mut().item_spacing = Vec2::new(2.0, 2.0);
-            debug!("Status Tab | Rendering [XMRig]");
-            ui.add_enabled_ui(xmrig_alive, |ui| {
-                // ui.set_min_size(min_size);
-                ui.add_sized(
-                    size,
-                    Label::new(
-                        RichText::new("[XMRig]")
-                            .color(LIGHT_GRAY)
-                            .text_style(TextStyle::Heading),
-                    ),
-                )
-                .on_hover_text("XMRig is online")
-                .on_disabled_hover_text("XMRig is offline");
-                let api = xmrig_api.lock().unwrap();
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Uptime").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_XMRIG_UPTIME);
-                ui.add_sized(size, Label::new(UptimeFull::from(api.uptime).as_str()));
-                ui.add_sized(size, Label::new(api.resources.to_string()));
-                ui.add_sized(
-                    size,
-                    Label::new(
-                        RichText::new("Hashrate\n(10s/1m/15m)")
-                            .underline()
-                            .color(BONE),
-                    ),
-                )
-                .on_hover_text(STATUS_XMRIG_HASHRATE);
-                ui.add_sized(size, Label::new(api.hashrate.to_string()));
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Difficulty").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_XMRIG_DIFFICULTY);
-                ui.add_sized(size, Label::new(api.diff.to_string()));
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Shares").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_XMRIG_SHARES);
-                ui.add_sized(
-                    size,
-                    Label::new(format!(
-                        "[Accepted: {}]\n[Rejected: {}]",
-                        api.accepted, api.rejected
-                    )),
-                );
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Pool").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_XMRIG_POOL);
-                ui.add_sized(size, Label::new(api.node.to_string()));
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Threads").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_XMRIG_THREADS);
-                ui.add_sized(
-                    size,
-                    Label::new(format!(
-                        "{}/{}",
-                        &xmrig_img.lock().unwrap().threads,
-                        max_threads
-                    )),
-                );
-                drop(api);
-            });
-        })
-        // })
+    debug!("Status Tab | Rendering [XMRig]");
+    ui.add_enabled_ui(xmrig_alive, |ui| {
+        // ui.set_min_size(min_size);
+        ui.label(
+            RichText::new("[XMRig]")
+                .color(LIGHT_GRAY)
+                .text_style(TextStyle::Heading),
+        )
+        .on_hover_text("XMRig is online")
+        .on_disabled_hover_text("XMRig is offline");
+        let api = xmrig_api.lock().unwrap();
+        ui.label(RichText::new("Uptime").underline().color(BONE))
+            .on_hover_text(STATUS_XMRIG_UPTIME);
+        ui.label(UptimeFull::from(api.uptime).as_str());
+        ui.label(api.resources.to_string());
+        ui.label(
+            RichText::new("Hashrate\n(10s/1m/15m)")
+                .underline()
+                .color(BONE),
+        )
+        .on_hover_text(STATUS_XMRIG_HASHRATE);
+        ui.label(api.hashrate.to_string());
+        ui.label(RichText::new("Difficulty").underline().color(BONE))
+            .on_hover_text(STATUS_XMRIG_DIFFICULTY);
+        ui.label(api.diff.to_string());
+        ui.label(RichText::new("Shares").underline().color(BONE))
+            .on_hover_text(STATUS_XMRIG_SHARES);
+        ui.label(format!(
+            "[Accepted: {}]\n[Rejected: {}]",
+            api.accepted, api.rejected
+        ));
+        ui.label(RichText::new("Pool").underline().color(BONE))
+            .on_hover_text(STATUS_XMRIG_POOL);
+        ui.label(api.node.to_string());
+        ui.label(RichText::new("Threads").underline().color(BONE))
+            .on_hover_text(STATUS_XMRIG_THREADS);
+        ui.label(format!(
+            "{}/{}",
+            &xmrig_img.lock().unwrap().threads,
+            max_threads
+        ));
+        drop(api);
     });
 }
 
-fn xvb(ui: &mut Ui, min_size: Vec2, size: Vec2, xvb_alive: bool, xvb_api: &Arc<Mutex<PubXvbApi>>) {
+fn xvb(ui: &mut Ui, xvb_alive: bool, xvb_api: &Arc<Mutex<PubXvbApi>>) {
     //
     let api = &xvb_api.lock().unwrap().stats_pub;
     let enabled = xvb_alive;
-    ui.group(|ui| {
-        ScrollArea::vertical().show(ui, |ui| {
-            ui.set_min_height(min_size.y * 34.0);
-            ui.vertical(|ui| {
-                debug!("Status Tab | Rendering [XvB]");
-                ui.add_enabled_ui(enabled, |ui| {
-                    // for now there is no API ping or /health, so we verify if the field reward_yearly is empty or not.
-                    // ui.set_min_size(min_size);
-                    ui.add_sized(
-                        size,
-                        Label::new(
-                            RichText::new("[XvB Raffle]")
-                                .color(LIGHT_GRAY)
-                                .text_style(TextStyle::Heading),
-                        ),
-                    )
-                    .on_hover_text("XvB API stats")
-                    .on_disabled_hover_text("No data received from XvB API");
-                    // [Round Type]
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Round Type").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_XVB_ROUND_TYPE);
-                    ui.add_sized(size, Label::new(api.round_type.to_string()));
-                    // [Time Remaining]
-                    ui.add_sized(
-                        size,
-                        Label::new(
-                            RichText::new("Round Time Remaining")
-                                .underline()
-                                .color(BONE),
-                        ),
-                    )
-                    .on_hover_text(STATUS_XVB_TIME_REMAIN);
-                    ui.add_sized(size, Label::new(format!("{} minutes", api.time_remain)));
-                    // Donated Hashrate
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Bonus Hashrate").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_XVB_DONATED_HR);
-                    ui.add_sized(
-                        size,
-                        Label::new(format!(
-                            "{}kH/s\n+\n{}kH/s\ndonated by\n{} donors\n with\n{} miners",
-                            api.bonus_hr, api.donate_hr, api.donate_miners, api.donate_workers
-                        )),
-                    );
-                    // Players
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Players").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_XVB_PLAYERS);
-                    ui.add_sized(
-                        size,
-                        Label::new(format!(
-                            "[Registered: {}]\n[Playing: {}]",
-                            api.players, api.players_round
-                        )),
-                    );
-                    // Winner
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Winner").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_XVB_WINNER);
-                    ui.add_sized(size, Label::new(&api.winner));
-                    // Share effort
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Share Effort").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_XVB_SHARE);
-                    ui.add_sized(size, Label::new(api.share_effort.to_string()));
-                    // Block reward
-                    ui.add_sized(
-                        size,
-                        Label::new(RichText::new("Block Reward").underline().color(BONE)),
-                    )
-                    .on_hover_text(STATUS_XVB_BLOCK_REWARD);
-                    ui.add_sized(size, Label::new(api.block_reward.to_string()));
-                    // reward yearly
-                    ui.add_sized(
-                        size,
-                        Label::new(
-                            RichText::new("Est. Reward (Yearly)")
-                                .underline()
-                                .color(BONE),
-                        ),
-                    )
-                    .on_hover_text(STATUS_XVB_YEARLY);
-                    if api.reward_yearly.is_empty() {
-                        ui.add_sized(size, Label::new("No information".to_string()));
-                    } else {
-                        ui.add_sized(
-                            size,
-                            Label::new(format!(
-                                "{}: {} XMR\n{}: {} XMR\n{}: {} XMR\n{}: {} XMR\n{}: {} XMR",
-                                XvbRound::Vip,
-                                api.reward_yearly[0],
-                                XvbRound::Donor,
-                                api.reward_yearly[1],
-                                XvbRound::DonorVip,
-                                api.reward_yearly[2],
-                                XvbRound::DonorWhale,
-                                api.reward_yearly[3],
-                                XvbRound::DonorMega,
-                                api.reward_yearly[4]
-                            )),
-                        );
-                    }
-                });
-            })
-            // by round
-        });
+    debug!("Status Tab | Rendering [XvB]");
+    ui.add_enabled_ui(enabled, |ui| {
+        // for now there is no API ping or /health, so we verify if the field reward_yearly is empty or not.
+        // ui.set_min_size(min_size);
+        ui.label(
+            RichText::new("[XvB Raffle]")
+                .color(LIGHT_GRAY)
+                .text_style(TextStyle::Heading),
+        )
+        .on_hover_text("XvB API stats")
+        .on_disabled_hover_text("No data received from XvB API");
+        // [Round Type]
+        ui.label(RichText::new("Round Type").underline().color(BONE))
+            .on_hover_text(STATUS_XVB_ROUND_TYPE);
+        ui.label(api.round_type.to_string());
+        // [Time Remaining]
+        ui.label(
+            RichText::new("Round Time Remaining")
+                .underline()
+                .color(BONE),
+        )
+        .on_hover_text(STATUS_XVB_TIME_REMAIN);
+        ui.label(format!("{} minutes", api.time_remain));
+        // Donated Hashrate
+        ui.label(RichText::new("Bonus Hashrate").underline().color(BONE))
+            .on_hover_text(STATUS_XVB_DONATED_HR);
+        ui.label(format!(
+            "{}kH/s\n+\n{}kH/s\ndonated by\n{} donors\n with\n{} miners",
+            api.bonus_hr, api.donate_hr, api.donate_miners, api.donate_workers
+        ));
+        // Players
+        ui.label(RichText::new("Players").underline().color(BONE))
+            .on_hover_text(STATUS_XVB_PLAYERS);
+        ui.label(format!(
+            "[Registered: {}]\n[Playing: {}]",
+            api.players, api.players_round
+        ));
+        // Winner
+        ui.label(RichText::new("Winner").underline().color(BONE))
+            .on_hover_text(STATUS_XVB_WINNER);
+        ui.label(&api.winner);
+        // Share effort
+        ui.label(RichText::new("Share Effort").underline().color(BONE))
+            .on_hover_text(STATUS_XVB_SHARE);
+        ui.label(api.share_effort.to_string());
+        // Block reward
+        ui.label(RichText::new("Block Reward").underline().color(BONE))
+            .on_hover_text(STATUS_XVB_BLOCK_REWARD);
+        ui.label(api.block_reward.to_string());
+        // reward yearly
+        ui.label(
+            RichText::new("Est. Reward (Yearly)")
+                .underline()
+                .color(BONE),
+        )
+        .on_hover_text(STATUS_XVB_YEARLY);
+        if api.reward_yearly.is_empty() {
+            ui.label("No information".to_string());
+        } else {
+            ui.label(format!(
+                "{}: {} XMR\n{}: {} XMR\n{}: {} XMR\n{}: {} XMR\n{}: {} XMR",
+                XvbRound::Vip,
+                api.reward_yearly[0],
+                XvbRound::Donor,
+                api.reward_yearly[1],
+                XvbRound::DonorVip,
+                api.reward_yearly[2],
+                XvbRound::DonorWhale,
+                api.reward_yearly[3],
+                XvbRound::DonorMega,
+                api.reward_yearly[4]
+            ));
+        }
     });
 }
 #[allow(clippy::too_many_arguments)]
-fn node(
-    ui: &mut Ui,
-    min_size: Vec2,
-    size: Vec2,
-    node_alive: bool,
-    node_api: &Arc<Mutex<PubNodeApi>>,
-) {
-    ui.group(|ui| {
-        ui.vertical(|ui| {
-            ui.set_min_height(min_size.y * 34.0);
-            debug!("Status Tab | Rendering [Node]");
-            ui.add_enabled_ui(node_alive, |ui| {
-                ui.set_min_size(min_size);
-                ui.add_sized(
-                    size,
-                    Label::new(
-                        RichText::new("[Node]")
-                            .color(LIGHT_GRAY)
-                            .text_style(TextStyle::Heading),
-                    ),
-                )
-                .on_hover_text("Node is online")
-                .on_disabled_hover_text("Node is offline");
-                let api = node_api.lock().unwrap();
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Uptime").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_NODE_UPTIME);
-                ui.add_sized(size, Label::new(api.uptime.to_string()));
+fn node(ui: &mut Ui, node_alive: bool, node_api: &Arc<Mutex<PubNodeApi>>) {
+    debug!("Status Tab | Rendering [Node]");
+    ui.add_enabled_ui(node_alive, |ui| {
+        ui.label(
+            RichText::new("[Node]")
+                .color(LIGHT_GRAY)
+                .text_style(TextStyle::Heading),
+        )
+        .on_hover_text("Node is online")
+        .on_disabled_hover_text("Node is offline");
+        let api = node_api.lock().unwrap();
+        ui.label(RichText::new("Uptime").underline().color(BONE))
+            .on_hover_text(STATUS_NODE_UPTIME);
+        ui.label(api.uptime.to_string());
 
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Block Height").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_NODE_BLOCK_HEIGHT);
-                ui.add_sized(size, Label::new(api.blockheight.to_string()));
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Network Difficulty").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_NODE_DIFFICULTY);
-                ui.add_sized(size, Label::new(api.difficulty.to_string()));
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Database size").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_NODE_DB_SIZE);
-                ui.add_sized(size, Label::new(api.database_size.to_owned()));
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Free space").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_NODE_FREESPACE);
-                ui.add_sized(size, Label::new(api.free_space.to_owned()));
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Network Type").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_NODE_NETTYPE);
-                ui.add_sized(size, Label::new(api.nettype.to_string()));
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Outgoing peers").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_NODE_OUT);
-                ui.add_sized(size, Label::new(api.outgoing_connections.to_string()));
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Incoming peers").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_NODE_IN);
-                ui.add_sized(size, Label::new(api.incoming_connections.to_string()));
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Synchronized").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_NODE_SYNC);
-                ui.add_sized(size, Label::new(api.synchronized.to_string()));
-                ui.add_sized(
-                    size,
-                    Label::new(RichText::new("Status").underline().color(BONE)),
-                )
-                .on_hover_text(STATUS_NODE_STATUS);
-                ui.add_sized(size, Label::new(api.status.to_string()));
-                drop(api);
-            });
-        })
+        ui.label(RichText::new("Block Height").underline().color(BONE))
+            .on_hover_text(STATUS_NODE_BLOCK_HEIGHT);
+        ui.label(api.blockheight.to_string());
+        ui.label(RichText::new("Network Difficulty").underline().color(BONE))
+            .on_hover_text(STATUS_NODE_DIFFICULTY);
+        ui.label(api.difficulty.to_string());
+        ui.label(RichText::new("Database size").underline().color(BONE))
+            .on_hover_text(STATUS_NODE_DB_SIZE);
+        ui.label(api.database_size.to_owned());
+        ui.label(RichText::new("Free space").underline().color(BONE))
+            .on_hover_text(STATUS_NODE_FREESPACE);
+        ui.label(api.free_space.to_owned());
+        ui.label(RichText::new("Network Type").underline().color(BONE))
+            .on_hover_text(STATUS_NODE_NETTYPE);
+        ui.label(api.nettype.to_string());
+        ui.label(RichText::new("Outgoing peers").underline().color(BONE))
+            .on_hover_text(STATUS_NODE_OUT);
+        ui.label(api.outgoing_connections.to_string());
+        ui.label(RichText::new("Incoming peers").underline().color(BONE))
+            .on_hover_text(STATUS_NODE_IN);
+        ui.label(api.incoming_connections.to_string());
+        ui.label(RichText::new("Synchronized").underline().color(BONE))
+            .on_hover_text(STATUS_NODE_SYNC);
+        ui.label(api.synchronized.to_string());
+        ui.label(RichText::new("Status").underline().color(BONE))
+            .on_hover_text(STATUS_NODE_STATUS);
+        ui.label(api.status.to_string());
+        drop(api);
     });
 }
diff --git a/src/app/panels/middle/xmrig.rs b/src/app/panels/middle/xmrig.rs
index e050aa1..1a00cb5 100644
--- a/src/app/panels/middle/xmrig.rs
+++ b/src/app/panels/middle/xmrig.rs
@@ -15,481 +15,195 @@
 // You should have received a copy of the GNU General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
+use crate::app::panels::middle::common::console::{console, input_args_field, start_options_field};
+use crate::app::panels::middle::common::list_poolnode::list_poolnode;
+use crate::app::panels::middle::common::state_edit_field::{
+    monero_address_field, slider_state_field,
+};
 use crate::constants::*;
-use crate::disk::pool::Pool;
 use crate::disk::state::Xmrig;
 use crate::helper::Process;
 use crate::helper::xrig::xmrig::PubXmrigApi;
-use crate::regex::{REGEXES, num_lines};
-use crate::utils::regex::Regexes;
-use egui::{
-    Button, Checkbox, ComboBox, Label, RichText, SelectableLabel, Slider, TextEdit, TextStyle,
-    Vec2, vec2,
-};
+use crate::miscs::height_txt_before_button;
+use crate::regex::REGEXES;
+use egui::{Checkbox, Ui, vec2};
 use log::*;
 
 use std::sync::{Arc, Mutex};
 
+use super::common::list_poolnode::PoolNode;
+use super::common::state_edit_field::StateTextEdit;
+
 impl Xmrig {
     #[inline(always)] // called once
     #[allow(clippy::too_many_arguments)]
     pub fn show(
         &mut self,
-        pool_vec: &mut Vec<(String, Pool)>,
+        pool_vec: &mut Vec<(String, PoolNode)>,
         process: &Arc<Mutex<Process>>,
         api: &Arc<Mutex<PubXmrigApi>>,
         buffer: &mut String,
-        size: Vec2,
         _ctx: &egui::Context,
         ui: &mut egui::Ui,
     ) {
-        let text_edit = size.y / 25.0;
-        //---------------------------------------------------------------------------------------------------- [Simple] Console
         debug!("XMRig Tab | Rendering [Console]");
         egui::ScrollArea::vertical().show(ui, |ui| {
-        ui.group(|ui| {
-            let text = &api.lock().unwrap().output;
-            let nb_lines = num_lines(text);
-            let (height, width) = if self.simple {
-                (size.y / 1.5, size.x - SPACE)
-            } else {
-                (size.y / 2.8, size.x - SPACE)
-            };
-            egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
-                ui.style_mut().override_text_style = Some(TextStyle::Small);
-                egui::ScrollArea::vertical()
-                    .stick_to_bottom(true)
-                    .max_width(width)
-                    .max_height(height)
-                    .auto_shrink([false; 2])
-                    // .show_viewport(ui, |ui, _| {
-                    .show_rows(
-                        ui,
-                        ui.text_style_height(&TextStyle::Small),
-                        nb_lines,
-                        |ui, row_range| {
-                            for i in row_range {
-                                if let Some(line) = text.lines().nth(i) {
-                                    ui.label(line);
-                                }
-                            }
-                        },
-                    );
-            });
-            //---------------------------------------------------------------------------------------------------- [Advanced] Console
-            if !self.simple {
-                ui.separator();
-                let response = ui
-                    .add_sized(
-                        [width, text_edit],
-                        TextEdit::hint_text(
-                            TextEdit::singleline(buffer),
-                            r#"Commands: [h]ashrate, [p]ause, [r]esume, re[s]ults, [c]onnection"#,
-                        ),
-                    )
-                    .on_hover_text(XMRIG_INPUT);
-                // If the user pressed enter, dump buffer contents into the process STDIN
-                if response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
-                    response.request_focus(); // Get focus back
-                    let buffer = std::mem::take(buffer); // Take buffer
-                    let mut process = process.lock().unwrap(); // Lock
-                    if process.is_alive() {
-                        process.input.push(buffer);
-                    } // Push only if alive
-                }
-            }
-        });
-
-        //---------------------------------------------------------------------------------------------------- Arguments
-        if !self.simple {
-            debug!("XMRig Tab | Rendering [Arguments]");
             ui.group(|ui| {
-                ui.horizontal(|ui| {
-                    let width = (size.x / 10.0) - SPACE;
-                    ui.add_sized([width, text_edit], Label::new("Command arguments:"));
-                    ui.add_sized(
-                        [ui.available_width(), text_edit],
-                        TextEdit::hint_text(
-                            TextEdit::singleline(&mut self.arguments),
-                            r#"--url <...> --user <...> --config <...>"#,
-                        ),
-                    )
-                    .on_hover_text(XMRIG_ARGUMENTS);
-                    self.arguments.truncate(1024);
-                })
-            });
-            ui.add_enabled_ui(self.arguments.is_empty(), |ui|{
-
-            //---------------------------------------------------------------------------------------------------- Address
-            debug!("XMRig Tab | Rendering [Address]");
-            ui.group(|ui| {
-                let width = size.x - SPACE;
-                ui.spacing_mut().text_edit_width = (width) - (SPACE * 3.0);
-                let text;
-                let color;
-                let len = format!("{:02}", self.address.len());
-                if self.address.is_empty() {
-                    text = format!("Monero Address [{}/95] ➖", len);
-                    color = LIGHT_GRAY;
-                } else if Regexes::addr_ok(&self.address) {
-                    text = format!("Monero Address [{}/95] ✔", len);
-                    color = GREEN;
-                } else {
-                    text = format!("Monero Address [{}/95] ❌", len);
-                    color = RED;
-                }
-                ui.add_sized(
-                    [width, text_edit],
-                    Label::new(RichText::new(text).color(color)),
-                );
-                ui.add_sized(
-                    [width, text_edit],
-                    TextEdit::hint_text(TextEdit::singleline(&mut self.address), "4..."),
-                )
-                .on_hover_text(XMRIG_ADDRESS);
-                self.address.truncate(95);
-            });
-            });
-        }
-
-        //---------------------------------------------------------------------------------------------------- Threads
-        if self.simple {
-            ui.add_space(SPACE);
-        }
-        debug!("XMRig Tab | Rendering [Threads]");
-        ui.vertical(|ui| {
-            let width = size.x / 10.0;
-            let text_width = width * 2.4;
-            ui.spacing_mut().slider_width = width * 6.5;
-            ui.spacing_mut().icon_width = width / 25.0;
-            ui.horizontal(|ui| {
-                ui.add_sized(
-                    [text_width, text_edit],
-                    Label::new(format!("Threads [1-{}]:", self.max_threads)),
-                );
-                ui.add_sized(
-                    [width, text_edit],
-                    Slider::new(&mut self.current_threads, 1..=self.max_threads),
-                )
-                .on_hover_text(XMRIG_THREADS);
-            });
-            #[cfg(not(target_os = "linux"))] // Pause on active isn't supported on Linux
-            ui.horizontal(|ui| {
-                ui.add_sized(
-                    [text_width, text_edit],
-                    Label::new("Pause on active [0-255]:".to_string()),
-                );
-                ui.add_sized([width, text_edit], Slider::new(&mut self.pause, 0..=255))
-                    .on_hover_text(format!("{} [{}] seconds.", XMRIG_PAUSE, self.pause));
-            });
-        });
-
-        //---------------------------------------------------------------------------------------------------- Simple
-        if !self.simple {
-            debug!("XMRig Tab | Rendering [Pool List] elements");
-            let width = ui.available_width() - 10.0;
-            let mut incorrect_input = false; // This will disable [Add/Delete] on bad input
-                                             // [Pool IP/Port]
-            ui.horizontal(|ui| {
-		ui.group(|ui| {
-			let width = width/10.0;
-			ui.vertical(|ui| {
-			ui.spacing_mut().text_edit_width = width*3.32;
-			ui.horizontal(|ui| {
-				let text;
-				let color;
-				let len = format!("{:02}", self.name.len());
-				if self.name.is_empty() {
-					text = format!("Name [ {}/30 ]➖", len);
-					color = LIGHT_GRAY;
-					incorrect_input = true;
-				} else if REGEXES.name.is_match(&self.name) {
-					text = format!("Name [ {}/30 ]✔", len);
-					color = GREEN;
-				} else {
-					text = format!("Name [ {}/30 ]❌", len);
-					color = RED;
-					incorrect_input = true;
-				}
-				ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
-				ui.text_edit_singleline(&mut self.name).on_hover_text(XMRIG_NAME);
-				self.name.truncate(30);
-			});
-			ui.horizontal(|ui| {
-				let text;
-				let color;
-				let len = format!("{:03}", self.ip.len());
-				if self.ip.is_empty() {
-					text = format!("  IP [{}/255]➖", len);
-					color = LIGHT_GRAY;
-					incorrect_input = true;
-				} else if self.ip == "localhost" || REGEXES.ipv4.is_match(&self.ip) || REGEXES.domain.is_match(&self.ip) {
-					text = format!("  IP [{}/255]✔", len);
-					color = GREEN;
-				} else {
-					text = format!("  IP [{}/255]❌", len);
-					color = RED;
-					incorrect_input = true;
-				}
-				ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
-				ui.text_edit_singleline(&mut self.ip).on_hover_text(XMRIG_IP);
-				self.ip.truncate(255);
-			});
-			ui.horizontal(|ui| {
-				let text;
-				let color;
-				let len = self.port.len();
-				if self.port.is_empty() {
-					text = format!("Port [  {}/5  ]➖", len);
-					color = LIGHT_GRAY;
-					incorrect_input = true;
-				} else if REGEXES.port.is_match(&self.port) {
-					text = format!("Port [  {}/5  ]✔", len);
-					color = GREEN;
-				} else {
-					text = format!("Port [  {}/5  ]❌", len);
-					color = RED;
-					incorrect_input = true;
-				}
-				ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
-				ui.text_edit_singleline(&mut self.port).on_hover_text(XMRIG_PORT);
-				self.port.truncate(5);
-			});
-			ui.horizontal(|ui| {
-				let text;
-				let color;
-				let len = format!("{:02}", self.rig.len());
-				if self.rig.is_empty() {
-					text = format!(" Rig [ {}/30 ]➖", len);
-					color = LIGHT_GRAY;
-				} else if REGEXES.name.is_match(&self.rig) {
-					text = format!(" Rig [ {}/30 ]✔", len);
-					color = GREEN;
-				} else {
-					text = format!(" Rig [ {}/30 ]❌", len);
-					color = RED;
-					incorrect_input = true;
-				}
-				ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
-				ui.text_edit_singleline(&mut self.rig).on_hover_text(XMRIG_RIG);
-				self.rig.truncate(30);
-			});
-		});
-
-		ui.vertical(|ui| {
-			let width = ui.available_width();
-			ui.add_space(1.0);
-			// [Manual node selection]
-			ui.spacing_mut().slider_width = width - 8.0;
-			ui.spacing_mut().icon_width = width / 25.0;
-			// [Node List]
-			debug!("XMRig Tab | Rendering [Node List] ComboBox");
-			let text = RichText::new(format!("{}. {}", self.selected_index+1, self.selected_name));
-			ComboBox::from_id_salt("manual_pool").selected_text(text).width(width).show_ui(ui, |ui| {
-				for (n, (name, pool)) in pool_vec.iter().enumerate() {
-					let text = format!("{}. {}\n     IP: {}\n   Port: {}\n    Rig: {}", n+1, name, pool.ip, pool.port, pool.rig);
-					if ui.add(SelectableLabel::new(self.selected_name == *name, text)).clicked() {
-						self.selected_index = n;
-						let pool = pool.clone();
-						self.selected_name.clone_from(name);
-						self.selected_rig.clone_from(&pool.rig);
-						self.selected_ip.clone_from(&pool.ip);
-						self.selected_port.clone_from(&pool.port);
-						self.name.clone_from(name);
-						self.rig = pool.rig;
-						self.ip = pool.ip;
-						self.port = pool.port;
-					}
-				}
-			});
-			// [Add/Save]
-			let pool_vec_len = pool_vec.len();
-			let mut exists = false;
-			let mut save_diff = true;
-			let mut existing_index = 0;
-			for (name, pool) in pool_vec.iter() {
-				if *name == self.name {
-					exists = true;
-					if self.rig == pool.rig && self.ip == pool.ip && self.port == pool.port {
-						save_diff = false;
-					}
-					break
-				}
-				existing_index += 1;
-			}
-			ui.horizontal(|ui| {
-				let text = if exists { LIST_SAVE } else { LIST_ADD };
-				let text = format!("{}\n    Currently selected pool: {}. {}\n    Current amount of pools: {}/1000", text, self.selected_index+1, self.selected_name, pool_vec_len);
-				// If the pool already exists, show [Save] and mutate the already existing pool
-				if exists {
-					ui.add_enabled_ui(!incorrect_input && save_diff, |ui|{
-					if ui.add_sized([width, text_edit], Button::new("Save")).on_hover_text(text).clicked() {
-						let pool = Pool {
-							rig: self.rig.clone(),
-							ip: self.ip.clone(),
-							port: self.port.clone(),
-						};
-						pool_vec[existing_index].1 = pool;
-						self.selected_name.clone_from(&self.name);
-						self.selected_rig.clone_from(&self.rig);
-						self.selected_ip.clone_from(&self.ip);
-						self.selected_port.clone_from(&self.port);
-						info!("Node | S | [index: {}, name: \"{}\", ip: \"{}\", port: {}, rig: \"{}\"]", existing_index+1, self.name, self.ip, self.port, self.rig);
-					}
-					});
-				// Else, add to the list
-				} else {
-					ui.add_enabled_ui(!incorrect_input && pool_vec_len < 1000, |ui|{
-					if ui.add_sized([width, text_edit], Button::new("Add")).on_hover_text(text).clicked() {
-						let pool = Pool {
-							rig: self.rig.clone(),
-							ip: self.ip.clone(),
-							port: self.port.clone(),
-						};
-						pool_vec.push((self.name.clone(), pool));
-						self.selected_index = pool_vec_len;
-						self.selected_name.clone_from(&self.name);
-						self.selected_rig.clone_from(&self.rig);
-						self.selected_ip.clone_from(&self.ip);
-						self.selected_port.clone_from(&self.port);
-						info!("Node | A | [index: {}, name: \"{}\", ip: \"{}\", port: {}, rig: \"{}\"]", pool_vec_len, self.name, self.ip, self.port, self.rig);
-					}
-					});
-				}
-			});
-			// [Delete]
-			ui.horizontal(|ui| {
-				ui.add_enabled_ui(pool_vec_len > 1, |ui|{
-					let text = format!("{}\n    Currently selected pool: {}. {}\n    Current amount of pools: {}/1000", LIST_DELETE, self.selected_index+1, self.selected_name, pool_vec_len);
-				if ui.add_sized([width, text_edit], Button::new("Delete")).on_hover_text(text).clicked() {
-					let new_name;
-					let new_pool;
-					match self.selected_index {
-						0 => {
-							new_name = pool_vec[1].0.clone();
-							new_pool = pool_vec[1].1.clone();
-							pool_vec.remove(0);
-						}
-						_ => {
-							pool_vec.remove(self.selected_index);
-							self.selected_index -= 1;
-							new_name = pool_vec[self.selected_index].0.clone();
-							new_pool = pool_vec[self.selected_index].1.clone();
-						}
-					};
-					self.selected_name.clone_from(&new_name);
-					self.selected_rig.clone_from(&new_pool.rig);
-					self.selected_ip.clone_from(&new_pool.ip);
-					self.selected_port.clone_from(&new_pool.port);
-					self.name = new_name;
-					self.rig = new_pool.rig;
-					self.ip = new_pool.ip;
-					self.port = new_pool.port;
-					info!("Node | D | [index: {}, name: \"{}\", ip: \"{}\", port: {}, rig\"{}\"]", self.selected_index, self.selected_name, self.selected_ip, self.selected_port, self.selected_rig);
-}
-				});
-
-			});
-			ui.horizontal(|ui| {
-				ui.add_enabled_ui(!self.name.is_empty() || !self.ip.is_empty() || !self.port.is_empty(), |ui|{
-				if ui.add_sized([width, text_edit], Button::new("Clear")).on_hover_text(LIST_CLEAR).clicked() {
-					self.name.clear();
-					self.rig.clear();
-					self.ip.clear();
-					self.port.clear();
-				}
-				});
-			});
-		});
-		});
-		});
-            ui.add_space(5.0);
-
-            debug!("XMRig Tab | Rendering [API] TextEdits");
-            // [HTTP API IP/Port]
-            ui.group(|ui| {
-                ui.horizontal(|ui| {
-                    ui.vertical(|ui| {
-                        let width = width / 10.0;
-                        ui.spacing_mut().text_edit_width = width * 2.39;
-                        // HTTP API
-                        ui.horizontal(|ui| {
-                            let text;
-                            let color;
-                            let len = format!("{:03}", self.api_ip.len());
-                            if self.api_ip.is_empty() {
-                                text = format!("HTTP API IP   [{}/255]➖", len);
-                                color = LIGHT_GRAY;
-                                incorrect_input = true;
-                            } else if self.api_ip == "localhost"
-                                || REGEXES.ipv4.is_match(&self.api_ip)
-                                || REGEXES.domain.is_match(&self.api_ip)
-                            {
-                                text = format!("HTTP API IP   [{}/255]✔", len);
-                                color = GREEN;
-                            } else {
-                                text = format!("HTTP API IP   [{}/255]❌", len);
-                                color = RED;
-                                incorrect_input = true;
-                            }
-                            ui.add_sized(
-                                [width, text_edit],
-                                Label::new(RichText::new(text).color(color)),
-                            );
-                            ui.text_edit_singleline(&mut self.api_ip)
-                                .on_hover_text(XMRIG_API_IP);
-                            self.api_ip.truncate(255);
-                        });
-                        ui.horizontal(|ui| {
-                            let text;
-                            let color;
-                            let len = self.api_port.len();
-                            if self.api_port.is_empty() {
-                                text = format!("HTTP API Port [  {}/5  ]➖", len);
-                                color = LIGHT_GRAY;
-                                incorrect_input = true;
-                            } else if REGEXES.port.is_match(&self.api_port) {
-                                text = format!("HTTP API Port [  {}/5  ]✔", len);
-                                color = GREEN;
-                            } else {
-                                text = format!("HTTP API Port [  {}/5  ]❌", len);
-                                color = RED;
-                                incorrect_input = true;
-                            }
-                            ui.add_sized(
-                                [width, text_edit],
-                                Label::new(RichText::new(text).color(color)),
-                            );
-                            ui.text_edit_singleline(&mut self.api_port)
-                                .on_hover_text(XMRIG_API_PORT);
-                            self.api_port.truncate(5);
-                        });
-                    });
-
+                let text = &api.lock().unwrap().output;
+                console(ui, text);
+                if !self.simple {
                     ui.separator();
-
-                    debug!("XMRig Tab | Rendering [TLS/Keepalive] buttons");
-                    ui.vertical(|ui| {
-                        // TLS/Keepalive
-                        ui.horizontal(|ui| {
-                            let width = (ui.available_width() / 2.0) - 11.0;
-                            let height = text_edit * 2.0;
-                            let size = vec2(width, height);
-                            //				let mut style = (*ctx.style()).clone();
-                            //				style.spacing.icon_width_inner = width / 8.0;
-                            //				style.spacing.icon_width = width / 6.0;
-                            //				style.spacing.icon_spacing = 20.0;
-                            //				ctx.set_style(style);
-                            ui.add_sized(size, Checkbox::new(&mut self.tls, "TLS Connection"))
-                                .on_hover_text(XMRIG_TLS);
-                            ui.separator();
-                            ui.add_sized(size, Checkbox::new(&mut self.keepalive, "Keepalive"))
-                                .on_hover_text(XMRIG_KEEPALIVE);
+                    input_args_field(
+                        ui,
+                        buffer,
+                        process,
+                        r#"Commands: [h]ashrate, [p]ause, [r]esume, re[s]ults, [c]onnection"#,
+                        XMRIG_INPUT,
+                    );
+                }
+            });
+            if !self.simple {
+                debug!("XMRig Tab | Rendering [Arguments]");
+                ui.horizontal(|ui| {
+                    start_options_field(
+                        ui,
+                        &mut self.arguments,
+                        r#"--url <...> --user <...> --config <...>"#,
+                        XMRIG_ARGUMENTS,
+                    );
+                });
+                ui.add_enabled_ui(self.arguments.is_empty(), |ui| {
+                    debug!("XMRig Tab | Rendering [Address]");
+                    monero_address_field(&mut self.address, ui, XMRIG_ADDRESS);
+                });
+            }
+            if self.simple {
+                ui.add_space(SPACE);
+            }
+            debug!("XMRig Tab | Rendering [Threads]");
+            ui.vertical_centered(|ui| {
+                ui.set_max_width(ui.available_width() * 0.75);
+                slider_state_field(
+                    ui,
+                    &format!("Threads [1-{}]:", self.max_threads),
+                    XMRIG_THREADS,
+                    &mut self.current_threads,
+                    1..=self.max_threads,
+                );
+                #[cfg(not(target_os = "linux"))] // Pause on active isn't supported on Linux
+                slider_state_field(
+                    ui,
+                    "Pause on active [0-255]:",
+                    &format!("{} [{}] seconds.", XMRIG_PAUSE, self.pause),
+                    &mut self.pause,
+                    0..=255,
+                );
+            });
+            if !self.simple {
+                debug!("XMRig Tab | Rendering [Pool List] elements");
+                let mut incorrect_input = false; // This will disable [Add/Delete] on bad input
+                ui.horizontal(|ui| {
+                    ui.group(|ui| {
+                        ui.vertical(|ui| {
+                            if !self.name_field(ui) {
+                                incorrect_input = false;
+                            }
+                            if !self.ip_field(ui) {
+                                incorrect_input = false;
+                            }
+                            if !self.rpc_port_field(ui) {
+                                incorrect_input = false;
+                            }
+                            if !self.rig_field(ui) {
+                                incorrect_input = false;
+                            }
+                        });
+                        ui.vertical(|ui| {
+                            list_poolnode(
+                                ui,
+                                &mut (&mut self.name, &mut self.ip, &mut self.port, &mut self.rig),
+                                &mut self.selected_pool,
+                                pool_vec,
+                                incorrect_input,
+                            );
                         });
                     });
                 });
-            });
-        }
-    });
+                ui.add_space(5.0);
+                debug!("XMRig Tab | Rendering [API] TextEdits");
+                // [HTTP API IP/Port]
+                ui.group(|ui| {
+                    ui.horizontal(|ui| {
+                        ui.vertical(|ui| {
+                            self.api_ip_field(ui);
+                            self.api_port_field(ui);
+                        });
+                        ui.separator();
+                        debug!("XMRig Tab | Rendering [TLS/Keepalive] buttons");
+                        ui.vertical(|ui| {
+                            // TLS/Keepalive
+                            ui.horizontal(|ui| {
+                                let width = (ui.available_width() / 2.0) - 11.0;
+                                let height =
+                                    height_txt_before_button(ui, &egui::TextStyle::Button) * 2.0;
+                                let size = vec2(width, height);
+                                ui.add_sized(size, Checkbox::new(&mut self.tls, "TLS Connection"))
+                                    .on_hover_text(XMRIG_TLS);
+                                ui.separator();
+                                ui.add_sized(size, Checkbox::new(&mut self.keepalive, "Keepalive"))
+                                    .on_hover_text(XMRIG_KEEPALIVE);
+                            });
+                        });
+                    });
+                });
+            }
+        });
+    }
+    fn name_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description("   Name     ")
+            .max_ch(30)
+            .help_msg(XMRIG_NAME)
+            .validations(&[|x| REGEXES.name.is_match(x)])
+            .build(ui, &mut self.name)
+    }
+    fn rpc_port_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description("   RPC PORT ")
+            .max_ch(5)
+            .help_msg(XMRIG_PORT)
+            .validations(&[|x| REGEXES.port.is_match(x)])
+            .build(ui, &mut self.port)
+    }
+    fn ip_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description("   IP       ")
+            .max_ch(255)
+            .help_msg(XMRIG_IP)
+            .validations(&[|x| REGEXES.ipv4.is_match(x) || REGEXES.domain.is_match(x)])
+            .build(ui, &mut self.ip)
+    }
+    fn rig_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description("   Name     ")
+            .max_ch(30)
+            .help_msg(XMRIG_RIG)
+            .build(ui, &mut self.rig)
+    }
+    fn api_ip_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description(" API IP   ")
+            .max_ch(255)
+            .help_msg(XMRIG_API_IP)
+            .validations(&[|x| REGEXES.ipv4.is_match(x) || REGEXES.domain.is_match(x)])
+            .build(ui, &mut self.api_ip)
+    }
+    fn api_port_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description(" API PORT ")
+            .max_ch(5)
+            .help_msg(XMRIG_API_PORT)
+            .validations(&[|x| REGEXES.port.is_match(x)])
+            .build(ui, &mut self.api_port)
     }
 }
diff --git a/src/app/panels/middle/xmrig_proxy.rs b/src/app/panels/middle/xmrig_proxy.rs
index 1f9dfdd..aaa361c 100644
--- a/src/app/panels/middle/xmrig_proxy.rs
+++ b/src/app/panels/middle/xmrig_proxy.rs
@@ -1,439 +1,201 @@
-use egui::{
-    Button, Checkbox, ComboBox, Label, RichText, SelectableLabel, TextEdit, TextStyle, Vec2, vec2,
-};
+use egui::{Checkbox, Label, TextStyle, Ui, vec2};
 use std::sync::{Arc, Mutex};
 
-use log::{debug, info};
+use log::debug;
 
-use crate::disk::pool::Pool;
+use crate::app::panels::middle::common::console::{console, input_args_field, start_options_field};
+use crate::app::panels::middle::common::list_poolnode::list_poolnode;
 use crate::disk::state::XmrigProxy;
 use crate::helper::Process;
 use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi;
-use crate::regex::{REGEXES, num_lines};
-use crate::utils::constants::DARK_GRAY;
+use crate::miscs::height_txt_before_button;
+use crate::regex::REGEXES;
 use crate::{
-    GREEN, LIGHT_GRAY, LIST_ADD, LIST_CLEAR, LIST_DELETE, LIST_SAVE, RED, SPACE, XMRIG_API_IP,
-    XMRIG_API_PORT, XMRIG_IP, XMRIG_KEEPALIVE, XMRIG_NAME, XMRIG_PORT, XMRIG_PROXY_ARGUMENTS,
-    XMRIG_PROXY_INPUT, XMRIG_PROXY_REDIRECT, XMRIG_PROXY_URL, XMRIG_RIG, XMRIG_TLS,
+    SPACE, XMRIG_API_IP, XMRIG_API_PORT, XMRIG_IP, XMRIG_KEEPALIVE, XMRIG_NAME, XMRIG_PORT,
+    XMRIG_PROXY_ARGUMENTS, XMRIG_PROXY_INPUT, XMRIG_PROXY_REDIRECT, XMRIG_PROXY_URL, XMRIG_RIG,
+    XMRIG_TLS,
 };
 
+use super::common::list_poolnode::PoolNode;
+use super::common::state_edit_field::StateTextEdit;
+
 impl XmrigProxy {
     #[inline(always)] // called once
     pub fn show(
         &mut self,
         process: &Arc<Mutex<Process>>,
-        pool_vec: &mut Vec<(String, Pool)>,
+        pool_vec: &mut Vec<(String, PoolNode)>,
         api: &Arc<Mutex<PubXmrigProxyApi>>,
         buffer: &mut String,
-        size: Vec2,
         ui: &mut egui::Ui,
     ) {
-        let width = size.x;
-        let height = size.y;
-        let space_h = height / 48.0;
-        let text_edit = size.y / 25.0;
-        egui::ScrollArea::vertical().show(ui, |ui| {
         ui.vertical_centered(|ui| {
-            ui.add_space(space_h);
+            ui.add_space(SPACE);
             ui.style_mut().override_text_style = Some(TextStyle::Heading);
             ui.hyperlink_to("XMRig-Proxy", XMRIG_PROXY_URL);
             ui.style_mut().override_text_style = Some(TextStyle::Body);
             ui.add(Label::new("High performant proxy for your miners"));
-            ui.add_space(space_h);
+            ui.add_space(SPACE);
         });
         // console output for log
         debug!("Xmrig-Proxy Tab | Rendering [Console]");
-        ui.group(|ui| {
-            let text = &api.lock().unwrap().output;
-            let nb_lines = num_lines(text);
-            let height = size.y / 2.8;
-            let width = size.x - (space_h / 2.0);
-            egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
-                ui.style_mut().override_text_style = Some(egui::TextStyle::Small
-                );
-                egui::ScrollArea::vertical()
-                    .stick_to_bottom(true)
-                    .max_width(width)
-                    .max_height(height)
-                    .auto_shrink([false; 2])
-                    // .show_viewport(ui, |ui, _| {
-                    .show_rows(
-                        ui,
-                        ui.text_style_height(&TextStyle::Small),
-                        nb_lines,
-                        |ui, row_range| {
-                            for i in row_range {
-                                if let Some(line) = text.lines().nth(i) {
-                                    ui.label(line);
-                                }
-                            }
-                        },
-                    );
-            });
-        });
-        //---------------------------------------------------------------------------------------------------- [Advanced] Console
-        if !self.simple {
-            ui.separator();
-            let response = ui
-                .add_sized(
-                    [width, text_edit],
-                    TextEdit::hint_text(
-                        TextEdit::singleline(buffer),
-                        r#"Commands: [h]ashrate, [c]onnections, [v]erbose, [w]orkers"#,
-                    ),
-                )
-                .on_hover_text(XMRIG_PROXY_INPUT);
-            // If the user pressed enter, dump buffer contents into the process STDIN
-            if response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
-                response.request_focus(); // Get focus back
-                let buffer = std::mem::take(buffer); // Take buffer
-                let mut process = process.lock().unwrap(); // Lock
-                if process.is_alive() {
-                    process.input.push(buffer);
-                } // Push only if alive
-            }
-
-            //---------------------------------------------------------------------------------------------------- Arguments
-            debug!("XMRig-Proxy Tab | Rendering [Arguments]");
+        egui::ScrollArea::vertical().show(ui, |ui| {
             ui.group(|ui| {
-                ui.horizontal(|ui| {
-                    let width = (size.x / 10.0) - SPACE;
-                    ui.add_sized([width, text_edit], Label::new("Command arguments:"));
-                    ui.add_sized(
-                        [ui.available_width(), text_edit],
-                        TextEdit::hint_text(
-                            TextEdit::singleline(&mut self.arguments),
-                            r#"--url <...> --user <...> --config <...>"#,
-                        ),
-                    )
-                    .on_hover_text(XMRIG_PROXY_ARGUMENTS);
-                    self.arguments.truncate(1024);
-                })
-            });
-            if !self.arguments.is_empty() {
-            	ui.disable();
-            }
-            ui.add_space(space_h);
-            ui.style_mut().spacing.icon_width_inner = width / 45.0;
-            ui.style_mut().spacing.icon_width = width / 35.0;
-            ui.style_mut().spacing.icon_spacing = space_h;
-            ui.checkbox(
-                &mut self.redirect_local_xmrig,
-                "Auto Redirect local Xmrig to Xmrig-Proxy",
-            )
-            .on_hover_text(XMRIG_PROXY_REDIRECT);
-
-            // idea
-            // need to warn the user if local firewall is blocking port
-            // need to warn the user if NAT is blocking port
-            // need to show local ip address
-            // need to show public ip
-
-            debug!("XMRig-Proxy Tab | Rendering [Pool List] elements");
-            let width = ui.available_width() - 10.0;
-            let mut incorrect_input = false; // This will disable [Add/Delete] on bad input
-                                             // [Pool IP/Port]
-            ui.horizontal(|ui| {
-		ui.group(|ui| {
-			let width = width/10.0;
-			ui.vertical(|ui| {
-			ui.spacing_mut().text_edit_width = width*3.32;
-			ui.horizontal(|ui| {
-				let text;
-				let color;
-				let len = format!("{:02}", self.name.len());
-				if self.name.is_empty() {
-					text = format!("Name [ {}/30 ]➖", len);
-					color = LIGHT_GRAY;
-					incorrect_input = true;
-				} else if REGEXES.name.is_match(&self.name) {
-					text = format!("Name [ {}/30 ]✔", len);
-					color = GREEN;
-				} else {
-					text = format!("Name [ {}/30 ]❌", len);
-					color = RED;
-					incorrect_input = true;
-				}
-				ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
-				ui.text_edit_singleline(&mut self.name).on_hover_text(XMRIG_NAME);
-				self.name.truncate(30);
-			});
-			ui.horizontal(|ui| {
-				let text;
-				let color;
-				let len = format!("{:03}", self.p2pool_ip.len());
-				if self.p2pool_ip.is_empty() {
-					text = format!("  IP [{}/255]➖", len);
-					color = LIGHT_GRAY;
-					incorrect_input = true;
-				} else if self.p2pool_ip == "localhost" || REGEXES.ipv4.is_match(&self.p2pool_ip) || REGEXES.domain.is_match(&self.p2pool_ip) {
-					text = format!("  IP [{}/255]✔", len);
-					color = GREEN;
-				} else {
-					text = format!("  IP [{}/255]❌", len);
-					color = RED;
-					incorrect_input = true;
-				}
-				ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
-				ui.text_edit_singleline(&mut self.p2pool_ip).on_hover_text(XMRIG_IP);
-				self.p2pool_ip.truncate(255);
-			});
-			ui.horizontal(|ui| {
-				let text;
-				let color;
-				let len = self.p2pool_port.len();
-				if self.p2pool_port.is_empty() {
-					text = format!("Port [  {}/5  ]➖", len);
-					color = LIGHT_GRAY;
-					incorrect_input = true;
-				} else if REGEXES.port.is_match(&self.p2pool_port) {
-					text = format!("Port [  {}/5  ]✔", len);
-					color = GREEN;
-				} else {
-					text = format!("Port [  {}/5  ]❌", len);
-					color = RED;
-					incorrect_input = true;
-				}
-				ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
-				ui.text_edit_singleline(&mut self.p2pool_port).on_hover_text(XMRIG_PORT);
-				self.p2pool_port.truncate(5);
-			});
-			ui.horizontal(|ui| {
-				let text;
-				let color;
-				let len = format!("{:02}", self.rig.len());
-				if self.rig.is_empty() {
-					text = format!(" Rig [ {}/30 ]➖", len);
-					color = LIGHT_GRAY;
-				} else if REGEXES.name.is_match(&self.rig) {
-					text = format!(" Rig [ {}/30 ]✔", len);
-					color = GREEN;
-				} else {
-					text = format!(" Rig [ {}/30 ]❌", len);
-					color = RED;
-					incorrect_input = true;
-				}
-				ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
-				ui.text_edit_singleline(&mut self.rig).on_hover_text(XMRIG_RIG);
-				self.rig.truncate(30);
-			});
-		});
-
-		ui.vertical(|ui| {
-			let width = ui.available_width();
-			ui.add_space(1.0);
-			// [Manual node selection]
-			ui.spacing_mut().slider_width = width - 8.0;
-			ui.spacing_mut().icon_width = width / 25.0;
-			// [Node List]
-			debug!("XMRig-Proxy Tab | Rendering [Node List] ComboBox");
-			let text = RichText::new(format!("{}. {}", self.selected_index+1, self.selected_name));
-			ComboBox::from_id_salt("manual_pool").selected_text(text).width(width).show_ui(ui, |ui| {
-				for (n, (name, pool)) in pool_vec.iter().enumerate() {
-					let text = format!("{}. {}\n     IP: {}\n   Port: {}\n    Rig: {}", n+1, name, pool.ip, pool.port, pool.rig);
-					if ui.add(SelectableLabel::new(self.selected_name == *name, text)).clicked() {
-						self.selected_index = n;
-						let pool = pool.clone();
-						self.selected_name.clone_from(name);
-						self.selected_rig.clone_from(&pool.rig);
-						self.selected_ip.clone_from(&pool.ip);
-						self.selected_port.clone_from(&pool.port);
-						self.name.clone_from(name);
-						self.rig = pool.rig;
-						self.p2pool_ip = pool.ip;
-						self.p2pool_port = pool.port;
-					}
-				}
-			});
-			// [Add/Save]
-			let pool_vec_len = pool_vec.len();
-			let mut exists = false;
-			let mut save_diff = true;
-			let mut existing_index = 0;
-			for (name, pool) in pool_vec.iter() {
-				if *name == self.name {
-					exists = true;
-					if self.rig == pool.rig && self.p2pool_ip == pool.ip && self.p2pool_port == pool.port {
-						save_diff = false;
-					}
-					break
-				}
-				existing_index += 1;
-			}
-			ui.horizontal(|ui| {
-				let text = if exists { LIST_SAVE } else { LIST_ADD };
-				let text = format!("{}\n    Currently selected pool: {}. {}\n    Current amount of pools: {}/1000", text, self.selected_index+1, self.selected_name, pool_vec_len);
-				// If the pool already exists, show [Save] and mutate the already existing pool
-				if exists {
-					ui.add_enabled_ui(!incorrect_input && save_diff, |ui|{
-					if ui.add_sized([width, text_edit], Button::new("Save")).on_hover_text(text).clicked() {
-						let pool = Pool {
-							rig: self.rig.clone(),
-							ip: self.p2pool_ip.clone(),
-							port: self.p2pool_port.clone(),
-						};
-						pool_vec[existing_index].1 = pool;
-						self.selected_name.clone_from(&self.name);
-						self.selected_rig.clone_from(&self.rig);
-						self.selected_ip.clone_from(&self.p2pool_ip);
-						self.selected_port.clone_from(&self.p2pool_port);
-						info!("Node | S | [index: {}, name: \"{}\", ip: \"{}\", port: {}, rig: \"{}\"]", existing_index+1, self.name, self.p2pool_ip, self.p2pool_port, self.rig);
-					}
-
-					});
-				// Else, add to the list
-				} else {
-					ui.add_enabled_ui(!incorrect_input && pool_vec_len < 1000, |ui|{
-					if ui.add_sized([width, text_edit], Button::new("Add")).on_hover_text(text).clicked() {
-						let pool = Pool {
-							rig: self.rig.clone(),
-							ip: self.p2pool_ip.clone(),
-							port: self.p2pool_port.clone(),
-						};
-						pool_vec.push((self.name.clone(), pool));
-						self.selected_index = pool_vec_len;
-						self.selected_name.clone_from(&self.name);
-						self.selected_rig.clone_from(&self.rig);
-						self.selected_ip.clone_from(&self.p2pool_ip);
-						self.selected_port.clone_from(&self.p2pool_port);
-						info!("Node | A | [index: {}, name: \"{}\", ip: \"{}\", port: {}, rig: \"{}\"]", pool_vec_len, self.name, self.p2pool_ip, self.p2pool_port, self.rig);
-					}
-
-					});
-				}
-			});
-			// [Delete]
-			ui.horizontal(|ui| {
-				ui.add_enabled_ui(pool_vec_len > 1, |ui|{
-				let text = format!("{}\n    Currently selected pool: {}. {}\n    Current amount of pools: {}/1000", LIST_DELETE, self.selected_index+1, self.selected_name, pool_vec_len);
-				if ui.add_sized([width, text_edit], Button::new("Delete")).on_hover_text(text).clicked() {
-					let new_name;
-					let new_pool;
-					match self.selected_index {
-						0 => {
-							new_name = pool_vec[1].0.clone();
-							new_pool = pool_vec[1].1.clone();
-							pool_vec.remove(0);
-						}
-						_ => {
-							pool_vec.remove(self.selected_index);
-							self.selected_index -= 1;
-							new_name = pool_vec[self.selected_index].0.clone();
-							new_pool = pool_vec[self.selected_index].1.clone();
-						}
-					};
-					self.selected_name.clone_from(&new_name);
-					self.selected_rig.clone_from(&new_pool.rig);
-					self.selected_ip.clone_from(&new_pool.ip);
-					self.selected_port.clone_from(&new_pool.port);
-					self.name = new_name;
-					self.rig = new_pool.rig;
-					self.p2pool_ip = new_pool.ip;
-					self.p2pool_port = new_pool.port;
-					info!("Node | D | [index: {}, name: \"{}\", ip: \"{}\", port: {}, rig\"{}\"]", self.selected_index, self.selected_name, self.selected_ip, self.selected_port, self.selected_rig);
-				}
-				});
-			});
-			ui.horizontal(|ui| {
-				ui.add_enabled_ui(!self.name.is_empty() || !self.p2pool_ip.is_empty() || !self.p2pool_port.is_empty(), |ui|{
-				if ui.add_sized([width, text_edit], Button::new("Clear")).on_hover_text(LIST_CLEAR).clicked() {
-					self.name.clear();
-					self.rig.clear();
-					self.p2pool_ip.clear();
-					self.p2pool_port.clear();
-				}
-				});
-			});
-		});
-		});
-		});
-            ui.add_space(5.0);
-
-            debug!("XMRig-Proxy Tab | Rendering [API] TextEdits");
-            // [HTTP API IP/Port]
-            ui.group(|ui| {
-                ui.horizontal(|ui| {
-                    ui.vertical(|ui| {
-                        let width = width / 10.0;
-                        ui.spacing_mut().text_edit_width = width * 2.39;
-                        // HTTP API
-                        ui.horizontal(|ui| {
-                            let text;
-                            let color;
-                            let len = format!("{:03}", self.api_ip.len());
-                            if self.api_ip.is_empty() {
-                                text = format!("HTTP API IP   [{}/255]➖", len);
-                                color = LIGHT_GRAY;
-                                incorrect_input = true;
-                            } else if self.api_ip == "localhost"
-                                || REGEXES.ipv4.is_match(&self.api_ip)
-                                || REGEXES.domain.is_match(&self.api_ip)
-                            {
-                                text = format!("HTTP API IP   [{}/255]✔", len);
-                                color = GREEN;
-                            } else {
-                                text = format!("HTTP API IP   [{}/255]❌", len);
-                                color = RED;
-                                incorrect_input = true;
-                            }
-                            ui.add_sized(
-                                [width, text_edit],
-                                Label::new(RichText::new(text).color(color)),
-                            );
-                            ui.text_edit_singleline(&mut self.api_ip)
-                                .on_hover_text(XMRIG_API_IP);
-                            self.api_ip.truncate(255);
-                        });
-                        ui.horizontal(|ui| {
-                            let text;
-                            let color;
-                            let len = self.api_port.len();
-                            if self.api_port.is_empty() {
-                                text = format!("HTTP API Port [  {}/5  ]➖", len);
-                                color = LIGHT_GRAY;
-                                incorrect_input = true;
-                            } else if REGEXES.port.is_match(&self.api_port) {
-                                text = format!("HTTP API Port [  {}/5  ]✔", len);
-                                color = GREEN;
-                            } else {
-                                text = format!("HTTP API Port [  {}/5  ]❌", len);
-                                color = RED;
-                                incorrect_input = true;
-                            }
-                            ui.add_sized(
-                                [width, text_edit],
-                                Label::new(RichText::new(text).color(color)),
-                            );
-                            ui.text_edit_singleline(&mut self.api_port)
-                                .on_hover_text(XMRIG_API_PORT);
-                            self.api_port.truncate(5);
-                        });
-                    });
-
+                let text = &api.lock().unwrap().output;
+                console(ui, text);
+                //---------------------------------------------------------------------------------------------------- [Advanced] Console
+                if !self.simple {
                     ui.separator();
+                    input_args_field(
+                        ui,
+                        buffer,
+                        process,
+                        r#"Commands: [h]ashrate, [c]onnections, [v]erbose, [w]orkers"#,
+                        XMRIG_PROXY_INPUT,
+                    );
+                }
+            });
+            if !self.simple {
+                //---------------------------------------------------------------------------------------------------- Arguments
+                debug!("XMRig-Proxy Tab | Rendering [Arguments]");
+                ui.horizontal(|ui| {
+                    start_options_field(
+                        ui,
+                        &mut self.arguments,
+                        r#"--url <...> --user <...> --config <...>"#,
+                        XMRIG_PROXY_ARGUMENTS,
+                    );
+                });
+                if !self.arguments.is_empty() {
+                    ui.disable();
+                }
+                ui.add_space(SPACE);
+                // ui.style_mut().spacing.icon_width_inner = width / 45.0;
+                // ui.style_mut().spacing.icon_width = width / 35.0;
+                // ui.style_mut().spacing.icon_spacing = space_h;
+                ui.checkbox(
+                    &mut self.redirect_local_xmrig,
+                    "Auto Redirect local Xmrig to Xmrig-Proxy",
+                )
+                .on_hover_text(XMRIG_PROXY_REDIRECT);
 
-                    debug!("XMRig-Proxy Tab | Rendering [TLS/Keepalive] buttons");
-                    ui.vertical(|ui| {
-                        // TLS/Keepalive
-                        ui.horizontal(|ui| {
-                            let width = (ui.available_width() / 2.0) - 11.0;
-                            let height = text_edit * 2.0;
-                            let size = vec2(width, height);
-                            //				let mut style = (*ctx.style()).clone();
-                            //				style.spacing.icon_width_inner = width / 8.0;
-                            //				style.spacing.icon_width = width / 6.0;
-                            //				style.spacing.icon_spacing = 20.0;
-                            //				ctx.set_style(style);
-                            ui.add_sized(size, Checkbox::new(&mut self.tls, "TLS Connection"))
-                                .on_hover_text(XMRIG_TLS);
-                            ui.separator();
-                            ui.add_sized(size, Checkbox::new(&mut self.keepalive, "Keepalive"))
-                                .on_hover_text(XMRIG_KEEPALIVE);
+                // idea
+                // need to warn the user if local firewall is blocking port
+                // need to warn the user if NAT is blocking port
+                // need to show local ip address
+                // need to show public ip
+
+                debug!("XMRig-Proxy Tab | Rendering [Pool List] elements");
+                // let width = ui.available_width() - 10.0;
+                let mut incorrect_input = false; // This will disable [Add/Delete] on bad input
+                // [Pool IP/Port]
+                ui.horizontal(|ui| {
+                    ui.group(|ui| {
+                        // let width = width / 10.0;
+                        ui.vertical(|ui| {
+                            if !self.name_field(ui) {
+                                incorrect_input = false;
+                            }
+                            if !self.ip_field(ui) {
+                                incorrect_input = false;
+                            }
+                            if !self.rpc_port_field(ui) {
+                                incorrect_input = false;
+                            }
+                            if !self.rig_field(ui) {
+                                incorrect_input = false;
+                            }
+                        });
+
+                        ui.vertical(|ui| {
+                            list_poolnode(
+                                ui,
+                                &mut (&mut self.name, &mut self.ip, &mut self.port, &mut self.rig),
+                                &mut self.selected_pool,
+                                pool_vec,
+                                incorrect_input,
+                            );
                         });
                     });
                 });
-            });
-        }
-    });
+                ui.add_space(5.0);
+
+                debug!("XMRig-Proxy Tab | Rendering [API] TextEdits");
+                // [HTTP API IP/Port]
+                ui.group(|ui| {
+                    ui.horizontal(|ui| {
+                        ui.vertical(|ui| {
+                            // HTTP API
+                            self.api_ip_field(ui);
+                            self.api_port_field(ui);
+                        });
+
+                        ui.separator();
+
+                        debug!("XMRig-Proxy Tab | Rendering [TLS/Keepalive] buttons");
+                        ui.vertical(|ui| {
+                            // TLS/Keepalive
+                            ui.horizontal(|ui| {
+                                let width = (ui.available_width() / 2.0) - 11.0;
+                                let height = height_txt_before_button(ui, &TextStyle::Button) * 2.0;
+                                let size = vec2(width, height);
+                                ui.add_sized(size, Checkbox::new(&mut self.tls, "TLS Connection"))
+                                    .on_hover_text(XMRIG_TLS);
+                                ui.separator();
+                                ui.add_sized(size, Checkbox::new(&mut self.keepalive, "Keepalive"))
+                                    .on_hover_text(XMRIG_KEEPALIVE);
+                            });
+                        });
+                    });
+                });
+            }
+        });
+    }
+    fn name_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description("   Name     ")
+            .max_ch(30)
+            .help_msg(XMRIG_NAME)
+            .validations(&[|x| REGEXES.name.is_match(x)])
+            .build(ui, &mut self.name)
+    }
+    fn rpc_port_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description("   RPC PORT ")
+            .max_ch(5)
+            .help_msg(XMRIG_PORT)
+            .validations(&[|x| REGEXES.port.is_match(x)])
+            .build(ui, &mut self.port)
+    }
+    fn ip_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description("   IP       ")
+            .max_ch(255)
+            .help_msg(XMRIG_IP)
+            .validations(&[|x| REGEXES.ipv4.is_match(x) || REGEXES.domain.is_match(x)])
+            .build(ui, &mut self.ip)
+    }
+    fn rig_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description("   Name     ")
+            .max_ch(30)
+            .help_msg(XMRIG_RIG)
+            .build(ui, &mut self.rig)
+    }
+    fn api_ip_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description(" API IP   ")
+            .max_ch(255)
+            .help_msg(XMRIG_API_IP)
+            .validations(&[|x| REGEXES.ipv4.is_match(x) || REGEXES.domain.is_match(x)])
+            .build(ui, &mut self.api_ip)
+    }
+    fn api_port_field(&mut self, ui: &mut Ui) -> bool {
+        StateTextEdit::new(ui)
+            .description(" API PORT ")
+            .max_ch(5)
+            .help_msg(XMRIG_API_PORT)
+            .validations(&[|x| REGEXES.port.is_match(x)])
+            .build(ui, &mut self.api_port)
     }
 }
diff --git a/src/app/panels/middle/xvb.rs b/src/app/panels/middle/xvb.rs
index 5d42e58..e35bbfd 100644
--- a/src/app/panels/middle/xvb.rs
+++ b/src/app/panels/middle/xvb.rs
@@ -1,30 +1,33 @@
 use std::sync::{Arc, Mutex};
 
-use egui::{Image, RichText, TextEdit, TextStyle, Ui, Vec2, vec2};
+use egui::{Align, Image, RichText, ScrollArea, TextStyle, Ui};
 use log::debug;
 use readable::num::Float;
 use readable::up::Uptime;
+use strum::EnumCount;
 
 use crate::XVB_MINING_ON_FIELD;
+use crate::app::panels::middle::common::console::console;
+use crate::app::panels::middle::common::header_tab::header_tab;
+use crate::app::panels::middle::common::state_edit_field::StateTextEdit;
 use crate::disk::state::{ManualDonationLevel, ManualDonationMetric, XvbMode};
 use crate::helper::xrig::xmrig::PubXmrigApi;
 use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi;
 use crate::helper::xvb::PubXvbApi;
 use crate::helper::xvb::priv_stats::RuntimeMode;
-use crate::regex::num_lines;
+use crate::miscs::height_txt_before_button;
 use crate::utils::constants::{
-    GREEN, LIGHT_GRAY, ORANGE, RED, XVB_DONATED_1H_FIELD, XVB_DONATED_24H_FIELD,
-    XVB_DONATION_LEVEL_DONOR_HELP, XVB_DONATION_LEVEL_MEGA_DONOR_HELP,
-    XVB_DONATION_LEVEL_VIP_DONOR_HELP, XVB_DONATION_LEVEL_WHALE_DONOR_HELP, XVB_FAILURE_FIELD,
-    XVB_HELP, XVB_HERO_SELECT, XVB_MANUAL_SLIDER_MANUAL_P2POOL_HELP,
-    XVB_MANUAL_SLIDER_MANUAL_XVB_HELP, XVB_MODE_MANUAL_DONATION_LEVEL_HELP,
-    XVB_MODE_MANUAL_P2POOL_HELP, XVB_MODE_MANUAL_XVB_HELP, XVB_ROUND_TYPE_FIELD, XVB_TOKEN_FIELD,
-    XVB_TOKEN_LEN, XVB_URL_RULES, XVB_WINNER_FIELD,
+    ORANGE, XVB_DONATED_1H_FIELD, XVB_DONATED_24H_FIELD, XVB_DONATION_LEVEL_DONOR_HELP,
+    XVB_DONATION_LEVEL_MEGA_DONOR_HELP, XVB_DONATION_LEVEL_VIP_DONOR_HELP,
+    XVB_DONATION_LEVEL_WHALE_DONOR_HELP, XVB_FAILURE_FIELD, XVB_HELP, XVB_HERO_SELECT,
+    XVB_MANUAL_SLIDER_MANUAL_P2POOL_HELP, XVB_MANUAL_SLIDER_MANUAL_XVB_HELP,
+    XVB_MODE_MANUAL_DONATION_LEVEL_HELP, XVB_MODE_MANUAL_P2POOL_HELP, XVB_MODE_MANUAL_XVB_HELP,
+    XVB_ROUND_TYPE_FIELD, XVB_TOKEN_LEN, XVB_URL_RULES, XVB_WINNER_FIELD,
 };
 use crate::utils::regex::Regexes;
 use crate::{
     constants::{BYTES_XVB, SPACE},
-    utils::constants::{DARK_GRAY, XVB_URL},
+    utils::constants::XVB_URL,
 };
 
 impl crate::disk::state::Xvb {
@@ -32,7 +35,6 @@ impl crate::disk::state::Xvb {
     #[allow(clippy::too_many_arguments)]
     pub fn show(
         &mut self,
-        size: Vec2,
         address: &str,
         _ctx: &egui::Context,
         ui: &mut egui::Ui,
@@ -41,96 +43,47 @@ impl crate::disk::state::Xvb {
         gui_api_xp: &Arc<Mutex<PubXmrigProxyApi>>,
         is_alive: bool,
     ) {
+        // let text_edit = ui.available_height() / 25.0;
+        // let website_height = ui.available_height() / 10.0;
+
+        // logo and website link
+        let logo = Some(Image::from_bytes("bytes:/xvb.png", BYTES_XVB));
+        header_tab(
+            ui,
+            logo,
+            &[
+                ("XMRvsBEAST", XVB_URL, ""),
+                (
+                    "Rules",
+                    XVB_URL_RULES,
+                    "Click here to read the rules and understand how the raffle works.",
+                ),
+                ("FAQ", "https://xmrvsbeast.com/p2pool/faq.html", ""),
+            ],
+            None,
+            true,
+        );
         egui::ScrollArea::vertical().show(ui, |ui| {
 
-            let text_edit = size.y / 25.0;
-            let website_height = size.y / 10.0;
-            let width = size.x;
-            let height = size.y;
-            let space_h = height / 48.0;
-
-            // logo and website link
-            ui.vertical_centered(|ui| {
-                 ui.add_sized(
-                     [width, website_height],
-                     Image::from_bytes("bytes:/xvb.png", BYTES_XVB),
-                 );
-                 ui.style_mut().override_text_style = Some(TextStyle::Heading);
-                 ui.add_space(space_h);
-                 ui.hyperlink_to("XMRvsBeast", XVB_URL);
-                 ui.add_space(space_h);
-            });
-
             // console output for log
             debug!("XvB Tab | Rendering [Console]");
             ui.group(|ui| {
                 let text = &api.lock().unwrap().output;
-                let nb_lines = num_lines(text);
-                let height = size.y / 2.8;
-                let width = size.x - (space_h / 2.0);
-                egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
-                    ui.style_mut().override_text_style = Some(TextStyle::Small);
-                    egui::ScrollArea::vertical()
-                        .stick_to_bottom(true)
-                        .max_width(width)
-                        .max_height(height)
-                        .auto_shrink([false; 2])
-                        // .show_viewport(ui, |ui, _| {
-                        .show_rows(
-                            ui,
-                            ui.text_style_height(&TextStyle::Small),
-                            nb_lines,
-                            |ui, row_range| {
-                                for i in row_range {
-                                    if let Some(line) = text.lines().nth(i) {
-                                        ui.label(line);
-                                    }
-                                }
-                            },
-                        );
-                });
+                // let nb_lines = num_lines(text);
+                console(ui, text);
             });
             // input token
-            let len_token = format!("{}", self.token.len());
-            let (text, color) = if self.token.is_empty() {
-                (
-                    format!("{} [{}/{}] ➖", XVB_TOKEN_FIELD, len_token, XVB_TOKEN_LEN),
-                    LIGHT_GRAY,
-                )
-            } else if self.token.parse::<u32>().is_ok() && self.token.len() < XVB_TOKEN_LEN {
-                (
-                    format!("{} [{}/{}]", XVB_TOKEN_FIELD, len_token, XVB_TOKEN_LEN),
-                    GREEN,
-                )
-            } else if self.token.parse::<u32>().is_ok() && self.token.len() == XVB_TOKEN_LEN {
-                (format!("{} ✔", XVB_TOKEN_FIELD), GREEN)
-            } else {
-                (
-                    format!("{} [{}/{}] ❌", XVB_TOKEN_FIELD, len_token, XVB_TOKEN_LEN),
-                    RED,
-                )
-            };
-            ui.add_space(space_h);
+            ui.add_space(SPACE);
             ui.horizontal(|ui| {
-            // hovering text is difficult because egui doesn't hover over inner widget. But on disabled does.
-                    ui.group(|ui| {
-                        ui.colored_label(color, text)
-                        .on_hover_text(XVB_HELP);
-                        ui.add(
-                            TextEdit::singleline(&mut self.token)
-                                .char_limit(9)
-                                .desired_width(ui.text_style_height(&TextStyle::Body) * 9.0)
-                                .vertical_align(egui::Align::Center),
-                            ).on_hover_text(XVB_HELP)
+                ui.group(|ui|{
+                    ui.style_mut().override_text_valign = Some(Align::Center);
+                    // ui.set_height(height_txt_before_button(ui, &TextStyle::Body));
+                    self.field_token(ui);
                 });
-                // .on_hover_text(XVB_HELP);
-                ui.add_space(height / 48.0);
-        ui.style_mut().spacing.icon_width_inner = width / 45.0;
-        ui.style_mut().spacing.icon_width = width / 35.0;
-        ui.style_mut().spacing.icon_spacing = space_h;
 
         // --------------------------- XVB Simple -------------------------------------------
         if self.simple {
+            ui.add_space(SPACE);
             ui.checkbox(&mut self.simple_hero_mode, "Hero Mode").on_hover_text(XVB_HERO_SELECT);
             // set runtime mode immediately if we are on simple mode.
             if self.simple_hero_mode {
@@ -140,14 +93,19 @@ impl crate::disk::state::Xvb {
             }
         }
     });
-        ui.add_space(space_h);
+        ui.add_space(SPACE);
          // --------------------------- XVB Advanced -----------------------------------------
          if !self.simple {
 
             ui.group(|ui| {
                 ui.vertical_centered(|ui| {
-                    ui.horizontal(|ui| {
-                        egui::ComboBox::from_label("")
+                        ui.style_mut().override_text_valign = Some(Align::Center);
+                        ui.set_height(0.0);
+                    // ui.horizontal_centered(|ui| {
+                        ui.set_height(0.0);
+                        let text_height = height_txt_before_button(ui, &TextStyle::Heading) * 1.4;
+                        // let text_height = 0.0;
+                        egui::ComboBox::from_label("").height(XvbMode::COUNT as f32 * (ui.text_style_height(&TextStyle::Button) + (ui.spacing().button_padding.y * 2.0) + ui.spacing().item_spacing.y))
                         .selected_text(self.mode.to_string())
                         .show_ui(ui, |ui| {
                                 ui.selectable_value(&mut self.mode, XvbMode::Auto,
@@ -166,7 +124,7 @@ impl crate::disk::state::Xvb {
                         });
                         if self.mode == XvbMode::ManualXvb || self.mode == XvbMode::ManualP2pool {
 
-                            ui.add_space(space_h);
+                            ui.add_space(SPACE);
 
                             let default_xmrig_hashrate = match self.manual_donation_metric {
                                 ManualDonationMetric::Hash => 1_000.0,
@@ -203,22 +161,22 @@ impl crate::disk::state::Xvb {
 
                             ui.horizontal(|ui| {
 
-                                if ui.add(egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Hash, "Hash")).clicked() {
+                                if ui.add_sized([0.0, text_height],egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Hash, "Hash")).clicked() {
                                     self.manual_donation_metric = ManualDonationMetric::Hash;
                                     self.manual_slider_amount = self.manual_amount_raw;
                                 }
-                                if ui.add(egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Kilo, "Kilo")).clicked() {
+                                if ui.add_sized([0.0, text_height],egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Kilo, "Kilo")).clicked() {
                                     self.manual_donation_metric = ManualDonationMetric::Kilo;
                                     self.manual_slider_amount = self.manual_amount_raw / 1000.0;
                                 };
-                                if ui.add(egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Mega, "Mega")).clicked() {
+                                if ui.add_sized([0.0, text_height],egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Mega, "Mega")).clicked() {
                                     self.manual_donation_metric = ManualDonationMetric::Mega;
                                     self.manual_slider_amount = self.manual_amount_raw / 1_000_000.0;
                                 };
-
-                                ui.spacing_mut().slider_width = width * 0.5;
+                                // less menu, less metrics buttons,less space, less metrics.
+                                ui.spacing_mut().slider_width = ui.available_width() * 0.3;
                                 ui.add_sized(
-                                    [width, text_edit],
+                                    [ui.available_width(), text_height],
                                     egui::Slider::new(&mut self.manual_slider_amount, 0.0..=(hashrate_xmrig as f64))
                                     .text(self.manual_donation_metric.to_string())
                                     .max_decimals(3)
@@ -228,6 +186,8 @@ impl crate::disk::state::Xvb {
                         }
 
                         if self.mode ==  XvbMode::ManualDonationLevel {
+                            ui.add_space(SPACE);
+                            ui.horizontal(|ui| {
                             ui.radio_value(&mut self.manual_donation_level, ManualDonationLevel::Donor,
                                 ManualDonationLevel::Donor.to_string())
                             .on_hover_text(XVB_DONATION_LEVEL_DONOR_HELP);
@@ -242,10 +202,12 @@ impl crate::disk::state::Xvb {
                             .on_hover_text(XVB_DONATION_LEVEL_MEGA_DONOR_HELP);
 
                             api.lock().unwrap().stats_priv.runtime_manual_donation_level = self.manual_donation_level.clone().into();
+                            });
                         }
+            ui.add_space(SPACE);
                     });
                 });
-            });
+            // });
 
             // Update manual_amount_raw based on slider
             match self.manual_donation_metric {
@@ -263,18 +225,18 @@ impl crate::disk::state::Xvb {
             // Set runtime_mode & runtime_manual_amount
             api.lock().unwrap().stats_priv.runtime_mode = self.mode.clone().into();
             api.lock().unwrap().stats_priv.runtime_manual_amount = self.manual_amount_raw;
-         ui.add_space(space_h);
+         ui.add_space(SPACE);
 
             // allow user to modify the buffer for p2pool
             // button
             ui.add_sized(
-                [width, text_edit],
+                [ui.available_width() * 0.8, height_txt_before_button(ui, &TextStyle::Button)],
                 egui::Slider::new(&mut self.p2pool_buffer, -100..=100)
                 .text("% P2Pool Buffer" )
             ).on_hover_text("Set the % amount of additional HR to send to p2pool. Will reduce (if positive) or augment (if negative) the chances to miss the p2pool window");
         }
 
-         ui.add_space(space_h);
+         ui.add_space(SPACE);
         // need to warn the user if no address is set in p2pool tab
         if !Regexes::addr_ok(address) {
             debug!("XvB Tab | Rendering warning text");
@@ -284,100 +246,62 @@ impl crate::disk::state::Xvb {
                 });
         }
             // private stats
-            ui.add_space(space_h);
+            ui.add_space(SPACE);
             // ui.add_enabled_ui(is_alive, |ui| {
             ui.add_enabled_ui(is_alive, |ui| {
                 let api = &api.lock().unwrap();
                 let priv_stats = &api.stats_priv;
                 let current_node = &api.current_node;
-                let width_stat = (ui.available_width() - SPACE * 4.0) / 5.0;
-                let height_stat = 0.0;
-                let size_stat = vec2(width_stat, height_stat);
-                ui.horizontal(|ui| {
-                    let round = match &priv_stats.round_participate {
-                        Some(r) => r.to_string(),
-                        None => "None".to_string(),
-                    };
-                    ui.add_sized(size_stat, |ui: &mut Ui| {
-                        ui.group(|ui| {
-                            let size_stat = vec2(
-                                ui.available_width(),
-                                0.0, // + ui.spacing().item_spacing.y,
-                            );
-                            ui.add_sized(size_stat, |ui: &mut Ui| {
-                                ui.vertical_centered(|ui| {
-                                    ui.label(XVB_FAILURE_FIELD);
-                                    ui.label(priv_stats.fails.to_string());
-                                })
-                                .response
-                            });
-                            ui.separator();
-                            ui.add_sized(size_stat, |ui: &mut Ui| {
-                                ui.vertical_centered(|ui| {
-                                    ui.label(XVB_DONATED_1H_FIELD);
-                                    ui.label(
-                                        [
+                let style_height = ui.text_style_height(&TextStyle::Body);
+        ui.spacing_mut().item_spacing = [style_height * 2.0, style_height * 2.0].into();
+
+                // let width_stat = (ui.available_width() - SPACE * 4.0) / 5.0;
+        let width_column = ui.text_style_height(&TextStyle::Body) * 16.0;
+        let height_column = 0.0;
+        ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
+                ScrollArea::horizontal().id_salt("horizontal").show(ui, |ui| {
+            ui.horizontal(|ui| {
+                    // Failures
+                    stat_box(ui, XVB_FAILURE_FIELD, &priv_stats.fails.to_string(), width_column, height_column, style_height);
+                    stat_box(ui, XVB_DONATED_1H_FIELD,
+                                        &[
                                             Float::from_3(priv_stats.donor_1hr_avg as f64).to_string(),
                                             " kH/s".to_string(),
                                         ]
-                                        .concat(),
-                                    );
-                                })
-                                .response
-                            });
-                            ui.separator();
-                            ui.add_sized(size_stat, |ui: &mut Ui| {
-                                ui.vertical_centered(|ui| {
-                                    ui.label(XVB_DONATED_24H_FIELD);
-                                    ui.label(
-                                        [
+                                        .concat()
+                        , width_column, height_column, style_height);
+                    stat_box(ui, XVB_DONATED_24H_FIELD,
+                                        &[
                                             Float::from_3(priv_stats.donor_24hr_avg as f64).to_string(),
                                             " kH/s".to_string(),
                                         ]
-                                        .concat(),
-                                    );
-                                })
-                                .response
-                            });
-                            ui.separator();
+                                        .concat()
+                        , width_column, height_column, style_height);
                             ui.add_enabled_ui(priv_stats.round_participate.is_some(), |ui| {
-                                ui.add_sized(size_stat, |ui: &mut Ui| {
-                                    ui.vertical_centered(|ui| {
-                                        ui.label(XVB_ROUND_TYPE_FIELD);
-                                        ui.label(round);
-                                    })
-                                    .response
-                                })
+                                 let round = match &priv_stats.round_participate {
+                        Some(r) => r.to_string(),
+                        None => "None".to_string(),
+                    };
+                    stat_box(ui, XVB_ROUND_TYPE_FIELD, &round, width_column, height_column, style_height);
+                    }).response
                                 .on_disabled_hover_text(
                                     "You do not yet have a share in the PPLNS Window.",
                                 );
-                            });
-                            ui.separator();
-                            ui.add_sized(size_stat, |ui: &mut Ui| {
-                                ui.vertical_centered(|ui| {
-                                    ui.label(XVB_WINNER_FIELD);
-                                    ui.label(if priv_stats.win_current {
+                    stat_box(ui, XVB_WINNER_FIELD,
+if priv_stats.win_current {
                                         "You are Winning the round !"
                                     } else {
                                         "You are not the winner"
-                                    });
-                                })
-                                .response
-                            });
-                        })
-                        .response
-                    });
+                                    }
+                        , width_column, height_column, style_height);
                 });
-                // indicators
-                ui.horizontal(|ui| {
-                    ui.add_sized(size_stat, |ui: &mut Ui| {
+                });
+                    ui.vertical(|ui| {
                         ui.group(|ui| {
-                            let size_stat = vec2(
-                                ui.available_width(),
-                                0.0, // + ui.spacing().item_spacing.y,
-                            );
-                            ui.add_sized(size_stat, |ui: &mut Ui| {
-                                ui.vertical_centered(|ui| {
+                            ui.set_width(width_column);
+                            ui.set_height(height_column);
+                            ui.vertical_centered(|ui| {
+                                ui.add_space(SPACE);
                                     ui.label(XVB_MINING_ON_FIELD)
                                         .on_hover_text_at_pointer(&priv_stats.msg_indicator);
                                     ui.label(
@@ -389,24 +313,44 @@ impl crate::disk::state::Xvb {
                                     ui.label(Uptime::from(priv_stats.time_switch_node).to_string())
                                         .on_hover_text_at_pointer(&priv_stats.msg_indicator)
                                 })
-                                .response
-                            })
-                        })
+                            });
+                    })
                         .response
-                        .on_disabled_hover_text("Algorithm is not running.")
+                        .on_disabled_hover_text("Algorithm is not running.");
+                // indicators
                     })
                     // currently mining on
                 });
-            });
-            // Rules link help
-            ui.horizontal_centered(|ui| {
-                // can't have horizontal and vertical centering work together so fix by this.
-                ui.add_space((width / 2.0) - (ui.text_style_height(&TextStyle::Heading) * 1.5));
-                ui.style_mut().override_text_style = Some(TextStyle::Heading);
-                ui.hyperlink_to("Rules", XVB_URL_RULES)
-                    .on_hover_text("Click here to read the rules and understand how the raffle works.");
-            });
-
-        });
+    }
+    fn field_token(&mut self, ui: &mut Ui) {
+        StateTextEdit::new(ui)
+            .help_msg(XVB_HELP)
+            .max_ch(XVB_TOKEN_LEN as u8)
+            .text_edit_width_same_as_max_ch(ui)
+            .description(" Token ")
+            .validations(&[|x| x.parse::<u32>().is_ok() && x.len() == XVB_TOKEN_LEN])
+            .build(ui, &mut self.token);
     }
 }
+fn stat_box(
+    ui: &mut Ui,
+    title: &str,
+    value: &str,
+    column_width: f32,
+    column_height: f32,
+    style_height: f32,
+) {
+    ui.vertical(|ui| {
+        ui.group(|ui| {
+            ui.set_width(column_width);
+            ui.set_height(column_height);
+            ui.vertical_centered(|ui| {
+                ui.spacing_mut().item_spacing = [style_height / 2.0, style_height / 2.0].into();
+                ui.add_space(SPACE * 3.0);
+                ui.label(title);
+                ui.label(value);
+                ui.add_space(SPACE);
+            });
+        });
+    });
+}
diff --git a/src/app/panels/quit_error.rs b/src/app/panels/quit_error.rs
index 2f28ebb..dde605a 100644
--- a/src/app/panels/quit_error.rs
+++ b/src/app/panels/quit_error.rs
@@ -189,7 +189,7 @@ impl crate::app::App {
                             .add_sized([width, height / 2.0], Button::new("Quit"))
                             .clicked()
                         {
-                            if self.state.gupax.save_before_quit {
+                            if self.state.gupax.auto.save_before_quit {
                                 self.save_before_quit();
                             }
                             exit(0);
diff --git a/src/app/panels/top.rs b/src/app/panels/top.rs
index d0bb408..03ffb5c 100644
--- a/src/app/panels/top.rs
+++ b/src/app/panels/top.rs
@@ -12,8 +12,6 @@ impl crate::app::App {
             ui.style_mut().spacing.item_spacing.x = 4.0;
             // spacing of separator, will reduce width size of the button. Low value so that tabs can be selected easily.
             let spacing_separator = 2.0;
-            // TODO if screen smaller, go on two lines.
-            // TODO if screen really to small, go on tab per line.
             ui.with_layout(egui::Layout::left_to_right(egui::Align::Min), |ui| {
                 ui.style_mut().override_text_style = Some(TextStyle::Heading);
                 let height = ui
diff --git a/src/app/quit.rs b/src/app/quit.rs
index 6bd590d..882999d 100644
--- a/src/app/quit.rs
+++ b/src/app/quit.rs
@@ -16,11 +16,11 @@ impl App {
                 return None;
             }
             info!("quit");
-            if self.state.gupax.ask_before_quit {
+            if self.state.gupax.auto.ask_before_quit {
                 // If we're already on the [ask_before_quit] screen and
                 // the user tried to exit again, exit.
                 if self.error_state.quit_twice {
-                    if self.state.gupax.save_before_quit {
+                    if self.state.gupax.auto.save_before_quit {
                         self.save_before_quit();
                     }
                     return Some(ViewportCommand::Close);
@@ -32,7 +32,7 @@ impl App {
                 Some(ViewportCommand::CancelClose)
             // Else, just quit.
             } else {
-                if self.state.gupax.save_before_quit {
+                if self.state.gupax.auto.save_before_quit {
                     self.save_before_quit();
                 }
                 Some(ViewportCommand::Close)
diff --git a/src/components/update.rs b/src/components/update.rs
index 8502eed..f7fa2fb 100644
--- a/src/components/update.rs
+++ b/src/components/update.rs
@@ -241,7 +241,7 @@ impl Update {
         #[cfg(feature = "distro")]
         return;
         // verify validity of absolute path for p2pool, xmrig and xmrig-proxy only if we want to update them.
-        if og.lock().unwrap().gupax.bundled {
+        if og.lock().unwrap().gupax.auto.bundled {
             // Check P2Pool path for safety
             // Attempt relative to absolute path
             // it's ok if file doesn't exist. User could enable bundled version for the first time.
@@ -465,7 +465,7 @@ impl Update {
         // arch
         // standalone or bundled
         // archive extension
-        let bundle = if og.lock().unwrap().gupax.bundled {
+        let bundle = if og.lock().unwrap().gupax.auto.bundled {
             "bundle"
         } else {
             "standalone"
@@ -577,7 +577,7 @@ impl Update {
                 path.display()
             );
             // if bundled, create directory for p2pool, xmrig and xmrig-proxy if not present
-            if og.lock().unwrap().gupax.bundled
+            if og.lock().unwrap().gupax.auto.bundled
                 && (name == P2POOL_BINARY
                     || name == XMRIG_BINARY
                     || name == XMRIG_PROXY_BINARY
diff --git a/src/disk/node.rs b/src/disk/node.rs
index 8c78407..dc83531 100644
--- a/src/disk/node.rs
+++ b/src/disk/node.rs
@@ -1,25 +1,25 @@
-use crate::disk::*;
+use crate::{app::panels::middle::common::list_poolnode::PoolNode, disk::*};
 use serde::{Deserialize, Serialize};
 //---------------------------------------------------------------------------------------------------- [Node] Impl
 impl Node {
-    pub fn localhost() -> Self {
-        Self {
+    pub fn localhost() -> PoolNode {
+        PoolNode::Node(Self {
             ip: "localhost".to_string(),
             rpc: "18081".to_string(),
             zmq: "18083".to_string(),
-        }
+        })
     }
 
-    pub fn new_vec() -> Vec<(String, Self)> {
+    pub fn new_vec() -> Vec<(String, PoolNode)> {
         vec![("Local Monero Node".to_string(), Self::localhost())]
     }
 
-    pub fn new_tuple() -> (String, Self) {
+    pub fn new_tuple() -> (String, PoolNode) {
         ("Local Monero Node".to_string(), Self::localhost())
     }
 
     // Convert [String] to [Node] Vec
-    pub fn from_str_to_vec(string: &str) -> Result<Vec<(String, Self)>, TomlError> {
+    pub fn from_str_to_vec(string: &str) -> Result<Vec<(String, PoolNode)>, TomlError> {
         let nodes: toml::map::Map<String, toml::Value> = match toml::de::from_str(string) {
             Ok(map) => {
                 info!("Node | Parse ... OK");
@@ -73,20 +73,23 @@ impl Node {
                 }
             };
             let node = Node { ip, rpc, zmq };
-            vec.push((key.clone(), node));
+            vec.push((key.clone(), PoolNode::Node(node)));
         }
         Ok(vec)
     }
 
     // Convert [Vec<(String, Self)>] into [String]
     // that can be written as a proper TOML file
-    pub fn to_string(vec: &[(String, Self)]) -> Result<String, TomlError> {
+    pub fn to_string(vec: &[(String, PoolNode)]) -> Result<String, TomlError> {
         let mut toml = String::new();
         for (key, value) in vec.iter() {
             write!(
                 toml,
                 "[\'{}\']\nip = {:#?}\nrpc = {:#?}\nzmq = {:#?}\n\n",
-                key, value.ip, value.rpc, value.zmq,
+                key,
+                value.ip(),
+                value.port(),
+                value.custom(),
             )?;
         }
         Ok(toml)
@@ -97,7 +100,7 @@ impl Node {
     //      |_ Create a default file if not found
     //   2. Deserialize [String] into a proper [Struct]
     //      |_ Attempt to merge if deserialization fails
-    pub fn get(path: &PathBuf) -> Result<Vec<(String, Self)>, TomlError> {
+    pub fn get(path: &PathBuf) -> Result<Vec<(String, PoolNode)>, TomlError> {
         // Read
         let file = File::Node;
         let string = match read_to_string(file, path) {
@@ -114,7 +117,7 @@ impl Node {
 
     // Completely overwrite current [node.toml]
     // with a new default version, and return [Vec<String, Self>].
-    pub fn create_new(path: &PathBuf) -> Result<Vec<(String, Self)>, TomlError> {
+    pub fn create_new(path: &PathBuf) -> Result<Vec<(String, PoolNode)>, TomlError> {
         info!("Node | Creating new default...");
         let new = Self::new_vec();
         let string = Self::to_string(&Self::new_vec())?;
@@ -124,7 +127,7 @@ impl Node {
     }
 
     // Save [Node] onto disk file [node.toml]
-    pub fn save(vec: &[(String, Self)], path: &PathBuf) -> Result<(), TomlError> {
+    pub fn save(vec: &[(String, PoolNode)], path: &PathBuf) -> Result<(), TomlError> {
         info!("Node | Saving to disk ... [{}]", path.display());
         let string = Self::to_string(vec)?;
         match fs::write(path, string) {
diff --git a/src/disk/pool.rs b/src/disk/pool.rs
index a75c586..d3d3383 100644
--- a/src/disk/pool.rs
+++ b/src/disk/pool.rs
@@ -1,23 +1,25 @@
+use crate::app::panels::middle::common::list_poolnode::PoolNode;
+
 use super::*;
 //---------------------------------------------------------------------------------------------------- [Pool] impl
 impl Pool {
-    pub fn p2pool() -> Self {
-        Self {
+    pub fn p2pool() -> PoolNode {
+        PoolNode::Pool(Self {
             rig: GUPAX_VERSION_UNDERSCORE.to_string(),
             ip: "localhost".to_string(),
             port: "3333".to_string(),
-        }
+        })
     }
 
-    pub fn new_vec() -> Vec<(String, Self)> {
+    pub fn new_vec() -> Vec<(String, PoolNode)> {
         vec![("Local P2Pool".to_string(), Self::p2pool())]
     }
 
-    pub fn new_tuple() -> (String, Self) {
+    pub fn new_tuple() -> (String, PoolNode) {
         ("Local P2Pool".to_string(), Self::p2pool())
     }
 
-    pub fn from_str_to_vec(string: &str) -> Result<Vec<(String, Self)>, TomlError> {
+    pub fn from_str_to_vec(string: &str) -> Result<Vec<(String, PoolNode)>, TomlError> {
         let pools: toml::map::Map<String, toml::Value> = match toml::de::from_str(string) {
             Ok(map) => {
                 info!("Pool | Parse ... OK");
@@ -72,24 +74,27 @@ impl Pool {
                 }
             };
             let pool = Pool { rig, ip, port };
-            vec.push((key.clone(), pool));
+            vec.push((key.clone(), PoolNode::Pool(pool)));
         }
         Ok(vec)
     }
 
-    pub fn to_string(vec: &[(String, Self)]) -> Result<String, TomlError> {
+    pub fn to_string(vec: &[(String, PoolNode)]) -> Result<String, TomlError> {
         let mut toml = String::new();
         for (key, value) in vec.iter() {
             write!(
                 toml,
                 "[\'{}\']\nrig = {:#?}\nip = {:#?}\nport = {:#?}\n\n",
-                key, value.rig, value.ip, value.port,
+                key,
+                value.custom(),
+                value.ip(),
+                value.port(),
             )?;
         }
         Ok(toml)
     }
 
-    pub fn get(path: &PathBuf) -> Result<Vec<(String, Self)>, TomlError> {
+    pub fn get(path: &PathBuf) -> Result<Vec<(String, PoolNode)>, TomlError> {
         // Read
         let file = File::Pool;
         let string = match read_to_string(file, path) {
@@ -104,7 +109,7 @@ impl Pool {
         Self::from_str_to_vec(&string)
     }
 
-    pub fn create_new(path: &PathBuf) -> Result<Vec<(String, Self)>, TomlError> {
+    pub fn create_new(path: &PathBuf) -> Result<Vec<(String, PoolNode)>, TomlError> {
         info!("Pool | Creating new default...");
         let new = Self::new_vec();
         let string = Self::to_string(&Self::new_vec())?;
@@ -113,7 +118,7 @@ impl Pool {
         Ok(new)
     }
 
-    pub fn save(vec: &[(String, Self)], path: &PathBuf) -> Result<(), TomlError> {
+    pub fn save(vec: &[(String, PoolNode)], path: &PathBuf) -> Result<(), TomlError> {
         info!("Pool | Saving to disk ... [{}]", path.display());
         let string = Self::to_string(vec)?;
         match fs::write(path, string) {
diff --git a/src/disk/state.rs b/src/disk/state.rs
index 8437d5e..1fb7023 100644
--- a/src/disk/state.rs
+++ b/src/disk/state.rs
@@ -1,8 +1,9 @@
 use anyhow::Result;
 use rand::{Rng, distributions::Alphanumeric, thread_rng};
+use strum::{EnumCount, EnumIter};
 
 use super::*;
-use crate::{components::node::RemoteNode, disk::status::*};
+use crate::{components::node::RemoteNode, disk::status::*, helper::ProcessName};
 //---------------------------------------------------------------------------------------------------- [State] Impl
 impl Default for State {
     fn default() -> Self {
@@ -12,7 +13,7 @@ impl Default for State {
 
 impl State {
     pub fn new() -> Self {
-        let max_threads = benri::threads!();
+        let max_threads = benri::threads!() as u16;
         let current_threads = if max_threads == 1 { 1 } else { max_threads / 2 };
         Self {
             status: Status::default(),
@@ -132,7 +133,6 @@ impl State {
             }
         }
     }
-
     // Take [String] as input, merge it with whatever the current [default] is,
     // leaving behind old keys+values and updating [default] with old valid ones.
     pub fn merge(old: &str) -> Result<Self, TomlError> {
@@ -179,14 +179,7 @@ pub struct Status {
 #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
 pub struct Gupax {
     pub simple: bool,
-    pub auto_update: bool,
-    pub auto_p2pool: bool,
-    pub auto_node: bool,
-    pub auto_xmrig: bool,
-    pub auto_xp: bool,
-    pub auto_xvb: bool,
-    pub ask_before_quit: bool,
-    pub save_before_quit: bool,
+    pub auto: AutoEnabled,
     pub p2pool_path: String,
     pub node_path: String,
     pub xmrig_path: String,
@@ -200,9 +193,94 @@ pub struct Gupax {
     pub selected_scale: f32,
     pub tab: Tab,
     pub ratio: Ratio,
-    pub bundled: bool,
 }
 
+#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
+pub struct AutoEnabled {
+    pub update: bool,
+    pub bundled: bool,
+    pub ask_before_quit: bool,
+    pub save_before_quit: bool,
+    pub processes: Vec<ProcessName>,
+}
+impl AutoEnabled {
+    pub fn enable(&mut self, auto: &AutoStart, enable: bool) {
+        match auto {
+            AutoStart::Update => self.update = enable,
+            AutoStart::Bundle => self.bundled = enable,
+            AutoStart::AskBeforeQuit => self.ask_before_quit = enable,
+            AutoStart::SaveBeforequit => self.save_before_quit = enable,
+            AutoStart::Process(p) => {
+                let processes = &mut self.processes;
+                if !processes.iter().any(|a| a == p) && enable {
+                    self.processes.push(*p);
+                } else if let Some(i) = processes.iter().position(|a| a == p) {
+                    if !enable {
+                        processes.remove(i);
+                    }
+                }
+            }
+        }
+    }
+    pub fn is_enabled(&self, auto: &AutoStart) -> bool {
+        match auto {
+            AutoStart::Update => self.update,
+            AutoStart::Bundle => self.bundled,
+            AutoStart::AskBeforeQuit => self.ask_before_quit,
+            AutoStart::SaveBeforequit => self.save_before_quit,
+            AutoStart::Process(p) => self.processes.iter().any(|a| a == p),
+        }
+    }
+}
+#[derive(PartialEq, strum::Display, EnumCount, EnumIter)]
+pub enum AutoStart {
+    #[strum(to_string = "Auto-Update")]
+    Update,
+    Bundle,
+    #[strum(to_string = "Confirm quit")]
+    AskBeforeQuit,
+    #[strum(to_string = "Save on exit")]
+    SaveBeforequit,
+    #[strum(to_string = "Auto-{0}")]
+    Process(ProcessName),
+}
+impl AutoStart {
+    pub const fn help_msg(&self) -> &str {
+        match self {
+            AutoStart::Update => GUPAX_AUTO_UPDATE,
+            AutoStart::Bundle => GUPAX_BUNDLED_UPDATE,
+            AutoStart::AskBeforeQuit => GUPAX_ASK_BEFORE_QUIT,
+            AutoStart::SaveBeforequit => GUPAX_SAVE_BEFORE_QUIT,
+            AutoStart::Process(p) => p.msg_auto_help(),
+        }
+    }
+    // todo: generate as const with all process in middle ?
+    // Would necessities unstable feature https://github.com/rust-lang/rust/issues/87575
+    pub const ALL: &[AutoStart] = &[
+        AutoStart::Update,
+        AutoStart::Bundle,
+        AutoStart::Process(ProcessName::Node),
+        AutoStart::Process(ProcessName::P2pool),
+        AutoStart::Process(ProcessName::Xmrig),
+        AutoStart::Process(ProcessName::XmrigProxy),
+        AutoStart::Process(ProcessName::Xvb),
+        AutoStart::AskBeforeQuit,
+        AutoStart::SaveBeforequit,
+    ];
+    // non const:
+    // let mut autos = AutoStart::iter().collect::<Vec<_>>();
+    // // remove ProcessName default
+    // autos.remove(AutoStart::COUNT - 1);
+    // // insert ProcessName before AskBeforeQuit
+    // let before_quit_index = autos
+    //     .iter()
+    //     .position(|a| *a == AutoStart::AskBeforeQuit)
+    //     .expect("Before quit should be in iter");
+    // ProcessName::iter()
+    //     .rev()
+    //     .for_each(|p| autos.insert(before_quit_index, AutoStart::Process(p)));
+    // autos
+}
 #[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
 pub struct P2pool {
     pub simple: bool,
@@ -213,7 +291,7 @@ pub struct P2pool {
     pub backup_host: bool,
     pub out_peers: u16,
     pub in_peers: u16,
-    pub log_level: u8,
+    pub log_level: u16,
     pub node: String,
     pub arguments: String,
     pub address: String,
@@ -221,11 +299,17 @@ pub struct P2pool {
     pub ip: String,
     pub rpc: String,
     pub zmq: String,
-    pub selected_index: usize,
-    pub selected_name: String,
-    pub selected_ip: String,
-    pub selected_rpc: String,
-    pub selected_zmq: String,
+    pub selected_node: SelectedPoolNode,
+}
+
+// compatible for P2Pool and Xmrig/Proxy
+#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
+pub struct SelectedPoolNode {
+    pub index: usize,
+    pub name: String,
+    pub ip: String,
+    pub rpc: String,
+    pub zmq_rig: String,
 }
 
 #[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
@@ -235,7 +319,7 @@ pub struct Node {
     pub api_port: String,
     pub out_peers: u16,
     pub in_peers: u16,
-    pub log_level: u8,
+    pub log_level: u16,
     pub arguments: String,
     pub zmq_ip: String,
     pub zmq_port: String,
@@ -268,13 +352,13 @@ impl Default for Node {
 #[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
 pub struct Xmrig {
     pub simple: bool,
-    pub pause: u8,
+    pub pause: u16,
     pub simple_rig: String,
     pub arguments: String,
     pub tls: bool,
     pub keepalive: bool,
-    pub max_threads: usize,
-    pub current_threads: usize,
+    pub max_threads: u16,
+    pub current_threads: u16,
     pub address: String,
     pub api_ip: String,
     pub api_port: String,
@@ -282,11 +366,7 @@ pub struct Xmrig {
     pub rig: String,
     pub ip: String,
     pub port: String,
-    pub selected_index: usize,
-    pub selected_name: String,
-    pub selected_rig: String,
-    pub selected_ip: String,
-    pub selected_port: String,
+    pub selected_pool: SelectedPoolNode,
     pub token: String,
 }
 
@@ -307,15 +387,41 @@ pub struct XmrigProxy {
     pub api_port: String,
     pub p2pool_ip: String,
     pub p2pool_port: String,
-    pub selected_index: usize,
-    pub selected_name: String,
-    pub selected_rig: String,
-    pub selected_ip: String,
-    pub selected_port: String,
+    pub selected_pool: SelectedPoolNode,
     pub token: String,
     pub redirect_local_xmrig: bool,
 }
 
+impl Gupax {
+    pub fn path_binary(&mut self, process: &BundledProcess) -> &mut String {
+        match process {
+            BundledProcess::Node => &mut self.node_path,
+            BundledProcess::P2Pool => &mut self.p2pool_path,
+            BundledProcess::Xmrig => &mut self.xmrig_path,
+            BundledProcess::XmrigProxy => &mut self.xmrig_proxy_path,
+        }
+    }
+}
+
+// do not include process that are from Gupaxx
+#[derive(EnumIter)]
+pub enum BundledProcess {
+    Node,
+    P2Pool,
+    Xmrig,
+    XmrigProxy,
+}
+impl BundledProcess {
+    pub fn process_name(&self) -> ProcessName {
+        match self {
+            BundledProcess::Node => ProcessName::Node,
+            BundledProcess::P2Pool => ProcessName::P2pool,
+            BundledProcess::Xmrig => ProcessName::Xmrig,
+            BundledProcess::XmrigProxy => ProcessName::XmrigProxy,
+        }
+    }
+}
+
 impl Default for XmrigProxy {
     fn default() -> Self {
         XmrigProxy {
@@ -335,11 +441,13 @@ impl Default for XmrigProxy {
             port: "3355".to_string(),
             p2pool_ip: "localhost".to_string(),
             p2pool_port: "3333".to_string(),
-            selected_index: 0,
-            selected_name: "Local P2Pool".to_string(),
-            selected_ip: "localhost".to_string(),
-            selected_rig: GUPAX_VERSION_UNDERSCORE.to_string(),
-            selected_port: "3333".to_string(),
+            selected_pool: SelectedPoolNode {
+                index: 0,
+                name: "Local P2Pool".to_string(),
+                ip: "localhost".to_string(),
+                rpc: "3333".to_string(),
+                zmq_rig: GUPAX_VERSION_UNDERSCORE.to_string(),
+            },
             api_ip: "localhost".to_string(),
             api_port: "18089".to_string(),
             tls: false,
@@ -361,7 +469,7 @@ pub struct Xvb {
     pub p2pool_buffer: i8,
 }
 
-#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize, Default)]
+#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize, Default, EnumCount, EnumIter)]
 pub enum XvbMode {
     #[default]
     Auto,
@@ -435,6 +543,20 @@ pub struct Version {
 }
 
 //---------------------------------------------------------------------------------------------------- [State] Defaults
+impl Default for AutoEnabled {
+    fn default() -> Self {
+        Self {
+            update: false,
+            #[cfg(feature = "bundle")]
+            bundled: true,
+            #[cfg(not(feature = "bundle"))]
+            bundled: false,
+            ask_before_quit: true,
+            save_before_quit: true,
+            processes: Vec::new(),
+        }
+    }
+}
 impl Default for Status {
     fn default() -> Self {
         Self {
@@ -452,14 +574,7 @@ impl Default for Gupax {
     fn default() -> Self {
         Self {
             simple: true,
-            auto_update: false,
-            auto_p2pool: false,
-            auto_node: false,
-            auto_xmrig: false,
-            auto_xp: false,
-            auto_xvb: false,
-            ask_before_quit: true,
-            save_before_quit: true,
+            auto: AutoEnabled::default(),
             p2pool_path: DEFAULT_P2POOL_PATH.to_string(),
             xmrig_path: DEFAULT_XMRIG_PATH.to_string(),
             node_path: DEFAULT_NODE_PATH.to_string(),
@@ -473,10 +588,6 @@ impl Default for Gupax {
             selected_scale: APP_DEFAULT_SCALE,
             ratio: Ratio::Width,
             tab: Tab::Xvb,
-            #[cfg(feature = "bundle")]
-            bundled: true,
-            #[cfg(not(feature = "bundle"))]
-            bundled: false,
         }
     }
 }
@@ -500,17 +611,19 @@ impl Default for P2pool {
             ip: "localhost".to_string(),
             rpc: "18081".to_string(),
             zmq: "18083".to_string(),
-            selected_index: 0,
-            selected_name: "Local Monero Node".to_string(),
-            selected_ip: "localhost".to_string(),
-            selected_rpc: "18081".to_string(),
-            selected_zmq: "18083".to_string(),
+            selected_node: SelectedPoolNode {
+                index: 0,
+                name: "Local Monero Node".to_string(),
+                ip: "localhost".to_string(),
+                rpc: "18081".to_string(),
+                zmq_rig: "18083".to_string(),
+            },
         }
     }
 }
 
 impl Xmrig {
-    fn with_threads(max_threads: usize, current_threads: usize) -> Self {
+    fn with_threads(max_threads: u16, current_threads: u16) -> Self {
         let xmrig = Self::default();
         Self {
             max_threads,
@@ -531,17 +644,19 @@ impl Default for Xmrig {
             rig: GUPAX_VERSION_UNDERSCORE.to_string(),
             ip: "localhost".to_string(),
             port: "3333".to_string(),
-            selected_index: 0,
-            selected_name: "Local P2Pool".to_string(),
-            selected_ip: "localhost".to_string(),
-            selected_rig: GUPAX_VERSION_UNDERSCORE.to_string(),
-            selected_port: "3333".to_string(),
             api_ip: "localhost".to_string(),
             api_port: "18088".to_string(),
             tls: false,
             keepalive: false,
             current_threads: 1,
             max_threads: 1,
+            selected_pool: SelectedPoolNode {
+                index: 0,
+                name: "Local Monero Node".to_string(),
+                ip: "localhost".to_string(),
+                rpc: "18081".to_string(),
+                zmq_rig: "18083".to_string(),
+            },
             token: thread_rng()
                 .sample_iter(Alphanumeric)
                 .take(16)
diff --git a/src/disk/status.rs b/src/disk/status.rs
index bda0ceb..93ac7e4 100644
--- a/src/disk/status.rs
+++ b/src/disk/status.rs
@@ -1,3 +1,6 @@
+use derive_more::derive::Display;
+use strum::{EnumCount, EnumIter};
+
 use super::*;
 //---------------------------------------------------------------------------------------------------- [Submenu] enum for [Status] tab
 #[derive(Clone, Copy, Eq, PartialEq, Debug, Deserialize, Serialize)]
@@ -25,7 +28,9 @@ impl Display for Submenu {
 
 //---------------------------------------------------------------------------------------------------- [PayoutView] enum for [Status/P2Pool] tab
 // The enum buttons for selecting which "view" to sort the payout log in.
-#[derive(Clone, Copy, Eq, PartialEq, Debug, Deserialize, Serialize)]
+#[derive(
+    Clone, Copy, Eq, PartialEq, Debug, Deserialize, Serialize, Display, EnumIter, EnumCount,
+)]
 pub enum PayoutView {
     Latest,   // Shows the most recent logs first
     Oldest,   // Shows the oldest logs first
@@ -33,6 +38,17 @@ pub enum PayoutView {
     Smallest, // Shows lowest to highest payouts
 }
 
+impl PayoutView {
+    pub const fn msg_help(&self) -> &str {
+        match self {
+            Self::Latest => STATUS_SUBMENU_LATEST,
+            Self::Oldest => STATUS_SUBMENU_OLDEST,
+            Self::Biggest => STATUS_SUBMENU_SMALLEST,
+            Self::Smallest => STATUS_SUBMENU_BIGGEST,
+        }
+    }
+}
+
 impl PayoutView {
     fn new() -> Self {
         Self::Latest
@@ -45,12 +61,6 @@ impl Default for PayoutView {
     }
 }
 
-impl Display for PayoutView {
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
-        write!(f, "{:?}", self)
-    }
-}
-
 //---------------------------------------------------------------------------------------------------- [Hash] enum for [Status/P2Pool]
 #[derive(Clone, Copy, Eq, PartialEq, Debug, Deserialize, Serialize)]
 #[allow(clippy::enum_variant_names)]
@@ -110,8 +120,10 @@ impl Hash {
 impl Display for Hash {
     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
         match self {
-            Hash::Hash => write!(f, "Hash"),
-            _ => write!(f, "{:?}hash", self),
+            Hash::Hash => write!(f, "H/s"),
+            Hash::Kilo => write!(f, "KH/s"),
+            Hash::Mega => write!(f, "MH/s"),
+            Hash::Giga => write!(f, "GH/s"),
         }
     }
 }
diff --git a/src/disk/tests.rs b/src/disk/tests.rs
index 4cf91ac..5074ba8 100644
--- a/src/disk/tests.rs
+++ b/src/disk/tests.rs
@@ -51,6 +51,13 @@ mod test {
 			ratio = "Width"
 			bundled = false
 
+			[gupax.auto]
+            update = false
+            bundled = false
+            ask_before_quit = false
+            save_before_quit = true
+            processes = []
+
 			[status]
 			submenu = "P2pool"
 			payout_view = "Oldest"
@@ -76,11 +83,13 @@ mod test {
 			ip = "192.168.1.123"
 			rpc = "18089"
 			zmq = "18083"
-			selected_index = 0
-			selected_name = "Local Monero Node"
-			selected_ip = "192.168.1.123"
-			selected_rpc = "18089"
-			selected_zmq = "18083"
+            
+            [p2pool.selected_node]
+            index = 0
+            name = "Local Monero Node"
+            ip = "localhost"
+            rpc = "18081"
+            zmq_rig = "18083"
 
 			[xmrig]
 			simple = true
@@ -98,13 +107,17 @@ mod test {
 			rig = "Gupaxx"
 			ip = "192.168.1.122"
 			port = "3333"
-			selected_index = 1
-			selected_name = "linux"
-			selected_rig = "Gupaxx"
-			selected_ip = "192.168.1.122"
-			selected_port = "3333"
             token = "testtoken"
 
+
+            [xmrig.selected_pool]
+            index = 0
+            name = "Local Monero Node"
+            ip = "localhost"
+            rpc = "18081"
+            zmq_rig = "18083"
+
+
             [xmrig_proxy]
             simple = true
             arguments = ""
@@ -121,13 +134,15 @@ mod test {
 			p2pool_ip = "localhost"
 			p2pool_port = "18088"
             token = "testtoken"
-			selected_index = 1
-			selected_name = "linux"
-			selected_rig = "Gupaxx"
-			selected_ip = "192.168.1.122"
-			selected_port = "3333"
             redirect_local_xmrig = true
 
+            [xmrig_proxy.selected_pool]
+            index = 0
+            name = "Local Monero Node"
+            ip = "localhost"
+            rpc = "18081"
+            zmq_rig = "18083"
+
             [xvb]
 			simple = true
 			simple_hero_mode = true
diff --git a/src/helper/mod.rs b/src/helper/mod.rs
index 82d893b..b83eb2c 100644
--- a/src/helper/mod.rs
+++ b/src/helper/mod.rs
@@ -33,6 +33,7 @@
 // This also includes all things related to handling the child processes (P2Pool/XMRig):
 // piping their stdout/stderr/stdin, accessing their APIs (HTTP + disk files), etc.
 
+use crate::components::gupax::FileType;
 use crate::components::update::{NODE_BINARY, P2POOL_BINARY, XMRIG_BINARY, XMRIG_PROXY_BINARY};
 //---------------------------------------------------------------------------------------------------- Import
 use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi;
@@ -46,6 +47,7 @@ use log::*;
 use node::PubNodeApi;
 use portable_pty::Child;
 use readable::up::Uptime;
+use serde::{Deserialize, Serialize};
 use std::fmt::Write;
 use std::path::Path;
 use std::{
@@ -54,7 +56,7 @@ use std::{
     thread,
     time::*,
 };
-use strum::EnumIter;
+use strum::{EnumCount, EnumIter};
 
 use self::xvb::{PubXvbApi, nodes::XvbNode};
 pub mod node;
@@ -250,18 +252,21 @@ impl Default for ProcessSignal {
     }
 }
 
-#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, EnumIter)]
+#[derive(
+    Copy, Clone, Eq, PartialEq, Debug, Display, EnumIter, EnumCount, Serialize, Deserialize, Default,
+)]
 pub enum ProcessName {
     Node,
     P2pool,
     Xmrig,
     #[display("Proxy")]
     XmrigProxy,
+    #[default]
     Xvb,
 }
 
 impl ProcessName {
-    pub fn binary_name(&self) -> &str {
+    pub const fn binary_name(&self) -> &str {
         match self {
             ProcessName::Node => NODE_BINARY,
             ProcessName::P2pool => P2POOL_BINARY,
@@ -270,6 +275,69 @@ impl ProcessName {
             ProcessName::Xvb => "",
         }
     }
+    pub const fn msg_binary_path_empty(&self) -> &str {
+        match self {
+            ProcessName::Node => NODE_PATH_EMPTY,
+            ProcessName::P2pool => P2POOL_PATH_EMPTY,
+            ProcessName::Xmrig => XMRIG_PATH_EMPTY,
+            ProcessName::XmrigProxy => XMRIG_PROXY_PATH_EMPTY,
+            ProcessName::Xvb => "",
+        }
+    }
+    pub const fn msg_binary_path_not_file(&self) -> &str {
+        match self {
+            ProcessName::Node => NODE_PATH_NOT_FILE,
+            ProcessName::P2pool => P2POOL_PATH_NOT_FILE,
+            ProcessName::Xmrig => XMRIG_PATH_NOT_FILE,
+            ProcessName::XmrigProxy => XMRIG_PROXY_PATH_NOT_FILE,
+            ProcessName::Xvb => "",
+        }
+    }
+    pub const fn msg_binary_path_invalid(&self) -> &str {
+        match self {
+            ProcessName::Node => NODE_PATH_NOT_VALID,
+            ProcessName::P2pool => P2POOL_PATH_NOT_VALID,
+            ProcessName::Xmrig => XMRIG_PATH_NOT_VALID,
+            ProcessName::XmrigProxy => XMRIG_PROXY_PATH_NOT_VALID,
+            ProcessName::Xvb => "",
+        }
+    }
+    pub const fn msg_binary_path_ok(&self) -> &str {
+        match self {
+            ProcessName::Node => NODE_PATH_OK,
+            ProcessName::P2pool => P2POOL_PATH_OK,
+            ProcessName::Xmrig => XMRIG_PATH_OK,
+            ProcessName::XmrigProxy => XMRIG_PROXY_PATH_OK,
+            ProcessName::Xvb => "",
+        }
+    }
+    pub const fn msg_path_edit(&self) -> &str {
+        match self {
+            ProcessName::Node => GUPAX_PATH_NODE,
+            ProcessName::P2pool => GUPAX_PATH_P2POOL,
+            ProcessName::Xmrig => GUPAX_PATH_XMRIG,
+            ProcessName::XmrigProxy => GUPAX_PATH_XMRIG_PROXY,
+            ProcessName::Xvb => "",
+        }
+    }
+    pub const fn msg_auto_help(&self) -> &str {
+        match self {
+            ProcessName::Node => GUPAX_AUTO_NODE,
+            ProcessName::P2pool => GUPAX_AUTO_P2POOL,
+            ProcessName::Xmrig => GUPAX_AUTO_XMRIG,
+            ProcessName::XmrigProxy => GUPAX_AUTO_XMRIG_PROXY,
+            ProcessName::Xvb => GUPAX_AUTO_XVB,
+        }
+    }
+    pub const fn file_type(&self) -> Option<FileType> {
+        match self {
+            ProcessName::Node => Some(FileType::Node),
+            ProcessName::P2pool => Some(FileType::P2pool),
+            ProcessName::Xmrig => Some(FileType::Xmrig),
+            ProcessName::XmrigProxy => Some(FileType::XmrigProxy),
+            ProcessName::Xvb => None,
+        }
+    }
 }
 
 impl std::fmt::Display for ProcessState {
@@ -374,7 +442,7 @@ impl Helper {
         pub_sys: &mut Sys,
         pid: &sysinfo::Pid,
         helper: &Helper,
-        max_threads: usize,
+        max_threads: u16,
     ) {
         let gupax_uptime = helper.uptime.to_string();
         let cpu = &sysinfo.cpus()[0];
@@ -416,7 +484,7 @@ impl Helper {
         helper: &Arc<Mutex<Self>>,
         mut sysinfo: sysinfo::System,
         pid: sysinfo::Pid,
-        max_threads: usize,
+        max_threads: u16,
     ) {
         // The ordering of these locks is _very_ important. They MUST be in sync with how the main GUI thread locks stuff
         // or a deadlock will occur given enough time. They will eventually both want to lock the [Arc<Mutex>] the other
diff --git a/src/helper/p2pool.rs b/src/helper/p2pool.rs
index b927b51..8e0e2cf 100644
--- a/src/helper/p2pool.rs
+++ b/src/helper/p2pool.rs
@@ -1,5 +1,6 @@
 use super::Helper;
 use super::Process;
+use crate::app::panels::middle::common::list_poolnode::PoolNode;
 use crate::components::node::RemoteNode;
 use crate::disk::state::P2pool;
 use crate::helper::ProcessName;
@@ -18,7 +19,7 @@ use crate::regex::estimated_hr;
 use crate::regex::nb_current_shares;
 use crate::{
     constants::*,
-    disk::{gupax_p2pool_api::GupaxP2poolApi, node::Node},
+    disk::gupax_p2pool_api::GupaxP2poolApi,
     helper::{MONERO_BLOCK_TIME_IN_SECONDS, P2POOL_BLOCK_TIME_IN_SECONDS},
     human::*,
     macros::*,
@@ -171,7 +172,7 @@ impl Helper {
         helper: &Arc<Mutex<Self>>,
         state: &P2pool,
         path: &Path,
-        backup_hosts: Option<Vec<Node>>,
+        backup_hosts: Option<Vec<PoolNode>>,
     ) {
         info!("P2Pool | Attempting to restart...");
         helper.lock().unwrap().p2pool.lock().unwrap().signal = ProcessSignal::Restart;
@@ -200,7 +201,7 @@ impl Helper {
         helper: &Arc<Mutex<Self>>,
         state: &P2pool,
         path: &Path,
-        backup_hosts: Option<Vec<Node>>,
+        backup_hosts: Option<Vec<PoolNode>>,
     ) {
         helper.lock().unwrap().p2pool.lock().unwrap().state = ProcessState::Middle;
 
@@ -253,7 +254,7 @@ impl Helper {
         helper: &Arc<Mutex<Self>>,
         state: &P2pool,
         path: &Path,
-        backup_hosts: Option<Vec<Node>>,
+        backup_hosts: Option<Vec<PoolNode>>,
     ) -> (Vec<String>, PathBuf, PathBuf, PathBuf) {
         let mut args = Vec::with_capacity(500);
         let path = path.to_path_buf();
@@ -282,13 +283,13 @@ impl Helper {
             // Push other nodes if `backup_host`.
             if let Some(nodes) = backup_hosts {
                 for node in nodes {
-                    if (node.ip.as_str(), node.rpc.as_str(), node.zmq.as_str()) != (ip, rpc, zmq) {
+                    if (node.ip(), node.port(), node.custom()) != (ip, rpc, zmq) {
                         args.push("--host".to_string());
-                        args.push(node.ip.to_string());
+                        args.push(node.ip().to_string());
                         args.push("--rpc-port".to_string());
-                        args.push(node.rpc.to_string());
+                        args.push(node.port().to_string());
                         args.push("--zmq-port".to_string());
-                        args.push(node.zmq.to_string());
+                        args.push(node.custom().to_string());
                     }
                 }
             }
@@ -395,20 +396,18 @@ impl Helper {
                 // Push other nodes if `backup_host`.
                 if let Some(nodes) = backup_hosts {
                     for node in nodes {
-                        let ip = if node.ip == "localhost" {
+                        let ip = if node.ip() == "localhost" {
                             "127.0.0.1"
                         } else {
-                            &node.ip
+                            node.ip()
                         };
-                        if (node.ip.as_str(), node.rpc.as_str(), node.zmq.as_str())
-                            != (ip, &state.rpc, &state.zmq)
-                        {
+                        if (node.ip(), node.port(), node.custom()) != (ip, &state.rpc, &state.zmq) {
                             args.push("--host".to_string());
-                            args.push(node.ip.to_string());
+                            args.push(node.ip().to_string());
                             args.push("--rpc-port".to_string());
-                            args.push(node.rpc.to_string());
+                            args.push(node.port().to_string());
                             args.push("--zmq-port".to_string());
-                            args.push(node.zmq.to_string());
+                            args.push(node.custom().to_string());
                         }
                     }
                 }
@@ -420,9 +419,9 @@ impl Helper {
                         "P2Pool Main".to_string()
                     },
                     address: Self::head_tail_of_monero_address(&state.address),
-                    host: state.selected_ip.to_string(),
-                    rpc: state.selected_rpc.to_string(),
-                    zmq: state.selected_zmq.to_string(),
+                    host: state.selected_node.ip.to_string(),
+                    rpc: state.selected_node.rpc.to_string(),
+                    zmq: state.selected_node.zmq_rig.to_string(),
                     out_peers: state.out_peers.to_string(),
                     in_peers: state.in_peers.to_string(),
                 };
diff --git a/src/helper/tests.rs b/src/helper/tests.rs
index 5c5d99f..28dd82a 100644
--- a/src/helper/tests.rs
+++ b/src/helper/tests.rs
@@ -298,13 +298,13 @@ Uptime         = 0h 2m 4s
         assert_eq!(p.miners.to_string(), "1,000");
         assert_eq!(
             p.solo_block_mean.to_string(),
-            "5 months, 21 days, 9 hours, 52 minutes"
+            "5 months\n21 days\n9 hours\n52 minutes"
         );
         assert_eq!(
             p.p2pool_block_mean.to_string(),
-            "3 days, 11 hours, 20 minutes"
+            "3 days\n11 hours\n20 minutes"
         );
-        assert_eq!(p.p2pool_share_mean.to_string(), "8 minutes, 20 seconds");
+        assert_eq!(p.p2pool_share_mean.to_string(), "8 minutes\n20 seconds");
         assert_eq!(p.p2pool_percent.to_string(), "0.040000%");
         assert_eq!(p.user_p2pool_percent.to_string(), "2.000000%");
         assert_eq!(p.user_monero_percent.to_string(), "0.000800%");
diff --git a/src/inits.rs b/src/inits.rs
index 3aec985..15c609d 100644
--- a/src/inits.rs
+++ b/src/inits.rs
@@ -24,6 +24,7 @@ use std::time::Instant;
 
 #[cold]
 #[inline(never)]
+// everything is resized from here with the scale.
 pub fn init_text_styles(ctx: &egui::Context, pixels_per_point: f32) {
     ctx.all_styles_mut(|style| {
         style.text_styles = [
@@ -34,13 +35,15 @@ pub fn init_text_styles(ctx: &egui::Context, pixels_per_point: f32) {
             (Heading, FontId::new(22.0, egui::FontFamily::Monospace)),
         ]
         .into();
-        style.spacing.icon_width_inner = 32.0;
-        style.spacing.icon_width = 64.0;
-        style.spacing.icon_spacing = 20.0;
-        style.spacing.scroll = egui::style::ScrollStyle {
-            bar_width: 8.0,
-            ..egui::style::ScrollStyle::solid()
-        };
+        style.spacing.icon_width_inner = 24.0;
+        style.spacing.icon_width = 48.0;
+        style.spacing.icon_spacing = 16.0;
+        style.spacing.button_padding = [8.0, 8.0].into();
+        style.spacing.item_spacing = [8.0, 8.0].into();
+        // style.spacing.scroll = egui::style::ScrollStyle {
+        // bar_width: 8.0,
+        // ..egui::style::ScrollStyle::solid()
+        // };
     });
     // Make sure scale f32 is a regular number.
     let pixels_per_point = clamp_scale(pixels_per_point);
@@ -134,7 +137,7 @@ pub fn init_auto(app: &mut App) {
 
     // [Auto-Update]
     #[cfg(not(feature = "distro"))]
-    if app.state.gupax.auto_update {
+    if app.state.gupax.auto.is_enabled(&AutoStart::Update) {
         Update::spawn_thread(
             &app.og,
             &app.state.gupax,
@@ -155,7 +158,12 @@ pub fn init_auto(app: &mut App) {
     }
 
     // [Auto-Node]
-    if app.state.gupax.auto_node {
+    if app
+        .state
+        .gupax
+        .auto
+        .is_enabled(&AutoStart::Process(ProcessName::Node))
+    {
         if !Gupax::path_is_file(&app.state.gupax.node_path) {
             warn!("Gupaxx | Node path is not a file! Skipping auto-node...");
         } else if !check_binary_path(&app.state.gupax.node_path, ProcessName::Node) {
@@ -177,7 +185,12 @@ pub fn init_auto(app: &mut App) {
         info!("Skipping auto-node...");
     }
     // [Auto-P2Pool]
-    if app.state.gupax.auto_p2pool {
+    if app
+        .state
+        .gupax
+        .auto
+        .is_enabled(&AutoStart::Process(ProcessName::P2pool))
+    {
         if !Regexes::addr_ok(&app.state.p2pool.address) {
             warn!("Gupaxx | P2Pool address is not valid! Skipping auto-p2pool...");
         } else if !Gupax::path_is_file(&app.state.gupax.p2pool_path) {
@@ -202,7 +215,12 @@ pub fn init_auto(app: &mut App) {
     }
 
     // [Auto-XMRig]
-    if app.state.gupax.auto_xmrig {
+    if app
+        .state
+        .gupax
+        .auto
+        .is_enabled(&AutoStart::Process(ProcessName::Xmrig))
+    {
         if !Gupax::path_is_file(&app.state.gupax.xmrig_path) {
             warn!("Gupaxx | XMRig path is not an executable! Skipping auto-xmrig...");
         } else if !check_binary_path(&app.state.gupax.xmrig_path, ProcessName::Xmrig) {
@@ -226,7 +244,12 @@ pub fn init_auto(app: &mut App) {
         info!("Skipping auto-xmrig...");
     }
     // [Auto-XMRig-Proxy]
-    if app.state.gupax.auto_xp {
+    if app
+        .state
+        .gupax
+        .auto
+        .is_enabled(&AutoStart::Process(ProcessName::XmrigProxy))
+    {
         if !Gupax::path_is_file(&app.state.gupax.xmrig_proxy_path) {
             warn!("Gupaxx | Xmrig-Proxy path is not a file! Skipping auto-xmrig_proxy...");
         } else if !check_binary_path(&app.state.gupax.xmrig_proxy_path, ProcessName::XmrigProxy) {
@@ -247,7 +270,12 @@ pub fn init_auto(app: &mut App) {
         info!("Skipping auto-XMRig-Proxy...");
     }
     // [Auto-XvB]
-    if app.state.gupax.auto_xvb {
+    if app
+        .state
+        .gupax
+        .auto
+        .is_enabled(&AutoStart::Process(ProcessName::Xvb))
+    {
         Helper::start_xvb(
             &app.helper,
             &app.state.xvb,
diff --git a/src/miscs.rs b/src/miscs.rs
index 68a7b1d..460cad6 100644
--- a/src/miscs.rs
+++ b/src/miscs.rs
@@ -132,6 +132,8 @@ pub fn cmp_f64(a: f64, b: f64) -> std::cmp::Ordering {
 use crate::disk::gupax_p2pool_api::GupaxP2poolApi;
 use crate::helper::ProcessName;
 use chrono::Local;
+use egui::TextStyle;
+use egui::Ui;
 use log::error;
 use log::warn;
 use regex::Regex;
@@ -182,3 +184,7 @@ pub fn client() -> ClientWithMiddleware {
         ))
         .build()
 }
+/// to get the right height that a text must take before a button to be aligned in the center correctly.
+pub fn height_txt_before_button(ui: &Ui, style: &TextStyle) -> f32 {
+    ui.style().spacing.button_padding.y * 2.0 + ui.text_style_height(style)
+}
diff --git a/src/utils/constants.rs b/src/utils/constants.rs
index d282c52..9558312 100644
--- a/src/utils/constants.rs
+++ b/src/utils/constants.rs
@@ -348,6 +348,7 @@ pub const GUPAX_TAB_STATUS: &str = "Set the tab Gupaxx starts on to: Status";
 pub const GUPAX_TAB_GUPAX: &str = "Set the tab Gupaxx starts on to: Gupaxx";
 pub const GUPAX_TAB_P2POOL: &str = "Set the tab Gupaxx starts on to: P2Pool";
 pub const GUPAX_TAB_XMRIG: &str = "Set the tab Gupaxx starts on to: XMRig";
+pub const GUPAX_TAB_XMRIG_PROXY: &str = "Set the tab Gupaxx starts on to: Proxy";
 pub const GUPAX_TAB_XVB: &str = "Set the tab Gupaxx starts on to: XvB";
 pub const GUPAX_TAB_NODE: &str = "Set the default tab Gupaxx starts on to: Node";
 
@@ -526,7 +527,6 @@ pub const XVB_TIME_ALGO: u32 = 600;
 pub const XVB_MIN_TIME_SEND: u32 = (XVB_TIME_ALGO as f32 * 0.01) as u32;
 pub const XVB_TOKEN_LEN: usize = 9;
 pub const XVB_HERO_SELECT: &str = "Donate as much as possible while keeping a share on p2pool, increases the odds of your round winning\nWhen modified, the algorithm will use the new choice at the next decision.";
-pub const XVB_TOKEN_FIELD: &str = "Token";
 pub const XVB_FAILURE_FIELD: &str = "Failures";
 pub const XVB_DONATED_1H_FIELD: &str = "Donated last hour";
 pub const XVB_DONATED_24H_FIELD: &str = "Donated last 24 hours";
diff --git a/src/utils/human.rs b/src/utils/human.rs
index c489d12..84e80fc 100644
--- a/src/utils/human.rs
+++ b/src/utils/human.rs
@@ -59,7 +59,7 @@ impl HumanTime {
     ) -> std::fmt::Result {
         if value > 0 {
             if *started {
-                f.write_str(", ")?;
+                f.write_str("\n")?;
             }
             write!(f, "{} {}", value, name)?;
             if value > 1 {
@@ -332,64 +332,64 @@ mod test {
         assert!(HumanTime::into_human(Duration::from_secs(2)).to_string() == "2 seconds");
         assert!(HumanTime::into_human(Duration::from_secs(59)).to_string() == "59 seconds");
         assert!(HumanTime::into_human(Duration::from_secs(60)).to_string() == "1 minute");
-        assert!(HumanTime::into_human(Duration::from_secs(61)).to_string() == "1 minute, 1 second");
+        assert!(HumanTime::into_human(Duration::from_secs(61)).to_string() == "1 minute\n1 second");
         assert!(
-            HumanTime::into_human(Duration::from_secs(62)).to_string() == "1 minute, 2 seconds"
+            HumanTime::into_human(Duration::from_secs(62)).to_string() == "1 minute\n2 seconds"
         );
         assert!(HumanTime::into_human(Duration::from_secs(120)).to_string() == "2 minutes");
         assert!(
-            HumanTime::into_human(Duration::from_secs(121)).to_string() == "2 minutes, 1 second"
+            HumanTime::into_human(Duration::from_secs(121)).to_string() == "2 minutes\n1 second"
         );
         assert!(
-            HumanTime::into_human(Duration::from_secs(122)).to_string() == "2 minutes, 2 seconds"
+            HumanTime::into_human(Duration::from_secs(122)).to_string() == "2 minutes\n2 seconds"
         );
         assert!(
-            HumanTime::into_human(Duration::from_secs(179)).to_string() == "2 minutes, 59 seconds"
+            HumanTime::into_human(Duration::from_secs(179)).to_string() == "2 minutes\n59 seconds"
         );
         assert!(
             HumanTime::into_human(Duration::from_secs(3599)).to_string()
-                == "59 minutes, 59 seconds"
+                == "59 minutes\n59 seconds"
         );
         assert!(HumanTime::into_human(Duration::from_secs(3600)).to_string() == "1 hour");
-        assert!(HumanTime::into_human(Duration::from_secs(3601)).to_string() == "1 hour, 1 second");
+        assert!(HumanTime::into_human(Duration::from_secs(3601)).to_string() == "1 hour\n1 second");
         assert!(
-            HumanTime::into_human(Duration::from_secs(3602)).to_string() == "1 hour, 2 seconds"
+            HumanTime::into_human(Duration::from_secs(3602)).to_string() == "1 hour\n2 seconds"
         );
-        assert!(HumanTime::into_human(Duration::from_secs(3660)).to_string() == "1 hour, 1 minute");
+        assert!(HumanTime::into_human(Duration::from_secs(3660)).to_string() == "1 hour\n1 minute");
         assert!(
-            HumanTime::into_human(Duration::from_secs(3720)).to_string() == "1 hour, 2 minutes"
+            HumanTime::into_human(Duration::from_secs(3720)).to_string() == "1 hour\n2 minutes"
         );
         assert!(
             HumanTime::into_human(Duration::from_secs(86399)).to_string()
-                == "23 hours, 59 minutes, 59 seconds"
+                == "23 hours\n59 minutes\n59 seconds"
         );
         assert!(HumanTime::into_human(Duration::from_secs(86400)).to_string() == "1 day");
-        assert!(HumanTime::into_human(Duration::from_secs(86401)).to_string() == "1 day, 1 second");
+        assert!(HumanTime::into_human(Duration::from_secs(86401)).to_string() == "1 day\n1 second");
         assert!(
-            HumanTime::into_human(Duration::from_secs(86402)).to_string() == "1 day, 2 seconds"
+            HumanTime::into_human(Duration::from_secs(86402)).to_string() == "1 day\n2 seconds"
         );
-        assert!(HumanTime::into_human(Duration::from_secs(86460)).to_string() == "1 day, 1 minute");
+        assert!(HumanTime::into_human(Duration::from_secs(86460)).to_string() == "1 day\n1 minute");
         assert!(
-            HumanTime::into_human(Duration::from_secs(86520)).to_string() == "1 day, 2 minutes"
+            HumanTime::into_human(Duration::from_secs(86520)).to_string() == "1 day\n2 minutes"
         );
-        assert!(HumanTime::into_human(Duration::from_secs(90000)).to_string() == "1 day, 1 hour");
-        assert!(HumanTime::into_human(Duration::from_secs(93600)).to_string() == "1 day, 2 hours");
+        assert!(HumanTime::into_human(Duration::from_secs(90000)).to_string() == "1 day\n1 hour");
+        assert!(HumanTime::into_human(Duration::from_secs(93600)).to_string() == "1 day\n2 hours");
         assert!(
             HumanTime::into_human(Duration::from_secs(604799)).to_string()
-                == "6 days, 23 hours, 59 minutes, 59 seconds"
+                == "6 days\n23 hours\n59 minutes\n59 seconds"
         );
         assert!(HumanTime::into_human(Duration::from_secs(604800)).to_string() == "7 days");
         assert!(HumanTime::into_human(Duration::from_secs(2630016)).to_string() == "1 month");
         assert!(
             HumanTime::into_human(Duration::from_secs(3234815)).to_string()
-                == "1 month, 6 days, 23 hours, 59 minutes, 59 seconds"
+                == "1 month\n6 days\n23 hours\n59 minutes\n59 seconds"
         );
         assert!(HumanTime::into_human(Duration::from_secs(5260032)).to_string() == "2 months");
         assert!(HumanTime::into_human(Duration::from_secs(31557600)).to_string() == "1 year");
         assert!(HumanTime::into_human(Duration::from_secs(63115200)).to_string() == "2 years");
         assert_eq!(
             HumanTime::into_human(Duration::from_secs(18446744073709551615)).to_string(),
-            "584542046090 years, 7 months, 15 days, 17 hours, 5 minutes, 3 seconds",
+            "584542046090 years\n7 months\n15 days\n17 hours\n5 minutes\n3 seconds",
         );
     }
 }