This commit is contained in:
Mike Dilger 2023-01-16 20:24:58 +13:00
parent c3e9f8b51f
commit 8703bbbf19
8 changed files with 82 additions and 12 deletions

View File

@ -10,7 +10,7 @@ use crate::signer::Signer;
use nostr_types::{Event, Id, PublicKeyHex, Url}; use nostr_types::{Event, Id, PublicKeyHex, Url};
use rusqlite::Connection; use rusqlite::Connection;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::sync::atomic::AtomicBool; use std::sync::atomic::{AtomicBool, AtomicU32};
use tokio::sync::{broadcast, mpsc, Mutex, RwLock}; use tokio::sync::{broadcast, mpsc, Mutex, RwLock};
/// Only one of these is ever created, via lazy_static!, and represents /// Only one of these is ever created, via lazy_static!, and represents
@ -73,6 +73,8 @@ pub struct Globals {
/// Failed Avatar Fetches /// Failed Avatar Fetches
pub failed_avatars: RwLock<HashSet<PublicKeyHex>>, pub failed_avatars: RwLock<HashSet<PublicKeyHex>>,
pub pixels_per_point_times_100: AtomicU32,
/// UI status message /// UI status message
pub status_message: RwLock<String>, pub status_message: RwLock<String>,
@ -106,6 +108,7 @@ lazy_static! {
feed: Feed::new(), feed: Feed::new(),
fetcher: Fetcher::new(), fetcher: Fetcher::new(),
failed_avatars: RwLock::new(HashSet::new()), failed_avatars: RwLock::new(HashSet::new()),
pixels_per_point_times_100: AtomicU32::new(139), // 100 dpi, 1/72th inch => 1.38888
status_message: RwLock::new("Welcome to Gossip. Status messages will appear here. Click them to dismiss them.".to_owned()), status_message: RwLock::new("Welcome to Gossip. Status messages will appear here. Click them to dismiss them.".to_owned()),
pull_following_merge: AtomicBool::new(true), pull_following_merge: AtomicBool::new(true),
} }

View File

@ -28,8 +28,8 @@ use std::ops::DerefMut;
use std::{env, mem, thread}; use std::{env, mem, thread};
use tracing_subscriber::filter::EnvFilter; use tracing_subscriber::filter::EnvFilter;
pub const AVATAR_SIZE: u32 = 48; pub const AVATAR_SIZE: u32 = 64; // points, not pixels
pub const AVATAR_SIZE_F32: f32 = 48.0; pub const AVATAR_SIZE_F32: f32 = 64.0; // points, not pixels
fn main() -> Result<(), Error> { fn main() -> Result<(), Error> {
if env::var("RUST_LOG").is_err() { if env::var("RUST_LOG").is_err() {

View File

@ -310,12 +310,13 @@ impl People {
// Finish this later (spawn) // Finish this later (spawn)
let apubkeyhex = pubkeyhex.to_owned(); let apubkeyhex = pubkeyhex.to_owned();
tokio::spawn(async move { tokio::spawn(async move {
let size = AVATAR_SIZE * GLOBALS.pixels_per_point_times_100.load(std::sync::atomic::Ordering::Relaxed) / 100;
if let Ok(image) = image::load_from_memory(&bytes) { if let Ok(image) = image::load_from_memory(&bytes) {
// Note: we can't use egui_extras::image::load_image_bytes because we // Note: we can't use egui_extras::image::load_image_bytes because we
// need to force a resize // need to force a resize
let image = image.resize( let image = image.resize(
AVATAR_SIZE, size,
AVATAR_SIZE, size,
image::imageops::FilterType::Nearest, image::imageops::FilterType::Nearest,
); // DynamicImage ); // DynamicImage
let image_buffer = image.into_rgba8(); // RgbaImage (ImageBuffer) let image_buffer = image.into_rgba8(); // RgbaImage (ImageBuffer)
@ -326,7 +327,7 @@ impl People {
GLOBALS.people.avatars_temp.insert(apubkeyhex, color_image); GLOBALS.people.avatars_temp.insert(apubkeyhex, color_image);
} else if let Ok(color_image) = egui_extras::image::load_svg_bytes_with_size( } else if let Ok(color_image) = egui_extras::image::load_svg_bytes_with_size(
&bytes, &bytes,
FitTo::Size(AVATAR_SIZE, AVATAR_SIZE), FitTo::Size(size, size),
) { ) {
GLOBALS.people.avatars_temp.insert(apubkeyhex, color_image); GLOBALS.people.avatars_temp.insert(apubkeyhex, color_image);
} else { } else {

View File

@ -15,6 +15,7 @@ pub const DEFAULT_POW: u8 = 0;
pub const DEFAULT_OFFLINE: bool = false; pub const DEFAULT_OFFLINE: bool = false;
pub const DEFAULT_LIGHT_MODE: bool = true; // true = light false = dark pub const DEFAULT_LIGHT_MODE: bool = true; // true = light false = dark
pub const DEFAULT_SET_CLIENT_TAG: bool = false; pub const DEFAULT_SET_CLIENT_TAG: bool = false;
pub const DEFAULT_OVERRIDE_DPI: Option<u32> = None;
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Settings { pub struct Settings {
@ -32,6 +33,7 @@ pub struct Settings {
pub offline: bool, pub offline: bool,
pub light_mode: bool, pub light_mode: bool,
pub set_client_tag: bool, pub set_client_tag: bool,
pub override_dpi: Option<u32>,
} }
impl Default for Settings { impl Default for Settings {
@ -51,6 +53,7 @@ impl Default for Settings {
offline: DEFAULT_OFFLINE, offline: DEFAULT_OFFLINE,
light_mode: DEFAULT_LIGHT_MODE, light_mode: DEFAULT_LIGHT_MODE,
set_client_tag: DEFAULT_SET_CLIENT_TAG, set_client_tag: DEFAULT_SET_CLIENT_TAG,
override_dpi: DEFAULT_OVERRIDE_DPI,
} }
} }
} }
@ -107,6 +110,16 @@ impl Settings {
"offline" => settings.offline = numstr_to_bool(row.1), "offline" => settings.offline = numstr_to_bool(row.1),
"light_mode" => settings.light_mode = numstr_to_bool(row.1), "light_mode" => settings.light_mode = numstr_to_bool(row.1),
"set_client_tag" => settings.set_client_tag = numstr_to_bool(row.1), "set_client_tag" => settings.set_client_tag = numstr_to_bool(row.1),
"override_dpi" => {
if row.1=="" {
settings.override_dpi = DEFAULT_OVERRIDE_DPI;
} else {
settings.override_dpi = match row.1.parse::<u32>() {
Ok(number) => Some(number),
_ => DEFAULT_OVERRIDE_DPI
};
}
},
_ => {} _ => {}
} }
} }
@ -139,7 +152,8 @@ impl Settings {
('pow', ?),\ ('pow', ?),\
('offline', ?),\ ('offline', ?),\
('light_mode', ?),\ ('light_mode', ?),\
('set_client_tag', ?)", ('set_client_tag', ?),\
('override_dpi', ?)",
)?; )?;
stmt.execute(( stmt.execute((
self.feed_chunk, self.feed_chunk,
@ -154,6 +168,7 @@ impl Settings {
bool_to_numstr(self.offline), bool_to_numstr(self.offline),
bool_to_numstr(self.light_mode), bool_to_numstr(self.light_mode),
bool_to_numstr(self.set_client_tag), bool_to_numstr(self.set_client_tag),
self.override_dpi,
))?; ))?;
// Save private key identity // Save private key identity

View File

@ -1,4 +1,5 @@
use super::{GossipUi, Page}; use super::{GossipUi, Page};
use crate::AVATAR_SIZE_F32;
use crate::comms::ToOverlordMessage; use crate::comms::ToOverlordMessage;
use crate::feed::FeedKind; use crate::feed::FeedKind;
use crate::globals::{Globals, GLOBALS}; use crate::globals::{Globals, GLOBALS};
@ -10,6 +11,7 @@ use egui::{
}; };
use linkify::{LinkFinder, LinkKind}; use linkify::{LinkFinder, LinkKind};
use nostr_types::{Event, EventKind, Id, IdHex, Tag}; use nostr_types::{Event, EventKind, Id, IdHex, Tag};
use std::sync::atomic::Ordering;
struct FeedPostParams { struct FeedPostParams {
id: Id, id: Id,
@ -442,13 +444,14 @@ fn render_post_actual(
} else { } else {
app.placeholder_avatar.clone() app.placeholder_avatar.clone()
}; };
let size = AVATAR_SIZE_F32 * GLOBALS.pixels_per_point_times_100.load(Ordering::Relaxed) as f32 / 100.0;
if ui if ui
.add( .add(
Image::new( Image::new(
&avatar, &avatar,
Vec2 { Vec2 {
x: crate::AVATAR_SIZE_F32, x: size,
y: crate::AVATAR_SIZE_F32, y: size,
}, },
) )
.sense(Sense::click()), .sense(Sense::click()),

View File

@ -21,6 +21,7 @@ use egui::{
}; };
use nostr_types::{Id, IdHex, PublicKey, PublicKeyHex, Tag}; use nostr_types::{Id, IdHex, PublicKey, PublicKeyHex, Tag};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::atomic::Ordering;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use zeroize::Zeroize; use zeroize::Zeroize;
@ -90,6 +91,8 @@ struct GossipUi {
avatars: HashMap<PublicKeyHex, TextureHandle>, avatars: HashMap<PublicKeyHex, TextureHandle>,
new_relay_url: String, new_relay_url: String,
tag_re: regex::Regex, tag_re: regex::Regex,
override_dpi: bool,
override_dpi_value: u32,
} }
impl Drop for GossipUi { impl Drop for GossipUi {
@ -100,9 +103,24 @@ impl Drop for GossipUi {
impl GossipUi { impl GossipUi {
fn new(cctx: &eframe::CreationContext<'_>) -> Self { fn new(cctx: &eframe::CreationContext<'_>) -> Self {
// grab settings to determine whether to render dark_mode or light_mode
let settings = GLOBALS.settings.blocking_read().clone(); let settings = GLOBALS.settings.blocking_read().clone();
if let Some(dpi) = settings.override_dpi {
let ppt: f32 = dpi as f32 / 72.0;
cctx.egui_ctx.set_pixels_per_point(ppt);
} else if let Some(ppt) = cctx.integration_info.native_pixels_per_point {
cctx.egui_ctx.set_pixels_per_point(ppt);
}
tracing::debug!("Pixels per point: {}", cctx.egui_ctx.pixels_per_point());
// Set global pixels_per_point_times_100, used for image scaling.
GLOBALS.pixels_per_point_times_100.store(
(cctx.egui_ctx.pixels_per_point() * 100.0) as u32,
Ordering::Relaxed
);
if !settings.light_mode { if !settings.light_mode {
cctx.egui_ctx.set_visuals(style::dark_mode_visuals()); cctx.egui_ctx.set_visuals(style::dark_mode_visuals());
} else { } else {
@ -141,6 +159,12 @@ impl GossipUi {
) )
}; };
let current_dpi = (cctx.egui_ctx.pixels_per_point() * 72.0) as u32;
let (override_dpi, override_dpi_value): (bool, u32) = match settings.override_dpi {
Some(v) => (true, v),
None => (false, current_dpi)
};
GossipUi { GossipUi {
next_frame: Instant::now(), next_frame: Instant::now(),
page: Page::Feed(FeedKind::General), page: Page::Feed(FeedKind::General),
@ -164,6 +188,8 @@ impl GossipUi {
avatars: HashMap::new(), avatars: HashMap::new(),
new_relay_url: "".to_owned(), new_relay_url: "".to_owned(),
tag_re: regex::Regex::new(r"(\#\[\d+\])").unwrap(), tag_re: regex::Regex::new(r"(\#\[\d+\])").unwrap(),
override_dpi,
override_dpi_value,
} }
} }

View File

@ -1,9 +1,11 @@
use super::{GossipUi, Page}; use super::{GossipUi, Page};
use crate::AVATAR_SIZE_F32;
use crate::comms::ToOverlordMessage; use crate::comms::ToOverlordMessage;
use crate::db::DbPerson; use crate::db::DbPerson;
use crate::globals::GLOBALS; use crate::globals::GLOBALS;
use eframe::egui; use eframe::egui;
use egui::{Context, Image, RichText, ScrollArea, Sense, Ui, Vec2}; use egui::{Context, Image, RichText, ScrollArea, Sense, Ui, Vec2};
use std::sync::atomic::Ordering;
mod follow; mod follow;
mod person; mod person;
@ -71,13 +73,14 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Fra
} else { } else {
app.placeholder_avatar.clone() app.placeholder_avatar.clone()
}; };
let size = AVATAR_SIZE_F32 * GLOBALS.pixels_per_point_times_100.load(Ordering::Relaxed) as f32 / 100.0;
if ui if ui
.add( .add(
Image::new( Image::new(
&avatar, &avatar,
Vec2 { Vec2 {
x: crate::AVATAR_SIZE_F32, x: size,
y: crate::AVATAR_SIZE_F32, y: size,
}, },
) )
.sense(Sense::click()), .sense(Sense::click()),

View File

@ -134,6 +134,25 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr
} }
}); });
ui.horizontal(|ui| {
ui.label("Override DPI: ")
.on_hover_text(
"On some systems, DPI is not reported properly. In other cases, people like to zoom in or out. This lets you.",
);
ui.checkbox(
&mut app.override_dpi,
"Override to ");
ui.add(Slider::new(&mut app.override_dpi_value, 72..=250).text("DPI"));
// set real setting if changed
app.settings.override_dpi = if app.override_dpi {
Some(app.override_dpi_value)
} else {
None
};
});
ui.add_space(12.0); ui.add_space(12.0);
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label("Maximum FPS: ") ui.label("Maximum FPS: ")