From 35ed03aa188c9e43605df9e91f739cfa4c227a01 Mon Sep 17 00:00:00 2001 From: CapsizeGlimmer <> Date: Fri, 5 Jun 2020 18:36:31 -0400 Subject: [PATCH] Implement chat mode icons in chat window --- .../element/icons/chat/broadcast_small.png | 3 + assets/voxygen/element/icons/chat/faction.png | 3 + .../element/icons/chat/faction_small.png | 3 + assets/voxygen/element/icons/chat/group.png | 3 + .../element/icons/chat/group_small.png | 3 + .../voxygen/element/icons/chat/kill_small.png | 3 + .../element/icons/chat/private_small.png | 3 + assets/voxygen/element/icons/chat/region.png | 3 + .../element/icons/chat/region_small.png | 3 + assets/voxygen/element/icons/chat/say.png | 3 + .../voxygen/element/icons/chat/say_small.png | 3 + assets/voxygen/element/icons/chat/tell.png | 3 + .../voxygen/element/icons/chat/tell_small.png | 3 + assets/voxygen/element/icons/chat/world.png | 3 + .../element/icons/chat/world_small.png | 3 + common/src/comp/chat.rs | 45 +++-- server/src/cmd.rs | 14 +- voxygen/src/hud/chat.rs | 174 ++++++++++++------ voxygen/src/hud/img_ids.rs | 12 +- voxygen/src/hud/overhead.rs | 1 + 20 files changed, 206 insertions(+), 85 deletions(-) create mode 100644 assets/voxygen/element/icons/chat/broadcast_small.png create mode 100644 assets/voxygen/element/icons/chat/faction.png create mode 100644 assets/voxygen/element/icons/chat/faction_small.png create mode 100644 assets/voxygen/element/icons/chat/group.png create mode 100644 assets/voxygen/element/icons/chat/group_small.png create mode 100644 assets/voxygen/element/icons/chat/kill_small.png create mode 100644 assets/voxygen/element/icons/chat/private_small.png create mode 100644 assets/voxygen/element/icons/chat/region.png create mode 100644 assets/voxygen/element/icons/chat/region_small.png create mode 100644 assets/voxygen/element/icons/chat/say.png create mode 100644 assets/voxygen/element/icons/chat/say_small.png create mode 100644 assets/voxygen/element/icons/chat/tell.png create mode 100644 assets/voxygen/element/icons/chat/tell_small.png create mode 100644 assets/voxygen/element/icons/chat/world.png create mode 100644 assets/voxygen/element/icons/chat/world_small.png diff --git a/assets/voxygen/element/icons/chat/broadcast_small.png b/assets/voxygen/element/icons/chat/broadcast_small.png new file mode 100644 index 0000000000..f4e11ee581 --- /dev/null +++ b/assets/voxygen/element/icons/chat/broadcast_small.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fecd03a12311c4e8123a6586983f41b97c77de2d31a4ab9fb4ff036f95756b62 +size 281 diff --git a/assets/voxygen/element/icons/chat/faction.png b/assets/voxygen/element/icons/chat/faction.png new file mode 100644 index 0000000000..322729d7f6 --- /dev/null +++ b/assets/voxygen/element/icons/chat/faction.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:315924a9a46e3387c1dc844df167032b7b5ac01cb1e9dc0d9336d0642c3829a8 +size 368 diff --git a/assets/voxygen/element/icons/chat/faction_small.png b/assets/voxygen/element/icons/chat/faction_small.png new file mode 100644 index 0000000000..992c9f1dd9 --- /dev/null +++ b/assets/voxygen/element/icons/chat/faction_small.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9f038ad259bce5e47a321761ae6c3e721b69e07d5564de0ecf5c4b512c51f7f1 +size 240 diff --git a/assets/voxygen/element/icons/chat/group.png b/assets/voxygen/element/icons/chat/group.png new file mode 100644 index 0000000000..b109d4dd8f --- /dev/null +++ b/assets/voxygen/element/icons/chat/group.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2f0a15259682f60dfa8ae1a8de52f2246743e6b06b8eab25fe7d5a416ae5498c +size 234 diff --git a/assets/voxygen/element/icons/chat/group_small.png b/assets/voxygen/element/icons/chat/group_small.png new file mode 100644 index 0000000000..6c2637ae1c --- /dev/null +++ b/assets/voxygen/element/icons/chat/group_small.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6908780b4fe40303cef95338b82e72d380d03f0b2e5d4bb6cc31ce18946a0bc5 +size 263 diff --git a/assets/voxygen/element/icons/chat/kill_small.png b/assets/voxygen/element/icons/chat/kill_small.png new file mode 100644 index 0000000000..925a6866d0 --- /dev/null +++ b/assets/voxygen/element/icons/chat/kill_small.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a07ac4a0a435a14847e28dda7d4447e56f3b4b7db3cbb478e4cc71bd2b2e5338 +size 359 diff --git a/assets/voxygen/element/icons/chat/private_small.png b/assets/voxygen/element/icons/chat/private_small.png new file mode 100644 index 0000000000..c7d4877bdd --- /dev/null +++ b/assets/voxygen/element/icons/chat/private_small.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:59a12c3ab7f409b49df84003a8a2efd3929feb187e6e8124438f2ef19a0b09a9 +size 238 diff --git a/assets/voxygen/element/icons/chat/region.png b/assets/voxygen/element/icons/chat/region.png new file mode 100644 index 0000000000..188dc6bb61 --- /dev/null +++ b/assets/voxygen/element/icons/chat/region.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2546647ffad4bbea8653e2aed2ffaa09ce83fe4cbe261952132147385cc7535b +size 641 diff --git a/assets/voxygen/element/icons/chat/region_small.png b/assets/voxygen/element/icons/chat/region_small.png new file mode 100644 index 0000000000..f7b5d644b4 --- /dev/null +++ b/assets/voxygen/element/icons/chat/region_small.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f04af02e8c27117a4476571c579b30a4fc905036f0dc41e822306f998b52d118 +size 442 diff --git a/assets/voxygen/element/icons/chat/say.png b/assets/voxygen/element/icons/chat/say.png new file mode 100644 index 0000000000..22572696f4 --- /dev/null +++ b/assets/voxygen/element/icons/chat/say.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4eed0d46a6b45f1bbea3cc377a92437b12b2638267529942065489ddeaf3b146 +size 523 diff --git a/assets/voxygen/element/icons/chat/say_small.png b/assets/voxygen/element/icons/chat/say_small.png new file mode 100644 index 0000000000..98bf8a1bd1 --- /dev/null +++ b/assets/voxygen/element/icons/chat/say_small.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:44e9e5b592c5ece4ae4e73bc7436ae859691fc5990f8ed55690d0ebdde2eb474 +size 357 diff --git a/assets/voxygen/element/icons/chat/tell.png b/assets/voxygen/element/icons/chat/tell.png new file mode 100644 index 0000000000..60cb01ff01 --- /dev/null +++ b/assets/voxygen/element/icons/chat/tell.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8ea8ee46472a2ca7cf7a7d56b7763ad81de3a8b5b84ba7d884853c042cd90c49 +size 431 diff --git a/assets/voxygen/element/icons/chat/tell_small.png b/assets/voxygen/element/icons/chat/tell_small.png new file mode 100644 index 0000000000..46e922693d --- /dev/null +++ b/assets/voxygen/element/icons/chat/tell_small.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0d48cb6b41f752d7696de7a5fbae32233a69c9138724ba914dbe09360e0f8e6b +size 319 diff --git a/assets/voxygen/element/icons/chat/world.png b/assets/voxygen/element/icons/chat/world.png new file mode 100644 index 0000000000..7dda8f8d6e --- /dev/null +++ b/assets/voxygen/element/icons/chat/world.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:317e46dfc0c7cd990dc24e436a2d57fcfd8858b8d6f2cffcbabda0601a03f24a +size 406 diff --git a/assets/voxygen/element/icons/chat/world_small.png b/assets/voxygen/element/icons/chat/world_small.png new file mode 100644 index 0000000000..b5d7c70dca --- /dev/null +++ b/assets/voxygen/element/icons/chat/world_small.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:305149ed08d99176a7449f73baf826e3d54af161af5053d65e20a35ba5ce5424 +size 287 diff --git a/common/src/comp/chat.rs b/common/src/comp/chat.rs index 57ca1d2596..5be6601c59 100644 --- a/common/src/comp/chat.rs +++ b/common/src/comp/chat.rs @@ -94,25 +94,28 @@ impl ChatMsg { } pub fn to_bubble(&self) -> Option<(SpeechBubble, Uid)> { - let tuple = match &self.chat_type { - ChatType::Broadcast => None, - ChatType::Private => None, - ChatType::Kill => None, - ChatType::Tell(u, _) => Some((SpeechBubbleIcon::Tell, u, None)), - ChatType::Say(u) => Some((SpeechBubbleIcon::Say, u, None)), - ChatType::Group(u, _s) => Some((SpeechBubbleIcon::Group, u, None)), - ChatType::Faction(u, _s) => Some((SpeechBubbleIcon::Faction, u, None)), - ChatType::Region(u) => Some((SpeechBubbleIcon::Region, u, None)), - ChatType::World(u) => Some((SpeechBubbleIcon::World, u, None)), - ChatType::Npc(u, r) => Some((SpeechBubbleIcon::None, u, Some(r))), - }; - tuple.map(|(icon, from, npc_rand)| { - if let Some(r) = npc_rand { - (SpeechBubble::npc_new(self.message.clone(), *r, icon), *from) - } else { - (SpeechBubble::player_new(self.message.clone(), icon), *from) - } - }) + let icon = self.icon(); + if let ChatType::Npc(from, r) = self.chat_type { + Some((SpeechBubble::npc_new(self.message.clone(), r, icon), from)) + } else { + self.uid() + .map(|from| (SpeechBubble::player_new(self.message.clone(), icon), from)) + } + } + + pub fn icon(&self) -> SpeechBubbleIcon { + match &self.chat_type { + ChatType::Broadcast => SpeechBubbleIcon::Broadcast, + ChatType::Private => SpeechBubbleIcon::Private, + ChatType::Kill => SpeechBubbleIcon::Kill, + ChatType::Tell(_u, _) => SpeechBubbleIcon::Tell, + ChatType::Say(_u) => SpeechBubbleIcon::Say, + ChatType::Group(_u, _s) => SpeechBubbleIcon::Group, + ChatType::Faction(_u, _s) => SpeechBubbleIcon::Faction, + ChatType::Region(_u) => SpeechBubbleIcon::Region, + ChatType::World(_u) => SpeechBubbleIcon::World, + ChatType::Npc(_u, _r) => SpeechBubbleIcon::None, + } } pub fn uid(&self) -> Option { @@ -174,6 +177,10 @@ pub enum SpeechBubbleIcon { Group, Faction, World, + // Server chat types + Broadcast, + Private, + Kill, // For NPCs Quest, // TODO not implemented Trade, // TODO not implemented diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 680126bb67..2370832476 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -652,16 +652,18 @@ fn handle_help( if let Some(cmd) = scan_fmt_some!(&args, &action.arg_fmt(), ChatCommand) { server.notify_client(client, ServerMsg::private(String::from(cmd.help_string()))); } else { + let mut message = String::new(); for cmd in CHAT_COMMANDS.iter() { if !cmd.needs_admin() || server.entity_is_admin(client) { - server.notify_client(client, ServerMsg::private(String::from(cmd.help_string()))); + message += &cmd.help_string(); + message += "\n"; } } - let shortcuts = CHAT_SHORTCUTS.iter().fold( - "Aditionally, you can use the following shortcuts:".to_string(), - |s, (k, v)| format!("{}\n/{} => /{}", s, k, v.keyword()), - ); - server.notify_client(client, ServerMsg::private(shortcuts.to_string())); + message += "Additionally, you can use the following shortcuts:"; + for (k, v) in CHAT_SHORTCUTS.iter() { + message += &format!(" /{} => /{}", k, v.keyword()); + } + server.notify_client(client, ServerMsg::private(message)); } } diff --git a/voxygen/src/hud/chat.rs b/voxygen/src/hud/chat.rs index bfa629c4b2..007ca53312 100644 --- a/voxygen/src/hud/chat.rs +++ b/voxygen/src/hud/chat.rs @@ -15,8 +15,8 @@ use conrod_core::{ self, cursor::{self, Index}, }, - widget::{self, Button, Id, List, Rectangle, Text, TextEdit}, - widget_ids, Colorable, Positionable, Sizeable, Ui, UiCell, Widget, WidgetCommon, + widget::{self, Button, Id, Image, List, Rectangle, Text, TextEdit}, + widget_ids, Color, Colorable, Positionable, Sizeable, Ui, UiCell, Widget, WidgetCommon, }; use specs::world::WorldExt; use std::collections::VecDeque; @@ -28,12 +28,15 @@ widget_ids! { chat_input, chat_input_bg, chat_arrow, - completion_box, + chat_icons[], } } const MAX_MESSAGES: usize = 100; +const CHAT_BOX_WIDTH: f64 = 470.0; +const CHAT_BOX_HEIGHT: f64 = 174.0; + #[derive(WidgetCommon)] pub struct Chat<'a> { new_messages: &'a mut VecDeque, @@ -291,10 +294,10 @@ impl<'a> Widget for Chat<'a> { Dimension::Absolute(y) => y + 6.0, _ => 0.0, }; - Rectangle::fill([470.0, y]) + Rectangle::fill([CHAT_BOX_WIDTH, y]) .rgba(0.0, 0.0, 0.0, transp + 0.1) .bottom_left_with_margins_on(ui.window, 10.0, 10.0) - .w(470.0) + .w(CHAT_BOX_WIDTH) .set(state.ids.chat_input_bg, ui); if let Some(str) = text_edit @@ -309,27 +312,8 @@ impl<'a> Widget for Chat<'a> { } } - let alias_of_uid = |uid| { - self.client - .player_list - .get(uid) - .map_or("".to_string(), |player_info| { - if player_info.is_admin { - format!("ADMIN - {}", player_info.player_alias) - } else { - player_info.player_alias.to_string() - } - }) - }; - let message_format = |uid, message, group| { - if let Some(group) = group { - format!("{{{}}} [{}]: {}", group, alias_of_uid(uid), message) - } else { - format!("[{}]: {}", alias_of_uid(uid), message) - } - }; // Message box - Rectangle::fill([470.0, 174.0]) + Rectangle::fill([CHAT_BOX_WIDTH, CHAT_BOX_HEIGHT]) .rgba(0.0, 0.0, 0.0, transp) .and(|r| { if input_focused { @@ -338,49 +322,30 @@ impl<'a> Widget for Chat<'a> { r.bottom_left_with_margins_on(ui.window, 10.0, 10.0) } }) + .crop_kids() .set(state.ids.message_box_bg, ui); let (mut items, _) = List::flow_down(state.messages.len() + 1) - .top_left_of(state.ids.message_box_bg) - .w_h(470.0, 174.0) + .top_left_with_margins_on(state.ids.message_box_bg, 0.0, 16.0) + .w_h(CHAT_BOX_WIDTH, CHAT_BOX_HEIGHT) .scroll_kids_vertically() .set(state.ids.message_box, ui); + if state.ids.chat_icons.len() < state.messages.len() { + state.update(|s| { + s.ids + .chat_icons + .resize(s.messages.len(), &mut ui.widget_id_generator()) + }); + } + while let Some(item) = items.next(ui) { // This would be easier if conrod used the v-metrics from rusttype. if item.i < state.messages.len() { - let ChatMsg { chat_type, message } = &state.messages[item.i]; - let (color, msg) = match chat_type { - ChatType::Private => (PRIVATE_COLOR, message.to_string()), - ChatType::Broadcast => (BROADCAST_COLOR, message.to_string()), - ChatType::Kill => (KILL_COLOR, message.to_string()), - ChatType::Tell(from, to) => { - let from_alias = alias_of_uid(&from); - let to_alias = alias_of_uid(&to); - if Some(from) - == self - .client - .state() - .ecs() - .read_storage() - .get(self.client.entity()) - { - (TELL_COLOR, format!("To [{}]: {}", to_alias, message)) - } else { - (TELL_COLOR, format!("From [{}]: {}", from_alias, message)) - } - }, - ChatType::Say(uid) => (SAY_COLOR, message_format(uid, message, None)), - ChatType::Group(uid, s) => (GROUP_COLOR, message_format(uid, message, Some(s))), - ChatType::Faction(uid, s) => { - (FACTION_COLOR, message_format(uid, message, Some(s))) - }, - ChatType::Region(uid) => (REGION_COLOR, message_format(uid, message, None)), - ChatType::World(uid) => (WORLD_COLOR, message_format(uid, message, None)), - ChatType::Npc(_uid, _r) => continue, // Should be filtered by hud/mod.rs - }; + let (color, msg, icon) = + render_chat_line(&state.messages[item.i], &self.imgs, &self.client); let text = Text::new(&msg) .font_size(self.fonts.opensans.scale(15)) .font_id(self.fonts.opensans.conrod_id) - .w(470.0) + .w(CHAT_BOX_WIDTH - 16.0) .color(color) .line_spacing(2.0); // Add space between messages. @@ -390,13 +355,19 @@ impl<'a> Widget for Chat<'a> { }; let widget = text.h(y); item.set(widget, ui); + let icon_id = state.ids.chat_icons[item.i]; + Image::new(icon) + .w_h(16.0, 16.0) + .top_left_with_margins_on(item.widget_id, 2.0, -16.0) + .parent(state.ids.message_box_bg) + .set(icon_id, ui); } else { // Spacer at bottom of the last message so that it is not cut off. // Needs to be larger than the space above. let widget = Text::new("") .font_size(self.fonts.opensans.scale(6)) .font_id(self.fonts.opensans.conrod_id) - .w(470.0); + .w(CHAT_BOX_WIDTH); item.set(widget, ui); }; } @@ -409,6 +380,7 @@ impl<'a> Widget for Chat<'a> { .hover_image(self.imgs.chat_arrow_mo) .press_image(self.imgs.chat_arrow_press) .bottom_right_with_margins_on(state.ids.message_box_bg, 0.0, -22.0) + .parent(id) .set(state.ids.chat_arrow, ui) .was_clicked() { @@ -511,3 +483,87 @@ fn cursor_offset_to_index( cursor::index_before_char(infos, offset) } + +fn render_chat_line( + ChatMsg { chat_type, message }: &ChatMsg, + imgs: &Imgs, + client: &Client, +) -> (Color, String, conrod_core::image::Id) { + let alias_of_uid = |uid| { + client + .player_list + .get(uid) + .map_or("".to_string(), |player_info| { + if player_info.is_admin { + format!("ADMIN - {}", player_info.player_alias) + } else { + player_info.player_alias.to_string() + } + }) + }; + let message_format = |uid, message, group| { + if let Some(group) = group { + format!("{{{}}} [{}]: {}", group, alias_of_uid(uid), message) + } else { + format!("[{}]: {}", alias_of_uid(uid), message) + } + }; + match chat_type { + ChatType::Private => (PRIVATE_COLOR, message.to_string(), imgs.chat_private_small), + ChatType::Broadcast => ( + BROADCAST_COLOR, + message.to_string(), + imgs.chat_broadcast_small, + ), + ChatType::Kill => (KILL_COLOR, message.to_string(), imgs.chat_kill_small), + ChatType::Tell(from, to) => { + let from_alias = alias_of_uid(&from); + let to_alias = alias_of_uid(&to); + if Some(from) + == client + .state() + .ecs() + .read_storage::() + .get(client.entity()) + { + ( + TELL_COLOR, + format!("To [{}]: {}", to_alias, message), + imgs.chat_tell_small, + ) + } else { + ( + TELL_COLOR, + format!("From [{}]: {}", from_alias, message), + imgs.chat_tell_small, + ) + } + }, + ChatType::Say(uid) => ( + SAY_COLOR, + message_format(uid, message, None), + imgs.chat_say_small, + ), + ChatType::Group(uid, s) => ( + GROUP_COLOR, + message_format(uid, message, Some(s)), + imgs.chat_group_small, + ), + ChatType::Faction(uid, s) => ( + FACTION_COLOR, + message_format(uid, message, Some(s)), + imgs.chat_faction_small, + ), + ChatType::Region(uid) => ( + REGION_COLOR, + message_format(uid, message, None), + imgs.chat_region_small, + ), + ChatType::World(uid) => ( + WORLD_COLOR, + message_format(uid, message, None), + imgs.chat_world_small, + ), + ChatType::Npc(_uid, _r) => panic!("NPCs can't talk"), // Should be filtered by hud/mod.rs + } +} diff --git a/voxygen/src/hud/img_ids.rs b/voxygen/src/hud/img_ids.rs index b7717367ff..21f742e49f 100644 --- a/voxygen/src/hud/img_ids.rs +++ b/voxygen/src/hud/img_ids.rs @@ -54,7 +54,6 @@ image_ids! { chat_arrow_press: "voxygen.element.buttons.arrow_down_press", - //////////////////////////////////////////////////////////////////////// @@ -298,6 +297,17 @@ image_ids! { dark_bubble_bottom_right: "voxygen.element.frames.bubble_dark.bottom_right", dark_bubble_tail: "voxygen.element.frames.bubble_dark.tail", + // Chat icons + chat_broadcast_small: "voxygen.element.icons.chat.broadcast_small", + chat_faction_small: "voxygen.element.icons.chat.faction_small", + chat_group_small: "voxygen.element.icons.chat.group_small", + chat_kill_small: "voxygen.element.icons.chat.kill_small", + chat_private_small: "voxygen.element.icons.chat.private_small", + chat_region_small: "voxygen.element.icons.chat.region_small", + chat_say_small: "voxygen.element.icons.chat.say_small", + chat_tell_small: "voxygen.element.icons.chat.tell_small", + chat_world_small: "voxygen.element.icons.chat.world_small", + nothing: (), } diff --git a/voxygen/src/hud/overhead.rs b/voxygen/src/hud/overhead.rs index da65e74d26..7bfc48d845 100644 --- a/voxygen/src/hud/overhead.rs +++ b/voxygen/src/hud/overhead.rs @@ -26,6 +26,7 @@ widget_ids! { speech_bubble_bottom, speech_bubble_bottom_right, speech_bubble_tail, + speech_bubble_icon, // Name name_bg,