diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 9fc4eee078..c05c328a5f 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -1777,7 +1777,7 @@ impl Hud { let speech_bubbles = &self.speech_bubbles; // Render overhead name tags and health bars - for (pos, info, bubble, _, _, health, _, height_offset, hpfl, in_group, is_me) in ( + for (pos, info, bubble, _, _, health, _, height_offset, hpfl, in_group) in ( &entities, &pos, interpolated.maybe(), @@ -1835,7 +1835,8 @@ impl Hud { || info.selected_entity.map_or(false, |s| s.0 == entity) || health.map_or(true, overhead::should_show_healthbar) || in_group - || is_merchant) + || is_merchant + || !is_me) && dist_sqr < (if in_group { NAMETAG_GROUP_RANGE @@ -1866,7 +1867,9 @@ impl Hud { 0.0 }, }); - let bubble = if dist_sqr < SPEECH_BUBBLE_RANGE.powi(2) { + let bubble = if (dist_sqr < SPEECH_BUBBLE_RANGE.powi(2) && !is_me) + || (is_me && global_state.settings.interface.speech_bubble_self) + { speech_bubbles.get(uid) } else { None @@ -1884,7 +1887,6 @@ impl Hud { body.height() * scale.map_or(1.0, |s| s.0) + 0.5, hpfl, in_group, - is_me, ) }) }, @@ -1904,7 +1906,6 @@ impl Hud { info, bubble, in_group, - is_me, &global_state.settings.interface, self.pulse, i18n, diff --git a/voxygen/src/hud/overhead.rs b/voxygen/src/hud/overhead.rs index 397e01d97e..3cb42953ef 100644 --- a/voxygen/src/hud/overhead.rs +++ b/voxygen/src/hud/overhead.rs @@ -81,7 +81,6 @@ pub struct Overhead<'a> { info: Option>, bubble: Option<&'a SpeechBubble>, in_group: bool, - is_me: bool, settings: &'a InterfaceSettings, pulse: f32, i18n: &'a Localization, @@ -97,7 +96,6 @@ impl<'a> Overhead<'a> { info: Option>, bubble: Option<&'a SpeechBubble>, in_group: bool, - is_me: bool, settings: &'a InterfaceSettings, pulse: f32, i18n: &'a Localization, @@ -108,7 +106,6 @@ impl<'a> Overhead<'a> { info, bubble, in_group, - is_me, settings, pulse, i18n, @@ -183,118 +180,115 @@ impl<'a> Widget for Overhead<'a> { const MANA_BAR_HEIGHT: f64 = BARSIZE * 1.5; const MANA_BAR_Y: f64 = MANA_BAR_HEIGHT / 2.0; // Only render info if not me - if !self.is_me { - if let Some(Info { - name, - health, - buffs, - energy, - combat_rating, - }) = self.info - { - // Used to set healthbar colours based on hp_percentage - let hp_percentage = health.map_or(100.0, |h| { - f64::from(h.current() / h.base_max().max(h.maximum()) * 100.0) - }); - // Compare levels to decide if a skull is shown - let health_current = health.map_or(1.0, |h| f64::from(h.current())); - let health_max = health.map_or(1.0, |h| f64::from(h.maximum())); - let name_y = if (health_current - health_max).abs() < 1e-6 { - MANA_BAR_Y + 20.0 - } else { - MANA_BAR_Y + 32.0 - }; - let font_size = if hp_percentage.abs() > 99.9 { 24 } else { 20 }; - // Show K for numbers above 10^3 and truncate them - // Show M for numbers above 10^6 and truncate them - let health_cur_txt = match health_current as u32 { - 0..=999 => format!("{:.0}", health_current.max(1.0)), - 1000..=999999 => format!("{:.0}K", (health_current / 1000.0).max(1.0)), - _ => format!("{:.0}M", (health_current as f64 / 1.0e6).max(1.0)), - }; - let health_max_txt = match health_max as u32 { - 0..=999 => format!("{:.0}", health_max.max(1.0)), - 1000..=999999 => format!("{:.0}K", (health_max / 1000.0).max(1.0)), - _ => format!("{:.0}M", (health_max as f64 / 1.0e6).max(1.0)), - }; - // Buffs - // Alignment - let buff_count = buffs.kinds.len().min(11); - Rectangle::fill_with([168.0, 100.0], color::TRANSPARENT) - .x_y(-1.0, name_y + 60.0) - .parent(id) - .set(state.ids.buffs_align, ui); + if let Some(Info { + name, + health, + buffs, + energy, + combat_rating, + }) = self.info + { + // Used to set healthbar colours based on hp_percentage + let hp_percentage = health.map_or(100.0, |h| { + f64::from(h.current() / h.base_max().max(h.maximum()) * 100.0) + }); + // Compare levels to decide if a skull is shown + let health_current = health.map_or(1.0, |h| f64::from(h.current())); + let health_max = health.map_or(1.0, |h| f64::from(h.maximum())); + let name_y = if (health_current - health_max).abs() < 1e-6 { + MANA_BAR_Y + 20.0 + } else { + MANA_BAR_Y + 32.0 + }; + let font_size = if hp_percentage.abs() > 99.9 { 24 } else { 20 }; + // Show K for numbers above 10^3 and truncate them + // Show M for numbers above 10^6 and truncate them + let health_cur_txt = match health_current as u32 { + 0..=999 => format!("{:.0}", health_current.max(1.0)), + 1000..=999999 => format!("{:.0}K", (health_current / 1000.0).max(1.0)), + _ => format!("{:.0}M", (health_current as f64 / 1.0e6).max(1.0)), + }; + let health_max_txt = match health_max as u32 { + 0..=999 => format!("{:.0}", health_max.max(1.0)), + 1000..=999999 => format!("{:.0}K", (health_max / 1000.0).max(1.0)), + _ => format!("{:.0}M", (health_max as f64 / 1.0e6).max(1.0)), + }; + // Buffs + // Alignment + let buff_count = buffs.kinds.len().min(11); + Rectangle::fill_with([168.0, 100.0], color::TRANSPARENT) + .x_y(-1.0, name_y + 60.0) + .parent(id) + .set(state.ids.buffs_align, ui); - let gen = &mut ui.widget_id_generator(); - if state.ids.buffs.len() < buff_count { - state.update(|state| state.ids.buffs.resize(buff_count, gen)); - }; - if state.ids.buff_timers.len() < buff_count { - state.update(|state| state.ids.buff_timers.resize(buff_count, gen)); - }; + let gen = &mut ui.widget_id_generator(); + if state.ids.buffs.len() < buff_count { + state.update(|state| state.ids.buffs.resize(buff_count, gen)); + }; + if state.ids.buff_timers.len() < buff_count { + state.update(|state| state.ids.buff_timers.resize(buff_count, gen)); + }; - let buff_ani = ((self.pulse * 4.0).cos() * 0.5 + 0.8) + 0.5; //Animation timer - let pulsating_col = Color::Rgba(1.0, 1.0, 1.0, buff_ani); - let norm_col = Color::Rgba(1.0, 1.0, 1.0, 1.0); - // Create Buff Widgets - if self.bubble.is_none() { - state - .ids - .buffs - .iter() - .copied() - .zip(state.ids.buff_timers.iter().copied()) - .zip(buffs.iter_active().map(get_buff_info)) - .enumerate() - .for_each(|(i, ((id, timer_id), buff))| { - // Limit displayed buffs - let max_duration = buff.data.duration; - let current_duration = buff.dur; - let duration_percentage = current_duration.map_or(1000.0, |cur| { - max_duration.map_or(1000.0, |max| { - cur.as_secs_f32() / max.as_secs_f32() * 1000.0 - }) - }) as u32; // Percentage to determine which frame of the timer overlay is displayed - let buff_img = get_buff_image(buff.kind, self.imgs); - let buff_widget = Image::new(buff_img).w_h(20.0, 20.0); - // Sort buffs into rows of 5 slots - let x = i % 5; - let y = i / 5; - let buff_widget = buff_widget.bottom_left_with_margins_on( - state.ids.buffs_align, - 0.0 + y as f64 * (21.0), - 0.0 + x as f64 * (21.0), - ); - buff_widget - .color( - if current_duration - .map_or(false, |cur| cur.as_secs_f32() < 10.0) - { - Some(pulsating_col) - } else { - Some(norm_col) - }, - ) - .set(id, ui); - - Image::new(match duration_percentage as u64 { - 875..=1000 => self.imgs.nothing, // 8/8 - 750..=874 => self.imgs.buff_0, // 7/8 - 625..=749 => self.imgs.buff_1, // 6/8 - 500..=624 => self.imgs.buff_2, // 5/8 - 375..=499 => self.imgs.buff_3, // 4/8 - 250..=374 => self.imgs.buff_4, // 3/8 - 125..=249 => self.imgs.buff_5, // 2/8 - 0..=124 => self.imgs.buff_6, // 1/8 - _ => self.imgs.nothing, + let buff_ani = ((self.pulse * 4.0).cos() * 0.5 + 0.8) + 0.5; //Animation timer + let pulsating_col = Color::Rgba(1.0, 1.0, 1.0, buff_ani); + let norm_col = Color::Rgba(1.0, 1.0, 1.0, 1.0); + // Create Buff Widgets + if self.bubble.is_none() { + state + .ids + .buffs + .iter() + .copied() + .zip(state.ids.buff_timers.iter().copied()) + .zip(buffs.iter_active().map(get_buff_info)) + .enumerate() + .for_each(|(i, ((id, timer_id), buff))| { + // Limit displayed buffs + let max_duration = buff.data.duration; + let current_duration = buff.dur; + let duration_percentage = current_duration.map_or(1000.0, |cur| { + max_duration.map_or(1000.0, |max| { + cur.as_secs_f32() / max.as_secs_f32() * 1000.0 }) - .w_h(20.0, 20.0) - .middle_of(id) - .set(timer_id, ui); - }); - } - // Name - Text::new(name) + }) as u32; // Percentage to determine which frame of the timer overlay is displayed + let buff_img = get_buff_image(buff.kind, self.imgs); + let buff_widget = Image::new(buff_img).w_h(20.0, 20.0); + // Sort buffs into rows of 5 slots + let x = i % 5; + let y = i / 5; + let buff_widget = buff_widget.bottom_left_with_margins_on( + state.ids.buffs_align, + 0.0 + y as f64 * (21.0), + 0.0 + x as f64 * (21.0), + ); + buff_widget + .color( + if current_duration.map_or(false, |cur| cur.as_secs_f32() < 10.0) { + Some(pulsating_col) + } else { + Some(norm_col) + }, + ) + .set(id, ui); + + Image::new(match duration_percentage as u64 { + 875..=1000 => self.imgs.nothing, // 8/8 + 750..=874 => self.imgs.buff_0, // 7/8 + 625..=749 => self.imgs.buff_1, // 6/8 + 500..=624 => self.imgs.buff_2, // 5/8 + 375..=499 => self.imgs.buff_3, // 4/8 + 250..=374 => self.imgs.buff_4, // 3/8 + 125..=249 => self.imgs.buff_5, // 2/8 + 0..=124 => self.imgs.buff_6, // 1/8 + _ => self.imgs.nothing, + }) + .w_h(20.0, 20.0) + .middle_of(id) + .set(timer_id, ui); + }); + } + // Name + Text::new(name) //Text::new(&format!("{} [{:?}]", name, combat_rating)) // <- Uncomment to debug combat ratings .font_id(self.fonts.cyri.conrod_id) .font_size(font_size) @@ -302,7 +296,7 @@ impl<'a> Widget for Overhead<'a> { .x_y(-1.0, name_y) .parent(id) .set(state.ids.name_bg, ui); - Text::new(name) + Text::new(name) //Text::new(&format!("{} [{:?}]", name, combat_rating)) // <- Uncomment to debug combat ratings .font_id(self.fonts.cyri.conrod_id) .font_size(font_size) @@ -317,296 +311,292 @@ impl<'a> Widget for Overhead<'a> { .parent(id) .set(state.ids.name, ui); - match health { - Some(health) - if should_show_healthbar(health) || decayed_health_displayed(health) => - { - // Show HP Bar - let hp_ani = (self.pulse * 4.0/* speed factor */).cos() * 0.5 + 1.0; //Animation timer - let crit_hp_color: Color = Color::Rgba(0.93, 0.59, 0.03, hp_ani); - let decayed_health = f64::from(1.0 - health.maximum() / health.base_max()); - // Background - Image::new(if self.in_group {self.imgs.health_bar_group_bg} else {self.imgs.enemy_health_bg}) + match health { + Some(health) + if should_show_healthbar(health) || decayed_health_displayed(health) => + { + // Show HP Bar + let hp_ani = (self.pulse * 4.0/* speed factor */).cos() * 0.5 + 1.0; //Animation timer + let crit_hp_color: Color = Color::Rgba(0.93, 0.59, 0.03, hp_ani); + let decayed_health = f64::from(1.0 - health.maximum() / health.base_max()); + // Background + Image::new(if self.in_group {self.imgs.health_bar_group_bg} else {self.imgs.enemy_health_bg}) .w_h(84.0 * BARSIZE, 10.0 * BARSIZE) .x_y(0.0, MANA_BAR_Y + 6.5) //-25.5) .color(Some(Color::Rgba(0.1, 0.1, 0.1, 0.8))) .parent(id) .set(state.ids.health_bar_bg, ui); - // % HP Filling - let size_factor = (hp_percentage / 100.0) * BARSIZE; - let w = if self.in_group { - 82.0 * size_factor - } else { - 73.0 * size_factor - }; - let h = 6.0 * BARSIZE; - let x = if self.in_group { - (0.0 + (hp_percentage / 100.0 * 41.0 - 41.0)) * BARSIZE - } else { - (4.5 + (hp_percentage / 100.0 * 36.45 - 36.45)) * BARSIZE - }; - Image::new(self.imgs.enemy_bar) - .w_h(w, h) - .x_y(x, MANA_BAR_Y + 8.0) - .color(if self.in_group { - // Different HP bar colors only for group members - Some(match hp_percentage { - x if (0.0..25.0).contains(&x) => crit_hp_color, - x if (25.0..50.0).contains(&x) => LOW_HP_COLOR, - _ => HP_COLOR, - }) - } else { - Some(ENEMY_HP_COLOR) + // % HP Filling + let size_factor = (hp_percentage / 100.0) * BARSIZE; + let w = if self.in_group { + 82.0 * size_factor + } else { + 73.0 * size_factor + }; + let h = 6.0 * BARSIZE; + let x = if self.in_group { + (0.0 + (hp_percentage / 100.0 * 41.0 - 41.0)) * BARSIZE + } else { + (4.5 + (hp_percentage / 100.0 * 36.45 - 36.45)) * BARSIZE + }; + Image::new(self.imgs.enemy_bar) + .w_h(w, h) + .x_y(x, MANA_BAR_Y + 8.0) + .color(if self.in_group { + // Different HP bar colors only for group members + Some(match hp_percentage { + x if (0.0..25.0).contains(&x) => crit_hp_color, + x if (25.0..50.0).contains(&x) => LOW_HP_COLOR, + _ => HP_COLOR, }) - .parent(id) - .set(state.ids.health_bar, ui); + } else { + Some(ENEMY_HP_COLOR) + }) + .parent(id) + .set(state.ids.health_bar, ui); - if decayed_health > 0.0 { - let x_decayed = if self.in_group { - (0.0 - (decayed_health * 41.0 - 41.0)) * BARSIZE - } else { - (4.5 - (decayed_health * 36.45 - 36.45)) * BARSIZE - }; - - let decay_bar_len = decayed_health - * if self.in_group { - 82.0 * BARSIZE - } else { - 73.0 * BARSIZE - }; - Image::new(self.imgs.enemy_bar) - .w_h(decay_bar_len, h) - .x_y(x_decayed, MANA_BAR_Y + 8.0) - .color(Some(QUALITY_EPIC)) - .parent(id) - .set(state.ids.decay_bar, ui); - } - let mut txt = format!("{}/{}", health_cur_txt, health_max_txt); - if health.is_dead { - txt = self.i18n.get("hud.group.dead").to_string() + if decayed_health > 0.0 { + let x_decayed = if self.in_group { + (0.0 - (decayed_health * 41.0 - 41.0)) * BARSIZE + } else { + (4.5 - (decayed_health * 36.45 - 36.45)) * BARSIZE }; - Text::new(&txt) - .mid_top_with_margin_on(state.ids.health_bar_bg, 2.0) - .font_size(10) - .font_id(self.fonts.cyri.conrod_id) - .color(TEXT_COLOR) + + let decay_bar_len = decayed_health + * if self.in_group { + 82.0 * BARSIZE + } else { + 73.0 * BARSIZE + }; + Image::new(self.imgs.enemy_bar) + .w_h(decay_bar_len, h) + .x_y(x_decayed, MANA_BAR_Y + 8.0) + .color(Some(QUALITY_EPIC)) .parent(id) - .set(state.ids.health_txt, ui); + .set(state.ids.decay_bar, ui); + } + let mut txt = format!("{}/{}", health_cur_txt, health_max_txt); + if health.is_dead { + txt = self.i18n.get("hud.group.dead").to_string() + }; + Text::new(&txt) + .mid_top_with_margin_on(state.ids.health_bar_bg, 2.0) + .font_size(10) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .parent(id) + .set(state.ids.health_txt, ui); - // % Mana Filling - if let Some(energy) = energy { - let energy_factor = f64::from(energy.current() / energy.maximum()); - let size_factor = energy_factor * BARSIZE; - let w = if self.in_group { - 80.0 * size_factor - } else { - 72.0 * size_factor - }; - let x = if self.in_group { - ((0.0 + (energy_factor * 40.0)) - 40.0) * BARSIZE - } else { - ((3.5 + (energy_factor * 36.5)) - 36.45) * BARSIZE - }; - Rectangle::fill_with([w, MANA_BAR_HEIGHT], STAMINA_COLOR) - .x_y( - x, MANA_BAR_Y, //-32.0, - ) - .parent(id) - .set(state.ids.mana_bar, ui); - } + // % Mana Filling + if let Some(energy) = energy { + let energy_factor = f64::from(energy.current() / energy.maximum()); + let size_factor = energy_factor * BARSIZE; + let w = if self.in_group { + 80.0 * size_factor + } else { + 72.0 * size_factor + }; + let x = if self.in_group { + ((0.0 + (energy_factor * 40.0)) - 40.0) * BARSIZE + } else { + ((3.5 + (energy_factor * 36.5)) - 36.45) * BARSIZE + }; + Rectangle::fill_with([w, MANA_BAR_HEIGHT], STAMINA_COLOR) + .x_y( + x, MANA_BAR_Y, //-32.0, + ) + .parent(id) + .set(state.ids.mana_bar, ui); + } - // Foreground - Image::new(if self.in_group {self.imgs.health_bar_group} else {self.imgs.enemy_health}) + // Foreground + Image::new(if self.in_group {self.imgs.health_bar_group} else {self.imgs.enemy_health}) .w_h(84.0 * BARSIZE, 10.0 * BARSIZE) .x_y(0.0, MANA_BAR_Y + 6.5) //-25.5) .color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.99))) .parent(id) .set(state.ids.health_bar_fg, ui); - let indicator_col = cr_color(combat_rating); - let artifact_diffculty = 122.0; + let indicator_col = cr_color(combat_rating); + let artifact_diffculty = 122.0; - if combat_rating > artifact_diffculty && !self.in_group { - let skull_ani = - ((self.pulse * 0.7/* speed factor */).cos() * 0.5 + 0.5) * 10.0; //Animation timer - Image::new(if skull_ani as i32 == 1 && rand::random::() < 0.9 { - self.imgs.skull_2 - } else { - self.imgs.skull - }) - .w_h(18.0 * BARSIZE, 18.0 * BARSIZE) - .x_y(-39.0 * BARSIZE, MANA_BAR_Y + 7.0) - .color(Some(Color::Rgba(1.0, 1.0, 1.0, 1.0))) - .parent(id) - .set(state.ids.level_skull, ui); + if combat_rating > artifact_diffculty && !self.in_group { + let skull_ani = + ((self.pulse * 0.7/* speed factor */).cos() * 0.5 + 0.5) * 10.0; //Animation timer + Image::new(if skull_ani as i32 == 1 && rand::random::() < 0.9 { + self.imgs.skull_2 } else { - Image::new(if self.in_group { - self.imgs.nothing - } else { - self.imgs.combat_rating_ico - }) - .w_h(7.0 * BARSIZE, 7.0 * BARSIZE) - .x_y(-37.0 * BARSIZE, MANA_BAR_Y + 6.0) - .color(Some(indicator_col)) - .parent(id) - .set(state.ids.level, ui); - } - }, - _ => {}, - } + self.imgs.skull + }) + .w_h(18.0 * BARSIZE, 18.0 * BARSIZE) + .x_y(-39.0 * BARSIZE, MANA_BAR_Y + 7.0) + .color(Some(Color::Rgba(1.0, 1.0, 1.0, 1.0))) + .parent(id) + .set(state.ids.level_skull, ui); + } else { + Image::new(if self.in_group { + self.imgs.nothing + } else { + self.imgs.combat_rating_ico + }) + .w_h(7.0 * BARSIZE, 7.0 * BARSIZE) + .x_y(-37.0 * BARSIZE, MANA_BAR_Y + 6.0) + .color(Some(indicator_col)) + .parent(id) + .set(state.ids.level, ui); + } + }, + _ => {}, } } // Speech bubble // Only render if setting or other players - if !self.is_me || self.settings.speech_bubble_self { - if let Some(bubble) = self.bubble { - let dark_mode = self.settings.speech_bubble_dark_mode; - let localizer = - |s: &str, i| -> String { self.i18n.get_variation(s, i).to_string() }; - let bubble_contents: String = bubble.message(localizer); - let (text_color, shadow_color) = bubble_color(bubble, dark_mode); - let mut text = Text::new(&bubble_contents) - .color(text_color) - .font_id(self.fonts.cyri.conrod_id) - .font_size(18) - .up_from(state.ids.name, 26.0) - .x_align_to(state.ids.name, Align::Middle) - .parent(id); + if let Some(bubble) = self.bubble { + let dark_mode = self.settings.speech_bubble_dark_mode; + let localizer = |s: &str, i| -> String { self.i18n.get_variation(s, i).to_string() }; + let bubble_contents: String = bubble.message(localizer); + let (text_color, shadow_color) = bubble_color(bubble, dark_mode); + let mut text = Text::new(&bubble_contents) + .color(text_color) + .font_id(self.fonts.cyri.conrod_id) + .font_size(18) + .up_from(state.ids.name, 26.0) + .x_align_to(state.ids.name, Align::Middle) + .parent(id); - if let Some(w) = text.get_w(ui) { - if w > MAX_BUBBLE_WIDTH { - text = text.w(MAX_BUBBLE_WIDTH); - } + if let Some(w) = text.get_w(ui) { + if w > MAX_BUBBLE_WIDTH { + text = text.w(MAX_BUBBLE_WIDTH); } - Image::new(if dark_mode { - self.imgs.dark_bubble_top_left - } else { - self.imgs.speech_bubble_top_left - }) - .w_h(16.0, 16.0) - .top_left_with_margin_on(state.ids.speech_bubble_text, -20.0) - .parent(id) - .set(state.ids.speech_bubble_top_left, ui); - Image::new(if dark_mode { - self.imgs.dark_bubble_top - } else { - self.imgs.speech_bubble_top - }) - .h(16.0) - .padded_w_of(state.ids.speech_bubble_text, -4.0) - .mid_top_with_margin_on(state.ids.speech_bubble_text, -20.0) - .parent(id) - .set(state.ids.speech_bubble_top, ui); - Image::new(if dark_mode { - self.imgs.dark_bubble_top_right - } else { - self.imgs.speech_bubble_top_right - }) - .w_h(16.0, 16.0) - .top_right_with_margin_on(state.ids.speech_bubble_text, -20.0) - .parent(id) - .set(state.ids.speech_bubble_top_right, ui); - Image::new(if dark_mode { - self.imgs.dark_bubble_left - } else { - self.imgs.speech_bubble_left - }) - .w(16.0) - .padded_h_of(state.ids.speech_bubble_text, -4.0) - .mid_left_with_margin_on(state.ids.speech_bubble_text, -20.0) - .parent(id) - .set(state.ids.speech_bubble_left, ui); - Image::new(if dark_mode { - self.imgs.dark_bubble_mid - } else { - self.imgs.speech_bubble_mid - }) - .padded_wh_of(state.ids.speech_bubble_text, -4.0) - .top_left_with_margin_on(state.ids.speech_bubble_text, -4.0) - .parent(id) - .set(state.ids.speech_bubble_mid, ui); - Image::new(if dark_mode { - self.imgs.dark_bubble_right - } else { - self.imgs.speech_bubble_right - }) - .w(16.0) - .padded_h_of(state.ids.speech_bubble_text, -4.0) - .mid_right_with_margin_on(state.ids.speech_bubble_text, -20.0) - .parent(id) - .set(state.ids.speech_bubble_right, ui); - Image::new(if dark_mode { - self.imgs.dark_bubble_bottom_left - } else { - self.imgs.speech_bubble_bottom_left - }) - .w_h(16.0, 16.0) - .bottom_left_with_margin_on(state.ids.speech_bubble_text, -20.0) - .parent(id) - .set(state.ids.speech_bubble_bottom_left, ui); - Image::new(if dark_mode { - self.imgs.dark_bubble_bottom - } else { - self.imgs.speech_bubble_bottom - }) - .h(16.0) - .padded_w_of(state.ids.speech_bubble_text, -4.0) - .mid_bottom_with_margin_on(state.ids.speech_bubble_text, -20.0) - .parent(id) - .set(state.ids.speech_bubble_bottom, ui); - Image::new(if dark_mode { - self.imgs.dark_bubble_bottom_right - } else { - self.imgs.speech_bubble_bottom_right - }) - .w_h(16.0, 16.0) - .bottom_right_with_margin_on(state.ids.speech_bubble_text, -20.0) - .parent(id) - .set(state.ids.speech_bubble_bottom_right, ui); - let tail = Image::new(if dark_mode { - self.imgs.dark_bubble_tail - } else { - self.imgs.speech_bubble_tail - }) - .parent(id) - .mid_bottom_with_margin_on(state.ids.speech_bubble_text, -32.0); + } + Image::new(if dark_mode { + self.imgs.dark_bubble_top_left + } else { + self.imgs.speech_bubble_top_left + }) + .w_h(16.0, 16.0) + .top_left_with_margin_on(state.ids.speech_bubble_text, -20.0) + .parent(id) + .set(state.ids.speech_bubble_top_left, ui); + Image::new(if dark_mode { + self.imgs.dark_bubble_top + } else { + self.imgs.speech_bubble_top + }) + .h(16.0) + .padded_w_of(state.ids.speech_bubble_text, -4.0) + .mid_top_with_margin_on(state.ids.speech_bubble_text, -20.0) + .parent(id) + .set(state.ids.speech_bubble_top, ui); + Image::new(if dark_mode { + self.imgs.dark_bubble_top_right + } else { + self.imgs.speech_bubble_top_right + }) + .w_h(16.0, 16.0) + .top_right_with_margin_on(state.ids.speech_bubble_text, -20.0) + .parent(id) + .set(state.ids.speech_bubble_top_right, ui); + Image::new(if dark_mode { + self.imgs.dark_bubble_left + } else { + self.imgs.speech_bubble_left + }) + .w(16.0) + .padded_h_of(state.ids.speech_bubble_text, -4.0) + .mid_left_with_margin_on(state.ids.speech_bubble_text, -20.0) + .parent(id) + .set(state.ids.speech_bubble_left, ui); + Image::new(if dark_mode { + self.imgs.dark_bubble_mid + } else { + self.imgs.speech_bubble_mid + }) + .padded_wh_of(state.ids.speech_bubble_text, -4.0) + .top_left_with_margin_on(state.ids.speech_bubble_text, -4.0) + .parent(id) + .set(state.ids.speech_bubble_mid, ui); + Image::new(if dark_mode { + self.imgs.dark_bubble_right + } else { + self.imgs.speech_bubble_right + }) + .w(16.0) + .padded_h_of(state.ids.speech_bubble_text, -4.0) + .mid_right_with_margin_on(state.ids.speech_bubble_text, -20.0) + .parent(id) + .set(state.ids.speech_bubble_right, ui); + Image::new(if dark_mode { + self.imgs.dark_bubble_bottom_left + } else { + self.imgs.speech_bubble_bottom_left + }) + .w_h(16.0, 16.0) + .bottom_left_with_margin_on(state.ids.speech_bubble_text, -20.0) + .parent(id) + .set(state.ids.speech_bubble_bottom_left, ui); + Image::new(if dark_mode { + self.imgs.dark_bubble_bottom + } else { + self.imgs.speech_bubble_bottom + }) + .h(16.0) + .padded_w_of(state.ids.speech_bubble_text, -4.0) + .mid_bottom_with_margin_on(state.ids.speech_bubble_text, -20.0) + .parent(id) + .set(state.ids.speech_bubble_bottom, ui); + Image::new(if dark_mode { + self.imgs.dark_bubble_bottom_right + } else { + self.imgs.speech_bubble_bottom_right + }) + .w_h(16.0, 16.0) + .bottom_right_with_margin_on(state.ids.speech_bubble_text, -20.0) + .parent(id) + .set(state.ids.speech_bubble_bottom_right, ui); + let tail = Image::new(if dark_mode { + self.imgs.dark_bubble_tail + } else { + self.imgs.speech_bubble_tail + }) + .parent(id) + .mid_bottom_with_margin_on(state.ids.speech_bubble_text, -32.0); - if dark_mode { - tail.w_h(22.0, 13.0) - } else { - tail.w_h(22.0, 28.0) - } - .set(state.ids.speech_bubble_tail, ui); + if dark_mode { + tail.w_h(22.0, 13.0) + } else { + tail.w_h(22.0, 28.0) + } + .set(state.ids.speech_bubble_tail, ui); - let mut text_shadow = Text::new(&bubble_contents) - .color(shadow_color) - .font_id(self.fonts.cyri.conrod_id) - .font_size(18) - .x_relative_to(state.ids.speech_bubble_text, 1.0) - .y_relative_to(state.ids.speech_bubble_text, -1.0) - .parent(id); - // Move text to front (conrod depth is lowest first; not a z-index) - text.depth(text_shadow.get_depth() - 1.0) - .set(state.ids.speech_bubble_text, ui); - if let Some(w) = text_shadow.get_w(ui) { - if w > MAX_BUBBLE_WIDTH { - text_shadow = text_shadow.w(MAX_BUBBLE_WIDTH); - } + let mut text_shadow = Text::new(&bubble_contents) + .color(shadow_color) + .font_id(self.fonts.cyri.conrod_id) + .font_size(18) + .x_relative_to(state.ids.speech_bubble_text, 1.0) + .y_relative_to(state.ids.speech_bubble_text, -1.0) + .parent(id); + // Move text to front (conrod depth is lowest first; not a z-index) + text.depth(text_shadow.get_depth() - 1.0) + .set(state.ids.speech_bubble_text, ui); + if let Some(w) = text_shadow.get_w(ui) { + if w > MAX_BUBBLE_WIDTH { + text_shadow = text_shadow.w(MAX_BUBBLE_WIDTH); } - text_shadow.set(state.ids.speech_bubble_shadow, ui); - let icon = if self.settings.speech_bubble_icon { - bubble_icon(bubble, self.imgs) - } else { - self.imgs.nothing - }; - Image::new(icon) + } + text_shadow.set(state.ids.speech_bubble_shadow, ui); + let icon = if self.settings.speech_bubble_icon { + bubble_icon(bubble, self.imgs) + } else { + self.imgs.nothing + }; + Image::new(icon) .w_h(16.0, 16.0) .top_left_with_margin_on(state.ids.speech_bubble_text, -16.0) // TODO: Figure out whether this should be parented. // .parent(id) .set(state.ids.speech_bubble_icon, ui); - } } } }