From 157d8924983e836884308ec13ab10323adcc54e9 Mon Sep 17 00:00:00 2001 From: 409 Date: Wed, 22 May 2024 04:55:45 +0200 Subject: [PATCH] feat: window borders --- README.md | 2 +- src/arguments.rs | 10 ++++++-- src/config.rs | 5 ++++ src/main.rs | 2 ++ src/runner/mod.rs | 65 ++++++++++++++++++++++++++++++++++------------- 5 files changed, 63 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 3225e50..df8390f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A practical application runner written in Rust. Inspired by [dmenu](https://tools.suckless.org/dmenu/) ### Features -- theming (colors, font family, font size, line spacing) +- theming (colors, font family, font size, line spacing, window border) - custom row count - prompt message - open menu on a specific display diff --git a/src/arguments.rs b/src/arguments.rs index cabe29b..d69f268 100644 --- a/src/arguments.rs +++ b/src/arguments.rs @@ -1,8 +1,8 @@ use clap::Parser; use crate::config::{ - BACKGROUND_COLOR, BACKGROUND_COLOR_ACTIVE, FONT_COLOR, FONT_COLOR_ACTIVE, FONT_POINT_SIZE, - LINE_SPACING, MAX_ITEM_DISPLAY_COUNT, + BACKGROUND_COLOR, BACKGROUND_COLOR_ACTIVE, BORDER_COLOR, BORDER_SIZE, FONT_COLOR, + FONT_COLOR_ACTIVE, FONT_POINT_SIZE, LINE_SPACING, MAX_ITEM_DISPLAY_COUNT, }; #[derive(Parser, Debug)] @@ -20,6 +20,12 @@ pub struct Arguments { #[arg(long, help = "The font color of the active item", default_value_t = String::from(FONT_COLOR_ACTIVE))] pub font_color_active: String, + #[arg(long, help = "The window border color", default_value_t = String::from(BORDER_COLOR))] + pub border_color: String, + + #[arg(long, help = "The window border size in pixels", default_value_t = BORDER_SIZE)] + pub border_size: u8, + #[arg(long, help = "The default background color", default_value_t = String::from(BACKGROUND_COLOR))] pub background_color: String, diff --git a/src/config.rs b/src/config.rs index 3f0de79..d2607ac 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,9 +9,14 @@ pub const FONT_COLOR_ACTIVE: &str = "#1e1e2e"; pub const BACKGROUND_COLOR: &str = "#1e1e2e"; pub const BACKGROUND_COLOR_ACTIVE: &str = "#89b4fa"; +pub const BORDER_SIZE: u8 = 1; +pub const BORDER_COLOR: &str = "#585b70"; + pub struct RunnerMenuSettings { pub font_color: String, pub font_color_active: String, + pub border_color: String, + pub border_size: u8, pub background_color: String, pub background_color_active: String, pub rows: u16, diff --git a/src/main.rs b/src/main.rs index 893cafa..0c739b1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,6 +27,8 @@ fn main() -> Result<(), Box> { font: args.font, font_color: args.font_color, font_color_active: args.font_color_active, + border_color: args.border_color, + border_size: args.border_size, background_color: args.background_color, background_color_active: args.background_color_active, rows: args.rows, diff --git a/src/runner/mod.rs b/src/runner/mod.rs index a264502..918b4e7 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -5,7 +5,7 @@ use sdl2::{ event::Event, keyboard::{Keycode, Mod}, rect::Rect, - render::Canvas, + render::{Canvas, WindowCanvas}, ttf, video::Window, Sdl, @@ -36,7 +36,7 @@ impl Runner { let font_path: String; let (window_width, window_height): (u32, u32); - window_width = 480; + window_width = 480 + (settings.border_size * 2) as u32; { font_path = get_font_path(match settings.font { @@ -52,7 +52,8 @@ impl Runner { window_height = (PADDING + ((font.height() as u16 + settings.line_spacing) * (1 + settings.rows)) - settings.line_spacing.div_euclid(2) - + PADDING) + + PADDING + + (settings.border_size * 2) as u16) .into(); } @@ -125,6 +126,8 @@ impl Runner { let font_color = color_from_hex(&self.settings.font_color).unwrap(); let font_color_active = color_from_hex(&self.settings.font_color_active).unwrap(); + let border_color = color_from_hex(&self.settings.border_color).unwrap(); + let font = self .ttf .load_font(&self.font_path, self.settings.font_size) @@ -137,6 +140,8 @@ impl Runner { 'run: loop { self.canvas.set_draw_color(background_color); self.canvas.clear(); + self.canvas.set_draw_color(border_color); + draw_borders(self.settings.border_size, self.window_size, &mut self.canvas); for event in event_pump.poll_iter() { match event { @@ -222,8 +227,10 @@ impl Runner { } } - let mut cursor_offset_x = PADDING; - let input_position_y: u16 = (PADDING + self.settings.line_spacing.div_ceil(4)).into(); + let mut cursor_offset_x = PADDING + self.settings.border_size as u16; + let input_position_y: u16 = (PADDING + self.settings.border_size as u16 - 1 + + self.settings.line_spacing.div_ceil(4)) + .into(); if !self.input.is_empty() || !self.prompt.is_empty() { let surface = font @@ -232,7 +239,7 @@ impl Runner { .expect("Error rendering text"); let rect = Rect::new( - PADDING.into(), + (PADDING + self.settings.border_size as u16).into(), input_position_y.into(), surface.width(), surface.height(), @@ -247,15 +254,17 @@ impl Runner { let _ = self.canvas.copy(&texture, None, Some(rect)); } - let cursor_rect = Rect::new( - cursor_offset_x.into(), - input_position_y.into(), - 3, - font.height() as u32, - ); + if self.canvas.window().has_input_focus() { + let cursor_rect = Rect::new( + cursor_offset_x.into(), + input_position_y.into(), + 3, + font.height() as u32, + ); - self.canvas.set_draw_color(background_color_active); - let _ = self.canvas.fill_rect(cursor_rect); + self.canvas.set_draw_color(background_color_active); + let _ = self.canvas.fill_rect(cursor_rect); + } // try to keep the selection centered let executables_len: u16 = filtered_executables.len() as u16; @@ -270,7 +279,8 @@ impl Runner { let mut display_count: u16 = 0; for i in start..end { - let offset = PADDING * 2 + let offset = self.settings.border_size as u16 + + PADDING * 2 + (font.height() as u16 + self.settings.line_spacing) * (display_count + 1); let surface = font @@ -283,16 +293,16 @@ impl Runner { .expect("Error rendering text"); let rect = Rect::new( - PADDING.into(), + (self.settings.border_size as u16 + PADDING).into(), offset.into(), surface.width(), surface.height(), ); let background_rect = Rect::new( - 0, + self.settings.border_size.into(), (offset - half_line_spacing).into(), - self.window_size.0, + self.window_size.0 - (self.settings.border_size as u32) * 2, (surface.height() + self.settings.line_spacing as u32).into(), ); @@ -340,3 +350,22 @@ fn filter_executables( filtered_executables.sort_by(|a, b| b.starts_with(input).cmp(&a.starts_with(input))); } + +fn draw_borders(border_size: u8, window_size: (u32, u32), canvas: &mut WindowCanvas) { + if border_size > 0 { + let _ = canvas.fill_rect(Rect::new(0, 0, window_size.0, border_size.into())); + let _ = canvas.fill_rect(Rect::new( + (window_size.0 - border_size as u32) as i32, + 0, + border_size.into(), + window_size.1, + )); + let _ = canvas.fill_rect(Rect::new( + 0, + (window_size.1 - border_size as u32) as i32, + window_size.0, + border_size.into(), + )); + let _ = canvas.fill_rect(Rect::new(0, 0, border_size.into(), window_size.1)); + } +}