Merge branch 'synis/chat-tweaks' into 'master'

Synis/chat tweaks

See merge request veloren/veloren!4289
This commit is contained in:
Imbris 2024-03-01 16:42:10 +00:00
commit 5c517e88c9
5 changed files with 211 additions and 75 deletions

View File

@ -50,6 +50,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added dungeon: Terracotta Ruins - Added dungeon: Terracotta Ruins
- Sand and crystal cave biome - Sand and crystal cave biome
- In commands that reference assets you can now use `#name` and press tab to cycle through assets with that name. - In commands that reference assets you can now use `#name` and press tab to cycle through assets with that name.
- Allow moving and resizing the chat with left and right mouse button respectively
### Changed ### Changed

View File

@ -2,7 +2,12 @@ use super::{
img_ids::Imgs, ChatTab, ERROR_COLOR, FACTION_COLOR, GROUP_COLOR, INFO_COLOR, KILL_COLOR, img_ids::Imgs, ChatTab, ERROR_COLOR, FACTION_COLOR, GROUP_COLOR, INFO_COLOR, KILL_COLOR,
OFFLINE_COLOR, ONLINE_COLOR, REGION_COLOR, SAY_COLOR, TELL_COLOR, TEXT_COLOR, WORLD_COLOR, OFFLINE_COLOR, ONLINE_COLOR, REGION_COLOR, SAY_COLOR, TELL_COLOR, TEXT_COLOR, WORLD_COLOR,
}; };
use crate::{cmd::complete, settings::chat::MAX_CHAT_TABS, ui::fonts::Fonts, GlobalState}; use crate::{
cmd::complete,
settings::chat::MAX_CHAT_TABS,
ui::{fonts::Fonts, Scale},
GlobalState,
};
use client::Client; use client::Client;
use common::comp::{group::Role, ChatMode, ChatMsg, ChatType}; use common::comp::{group::Role, ChatMode, ChatMsg, ChatType};
use conrod_core::{ use conrod_core::{
@ -20,9 +25,11 @@ use conrod_core::{
use i18n::Localization; use i18n::Localization;
use i18n_helpers::localize_chat_message; use i18n_helpers::localize_chat_message;
use std::collections::{HashSet, VecDeque}; use std::collections::{HashSet, VecDeque};
use vek::{approx::AbsDiffEq, Vec2};
widget_ids! { widget_ids! {
struct Ids { struct Ids {
draggable_area,
message_box, message_box,
message_box_bg, message_box_bg,
chat_input, chat_input,
@ -48,14 +55,13 @@ widget_ids! {
/*#[const_tweaker::tweak(min = 0.0, max = 60.0, step = 1.0)] /*#[const_tweaker::tweak(min = 0.0, max = 60.0, step = 1.0)]
const X: f64 = 18.0;*/ const X: f64 = 18.0;*/
const MAX_MESSAGES: usize = 100; pub const MAX_MESSAGES: usize = 100;
const CHAT_ICON_WIDTH: f64 = 16.0; const CHAT_ICON_WIDTH: f64 = 16.0;
const CHAT_MARGIN_THICKNESS: f64 = 2.0; const CHAT_MARGIN_THICKNESS: f64 = 2.0;
const CHAT_ICON_HEIGHT: f64 = 16.0; const CHAT_ICON_HEIGHT: f64 = 16.0;
const CHAT_BOX_WIDTH: f64 = 470.0; const MIN_DIMENSION: Vec2<f64> = Vec2::new(400.0, 150.0);
const CHAT_BOX_INPUT_WIDTH: f64 = 460.0 - CHAT_ICON_WIDTH - 1.0; const MAX_DIMENSION: Vec2<f64> = Vec2::new(650.0, 500.0);
const CHAT_BOX_HEIGHT: f64 = 154.0;
const CHAT_TAB_HEIGHT: f64 = 20.0; const CHAT_TAB_HEIGHT: f64 = 20.0;
const CHAT_TAB_ALL_WIDTH: f64 = 40.0; const CHAT_TAB_ALL_WIDTH: f64 = 40.0;
@ -78,6 +84,7 @@ pub struct Chat<'a> {
// TODO: add an option to adjust this // TODO: add an option to adjust this
history_max: usize, history_max: usize,
scale: Scale,
localized_strings: &'a Localization, localized_strings: &'a Localization,
} }
@ -91,6 +98,7 @@ impl<'a> Chat<'a> {
imgs: &'a Imgs, imgs: &'a Imgs,
fonts: &'a Fonts, fonts: &'a Fonts,
localized_strings: &'a Localization, localized_strings: &'a Localization,
scale: Scale,
) -> Self { ) -> Self {
Self { Self {
pulse, pulse,
@ -105,6 +113,7 @@ impl<'a> Chat<'a> {
common: widget::CommonBuilder::default(), common: widget::CommonBuilder::default(),
history_max: 32, history_max: 32,
localized_strings, localized_strings,
scale,
} }
} }
@ -179,6 +188,9 @@ pub enum Event {
Focus(Id), Focus(Id),
ChangeChatTab(Option<usize>), ChangeChatTab(Option<usize>),
ShowChatTabSettings(usize), ShowChatTabSettings(usize),
ResizeChat(Vec2<f64>),
MoveChat(Vec2<f64>),
DisableForceChat,
} }
impl<'a> Widget for Chat<'a> { impl<'a> Widget for Chat<'a> {
@ -221,9 +233,12 @@ impl<'a> Widget for Chat<'a> {
let mut events = Vec::new(); let mut events = Vec::new();
let chat_settings = &self.global_state.settings.chat; let chat_settings = &self.global_state.settings.chat;
let force_chat = !(&self.global_state.settings.interface.toggle_chat);
let chat_tabs = &chat_settings.chat_tabs; let chat_tabs = &chat_settings.chat_tabs;
let current_chat_tab = chat_settings.chat_tab_index.and_then(|i| chat_tabs.get(i)); let current_chat_tab = chat_settings.chat_tab_index.and_then(|i| chat_tabs.get(i));
let chat_size = Vec2::new(chat_settings.chat_size_x, chat_settings.chat_size_y);
let chat_pos = Vec2::new(chat_settings.chat_pos_x, chat_settings.chat_pos_y);
let chat_box_input_width = chat_size.x - CHAT_ICON_WIDTH - 12.0;
// Empty old messages // Empty old messages
state.update(|s| { state.update(|s| {
@ -232,6 +247,47 @@ impl<'a> Widget for Chat<'a> {
} }
}); });
let chat_in_screen_upper = chat_pos.y > self.global_state.window.logical_size().y / 2.0;
let pos_delta: Vec2<f64> = ui
.widget_input(state.ids.draggable_area)
.drags()
.left()
.map(|drag| Vec2::<f64>::from(drag.delta_xy))
.sum();
let new_pos = (chat_pos + pos_delta).map(|e| e.max(0.)).map2(
self.scale
.scale_point(self.global_state.window.logical_size())
- Vec2::unit_y() * CHAT_TAB_HEIGHT
- chat_size,
|e, bounds| e.min(bounds),
);
if new_pos.abs_diff_ne(&chat_pos, f64::EPSILON) {
events.push(Event::MoveChat(new_pos));
}
let size_delta: Vec2<f64> = ui
.widget_input(state.ids.draggable_area)
.drags()
.right()
.map(|drag| Vec2::<f64>::from(drag.delta_xy))
.sum();
let new_size = (chat_size + size_delta)
.map3(
self.scale.scale_point(MIN_DIMENSION),
self.scale.scale_point(MAX_DIMENSION),
|sz, min, max| sz.clamp(min, max),
)
.map2(
self.scale
.scale_point(self.global_state.window.logical_size())
- Vec2::unit_y() * CHAT_TAB_HEIGHT
- new_pos,
|e, bounds| e.min(bounds),
);
if new_size.abs_diff_ne(&chat_size, f64::EPSILON) {
events.push(Event::ResizeChat(new_size));
}
// Maintain scrolling // // Maintain scrolling //
if !self.new_messages.is_empty() { if !self.new_messages.is_empty() {
for message in self.new_messages.iter() { for message in self.new_messages.iter() {
@ -307,7 +363,13 @@ impl<'a> Widget for Chat<'a> {
if let Some(replacement) = &s.completions.get(s.completions_index.unwrap()) { if let Some(replacement) = &s.completions.get(s.completions_index.unwrap()) {
let (completed, offset) = let (completed, offset) =
do_tab_completion(cursor, &s.input.message, replacement); do_tab_completion(cursor, &s.input.message, replacement);
force_cursor = cursor_offset_to_index(offset, &completed, ui, self.fonts); force_cursor = cursor_offset_to_index(
offset,
&completed,
ui,
self.fonts,
chat_box_input_width,
);
s.input.message = completed; s.input.message = completed;
} }
}); });
@ -339,6 +401,7 @@ impl<'a> Widget for Chat<'a> {
&s.input.message, &s.input.message,
ui, ui,
self.fonts, self.fonts,
chat_box_input_width,
); );
} else { } else {
s.input.message.clear(); s.input.message.clear();
@ -375,7 +438,7 @@ impl<'a> Widget for Chat<'a> {
// Any changes to this TextEdit's width and font size must be reflected in // Any changes to this TextEdit's width and font size must be reflected in
// `cursor_offset_to_index` below. // `cursor_offset_to_index` below.
let mut text_edit = TextEdit::new(&state.input.message) let mut text_edit = TextEdit::new(&state.input.message)
.w(CHAT_BOX_INPUT_WIDTH) .w(chat_box_input_width)
.restrict_to_height(false) .restrict_to_height(false)
.color(color) .color(color)
.line_spacing(2.0) .line_spacing(2.0)
@ -390,22 +453,28 @@ impl<'a> Widget for Chat<'a> {
Dimension::Absolute(y) => y + 6.0, Dimension::Absolute(y) => y + 6.0,
_ => 0.0, _ => 0.0,
}; };
Rectangle::fill([CHAT_BOX_WIDTH, y]) Rectangle::fill([chat_size.x, y])
.rgba(0.0, 0.0, 0.0, chat_settings.chat_opacity + 0.1) .rgba(0.0, 0.0, 0.0, chat_settings.chat_opacity)
.bottom_left_with_margins_on(ui.window, 10.0, 10.0) .w(chat_size.x)
.w(CHAT_BOX_WIDTH) .and(|r| {
if chat_in_screen_upper {
r.down_from(state.ids.message_box_bg, CHAT_MARGIN_THICKNESS / 2.0)
} else {
r.bottom_left_with_margins_on(ui.window, chat_pos.y, chat_pos.x)
}
})
.set(state.ids.chat_input_bg, ui); .set(state.ids.chat_input_bg, ui);
//border around focused chat window //border around focused chat window
let border_color = adjust_border_opacity(color, chat_settings.chat_opacity); let border_color = adjust_border_opacity(color, chat_settings.chat_opacity);
//top line //top line
Line::centred([0.0, 0.0], [CHAT_BOX_WIDTH, 0.0]) Line::centred([0.0, 0.0], [chat_size.x, 0.0])
.color(border_color) .color(border_color)
.thickness(CHAT_MARGIN_THICKNESS) .thickness(CHAT_MARGIN_THICKNESS)
.top_left_of(state.ids.chat_input_bg) .top_left_of(state.ids.chat_input_bg)
.set(state.ids.chat_input_border_up, ui); .set(state.ids.chat_input_border_up, ui);
//bottom line //bottom line
Line::centred([0.0, 0.0], [CHAT_BOX_WIDTH, 0.0]) Line::centred([0.0, 0.0], [chat_size.x, 0.0])
.color(border_color) .color(border_color)
.thickness(CHAT_MARGIN_THICKNESS) .thickness(CHAT_MARGIN_THICKNESS)
.bottom_left_of(state.ids.chat_input_bg) .bottom_left_of(state.ids.chat_input_bg)
@ -433,16 +502,16 @@ impl<'a> Widget for Chat<'a> {
} }
// Message box // Message box
Rectangle::fill([CHAT_BOX_WIDTH, CHAT_BOX_HEIGHT]) Rectangle::fill([chat_size.x, chat_size.y])
.rgba(0.0, 0.0, 0.0, chat_settings.chat_opacity) .rgba(0.0, 0.0, 0.0, chat_settings.chat_opacity)
.and(|r| { .and(|r| {
if input_focused { if input_focused && !chat_in_screen_upper {
r.up_from( r.up_from(
state.ids.chat_input_border_up, state.ids.chat_input_border_up,
0.0 + CHAT_MARGIN_THICKNESS / 2.0, 0.0 + CHAT_MARGIN_THICKNESS / 2.0,
) )
} else { } else {
r.bottom_left_with_margins_on(ui.window, 10.0, 10.0) r.bottom_left_with_margins_on(ui.window, chat_pos.y, chat_pos.x)
} }
}) })
.crop_kids() .crop_kids()
@ -503,13 +572,13 @@ impl<'a> Widget for Chat<'a> {
.resize(n_badges, &mut ui.widget_id_generator()) .resize(n_badges, &mut ui.widget_id_generator())
}) })
} }
Rectangle::fill_with([CHAT_ICON_WIDTH, CHAT_BOX_HEIGHT], color::TRANSPARENT) Rectangle::fill_with([CHAT_ICON_WIDTH, chat_size.y], color::TRANSPARENT)
.top_left_with_margins_on(state.ids.message_box_bg, 0.0, 0.0) .top_left_with_margins_on(state.ids.message_box_bg, 0.0, 0.0)
.crop_kids() .crop_kids()
.set(state.ids.chat_icon_align, ui); .set(state.ids.chat_icon_align, ui);
let (mut items, _) = List::flow_down(messages.len() + 1) let (mut items, _) = List::flow_down(messages.len() + 1)
.top_left_with_margins_on(state.ids.message_box_bg, 0.0, CHAT_ICON_WIDTH) .top_left_with_margins_on(state.ids.message_box_bg, 0.0, CHAT_ICON_WIDTH)
.w_h(CHAT_BOX_WIDTH - CHAT_ICON_WIDTH, CHAT_BOX_HEIGHT) .w_h(chat_size.x - CHAT_ICON_WIDTH, chat_size.y)
.scroll_kids_vertically() .scroll_kids_vertically()
.set(state.ids.message_box, ui); .set(state.ids.message_box, ui);
@ -527,9 +596,11 @@ impl<'a> Widget for Chat<'a> {
let text = Text::new(text) let text = Text::new(text)
.font_size(self.fonts.opensans.scale(15)) .font_size(self.fonts.opensans.scale(15))
.font_id(self.fonts.opensans.conrod_id) .font_id(self.fonts.opensans.conrod_id)
.w(CHAT_BOX_WIDTH - 17.0) .w(chat_size.x - CHAT_ICON_WIDTH - 1.0)
.wrap_by_word()
.color(color) .color(color)
.line_spacing(2.0); .line_spacing(2.0);
// Add space between messages. // Add space between messages.
let y = match text.get_y_dimension(ui) { let y = match text.get_y_dimension(ui) {
Dimension::Absolute(y) => y + 2.0, Dimension::Absolute(y) => y + 2.0,
@ -561,7 +632,7 @@ impl<'a> Widget for Chat<'a> {
Text::new("") Text::new("")
.font_size(self.fonts.opensans.scale(6)) .font_size(self.fonts.opensans.scale(6))
.font_id(self.fonts.opensans.conrod_id) .font_id(self.fonts.opensans.conrod_id)
.w(CHAT_BOX_WIDTH), .w(chat_size.x),
ui, ui,
); );
}; };
@ -581,10 +652,10 @@ impl<'a> Widget for Chat<'a> {
.filter(|t| t <= &1.5) .filter(|t| t <= &1.5)
{ {
let alpha = 1.0 - (time_since_hover / 1.5).powi(4); let alpha = 1.0 - (time_since_hover / 1.5).powi(4);
let shading = color::rgba(1.0, 0.82, 0.27, (chat_settings.chat_opacity + 0.1) * alpha); let shading = color::rgba(1.0, 0.82, 0.27, chat_settings.chat_opacity * alpha);
Rectangle::fill([CHAT_BOX_WIDTH, CHAT_TAB_HEIGHT]) Rectangle::fill([chat_size.x, CHAT_TAB_HEIGHT])
.rgba(0.0, 0.0, 0.0, (chat_settings.chat_opacity + 0.1) * alpha) .rgba(0.0, 0.0, 0.0, chat_settings.chat_opacity * alpha)
.up_from(state.ids.message_box_bg, 0.0) .up_from(state.ids.message_box_bg, 0.0)
.set(state.ids.chat_tab_align, ui); .set(state.ids.chat_tab_align, ui);
if ui if ui
@ -614,7 +685,7 @@ impl<'a> Widget for Chat<'a> {
events.push(Event::ChangeChatTab(None)); events.push(Event::ChangeChatTab(None));
} }
let chat_tab_width = (CHAT_BOX_WIDTH - CHAT_TAB_ALL_WIDTH) / (MAX_CHAT_TABS as f64); let chat_tab_width = (chat_size.x - CHAT_TAB_ALL_WIDTH) / (MAX_CHAT_TABS as f64);
if state.ids.chat_tabs.len() < chat_tabs.len() { if state.ids.chat_tabs.len() < chat_tabs.len() {
state.update(|s| { state.update(|s| {
@ -709,10 +780,23 @@ impl<'a> Widget for Chat<'a> {
} else if keyboard_capturer == Some(id) { } else if keyboard_capturer == Some(id) {
events.push(Event::Focus(state.ids.chat_input)); events.push(Event::Focus(state.ids.chat_input));
} }
// If either Return or Enter is pressed and the input box is not empty, send the current message. // If either Return or Enter is pressed and the input box is not empty, send the current
else if ui.widget_input(state.ids.chat_input).presses().key().any( // message.
|key_press| matches!(key_press.key, Key::Return | Key::NumPadEnter if !state.input.message.is_empty()), else if ui
) { .widget_input(state.ids.chat_input)
.presses()
.key()
.any(|key_press| {
let has_message = !state.input.message.is_empty();
let pressed = matches!(key_press.key, Key::Return | Key::NumPadEnter);
if pressed {
// If chat was hidden, scroll to bottom the next time it is opened
state.update(|s| s.scroll_next |= force_chat);
events.push(Event::DisableForceChat);
}
has_message && pressed
})
{
let msg = state.input.message.clone(); let msg = state.input.message.clone();
state.update(|s| { state.update(|s| {
s.input.message.clear(); s.input.message.clear();
@ -736,6 +820,16 @@ impl<'a> Widget for Chat<'a> {
events.push(Event::SendMessage(msg)); events.push(Event::SendMessage(msg));
} }
} }
Rectangle::fill_with([chat_size.x, chat_size.y], color::TRANSPARENT)
.and(|r| {
if input_focused {
r.up_from(state.ids.chat_input_border_up, CHAT_MARGIN_THICKNESS / 2.0)
} else {
r.bottom_left_with_margins_on(ui.window, chat_pos.y, chat_pos.x)
}
})
.set(state.ids.draggable_area, ui);
events events
} }
} }
@ -783,13 +877,19 @@ fn do_tab_completion(cursor: usize, input: &str, word: &str) -> (String, usize)
} }
} }
fn cursor_offset_to_index(offset: usize, text: &str, ui: &Ui, fonts: &Fonts) -> Option<Index> { fn cursor_offset_to_index(
offset: usize,
text: &str,
ui: &Ui,
fonts: &Fonts,
input_width: f64,
) -> Option<Index> {
// This moves the cursor to the given offset. Conrod is a pain. // This moves the cursor to the given offset. Conrod is a pain.
// //
// Width and font must match that of the chat TextEdit // Width and font must match that of the chat TextEdit
let font = ui.fonts.get(fonts.opensans.conrod_id)?; let font = ui.fonts.get(fonts.opensans.conrod_id)?;
let font_size = fonts.opensans.scale(15); let font_size = fonts.opensans.scale(15);
let infos = text::line::infos(text, font, font_size).wrap_by_whitespace(CHAT_BOX_INPUT_WIDTH); let infos = text::line::infos(text, font, font_size).wrap_by_whitespace(input_width);
cursor::index_before_char(infos, offset) cursor::index_before_char(infos, offset)
} }

View File

@ -1271,6 +1271,9 @@ pub struct Hud {
failed_entity_pickups: HashMap<EcsEntity, CollectFailedData>, failed_entity_pickups: HashMap<EcsEntity, CollectFailedData>,
new_loot_messages: VecDeque<LootMessage>, new_loot_messages: VecDeque<LootMessage>,
new_messages: VecDeque<comp::ChatMsg>, new_messages: VecDeque<comp::ChatMsg>,
// NOTE Used for storing messages sent while the chat is hidden. This is needed because NPC
// speech uses new_messages so we need to clear it every frame.
message_backlog: VecDeque<comp::ChatMsg>,
new_notifications: VecDeque<Notification>, new_notifications: VecDeque<Notification>,
speech_bubbles: HashMap<Uid, comp::SpeechBubble>, speech_bubbles: HashMap<Uid, comp::SpeechBubble>,
content_bubbles: Vec<(Vec3<f32>, comp::SpeechBubble)>, content_bubbles: Vec<(Vec3<f32>, comp::SpeechBubble)>,
@ -1292,6 +1295,7 @@ pub struct Hud {
floaters: Floaters, floaters: Floaters,
voxel_minimap: VoxelMinimap, voxel_minimap: VoxelMinimap,
map_drag: Vec2<f64>, map_drag: Vec2<f64>,
force_chat: bool,
} }
impl Hud { impl Hud {
@ -1368,6 +1372,7 @@ impl Hud {
failed_entity_pickups: HashMap::default(), failed_entity_pickups: HashMap::default(),
new_loot_messages: VecDeque::new(), new_loot_messages: VecDeque::new(),
new_messages: VecDeque::new(), new_messages: VecDeque::new(),
message_backlog: VecDeque::new(),
new_notifications: VecDeque::new(), new_notifications: VecDeque::new(),
speech_bubbles: HashMap::new(), speech_bubbles: HashMap::new(),
content_bubbles: Vec::new(), content_bubbles: Vec::new(),
@ -1427,6 +1432,7 @@ impl Hud {
block_floaters: Vec::new(), block_floaters: Vec::new(),
}, },
map_drag: Vec2::zero(), map_drag: Vec2::zero(),
force_chat: false,
} }
} }
@ -1463,6 +1469,7 @@ impl Hud {
if global_state.settings.interface.map_show_voxel_map { if global_state.settings.interface.map_show_voxel_map {
self.voxel_minimap.maintain(client, &mut self.ui); self.voxel_minimap.maintain(client, &mut self.ui);
} }
let scale = self.ui.scale();
let (ref mut ui_widgets, ref mut item_tooltip_manager, ref mut tooltip_manager) = let (ref mut ui_widgets, ref mut item_tooltip_manager, ref mut tooltip_manager) =
&mut self.ui.set_widgets(); &mut self.ui.set_widgets();
// self.ui.set_item_widgets(); pulse time for pulsating elements // self.ui.set_item_widgets(); pulse time for pulsating elements
@ -3445,12 +3452,50 @@ impl Hud {
} }
} }
if global_state.settings.audio.subtitles {
Subtitles::new(
client,
&global_state.settings,
&global_state.audio.get_listener().clone(),
&mut global_state.audio.subtitles,
&self.fonts,
i18n,
)
.set(self.ids.subtitles, ui_widgets);
}
//Loot
LootScroller::new(
&mut self.new_loot_messages,
client,
&info,
&self.show,
&self.imgs,
&self.item_imgs,
&self.rot_imgs,
&self.fonts,
i18n,
&self.item_i18n,
&msm,
item_tooltip_manager,
self.pulse,
)
.set(self.ids.loot_scroller, ui_widgets);
self.new_loot_messages.clear();
// Don't put NPC messages in chat box. // Don't put NPC messages in chat box.
self.new_messages self.new_messages
.retain(|m| !matches!(m.chat_type, comp::ChatType::Npc(_))); .retain(|m| !matches!(m.chat_type, comp::ChatType::Npc(_)));
// Chat box // Chat box
if global_state.settings.interface.toggle_chat { // Draw this after loot scroller and subtitles so it can be dragged
// even when hovering over them
// TODO look into parenting and then settings movable widgets to floating
if global_state.settings.interface.toggle_chat || self.force_chat {
for hidden in self.message_backlog.drain(..).rev() {
self.new_messages.push_front(hidden);
}
for event in Chat::new( for event in Chat::new(
&mut self.new_messages, &mut self.new_messages,
client, client,
@ -3459,6 +3504,7 @@ impl Hud {
&self.imgs, &self.imgs,
&self.fonts, &self.fonts,
i18n, i18n,
scale,
) )
.and_then(self.force_chat_input.take(), |c, input| c.input(input)) .and_then(self.force_chat_input.take(), |c, input| c.input(input))
.and_then(self.tab_complete.take(), |c, input| { .and_then(self.tab_complete.take(), |c, input| {
@ -3488,44 +3534,28 @@ impl Hud {
self.show.settings_tab = SettingsTab::Chat; self.show.settings_tab = SettingsTab::Chat;
self.show.settings(true); self.show.settings(true);
}, },
chat::Event::ResizeChat(size) => {
global_state.settings.chat.chat_size_x = size.x;
global_state.settings.chat.chat_size_y = size.y;
},
chat::Event::MoveChat(pos) => {
global_state.settings.chat.chat_pos_x = pos.x;
global_state.settings.chat.chat_pos_y = pos.y;
},
chat::Event::DisableForceChat => {
self.force_chat = false;
},
} }
} }
} else {
self.message_backlog.extend(self.new_messages.drain(..));
while self.message_backlog.len() > chat::MAX_MESSAGES {
self.message_backlog.pop_front();
}
} }
if global_state.settings.audio.subtitles { self.new_messages.clear();
Subtitles::new( self.new_notifications.clear();
client,
&global_state.settings,
&global_state.audio.get_listener().clone(),
&mut global_state.audio.subtitles,
&self.fonts,
i18n,
)
.set(self.ids.subtitles, ui_widgets);
}
self.new_messages = VecDeque::new();
self.new_notifications = VecDeque::new();
//Loot
LootScroller::new(
&mut self.new_loot_messages,
client,
&info,
&self.show,
&self.imgs,
&self.item_imgs,
&self.rot_imgs,
&self.fonts,
i18n,
&self.item_i18n,
&msm,
item_tooltip_manager,
self.pulse,
)
.set(self.ids.loot_scroller, ui_widgets);
self.new_loot_messages = VecDeque::new();
// Windows // Windows
@ -4608,18 +4638,10 @@ impl Hud {
if show.map { if show.map {
let new_zoom_lvl = (global_state.settings.interface.map_zoom * factor) let new_zoom_lvl = (global_state.settings.interface.map_zoom * factor)
.clamped(1.25, max_zoom / 64.0); .clamped(1.25, max_zoom / 64.0);
global_state.settings.interface.map_zoom = new_zoom_lvl; global_state.settings.interface.map_zoom = new_zoom_lvl;
global_state
.settings
.save_to_file_warn(&global_state.config_dir);
} else if global_state.settings.interface.minimap_show { } else if global_state.settings.interface.minimap_show {
let new_zoom_lvl = global_state.settings.interface.minimap_zoom * factor; let new_zoom_lvl = global_state.settings.interface.minimap_zoom * factor;
global_state.settings.interface.minimap_zoom = new_zoom_lvl; global_state.settings.interface.minimap_zoom = new_zoom_lvl;
global_state
.settings
.save_to_file_warn(&global_state.config_dir);
} }
show.map && global_state.settings.interface.minimap_show show.map && global_state.settings.interface.minimap_show
@ -4688,6 +4710,7 @@ impl Hud {
self.ui.focus_widget(if self.typing() { self.ui.focus_widget(if self.typing() {
None None
} else { } else {
self.force_chat = true;
Some(self.ids.chat) Some(self.ids.chat)
}); });
true true
@ -4695,6 +4718,7 @@ impl Hud {
WinEvent::InputUpdate(GameInput::Escape, true) => { WinEvent::InputUpdate(GameInput::Escape, true) => {
if self.typing() { if self.typing() {
self.ui.focus_widget(None); self.ui.focus_widget(None);
self.force_chat = false;
} else if self.show.trade { } else if self.show.trade {
self.events.push(Event::TradeAction(TradeAction::Decline)); self.events.push(Event::TradeAction(TradeAction::Decline));
} else { } else {
@ -4720,6 +4744,7 @@ impl Hud {
GameInput::Command if state => { GameInput::Command if state => {
self.force_chat_input = Some("/".to_owned()); self.force_chat_input = Some("/".to_owned());
self.force_chat_cursor = Some(Index { line: 0, char: 1 }); self.force_chat_cursor = Some(Index { line: 0, char: 1 });
self.force_chat = true;
self.ui.focus_widget(Some(self.ids.chat)); self.ui.focus_widget(Some(self.ids.chat));
true true
}, },

View File

@ -162,7 +162,7 @@ impl<'a> Widget for Chat<'a> {
if let Some(new_val) = ImageSlider::continuous( if let Some(new_val) = ImageSlider::continuous(
chat_settings.chat_opacity, chat_settings.chat_opacity,
0.0, 0.0,
0.9, 1.0,
self.imgs.slider_indicator, self.imgs.slider_indicator,
self.imgs.slider, self.imgs.slider,
) )

View File

@ -7,6 +7,8 @@ use serde::{Deserialize, Serialize};
use std::collections::HashSet; use std::collections::HashSet;
pub const MAX_CHAT_TABS: usize = 5; pub const MAX_CHAT_TABS: usize = 5;
pub const DEFAULT_CHAT_BOX_WIDTH: f64 = 470.0;
pub const DEFAULT_CHAT_BOX_HEIGHT: f64 = 150.0;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct ChatFilter { pub struct ChatFilter {
@ -74,6 +76,10 @@ pub struct ChatSettings {
pub chat_tabs: Vec<ChatTab>, pub chat_tabs: Vec<ChatTab>,
pub chat_tab_index: Option<usize>, pub chat_tab_index: Option<usize>,
pub chat_cmd_prefix: char, pub chat_cmd_prefix: char,
pub chat_pos_x: f64,
pub chat_pos_y: f64,
pub chat_size_x: f64,
pub chat_size_y: f64,
} }
impl Default for ChatSettings { impl Default for ChatSettings {
@ -84,6 +90,10 @@ impl Default for ChatSettings {
chat_tabs: vec![ChatTab::default()], chat_tabs: vec![ChatTab::default()],
chat_tab_index: Some(0), chat_tab_index: Some(0),
chat_cmd_prefix: '/', chat_cmd_prefix: '/',
chat_pos_x: 10.0,
chat_pos_y: 10.0,
chat_size_x: DEFAULT_CHAT_BOX_WIDTH,
chat_size_y: DEFAULT_CHAT_BOX_HEIGHT,
} }
} }
} }