gui as default and more ui

This commit is contained in:
MeexReay 2025-04-16 19:51:37 +03:00
parent 904ac31a97
commit a85442f57d
12 changed files with 470 additions and 152 deletions

149
Cargo.lock generated
View File

@ -11,6 +11,21 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.6.18" version = "0.6.18"
@ -78,6 +93,7 @@ name = "bRAC"
version = "0.1.2+2.0" version = "0.1.2+2.0"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"chrono",
"clap", "clap",
"colored", "colored",
"crossterm", "crossterm",
@ -97,6 +113,12 @@ version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "bumpalo"
version = "3.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.5.0" version = "1.5.0"
@ -157,6 +179,20 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrono"
version = "0.4.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-link",
]
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.36" version = "4.5.36"
@ -688,6 +724,30 @@ dependencies = [
"windows", "windows",
] ]
[[package]]
name = "iana-time-zone"
version = "0.1.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.7.1" version = "2.7.1"
@ -710,6 +770,16 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "js-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.5.0" version = "1.5.0"
@ -822,6 +892,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.20.3" version = "1.20.3"
@ -1077,6 +1156,12 @@ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
[[package]]
name = "rustversion"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.19" version = "1.0.19"
@ -1357,6 +1442,64 @@ dependencies = [
"wit-bindgen-rt", "wit-bindgen-rt",
] ]
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"unicode-ident",
]
[[package]] [[package]]
name = "widestring" name = "widestring"
version = "1.1.0" version = "1.1.0"
@ -1429,6 +1572,12 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "windows-link"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
[[package]] [[package]]
name = "windows-result" name = "windows-result"
version = "0.1.2" version = "0.1.2"

View File

@ -14,12 +14,14 @@ serde_yml = "0.0.12"
crossterm = { version = "0.29.0", optional = true } crossterm = { version = "0.29.0", optional = true }
homedir = { version = "0.3.4", optional = true } homedir = { version = "0.3.4", optional = true }
native-tls = { version = "0.2.14", optional = true } native-tls = { version = "0.2.14", optional = true }
gtk4 = { version = "0.9.6", optional = true } gtk4 = { version = "0.9.6", optional = true, features = [ "v4_10" ] }
cfg-if = "1.0.0" cfg-if = "1.0.0"
chrono = { version = "0.4.40", optional = true }
[features] [features]
default = ["ssl", "homedir", "gtk_gui"] default = ["ssl", "homedir", "gtk_gui"]
tui = ["ssl", "homedir", "pretty_tui"]
ssl = ["dep:native-tls"] ssl = ["dep:native-tls"]
pretty_tui = ["dep:crossterm"] pretty_tui = ["dep:crossterm"]
gtk_gui = ["dep:gtk4"] gtk_gui = ["dep:gtk4", "dep:chrono"]
homedir = ["dep:homedir"] homedir = ["dep:homedir"]

View File

@ -9,6 +9,7 @@ better RAC client
## features ## features
- gtk4 GUI
- cheat commands (type /help) - cheat commands (type /help)
- no ip and date visible - no ip and date visible
- uses TOR proxy server by default (meex.lol:11234) - uses TOR proxy server by default (meex.lol:11234)
@ -19,7 +20,7 @@ better RAC client
- RACS compatible (--enable-ssl or in --configure enable SSL) - RACS compatible (--enable-ssl or in --configure enable SSL)
- chunked reading messages - chunked reading messages
![image](https://github.com/user-attachments/assets/a2858662-50f1-4554-949c-f55addf48fcc) ![screenshot](image.png)
## how to run ## how to run
@ -43,18 +44,19 @@ cargo build -r # build release (target/release/bRAC)
cargo run -r # run (builds and runs bRAC itself) cargo run -r # run (builds and runs bRAC itself)
``` ```
TUI version:
```bash
cargo build -r --no-default-features -F tui
cargo run -r --no-default-features -F tui
```
Minimal version: Minimal version:
```bash ```bash
cargo build -r --no-default-features cargo build -r --no-default-features
cargo run -r --no-default-features cargo run -r --no-default-features
``` ```
GTK version:
```bash
cargo build -rF gtk_gui
cargo run -rF gtk_gui
```
### nix package ### nix package
@ -72,11 +74,11 @@ nix build github:MeexReay/bRAC#bRAC-minimal
nix run github:MeexReay/bRAC#bRAC-minimal nix run github:MeexReay/bRAC#bRAC-minimal
``` ```
GTK version: TUI version:
```bash ```bash
nix build github:MeexReay/bRAC#bRAC-gtk nix build github:MeexReay/bRAC#bRAC-tui
nix run github:MeexReay/bRAC#bRAC-gtk nix run github:MeexReay/bRAC#bRAC-tui
``` ```
## default config ## default config

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

View File

@ -55,15 +55,20 @@
devShells.default = self'.devShells.stable; devShells.default = self'.devShells.stable;
packages.bRAC = (rustPackage { packages.bRAC = (rustPackage {
version = "-gtk";
features = "ssl homedir gtk_gui";
deps = with pkgs; [
pkg-config
openssl
gtk4
pango
];
});
packages.bRAC-tui = (rustPackage {
version = ""; version = "";
features = "default"; features = "default";
deps = with pkgs; [ pkg-config openssl ]; deps = with pkgs; [ pkg-config openssl ];
}); });
packages.bRAC-gtk = (rustPackage {
version = "-gtk";
features = "ssl homedir gtk_gui";
deps = with pkgs; [ pkg-config openssl gtk4 pango ];
});
packages.bRAC-minimal = (rustPackage { packages.bRAC-minimal = (rustPackage {
version = "-minimal"; version = "-minimal";
features = ""; features = "";

BIN
icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
konata.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
logo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,18 +0,0 @@
{ pkgs ? import <nixpkgs> {} }:
let
devDeps = with pkgs; [
pkg-config
openssl
gtk4
pango
];
in pkgs.mkShell {
shellHook = ''
export RUST_SRC_PATH=${pkgs.rustPlatform.rustLibSrc}
'';
buildInputs = devDeps;
nativeBuildInputs = with pkgs; [
rustc
cargo
] ++ devDeps;
}

View File

@ -32,12 +32,12 @@ lazy_static! {
cfg_if! { cfg_if! {
if #[cfg(feature = "gtk_gui")] { if #[cfg(feature = "pretty_tui")] {
mod gtk_gui;
pub use gtk_gui::*;
} else if #[cfg(feature = "pretty_tui")] {
mod pretty_tui; mod pretty_tui;
pub use pretty_tui::*; pub use pretty_tui::*;
} else if #[cfg(feature = "gtk_gui")] {
mod gtk_gui;
pub use gtk_gui::*;
} else { } else {
mod minimal_tui; mod minimal_tui;
pub use minimal_tui::*; pub use minimal_tui::*;

View File

@ -1,20 +1,26 @@
use std::rc::Rc;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use std::time::Duration; use std::time::{Duration, SystemTime};
use chrono::Local;
use colored::{Color, Colorize}; use colored::{Color, Colorize};
use gtk4::gdk::{Cursor, Display}; use gtk4::gdk::{Cursor, Display, Texture};
use gtk4::gdk_pixbuf::PixbufLoader; use gtk4::gdk_pixbuf::{Pixbuf, PixbufAnimation, PixbufLoader};
use gtk4::gio::MenuModel; use gtk4::gio::{ActionEntry, ApplicationFlags, MemoryInputStream, Menu, MenuItem, MenuModel};
use gtk4::glib::clone::Downgrade; use gtk4::glib::clone::Downgrade;
use gtk4::{gio, Image, Justification, ListBox, pango::WrapMode};
use gtk4::glib::timeout_add_local;
use gtk4::glib::{idle_add_local, idle_add_local_once, ControlFlow, source::timeout_add_local_once}; use gtk4::glib::{idle_add_local, idle_add_local_once, ControlFlow, source::timeout_add_local_once};
use gtk4::{glib, glib::clone, Align, Box as GtkBox, Label, ScrolledWindow}; use gtk4::{glib, glib::clone, Align, Box as GtkBox, Label, ScrolledWindow};
use gtk4::{CssProvider, Entry, Orientation, Overlay, Picture, PopoverMenuBar}; use gtk4::{AboutDialog, AlertDialog, ButtonsType, Calendar, CssProvider, Entry, Fixed, License, MessageDialog, MessageType, Orientation, Overlay, Picture, PopoverMenuBar, SelectionMode, Window};
use gtk4::prelude::*; use gtk4::prelude::*;
use gtk4::{Application, ApplicationWindow, Button}; use gtk4::{Application, ApplicationWindow, Button};
use rand::Rng;
use std::sync::mpsc::{channel, Sender, Receiver}; use std::sync::mpsc::{channel, Sender, Receiver};
use std::error::Error; use std::error::Error;
use std::thread; use std::thread;
use std::cell::RefCell; use std::cell::RefCell;
use std::io::Bytes;
use crate::config::Context; use crate::config::Context;
use crate::proto::{connect, read_messages}; use crate::proto::{connect, read_messages};
@ -85,15 +91,217 @@ pub fn recv_tick(ctx: Arc<Context>) -> Result<(), Box<dyn Error>> {
Ok(()) Ok(())
} }
fn build_ui(ctx: Arc<Context>, app: &Application) { fn load_pixbuf(data: &[u8]) -> Pixbuf {
let loader = PixbufLoader::new();
loader.write(data).unwrap();
loader.close().unwrap();
loader.pixbuf().unwrap()
}
fn build_menu(ctx: Arc<Context>, app: &Application) {
let menu = Menu::new();
let file_menu = Menu::new();
file_menu.append(Some("New File"), Some("app.file_new"));
file_menu.append(Some("Make a bottleflip"), Some("app.make_bottleflip"));
file_menu.append(Some("Export brain to jpeg"), Some("unavailable"));
file_menu.append(Some("About"), Some("app.about"));
let edit_menu = Menu::new();
edit_menu.append(Some("Edit File"), Some("app.file_edit"));
edit_menu.append(Some("Create a new parallel reality"), Some("app.parallel_reality_create"));
menu.append_submenu(Some("File"), &file_menu);
menu.append_submenu(Some("Edit"), &edit_menu);
app.set_menubar(Some((&menu).into()));
// GtkAlertDialog::builder()
// .title("Successful editioning")
// .text("your file was edited")
// .buttons(ButtonsType::Ok)
// .application(&app)
// .message_type(MessageType::Info)
// .build()
// .present();
// AlertDialog::builder()
// .message("Successful editioning")
// .detail("your file was edited")
// .buttons(["okey"])
// .build()
// .present(None);
app.add_action_entries([
ActionEntry::builder("file_new")
.activate(move |a: &Application, _, _| {
AlertDialog::builder()
.message("Successful creatin")
.detail("your file was created")
.buttons(["ok", "cancel", "confirm", "click"])
.build()
.show(Some(&a.windows()[0]));
}
)
.build(),
ActionEntry::builder("make_bottleflip")
.activate(move |a: &Application, _, _| {
AlertDialog::builder()
.message("Sorry")
.detail("bottleflip gone wrong :(")
.buttons(["yes", "no"])
.build()
.show(Some(&a.windows()[0]));
}
)
.build(),
ActionEntry::builder("parallel_reality_create")
.activate(move |a: &Application, _, _| {
AlertDialog::builder()
.message("Your new parallel reality has been created")
.detail(format!("Your parallel reality code: {}", rand::rng().random_range(1..100)))
.buttons(["chocolate"])
.build()
.show(Some(&a.windows()[0]));
}
)
.build(),
ActionEntry::builder("file_edit")
.activate(move |a: &Application, _, _| {
AlertDialog::builder()
.message("Successful editioning")
.detail("your file was edited")
.buttons(["okey"])
.build()
.show(Some(&a.windows()[0]));
}
)
.build(),
ActionEntry::builder("about")
.activate(clone!(
#[weak] app,
move |_, _, _| {
AboutDialog::builder()
.application(&app)
.authors(["TheMixRay", "MeexReay"])
.license(" DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.")
.comments("better RAC client")
.website("https://github.com/MeexReay/bRAC")
.website_label("source code")
.logo(&Texture::for_pixbuf(&load_pixbuf(include_bytes!("../../icon.png"))))
.build()
.present();
}
))
.build()
]);
}
fn build_ui(ctx: Arc<Context>, app: &Application) -> UiModel {
let main_box = GtkBox::new(Orientation::Vertical, 5); let main_box = GtkBox::new(Orientation::Vertical, 5);
let widget_box_overlay = Overlay::new();
let widget_box = GtkBox::new(Orientation::Horizontal, 5);
widget_box.set_css_classes(&["widget_box"]);
widget_box.append(&Calendar::builder()
.css_classes(["calendar"])
.show_heading(false)
.can_target(false)
.build());
let server_list_vbox = GtkBox::new(Orientation::Vertical, 5);
let server_list = ListBox::new();
server_list.append(&Label::builder().label("meex.lol:42666").halign(Align::Start).selectable(true).build());
server_list.append(&Label::builder().label("meex.lol:11234").halign(Align::Start).selectable(true).build());
server_list.append(&Label::builder().label("91.192.22.20:42666").halign(Align::Start).selectable(true).build());
server_list_vbox.append(&Label::builder().label("Server List:").build());
server_list_vbox.append(&server_list);
widget_box.append(&server_list_vbox);
let fixed = Fixed::new();
fixed.set_can_target(false);
let konata = Picture::for_pixbuf(&load_pixbuf(include_bytes!("../../konata.png")));
konata.set_size_request(174, 127);
fixed.put(&konata, 325.0, 4.0);
let logo = Picture::for_pixbuf(&load_pixbuf(include_bytes!("../../logo.gif")));
logo.set_size_request(152, 64);
let logo_anim = PixbufAnimation::from_stream(
&MemoryInputStream::from_bytes(
&glib::Bytes::from(include_bytes!("../../logo.gif"))
),
None::<&gio::Cancellable>
).unwrap().iter(Some(SystemTime::now()));
timeout_add_local(Duration::from_millis(30), {
let logo = logo.clone();
let logo_anim = logo_anim.clone();
move || {
logo.set_pixbuf(Some(&logo_anim.pixbuf()));
logo_anim.advance(SystemTime::now());
ControlFlow::Continue
}
});
fixed.put(&logo, 262.0, 4.0);
let time = Label::builder()
.label(&Local::now().format("%H:%M").to_string())
.justify(Justification::Right)
.css_classes(["time"])
.build();
timeout_add_local(Duration::from_secs(1), {
let time = time.clone();
move || {
time.set_label(&Local::now().format("%H:%M").to_string());
ControlFlow::Continue
}
});
fixed.put(&time, 432.0, 4.0);
widget_box_overlay.add_overlay(&fixed);
widget_box_overlay.set_child(Some(&widget_box));
main_box.append(&widget_box_overlay);
let chat_box = GtkBox::new(Orientation::Vertical, 2); let chat_box = GtkBox::new(Orientation::Vertical, 2);
let chat_scrolled = ScrolledWindow::builder() let chat_scrolled = ScrolledWindow::builder()
.child(&chat_box) .child(&chat_box)
.vexpand(true) .vexpand(true)
.hexpand(true) .hexpand(true)
.margin_bottom(5)
.margin_end(5)
.margin_start(5)
.propagate_natural_height(true) .propagate_natural_height(true)
.build(); .build();
@ -101,8 +309,13 @@ fn build_ui(ctx: Arc<Context>, app: &Application) {
let send_box = GtkBox::new(Orientation::Horizontal, 5); let send_box = GtkBox::new(Orientation::Horizontal, 5);
send_box.set_margin_bottom(5);
send_box.set_margin_end(5);
send_box.set_margin_start(5);
let text_entry = Entry::builder() let text_entry = Entry::builder()
.placeholder_text("Message") .placeholder_text("Message")
.css_classes(["send-button"])
.hexpand(true) .hexpand(true)
.build(); .build();
@ -110,6 +323,7 @@ fn build_ui(ctx: Arc<Context>, app: &Application) {
let send_btn = Button::builder() let send_btn = Button::builder()
.label("Send") .label("Send")
.css_classes(["send-text"])
.cursor(&Cursor::from_name("pointer", None).unwrap()) .cursor(&Cursor::from_name("pointer", None).unwrap())
.build(); .build();
@ -168,24 +382,13 @@ fn build_ui(ctx: Arc<Context>, app: &Application) {
} }
}); });
let overlay = Overlay::new(); // let logo = Picture::for_pixbuf(&load_pixbuf(include_bytes!("../../brac_logo.png")));
// logo.set_size_request(500, 189);
overlay.set_child(Some(&main_box)); // logo.set_can_target(false);
// logo.set_can_focus(false);
let bytes = include_bytes!("../../brac_logo.png"); // logo.set_halign(Align::End);
let loader = PixbufLoader::new(); // logo.set_valign(Align::Start);
loader.write(bytes).unwrap(); // overlay.add_overlay(&logo);
loader.close().unwrap();
let pixbuf = loader.pixbuf().unwrap();
let logo = Picture::for_pixbuf(&pixbuf);
logo.set_size_request(500, 189);
logo.set_can_target(false);
logo.set_can_focus(false);
logo.set_halign(Align::End);
logo.set_valign(Align::Start);
overlay.add_overlay(&logo);
let window = ApplicationWindow::builder() let window = ApplicationWindow::builder()
.application(app) .application(app)
@ -195,7 +398,7 @@ fn build_ui(ctx: Arc<Context>, app: &Application) {
.resizable(false) .resizable(false)
.decorated(true) .decorated(true)
.show_menubar(true) .show_menubar(true)
.child(&overlay) .child(&main_box)
.build(); .build();
window.connect_default_width_notify({ window.connect_default_width_notify({
@ -212,15 +415,12 @@ fn build_ui(ctx: Arc<Context>, app: &Application) {
} }
}); });
window.show(); window.present();
let ui = UiModel { UiModel {
chat_scrolled, chat_scrolled,
chat_box chat_box
}; }
setup(ctx.clone(), ui);
load_css();
} }
fn setup(ctx: Arc<Context>, ui: UiModel) { fn setup(ctx: Arc<Context>, ui: UiModel) {
@ -273,91 +473,42 @@ fn setup(ctx: Arc<Context>, ui: UiModel) {
fn load_css() { fn load_css() {
let provider = CssProvider::new(); let provider = CssProvider::new();
provider.load_from_data(" provider.load_from_data("
.send-button, .send-text { border-radius: 0; }
* { .calendar {
border-radius: 0; transform: scale(0.6);
margin: -35px;
} }
.widget_box {
.message-content { box-shadow: 0 10px 10px rgba(0, 0, 0, 0.20);
color: #000000; border-bottom: 2px solid rgba(0, 0, 0, 0.20);
} }
.time {
.message-date { font-size: 20px;
color: #555555; font-family: monospace;
}
.message-ip {
color: #777777;
}
.message-name {
font-weight: bold; font-weight: bold;
} }
.message-name-black { .message-content { color:rgb(255, 255, 255); }
color: #2E2E2E; /* Темный черный */ .message-date { color:rgb(146, 146, 146); }
} .message-ip { color:rgb(73, 73, 73); }
.message-name { font-weight: bold; }
.message-name-red {
color: #8B0000; /* Темный красный */
}
.message-name-green {
color: #006400; /* Темный зеленый */
}
.message-name-yellow {
color: #8B8B00; /* Темный желтый */
}
.message-name-blue {
color: #00008B; /* Темный синий */
}
.message-name-magenta {
color: #8B008B; /* Темный пурпурный */
}
.message-name-cyan {
color: #008B8B; /* Темный бирюзовый */
}
.message-name-white {
color: #A9A9A9; /* Темный белый */
}
.message-name-bright-black {
color: #555555; /* Яркий черный */
}
.message-name-bright-red {
color: #FF0000; /* Яркий красный */
}
.message-name-bright-green {
color: #00FF00; /* Яркий зеленый */
}
.message-name-bright-yellow {
color: #FFFF00; /* Яркий желтый */
}
.message-name-bright-blue {
color: #0000FF; /* Яркий синий */
}
.message-name-bright-magenta {
color: #FF00FF; /* Яркий пурпурный */
}
.message-name-bright-cyan {
color: #00FFFF; /* Яркий бирюзовый */
}
.message-name-bright-white {
color: #FFFFFF; /* Яркий белый */
}
.message-name-black { color: #2E2E2E; }
.message-name-bright-black { color: #555555; }
.message-name-red { color: #8B0000; }
.message-name-bright-red { color: #FF0000; }
.message-name-green { color: #006400; }
.message-name-bright-green { color: #00FF00; }
.message-name-yellow { color: #8B8B00; }
.message-name-bright-yellow { color: #FFFF00; }
.message-name-blue { color: #00008B; }
.message-name-bright-blue { color: #0000FF; }
.message-name-bright-magenta { color: #FF00FF; }
.message-name-magenta { color: #8B008B; }
.message-name-cyan { color: #008B8B; }
.message-name-bright-cyan { color: #00FFFF; }
.message-name-white { color: #A9A9A9; }
.message-name-bright-white { color: #FFFFFF; }
"); ");
gtk4::style_context_add_provider_for_display( gtk4::style_context_add_provider_for_display(
@ -382,6 +533,9 @@ fn on_add_message(ctx: Arc<Context>, ui: &UiModel, message: String) {
.margin_end(10) .margin_end(10)
.halign(Align::Start) .halign(Align::Start)
.css_classes(["message-ip"]) .css_classes(["message-ip"])
.selectable(true)
.wrap(true)
.wrap_mode(WrapMode::Char)
.build(); .build();
hbox.append(&ip); hbox.append(&ip);
@ -392,6 +546,9 @@ fn on_add_message(ctx: Arc<Context>, ui: &UiModel, message: String) {
.label(format!("[{date}]")) .label(format!("[{date}]"))
.halign(Align::Start) .halign(Align::Start)
.css_classes(["message-date"]) .css_classes(["message-date"])
.selectable(true)
.wrap(true)
.wrap_mode(WrapMode::Char)
.build(); .build();
hbox.append(&date); hbox.append(&date);
@ -421,6 +578,9 @@ fn on_add_message(ctx: Arc<Context>, ui: &UiModel, message: String) {
.label(format!("<{name}>")) .label(format!("<{name}>"))
.halign(Align::Start) .halign(Align::Start)
.css_classes(["message-name", &format!("message-name-{}", color)]) .css_classes(["message-name", &format!("message-name-{}", color)])
.selectable(true)
.wrap(true)
.wrap_mode(WrapMode::Char)
.build(); .build();
hbox.append(&name); hbox.append(&name);
@ -430,6 +590,9 @@ fn on_add_message(ctx: Arc<Context>, ui: &UiModel, message: String) {
.label(content) .label(content)
.halign(Align::Start) .halign(Align::Start)
.css_classes(["message-content"]) .css_classes(["message-content"])
.selectable(true)
.wrap(true)
.wrap_mode(WrapMode::Char)
.build(); .build();
hbox.append(&content); hbox.append(&content);
@ -438,6 +601,9 @@ fn on_add_message(ctx: Arc<Context>, ui: &UiModel, message: String) {
.label(message) .label(message)
.halign(Align::Start) .halign(Align::Start)
.css_classes(["message-content"]) .css_classes(["message-content"])
.selectable(true)
.wrap(true)
.wrap_mode(WrapMode::Char)
.build(); .build();
hbox.append(&content); hbox.append(&content);
@ -445,28 +611,40 @@ fn on_add_message(ctx: Arc<Context>, ui: &UiModel, message: String) {
ui.chat_box.append(&hbox); ui.chat_box.append(&hbox);
timeout_add_local_once(Duration::from_millis(100), move || { timeout_add_local_once(Duration::from_millis(1000), move || {
GLOBAL.with(|global| { GLOBAL.with(|global| {
if let Some((ui, _)) = &*global.borrow() { if let Some((ui, _)) = &*global.borrow() {
let o = &ui.chat_scrolled; let o = &ui.chat_scrolled;
o.vadjustment().set_value(o.vadjustment().upper() - o.vadjustment().page_size()); o.vadjustment().set_value(o.vadjustment().upper() - o.vadjustment().page_size());
} }
}); });
println!("12s3");
}); });
} }
pub fn run_main_loop(ctx: Arc<Context>) { pub fn run_main_loop(ctx: Arc<Context>) {
let application = Application::builder() let application = Application::builder()
.application_id("ru.themixray.bRAC") .application_id("ru.themixray.bRAC")
.flags(ApplicationFlags::empty())
.build(); .build();
application.connect_activate({ application.connect_activate({
let ctx = ctx.clone(); let ctx = ctx.clone();
move |app| { move |app| {
build_ui(ctx.clone(), app); let ui = build_ui(ctx.clone(), app);
setup(ctx.clone(), ui);
load_css();
} }
}); });
application.run(); application.connect_startup({
let ctx = ctx.clone();
move |app| {
build_menu(ctx.clone(), app);
}
});
application.run_with_args::<&str>(&[]);
} }