diff --git a/audio/src/export/export_type.rs b/audio/src/export/export_type.rs index 4e3fcc7a..406cf884 100644 --- a/audio/src/export/export_type.rs +++ b/audio/src/export/export_type.rs @@ -2,7 +2,7 @@ use common::open_file::Extension; use serde::{Deserialize, Serialize}; /// This determines what we're exporting to. -#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize, Serialize, Default)] +#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize, Serialize, Default, Hash)] pub enum ExportType { #[default] Wav, diff --git a/changelog.md b/changelog.md index 16d90c34..48d949a1 100644 --- a/changelog.md +++ b/changelog.md @@ -8,6 +8,7 @@ These are the optimizations: - In `audio`, `Synthesizer` (which no longer exists) ran a very fast infinite loop to send samples to `Player`, and the loop needlessly consumed CPU resources. I replaced this loop with a bunch of `Arc>` values that are shared between `Conn` and `Player`. As a result of removing `Synthesizer` I had to reorganize all of the exporter code. There are a lot of small changes that I'm not going to list here because let's be real, no one reads verbose changelogs, but the most noticeable change is that `Exporter` is a field in `Conn` and is no longer shared (there is no `Arc>` anywhere in the code). This change affects a *lot* of the codebase, but it's mostly just refactoring with zero functional differences. - In `input`, `Input` checked for key downs and presses very inefficently. I only had to change two lines of code to make it much faster. This optimizes CPU usage by roughly 10%. +- A tiny optimization to drawing panel backgrounds. This required refactoring throughout `render`. I think that there are more tiny optimizations that could be made in `render` that cumulatively might make more of a difference. This update doesn't have any new features or bug fixes. In the future, I'm going to reserve major releases (0.x.0) for big new features, but I had to rewrite so much of Cacophony's code, and the results are such a big improvement, that I'm making this a major release anyway. diff --git a/render/src/export_panel.rs b/render/src/export_panel.rs index 9aaa4bb2..aa59fb84 100644 --- a/render/src/export_panel.rs +++ b/render/src/export_panel.rs @@ -14,29 +14,29 @@ pub(crate) struct ExportPanel { } impl ExportPanel { - pub fn new(config: &Ini, text: &Text) -> Self { + pub fn new(config: &Ini, renderer: &Renderer, text: &Text) -> Self { let window_grid_size = get_window_grid_size(config); let h: u32 = 3; let y = window_grid_size[1] / 2 - 1; let w = window_grid_size[0] / 4; let x = window_grid_size[0] / 2 - w / 2; - let panel = Panel::new(PanelType::ExportState, [x, y], [w, h], text); + let position = [x, y]; + let size = [w, h]; + let panel = Panel::new(PanelType::ExportState, position, size, renderer, text); let popup = Popup::new(PanelType::ExportState); let decaying = text.get("EXPORT_PANEL_APPENDING_DECAY"); let decaying_label = Label::new( [ - panel.rect.position[0] + panel.rect.size[0] / 2 - - decaying.chars().count() as u32 / 2, - panel.rect.position[1] + 1, + position[0] + size[0] / 2 - decaying.chars().count() as u32 / 2, + position[1] + 1, ], decaying, ); let writing = text.get("EXPORT_PANEL_WRITING"); let writing_label = Label::new( [ - panel.rect.position[0] + panel.rect.size[0] / 2 - - writing.chars().count() as u32 / 2, - panel.rect.position[1] + 1, + position[0] + size[0] / 2 - writing.chars().count() as u32 / 2, + position[1] + 1, ], writing, ); @@ -63,8 +63,10 @@ impl Drawable for ExportPanel { let samples = format!("{}/{}", exported_samples, total_samples); // Draw the string. let w = samples.chars().count() as u32; - let x = self.panel.rect.position[0] + self.panel.rect.size[0] / 2 - w / 2; - let y = self.panel.rect.position[1] + 1; + let x = self.panel.background.grid_rect.position[0] + + self.panel.background.grid_rect.size[0] / 2 + - w / 2; + let y = self.panel.background.grid_rect.position[1] + 1; let label = Label { position: [x, y], text: samples, diff --git a/render/src/export_settings_panel.rs b/render/src/export_settings_panel.rs index 0a3f245d..56f7c3b1 100644 --- a/render/src/export_settings_panel.rs +++ b/render/src/export_settings_panel.rs @@ -3,6 +3,7 @@ use crate::Focus; use audio::export::{ExportSetting, ExportType, MultiFileSuffix}; use audio::exporter::{Exporter, MP3_BIT_RATES}; use common::IndexedValues; +use hashbrown::HashMap; use serde::de::DeserializeOwned; use serde::Serialize; use text::ValueMap; @@ -10,9 +11,9 @@ use util::KV_PADDING; /// Export settings panel. pub(crate) struct ExportSettingsPanel { - /// The position of the panel. + /// The panel position. position: [u32; 2], - /// The width of the panel. + /// The panel width. width: u32, /// The title label for the panel. title: Label, @@ -26,10 +27,12 @@ pub(crate) struct ExportSettingsPanel { quality: KeyListCorners, /// String values of multi-file suffixes. multi_file_suffixes: ValueMap, + /// Panel background sizes per export type. + backgrounds: HashMap, } impl ExportSettingsPanel { - pub fn new(config: &Ini, text: &Text) -> Self { + pub fn new(config: &Ini, renderer: &Renderer, exporter: &Exporter, text: &Text) -> Self { let (open_file_position, open_file_size) = get_open_file_rect(config); let position = [ open_file_position[0], @@ -72,6 +75,49 @@ impl ExportSettingsPanel { text, ); + // Calculate the background sizes per export type. + let mut backgrounds = HashMap::new(); + backgrounds.insert( + ExportType::Wav, + PanelBackground::new( + position, + [width, exporter.wav_settings.index.get_length() as u32 + 3], + renderer, + ), + ); + backgrounds.insert( + ExportType::Mid, + PanelBackground::new( + position, + [width, exporter.mid_settings.index.get_length() as u32 + 2], + renderer, + ), + ); + backgrounds.insert( + ExportType::MP3, + PanelBackground::new( + position, + [width, exporter.mp3_settings.index.get_length() as u32 + 4], + renderer, + ), + ); + backgrounds.insert( + ExportType::Ogg, + PanelBackground::new( + position, + [width, exporter.ogg_settings.index.get_length() as u32 + 4], + renderer, + ), + ); + backgrounds.insert( + ExportType::Flac, + PanelBackground::new( + position, + [width, exporter.flac_settings.index.get_length() as u32 + 4], + renderer, + ), + ); + Self { position, width, @@ -81,6 +127,7 @@ impl ExportSettingsPanel { mp3_bit_rate, quality, multi_file_suffixes, + backgrounds, } } @@ -315,26 +362,19 @@ impl Drawable for ExportSettingsPanel { fn update(&self, renderer: &Renderer, state: &State, conn: &Conn, text: &Text, _: &PathsState) { // Get the focus. let focus = state.panels[state.focus.get()] == PanelType::ExportSettings; - // Get the height of the panel. - let e = conn.exporter.export_type.get(); - let h = match &e { - ExportType::Wav => conn.exporter.wav_settings.index.get_length() + 2, - ExportType::Mid => conn.exporter.mid_settings.index.get_length() + 1, - ExportType::MP3 => conn.exporter.mp3_settings.index.get_length() + 3, - ExportType::Ogg => conn.exporter.ogg_settings.index.get_length() + 3, - ExportType::Flac => conn.exporter.flac_settings.index.get_length() + 3, - } as u32 - + 1; - // Draw the panel. let color: ColorKey = if focus { ColorKey::FocusDefault } else { ColorKey::NoFocus }; - let rect = Rectangle::new(self.position, [self.width, h]); - renderer.rectangle(&rect, &ColorKey::Background); - renderer.border(&rect, &color); + let background = &self.backgrounds[&conn.exporter.export_type.get()]; + renderer.rectangle_pixel( + background.background.position, + background.background.size, + &color, + ); + renderer.rectangle_lines(&background.border, &color); renderer.rectangle(&self.title_rect, &ColorKey::Background); renderer.text(&self.title, &color); diff --git a/render/src/field_params.rs b/render/src/field_params.rs index f082b881..d9d78f53 100644 --- a/render/src/field_params.rs +++ b/render/src/field_params.rs @@ -7,7 +7,9 @@ mod key_width; mod label; mod label_ref; mod list; +mod panel_background; mod rectangle; +mod rectangle_pixel; pub(super) mod util; mod width; pub(crate) use boolean::Boolean; @@ -20,6 +22,8 @@ pub(crate) use label::Label; pub(crate) use label_rectangle::LabelRectangle; pub(crate) use label_ref::LabelRef; pub(crate) use list::List; +pub(crate) use panel_background::PanelBackground; pub(crate) use rectangle::Rectangle; +pub(crate) use rectangle_pixel::RectanglePixel; pub(super) use width::Width; mod label_rectangle; diff --git a/render/src/field_params/panel_background.rs b/render/src/field_params/panel_background.rs new file mode 100644 index 00000000..687debd1 --- /dev/null +++ b/render/src/field_params/panel_background.rs @@ -0,0 +1,40 @@ +use super::{Rectangle, RectanglePixel}; +use crate::Renderer; + +/// A background rectangle and a border rectangle, both in pixel units. +#[derive(Clone)] +pub(crate) struct PanelBackground { + /// The background. + pub background: RectanglePixel, + /// The border. + pub border: RectanglePixel, + /// The rectangle in grid units. + pub grid_rect: Rectangle, +} + +impl PanelBackground { + pub fn new(position: [u32; 2], size: [u32; 2], renderer: &Renderer) -> Self { + let background = RectanglePixel::new( + renderer.grid_to_pixel(position), + renderer.grid_to_pixel(size), + ); + let border = renderer.get_border_rect(position, size); + let grid_rect = Rectangle::new(position, size); + Self { + background, + border, + grid_rect, + } + } + + /// Adjust the size by a delta in grid units. + pub fn resize_by(&mut self, delta: [u32; 2], renderer: &Renderer) { + self.grid_rect.size[0] += delta[0]; + self.grid_rect.size[1] += delta[1]; + let delta = renderer.grid_to_pixel(delta); + self.background.size[0] += delta[0]; + self.background.size[1] += delta[1]; + self.border.size[0] += delta[0]; + self.border.size[1] += delta[1]; + } +} diff --git a/render/src/field_params/rectangle_pixel.rs b/render/src/field_params/rectangle_pixel.rs new file mode 100644 index 00000000..76f23bee --- /dev/null +++ b/render/src/field_params/rectangle_pixel.rs @@ -0,0 +1,14 @@ +/// A rectangle has a position and a size. +#[derive(Clone)] +pub(crate) struct RectanglePixel { + /// The position in pixel units. + pub position: [f32; 2], + /// The size in pixel units. + pub size: [f32; 2], +} + +impl RectanglePixel { + pub fn new(position: [f32; 2], size: [f32; 2]) -> Self { + Self { position, size } + } +} diff --git a/render/src/links_panel.rs b/render/src/links_panel.rs index d1d80e73..e0769bb1 100644 --- a/render/src/links_panel.rs +++ b/render/src/links_panel.rs @@ -17,7 +17,7 @@ pub(crate) struct LinksPanel { } impl LinksPanel { - pub fn new(config: &Ini, text: &Text, input: &Input) -> Self { + pub fn new(config: &Ini, renderer: &Renderer, text: &Text, input: &Input) -> Self { // Get each label. The x coordinate is right now at 0. let mut y = MAIN_MENU_HEIGHT + 1; let mut tooltips = Tooltips::default(); @@ -70,7 +70,7 @@ impl LinksPanel { discord.position[0] = label_x; github.position[0] = label_x; // Define the panel. - let panel = Panel::new(PanelType::Links, [x, y], [w, h], text); + let panel = Panel::new(PanelType::Links, [x, y], [w, h], renderer, text); let labels = [website, discord, github]; let popup = Popup::new(PanelType::Links); Self { diff --git a/render/src/main_menu.rs b/render/src/main_menu.rs index 70aff6f6..1bd47e48 100644 --- a/render/src/main_menu.rs +++ b/render/src/main_menu.rs @@ -65,9 +65,9 @@ pub(crate) struct MainMenu { impl MainMenu { pub fn new( config: &Ini, + renderer: &Renderer, input: &Input, text: &mut Text, - renderer: &Renderer, remote_version: Option, ) -> Self { // Get the width of the panel. @@ -80,6 +80,7 @@ impl MainMenu { PanelType::MainMenu, position, [width, MAIN_MENU_HEIGHT], + renderer, text, ); // Add an update notice to the title. @@ -95,8 +96,8 @@ impl MainMenu { ); // Get the fields. - let mut x = panel.rect.position[0] + 2; - let y = panel.rect.position[1] + 1; + let mut x = position[0] + 2; + let y = position[1] + 1; let help = Self::label_from_key("MAIN_MENU_HELP", &mut x, y, text); x += 4; let mut tooltips = Tooltips::default(); diff --git a/render/src/music_panel.rs b/render/src/music_panel.rs index a3fd169d..17766b2a 100644 --- a/render/src/music_panel.rs +++ b/render/src/music_panel.rs @@ -20,7 +20,7 @@ pub(crate) struct MusicPanel { } impl MusicPanel { - pub fn new(config: &Ini, text: &Text) -> Self { + pub fn new(config: &Ini, renderer: &Renderer, text: &Text) -> Self { // Get the width of the panel. let mut width = get_tracks_panel_width(config); // Get the panel. @@ -28,12 +28,13 @@ impl MusicPanel { PanelType::Music, MUSIC_PANEL_POSITION, [width, MUSIC_PANEL_HEIGHT], + renderer, text, ); // Move the (x, y) coordinates inward by 1. - let x = panel.rect.position[0] + 1; - let mut y = panel.rect.position[1] + 1; + let x = MUSIC_PANEL_POSITION[0] + 1; + let mut y = MUSIC_PANEL_POSITION[1] + 1; // Shorten the width for the fields. width -= 2; let w_usize = width as usize; diff --git a/render/src/open_file_panel.rs b/render/src/open_file_panel.rs index 1ade543a..f500bcee 100644 --- a/render/src/open_file_panel.rs +++ b/render/src/open_file_panel.rs @@ -13,7 +13,7 @@ pub(crate) struct OpenFilePanel { /// The titles for each open-file type. titles: HashMap, /// The background of the filename prompt. - prompt: Rectangle, + prompt: PanelBackground, /// The filename extension. extension: Width, /// The filename input. @@ -27,28 +27,23 @@ pub(crate) struct OpenFilePanel { } impl OpenFilePanel { - pub fn new(config: &Ini, text: &Text) -> Self { + pub fn new(config: &Ini, renderer: &Renderer, text: &Text) -> Self { let (position, size) = get_open_file_rect(config); - let panel = Panel::new(PanelType::OpenFile, position, size, text); - - let prompt = Rectangle::new( - [ - panel.rect.position[0], - panel.rect.position[1] + panel.rect.size[1], - ], - [panel.rect.size[0], OPEN_FILE_PANEL_PROMPT_HEIGHT], - ); + let panel = Panel::new(PanelType::OpenFile, position, size, renderer, text); + let prompt_position = [position[0], position[1] + size[1]]; + let prompt_size = [size[0], OPEN_FILE_PANEL_PROMPT_HEIGHT]; + let prompt = PanelBackground::new(prompt_position, prompt_size, renderer); let extension = Width::new( [ - prompt.position[0] + prompt.size[0] - EXTENSION_WIDTH - 1, - prompt.position[1] + 1, + prompt_position[0] + prompt_size[0] - EXTENSION_WIDTH - 1, + prompt_position[1] + 1, ], EXTENSION_WIDTH as usize, ); let input = Width::new( - [prompt.position[0] + 1, prompt.position[1] + 1], - (prompt.size[0] - EXTENSION_WIDTH - 3) as usize, + [prompt_position[0] + 1, prompt_position[1] + 1], + (prompt_size[0] - EXTENSION_WIDTH - 3) as usize, ); let input_rect = Rectangle::new(input.position, [input.width_u32, 1]); @@ -94,9 +89,9 @@ impl OpenFilePanel { // Get the scroll labels. let mut scroll_labels = HashMap::new(); - let panel_x = panel.rect.position[0]; - let panel_w = panel.rect.size[0]; - let label_y = panel.rect.position[1] + panel.rect.size[1] - 2; + let panel_x = position[0]; + let panel_w = size[0]; + let label_y = position[1] + size[1] - 2; scroll_labels.insert( PagePosition::First, Self::get_scroll_label("OPEN_FILE_PANEL_DOWN", text, panel_x, panel_w, label_y), @@ -109,7 +104,6 @@ impl OpenFilePanel { PagePosition::Last, Self::get_scroll_label("OPEN_FILE_PANEL_UP", text, panel_x, panel_w, label_y), ); - Self { panel, prompt, @@ -153,16 +147,20 @@ impl Drawable for OpenFilePanel { ColorKey::NoFocus }; // Draw the panel background. - renderer.rectangle(&self.panel.rect, &ColorKey::Background); - renderer.border(&self.panel.rect, &focus_color); + renderer.rectangle_pixel( + self.panel.background.background.position, + self.panel.background.background.size, + &ColorKey::Background, + ); + renderer.rectangle_lines(&self.panel.background.border, &focus_color); // Draw the title. let title = &self.titles[&paths_state.open_file_type]; renderer.rectangle(&title.rect, &ColorKey::Background); renderer.text(&title.label, &focus_color); // Draw the working directory. - let mut x = self.panel.rect.position[0] + 1; - let mut y = self.panel.rect.position[1] + 1; - let mut length = (self.panel.rect.size[0] - 2) as usize; + let mut x = self.panel.background.grid_rect.position[0] + 1; + let mut y = self.panel.background.grid_rect.position[1] + 1; + let mut length = (self.panel.background.grid_rect.size[0] - 2) as usize; // Show the current directory. let cwd = Label { @@ -178,7 +176,7 @@ impl Drawable for OpenFilePanel { // Prepare to show the children. x += 1; - let height: u32 = self.panel.rect.size[1] - 4; + let height: u32 = self.panel.background.grid_rect.size[1] - 4; y += 1; length -= 1; let width = length as u32; @@ -230,9 +228,13 @@ impl Drawable for OpenFilePanel { // Possibly show the input dialogue. if let Some(filename) = &paths_state.get_filename() { // Draw the background of the prompt. - renderer.rectangle(&self.prompt, &ColorKey::Background); - renderer.border( - &self.prompt, + renderer.rectangle_pixel( + self.prompt.background.position, + self.prompt.background.size, + &ColorKey::Background, + ); + renderer.rectangle_lines( + &self.prompt.border, &if focus { ColorKey::FocusDefault } else { diff --git a/render/src/panel.rs b/render/src/panel.rs index 31aa0a4a..4cbffa46 100644 --- a/render/src/panel.rs +++ b/render/src/panel.rs @@ -11,14 +11,20 @@ pub(crate) use ini::Ini; pub(crate) struct Panel { /// The type of panel. panel_type: PanelType, - /// The position and size of the panel in grid units. - pub rect: Rectangle, + /// The panel background. + pub background: PanelBackground, /// The title label for the panel. pub title: LabelRectangle, } impl Panel { - pub fn new(panel_type: PanelType, position: [u32; 2], size: [u32; 2], text: &Text) -> Self { + pub fn new( + panel_type: PanelType, + position: [u32; 2], + size: [u32; 2], + renderer: &Renderer, + text: &Text, + ) -> Self { // Get the title from the panel type. let title = match panel_type { PanelType::MainMenu => format!("{} v{}", text.get("TITLE_MAIN_MENU"), VERSION), @@ -36,7 +42,7 @@ impl Panel { Self { panel_type, title, - rect: Rectangle::new(position, size), + background: PanelBackground::new(position, size, renderer), } } @@ -52,8 +58,12 @@ impl Panel { /// Draw an empty panel. The border and title text will be an explicitly defined color. pub fn update_ex(&self, color: &ColorKey, renderer: &Renderer) { - renderer.rectangle(&self.rect, &ColorKey::Background); - renderer.border(&self.rect, color); + renderer.rectangle_pixel( + self.background.background.position, + self.background.background.size, + &ColorKey::Background, + ); + renderer.rectangle_lines(&self.background.border, color); renderer.rectangle(&self.title.rect, &ColorKey::Background); renderer.text(&self.title.label, color); } diff --git a/render/src/panels.rs b/render/src/panels.rs index b17d0fe7..be8cc8f1 100644 --- a/render/src/panels.rs +++ b/render/src/panels.rs @@ -37,19 +37,21 @@ impl Panels { config: &Ini, input: &Input, state: &State, + conn: &Conn, text: &mut Text, renderer: &Renderer, remote_version: Option, ) -> Self { - let music_panel = MusicPanel::new(config, text); - let main_menu = MainMenu::new(config, input, text, renderer, remote_version); - let tracks_panel = TracksPanel::new(config, text); - let open_file_panel = OpenFilePanel::new(config, text); - let piano_roll_panel = PianoRollPanel::new(config, state, text, renderer); - let export_panel = ExportPanel::new(config, text); - let export_settings_panel = ExportSettingsPanel::new(config, text); - let quit_panel = QuitPanel::new(config, text, input); - let links_panel = LinksPanel::new(config, text, input); + let music_panel = MusicPanel::new(config, renderer, text); + let main_menu = MainMenu::new(config, renderer, input, text, remote_version); + let tracks_panel = TracksPanel::new(config, renderer, text); + let open_file_panel = OpenFilePanel::new(config, renderer, text); + let piano_roll_panel = PianoRollPanel::new(config, renderer, state, text); + let export_panel = ExportPanel::new(config, renderer, text); + let export_settings_panel = + ExportSettingsPanel::new(config, renderer, &conn.exporter, text); + let quit_panel = QuitPanel::new(config, renderer, text, input); + let links_panel = LinksPanel::new(config, renderer, text, input); Self { music_panel, main_menu, diff --git a/render/src/piano_roll_panel.rs b/render/src/piano_roll_panel.rs index 4ad3bcd3..02ddb998 100644 --- a/render/src/piano_roll_panel.rs +++ b/render/src/piano_roll_panel.rs @@ -46,19 +46,20 @@ pub struct PianoRollPanel { } impl PianoRollPanel { - pub fn new(config: &Ini, state: &State, text: &Text, renderer: &Renderer) -> Self { + pub fn new(config: &Ini, renderer: &Renderer, state: &State, text: &Text) -> Self { let piano_roll_panel_position = get_piano_roll_panel_position(config); let piano_roll_panel_size = get_piano_roll_panel_size(config); let panel_single_track = Panel::new( PanelType::PianoRoll, piano_roll_panel_position, piano_roll_panel_size, + renderer, text, ); let top_bar = TopBar::new(config, text); let note_names_position = [ - panel_single_track.rect.position[0] + 1, - panel_single_track.rect.position[1] + PIANO_ROLL_PANEL_TOP_BAR_HEIGHT + 1, + piano_roll_panel_position[0] + 1, + piano_roll_panel_position[1] + PIANO_ROLL_PANEL_TOP_BAR_HEIGHT + 1, ]; let piano_roll_rows_size = get_viewport_size(config); let note_name_positions: Vec<[u32; 2]> = (note_names_position[1] @@ -85,7 +86,9 @@ impl PianoRollPanel { let volume = Volume::new(config, text, renderer); let multi_track = MultiTrack::new(config, renderer); let mut panel_multi_track = panel_single_track.clone(); - panel_multi_track.rect.size[1] += volume.rect.size[1]; + panel_multi_track + .background + .resize_by([0, volume.rect.size[1]], renderer); let volume_size_f = renderer.grid_to_pixel(volume.rect.size); let time_line_bottom_single_track = piano_roll_rows_rect[1] + piano_roll_rows_rect[3]; let time_line_bottoms = [ @@ -306,7 +309,8 @@ impl Drawable for PianoRollPanel { } else { ColorKey::NoFocus }; - let cursor_x = panel.rect.position[0] + PIANO_ROLL_PANEL_NOTE_NAMES_WIDTH + 1; + let cursor_x = + panel.background.grid_rect.position[0] + PIANO_ROLL_PANEL_NOTE_NAMES_WIDTH + 1; let cursor_string = text.get_with_values( "PIANO_ROLL_PANEL_CURSOR_TIME", &[&ppq_to_string(state.time.cursor)], @@ -406,8 +410,9 @@ impl Drawable for PianoRollPanel { "PIANO_ROLL_PANEL_VIEW_DT", &[&ppq_to_string(dt[0].get_u()), &ppq_to_string(dt[1].get_u())], ); - let dt_x = - panel.rect.position[0] + panel.rect.size[0] - dt_string.chars().count() as u32 - 1; + let dt_x = panel.background.grid_rect.position[0] + panel.background.grid_rect.size[0] + - dt_string.chars().count() as u32 + - 1; let dt_label = Label { text: dt_string, position: [dt_x, self.time_y], diff --git a/render/src/quit_panel.rs b/render/src/quit_panel.rs index 6c3a8db4..1738d9b9 100644 --- a/render/src/quit_panel.rs +++ b/render/src/quit_panel.rs @@ -16,7 +16,7 @@ pub(crate) struct QuitPanel { } impl QuitPanel { - pub fn new(config: &Ini, text: &Text, input: &Input) -> Self { + pub fn new(config: &Ini, renderer: &Renderer, text: &Text, input: &Input) -> Self { let mut tooltips = Tooltips::default(); // Get the width of the panel. let yes = tooltips @@ -33,7 +33,7 @@ impl QuitPanel { let x = window_grid_size[0] / 2 - w / 2; let y = window_grid_size[1] / 2 - h / 2; // Define the panel. - let panel = Panel::new(PanelType::Quit, [x, y], [w, h], text); + let panel = Panel::new(PanelType::Quit, [x, y], [w, h], renderer, text); // Define the labels. let yes = Label::new([x + 2, y + 1], yes); let no = Label::new([yes.position[0] + yes_w, yes.position[1]], no); diff --git a/render/src/renderer.rs b/render/src/renderer.rs index 97ea51a2..1475220d 100644 --- a/render/src/renderer.rs +++ b/render/src/renderer.rs @@ -144,14 +144,22 @@ impl Renderer { /// - `rectangle` The position and size of the bordered area. /// - `color` A `ColorKey` for the rectangle. pub(crate) fn border(&self, rect: &Rectangle, color: &ColorKey) { - let mut xy = self.grid_to_pixel(rect.position); - xy[0] += self.border_offsets[0]; - xy[1] += self.border_offsets[1]; - let mut wh = self.grid_to_pixel(rect.size); - wh[0] += self.border_offsets[2]; - wh[1] += self.border_offsets[3]; - let color = self.colors[color]; - draw_rectangle_lines(xy[0], xy[1], wh[0], wh[1], self.line_width, color); + self.rectangle_lines(&self.get_border_rect(rect.position, rect.size), color); + } + + /// Draw a border that is slightly offset from the edges of the cells. + /// + /// - `rectangle` The position and size of the bordered area. + /// - `color` A `ColorKey` for the rectangle. + pub(crate) fn rectangle_lines(&self, rect: &RectanglePixel, color: &ColorKey) { + draw_rectangle_lines( + rect.position[0], + rect.position[1], + rect.size[0], + rect.size[1], + self.line_width, + self.colors[color], + ); } /// Draw text. @@ -616,6 +624,17 @@ impl Renderer { ] } + /// Returns the position of the size of a border rectangle in pixels. + pub(crate) fn get_border_rect(&self, position: [u32; 2], size: [u32; 2]) -> RectanglePixel { + let mut position = self.grid_to_pixel(position); + position[0] += self.border_offsets[0]; + position[1] += self.border_offsets[1]; + let mut size = self.grid_to_pixel(size); + size[0] += self.border_offsets[2]; + size[1] += self.border_offsets[3]; + RectanglePixel::new(position, size) + } + /// Parse a serialized 3-element array as an RGBA color. fn parse_color(value: &str) -> Color { let c: Result<[u8; 3], serde_json::Error> = serde_json::from_str(value); diff --git a/render/src/tracks_panel.rs b/render/src/tracks_panel.rs index 3da648f4..595c44db 100644 --- a/render/src/tracks_panel.rs +++ b/render/src/tracks_panel.rs @@ -27,14 +27,21 @@ pub struct TracksPanel { } impl TracksPanel { - pub fn new(config: &Ini, text: &Text) -> Self { + pub fn new(config: &Ini, renderer: &Renderer, text: &Text) -> Self { // Get the panel. let width = get_tracks_panel_width(config); let grid_size = get_window_grid_size(config); let height = grid_size[1] - MUSIC_PANEL_HEIGHT; let x = MUSIC_PANEL_POSITION[0]; let y = MUSIC_PANEL_POSITION[1] + MUSIC_PANEL_HEIGHT; - let panel = Panel::new(PanelType::Tracks, [x, y], [width, height], text); + let panel_position = [x, y]; + let panel = Panel::new( + PanelType::Tracks, + panel_position, + [width, height], + renderer, + text, + ); // Get the sizes. let track_width = width - 2; let track_size_sf = [track_width, TRACK_HEIGHT_SOUNDFONT]; @@ -82,8 +89,8 @@ impl Drawable for TracksPanel { }; // Draw the tracks. - let x = self.panel.rect.position[0] + 1; - let mut y = self.panel.rect.position[1] + 1; + let x = self.panel.background.grid_rect.position[0] + 1; + let mut y = self.panel.background.grid_rect.position[1] + 1; for i in track_page { let track = &state.music.midi_tracks[i]; let channel = track.channel; diff --git a/src/main.rs b/src/main.rs index 2e62e4a6..aa0be3b4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -82,6 +82,7 @@ async fn main() { &config, &input, &state, + &conn, &mut text, &renderer, remote_version,