feat: window borders
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
A practical application runner written in Rust. Inspired by [dmenu](https://tools.suckless.org/dmenu/)
|
A practical application runner written in Rust. Inspired by [dmenu](https://tools.suckless.org/dmenu/)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
- theming (colors, font family, font size, line spacing)
|
- theming (colors, font family, font size, line spacing, window border)
|
||||||
- custom row count
|
- custom row count
|
||||||
- prompt message
|
- prompt message
|
||||||
- open menu on a specific display
|
- open menu on a specific display
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
use crate::config::{
|
use crate::config::{
|
||||||
BACKGROUND_COLOR, BACKGROUND_COLOR_ACTIVE, FONT_COLOR, FONT_COLOR_ACTIVE, FONT_POINT_SIZE,
|
BACKGROUND_COLOR, BACKGROUND_COLOR_ACTIVE, BORDER_COLOR, BORDER_SIZE, FONT_COLOR,
|
||||||
LINE_SPACING, MAX_ITEM_DISPLAY_COUNT,
|
FONT_COLOR_ACTIVE, FONT_POINT_SIZE, LINE_SPACING, MAX_ITEM_DISPLAY_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[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))]
|
#[arg(long, help = "The font color of the active item", default_value_t = String::from(FONT_COLOR_ACTIVE))]
|
||||||
pub font_color_active: String,
|
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))]
|
#[arg(long, help = "The default background color", default_value_t = String::from(BACKGROUND_COLOR))]
|
||||||
pub background_color: String,
|
pub background_color: String,
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,14 @@ pub const FONT_COLOR_ACTIVE: &str = "#1e1e2e";
|
|||||||
pub const BACKGROUND_COLOR: &str = "#1e1e2e";
|
pub const BACKGROUND_COLOR: &str = "#1e1e2e";
|
||||||
pub const BACKGROUND_COLOR_ACTIVE: &str = "#89b4fa";
|
pub const BACKGROUND_COLOR_ACTIVE: &str = "#89b4fa";
|
||||||
|
|
||||||
|
pub const BORDER_SIZE: u8 = 1;
|
||||||
|
pub const BORDER_COLOR: &str = "#585b70";
|
||||||
|
|
||||||
pub struct RunnerMenuSettings {
|
pub struct RunnerMenuSettings {
|
||||||
pub font_color: String,
|
pub font_color: String,
|
||||||
pub font_color_active: String,
|
pub font_color_active: String,
|
||||||
|
pub border_color: String,
|
||||||
|
pub border_size: u8,
|
||||||
pub background_color: String,
|
pub background_color: String,
|
||||||
pub background_color_active: String,
|
pub background_color_active: String,
|
||||||
pub rows: u16,
|
pub rows: u16,
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
font: args.font,
|
font: args.font,
|
||||||
font_color: args.font_color,
|
font_color: args.font_color,
|
||||||
font_color_active: args.font_color_active,
|
font_color_active: args.font_color_active,
|
||||||
|
border_color: args.border_color,
|
||||||
|
border_size: args.border_size,
|
||||||
background_color: args.background_color,
|
background_color: args.background_color,
|
||||||
background_color_active: args.background_color_active,
|
background_color_active: args.background_color_active,
|
||||||
rows: args.rows,
|
rows: args.rows,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use sdl2::{
|
|||||||
event::Event,
|
event::Event,
|
||||||
keyboard::{Keycode, Mod},
|
keyboard::{Keycode, Mod},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::Canvas,
|
render::{Canvas, WindowCanvas},
|
||||||
ttf,
|
ttf,
|
||||||
video::Window,
|
video::Window,
|
||||||
Sdl,
|
Sdl,
|
||||||
@@ -36,7 +36,7 @@ impl Runner {
|
|||||||
|
|
||||||
let font_path: String;
|
let font_path: String;
|
||||||
let (window_width, window_height): (u32, u32);
|
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 {
|
font_path = get_font_path(match settings.font {
|
||||||
@@ -52,7 +52,8 @@ impl Runner {
|
|||||||
window_height = (PADDING
|
window_height = (PADDING
|
||||||
+ ((font.height() as u16 + settings.line_spacing) * (1 + settings.rows))
|
+ ((font.height() as u16 + settings.line_spacing) * (1 + settings.rows))
|
||||||
- settings.line_spacing.div_euclid(2)
|
- settings.line_spacing.div_euclid(2)
|
||||||
+ PADDING)
|
+ PADDING
|
||||||
|
+ (settings.border_size * 2) as u16)
|
||||||
.into();
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,6 +126,8 @@ impl Runner {
|
|||||||
let font_color = color_from_hex(&self.settings.font_color).unwrap();
|
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 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
|
let font = self
|
||||||
.ttf
|
.ttf
|
||||||
.load_font(&self.font_path, self.settings.font_size)
|
.load_font(&self.font_path, self.settings.font_size)
|
||||||
@@ -137,6 +140,8 @@ impl Runner {
|
|||||||
'run: loop {
|
'run: loop {
|
||||||
self.canvas.set_draw_color(background_color);
|
self.canvas.set_draw_color(background_color);
|
||||||
self.canvas.clear();
|
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() {
|
for event in event_pump.poll_iter() {
|
||||||
match event {
|
match event {
|
||||||
@@ -222,8 +227,10 @@ impl Runner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cursor_offset_x = PADDING;
|
let mut cursor_offset_x = PADDING + self.settings.border_size as u16;
|
||||||
let input_position_y: u16 = (PADDING + self.settings.line_spacing.div_ceil(4)).into();
|
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() {
|
if !self.input.is_empty() || !self.prompt.is_empty() {
|
||||||
let surface = font
|
let surface = font
|
||||||
@@ -232,7 +239,7 @@ impl Runner {
|
|||||||
.expect("Error rendering text");
|
.expect("Error rendering text");
|
||||||
|
|
||||||
let rect = Rect::new(
|
let rect = Rect::new(
|
||||||
PADDING.into(),
|
(PADDING + self.settings.border_size as u16).into(),
|
||||||
input_position_y.into(),
|
input_position_y.into(),
|
||||||
surface.width(),
|
surface.width(),
|
||||||
surface.height(),
|
surface.height(),
|
||||||
@@ -247,6 +254,7 @@ impl Runner {
|
|||||||
let _ = self.canvas.copy(&texture, None, Some(rect));
|
let _ = self.canvas.copy(&texture, None, Some(rect));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.canvas.window().has_input_focus() {
|
||||||
let cursor_rect = Rect::new(
|
let cursor_rect = Rect::new(
|
||||||
cursor_offset_x.into(),
|
cursor_offset_x.into(),
|
||||||
input_position_y.into(),
|
input_position_y.into(),
|
||||||
@@ -256,6 +264,7 @@ impl Runner {
|
|||||||
|
|
||||||
self.canvas.set_draw_color(background_color_active);
|
self.canvas.set_draw_color(background_color_active);
|
||||||
let _ = self.canvas.fill_rect(cursor_rect);
|
let _ = self.canvas.fill_rect(cursor_rect);
|
||||||
|
}
|
||||||
|
|
||||||
// try to keep the selection centered
|
// try to keep the selection centered
|
||||||
let executables_len: u16 = filtered_executables.len() as u16;
|
let executables_len: u16 = filtered_executables.len() as u16;
|
||||||
@@ -270,7 +279,8 @@ impl Runner {
|
|||||||
let mut display_count: u16 = 0;
|
let mut display_count: u16 = 0;
|
||||||
|
|
||||||
for i in start..end {
|
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);
|
+ (font.height() as u16 + self.settings.line_spacing) * (display_count + 1);
|
||||||
|
|
||||||
let surface = font
|
let surface = font
|
||||||
@@ -283,16 +293,16 @@ impl Runner {
|
|||||||
.expect("Error rendering text");
|
.expect("Error rendering text");
|
||||||
|
|
||||||
let rect = Rect::new(
|
let rect = Rect::new(
|
||||||
PADDING.into(),
|
(self.settings.border_size as u16 + PADDING).into(),
|
||||||
offset.into(),
|
offset.into(),
|
||||||
surface.width(),
|
surface.width(),
|
||||||
surface.height(),
|
surface.height(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let background_rect = Rect::new(
|
let background_rect = Rect::new(
|
||||||
0,
|
self.settings.border_size.into(),
|
||||||
(offset - half_line_spacing).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(),
|
(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)));
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user