feat: Option to show a custom window title (#215)

closes https://github.com/Aloxaf/silicon/issues/180
This commit is contained in:
Marco Pinto 2022-11-14 01:36:15 +00:00 committed by GitHub
parent 21d9447caa
commit 4d15f35dee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 105 additions and 22 deletions

View File

@ -120,6 +120,12 @@ The color can be `#RGB[A]` or `#RRGGBB[AA]`
silicon ./target/test.rs -o test.png --background '#fff0'
```
Show window title
```bash
silicon ./target/test.rs -o test.png --window-title "target/test.rs"
```
see `silicon --help` for detail
## Adding new syntaxes / themes

View File

@ -150,6 +150,10 @@ pub struct Config {
#[structopt(long)]
pub no_window_controls: bool,
/// Show window title
#[structopt(long, value_name = "WINDOW_TITLE")]
pub window_title: Option<String>,
/// Hide the line number.
#[structopt(long)]
pub no_line_number: bool,
@ -269,10 +273,10 @@ impl Config {
let formatter = ImageFormatterBuilder::new()
.line_pad(self.line_pad)
.window_controls(!self.no_window_controls)
.window_title(self.window_title.clone())
.line_number(!self.no_line_number)
.font(self.font.clone().unwrap_or_default())
.round_corner(!self.no_round_corner)
.window_controls(!self.no_window_controls)
.shadow_adder(self.get_shadow_adder()?)
.tab_width(self.tab_width)
.highlight_lines(self.highlight_lines.clone().unwrap_or_default())

View File

@ -15,6 +15,19 @@ pub struct ImageFormatter {
/// pad of top of the code area
/// Default: 50
code_pad_top: u32,
/// Title bar padding
/// Default: 15
title_bar_pad: u32,
/// Whether to show window controls or not
window_controls: bool,
/// Width for window controls
/// Default: 120
window_controls_width: u32,
/// Height for window controls
/// Default: 40
window_controls_height: u32,
/// Window title
window_title: Option<String>,
/// show line number
/// Default: true
line_number: bool,
@ -52,6 +65,8 @@ pub struct ImageFormatterBuilder<S> {
highlight_lines: Vec<u32>,
/// Whether show the window controls
window_controls: bool,
/// Window title
window_title: Option<String>,
/// Whether round the corner of the image
round_corner: bool,
/// Shadow adder,
@ -69,6 +84,7 @@ impl<S: AsRef<str> + Default> ImageFormatterBuilder<S> {
line_pad: 2,
line_number: true,
window_controls: true,
window_title: None,
round_corner: true,
tab_width: 4,
..Default::default()
@ -105,6 +121,12 @@ impl<S: AsRef<str> + Default> ImageFormatterBuilder<S> {
self
}
/// Window title
pub fn window_title(mut self, title: Option<String>) -> Self {
self.window_title = title;
self
}
/// Whether round the corner
pub fn round_corner(mut self, b: bool) -> Self {
self.round_corner = b;
@ -136,11 +158,17 @@ impl<S: AsRef<str> + Default> ImageFormatterBuilder<S> {
FontCollection::new(&self.font)?
};
let code_pad_top = if self.window_controls { 50 } else { 0 };
let title_bar = self.window_controls || self.window_title.is_some();
Ok(ImageFormatter {
line_pad: self.line_pad,
code_pad: 25,
code_pad_top: if title_bar { 50 } else { 0 },
title_bar_pad: 15,
window_controls: self.window_controls,
window_controls_width: 120,
window_controls_height: 40,
window_title: self.window_title,
line_number: self.line_number,
line_number_pad: 6,
line_number_chars: 0,
@ -148,7 +176,6 @@ impl<S: AsRef<str> + Default> ImageFormatterBuilder<S> {
round_corner: self.round_corner,
shadow_adder: self.shadow_adder,
tab_width: self.tab_width,
code_pad_top,
font,
line_offset: self.line_offset,
})
@ -161,7 +188,7 @@ struct Drawable {
/// max number of line of the picture
max_lineno: u32,
/// arguments for draw_text_mut
drawables: Vec<(u32, u32, Color, FontStyle, String)>,
drawables: Vec<(u32, u32, Option<Color>, FontStyle, String)>,
}
impl ImageFormatter {
@ -214,7 +241,7 @@ impl ImageFormatter {
drawables.push((
width,
height,
style.foreground,
Some(style.foreground),
style.font_style.into(),
text.to_owned(),
));
@ -226,6 +253,29 @@ impl ImageFormatter {
max_lineno = i as u32;
}
if self.window_title.is_some() {
let title = self.window_title.as_ref().unwrap();
let title_width = self.font.get_text_len(title);
let ctrls_offset = if self.window_controls {
self.window_controls_width + self.title_bar_pad
} else {
0
};
let ctrls_center = self.window_controls_height / 2;
drawables.push((
ctrls_offset + self.title_bar_pad,
self.title_bar_pad + ctrls_center - self.font.get_font_height() / 2,
None,
FontStyle::BOLD,
title.to_string(),
));
let title_bar_width = ctrls_offset + title_width + self.title_bar_pad * 2;
max_width = max_width.max(title_bar_width);
}
Drawable {
max_width,
max_lineno,
@ -288,10 +338,8 @@ impl ImageFormatter {
let foreground = theme.settings.foreground.unwrap();
let background = theme.settings.background.unwrap();
let foreground = foreground.to_rgba();
let background = background.to_rgba();
let mut image = DynamicImage::ImageRgba8(RgbaImage::from_pixel(size.0, size.1, background));
let mut image =
DynamicImage::ImageRgba8(RgbaImage::from_pixel(size.0, size.1, background.to_rgba()));
if !self.highlight_lines.is_empty() {
let highlight_lines = self
@ -302,18 +350,23 @@ impl ImageFormatter {
self.highlight_lines(&mut image, highlight_lines);
}
if self.line_number {
self.draw_line_number(&mut image, drawables.max_lineno, foreground);
self.draw_line_number(&mut image, drawables.max_lineno, foreground.to_rgba());
}
for (x, y, color, style, text) in drawables.drawables {
let color = color.to_rgba();
let color = color.unwrap_or(foreground).to_rgba();
self.font
.draw_text_mut(&mut image, color, x, y, style, &text);
}
// draw_window_controls == true
if self.code_pad_top != 0 {
add_window_controls(&mut image);
if self.window_controls {
let params = WindowControlsParams {
width: self.window_controls_width,
height: self.window_controls_height,
padding: self.title_bar_pad,
radius: self.window_controls_width / 3 / 4,
};
add_window_controls(&mut image, &params);
}
if self.round_corner {

View File

@ -66,8 +66,15 @@ impl ToRgba for syntect::highlighting::Color {
}
}
pub struct WindowControlsParams {
pub width: u32,
pub height: u32,
pub padding: u32,
pub radius: u32,
}
/// Add the window controls for image
pub(crate) fn add_window_controls(image: &mut DynamicImage) {
pub(crate) fn add_window_controls(image: &mut DynamicImage, params: &WindowControlsParams) {
let color = [
("#FF5F56", "#E0443E"),
("#FFBD2E", "#DEA123"),
@ -77,27 +84,40 @@ pub(crate) fn add_window_controls(image: &mut DynamicImage) {
let mut background = image.get_pixel(37, 37);
background.0[3] = 0;
let mut title_bar = RgbaImage::from_pixel(120 * 3, 40 * 3, background);
let mut title_bar = RgbaImage::from_pixel(params.width * 3, params.height * 3, background);
let step = (params.radius * 2) as i32;
let spacer = (step * 2) as i32;
let center_y = (params.height / 2) as i32;
for (i, (fill, outline)) in color.iter().enumerate() {
draw_filled_circle_mut(
&mut title_bar,
(((i * 40) as i32 + 20) * 3, 20 * 3),
11 * 3,
((i as i32 * spacer + step) * 3, center_y * 3),
(params.radius + 1) as i32 * 3,
outline.to_rgba().unwrap(),
);
draw_filled_circle_mut(
&mut title_bar,
(((i * 40) as i32 + 20) * 3, 20 * 3),
10 * 3,
((i as i32 * spacer + step) * 3, center_y * 3),
params.radius as i32 * 3,
fill.to_rgba().unwrap(),
);
}
// create a big image and resize it to blur the edge
// it looks better than `blur()`
let title_bar = resize(&title_bar, 120, 40, FilterType::Triangle);
let title_bar = resize(
&title_bar,
params.width,
params.height,
FilterType::Triangle,
);
copy_alpha(&title_bar, image.as_mut_rgba8().unwrap(), 15, 15);
copy_alpha(
&title_bar,
image.as_mut_rgba8().unwrap(),
params.padding,
params.padding,
);
}
#[derive(Clone, Debug)]