mirror of https://github.com/Aloxaf/silicon
feat: Option to show a custom window title (#215)
closes https://github.com/Aloxaf/silicon/issues/180
This commit is contained in:
parent
21d9447caa
commit
4d15f35dee
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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, ¶ms);
|
||||
}
|
||||
|
||||
if self.round_corner {
|
||||
|
|
36
src/utils.rs
36
src/utils.rs
|
@ -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)]
|
||||
|
|
Loading…
Reference in New Issue