diff options
3 files changed, 148 insertions, 38 deletions
diff --git a/main/data/conversation_content_view/view.ui b/main/data/conversation_content_view/view.ui index 51133890..fc7132aa 100644 --- a/main/data/conversation_content_view/view.ui +++ b/main/data/conversation_content_view/view.ui @@ -18,15 +18,49 @@ <property name="expand">True</property> <property name="visible">True</property> <child> - <object class="GtkBox"> - <property name="orientation">vertical</property> + <object class="GtkEventBox" id="main_wrap_event_box"> + <property name="valign">end</property> <property name="visible">True</property> - <child> - <object class="GtkBox" id="main"> - <property name="margin-bottom">15</property> - <property name="expand">False</property> - <property name="orientation">vertical</property> - <property name="visible">True</property> + <child> + <object class="GtkOverlay"> + <property name="visible">True</property> + <child> + <object class="GtkEventBox" id="main_event_box"> + <property name="visible">True</property> + <child> + <object class="GtkBox" id="main"> + <property name="margin-bottom">15</property> + <property name="expand">False</property> + <property name="orientation">vertical</property> + <property name="visible">True</property> + </object> + </child> + </object> + </child> + <child type="overlay"> + <object class="GtkBox" id="message_menu_box"> + <property name="margin-right">10</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">end</property> + <property name="valign">start</property> + <child> + <object class="GtkMenuButton" id="emoji_button"> + <property name="vexpand">False</property> + <property name="halign">end</property> + <property name="valign">end</property> + <property name="visible">True</property> + <child> + <object class="GtkImage"> + <property name="icon-name">dino-emoticon-add-symbolic</property> + <property name="icon-size">1</property> + <property name="visible">True</property> + </object> + </child> + </object> + </child> + </object> + </child> </object> </child> </object> diff --git a/main/src/ui/conversation_content_view/conversation_item_skeleton.vala b/main/src/ui/conversation_content_view/conversation_item_skeleton.vala index dbba2276..a87c8489 100644 --- a/main/src/ui/conversation_content_view/conversation_item_skeleton.vala +++ b/main/src/ui/conversation_content_view/conversation_item_skeleton.vala @@ -22,7 +22,7 @@ public class ConversationItemSkeleton : EventBox { private Box header_content_box = new Box(Orientation.VERTICAL, 0) { visible=true }; private ItemMetaDataHeader metadata_header; - public ConversationItemSkeleton(StreamInteractor stream_interactor, Conversation conversation, Plugins.MetaConversationItem item) { + public ConversationItemSkeleton(StreamInteractor stream_interactor, Conversation conversation, Plugins.MetaConversationItem item, bool initial_item) { this.stream_interactor = stream_interactor; this.conversation = conversation; this.item = item; @@ -44,23 +44,17 @@ public class ConversationItemSkeleton : EventBox { } image_content_box.add(header_content_box); - this.add(image_content_box); - - if (item.get_type().is_a(typeof(ContentMetaItem))) { - this.motion_notify_event.connect((event) => { - this.set_state_flags(StateFlags.PRELIGHT, false); - return false; - }); - this.enter_notify_event.connect((event) => { - this.set_state_flags(StateFlags.PRELIGHT, false); - return false; - }); - this.leave_notify_event.connect((event) => { - this.unset_state_flags(StateFlags.PRELIGHT); - return false; - }); + + if (initial_item) { + this.add(image_content_box); + } else { + Revealer revealer = new Revealer() { transition_duration=200, transition_type = RevealerTransitionType.SLIDE_UP, visible = true }; + revealer.add_with_properties(image_content_box); + revealer.reveal_child = true; + this.add(revealer); } + this.notify["show-skeleton"].connect(update_margin); this.notify["last-group-item"].connect(update_margin); diff --git a/main/src/ui/conversation_content_view/conversation_view.vala b/main/src/ui/conversation_content_view/conversation_view.vala index 6c286fc0..f7f1faf2 100644 --- a/main/src/ui/conversation_content_view/conversation_view.vala +++ b/main/src/ui/conversation_content_view/conversation_view.vala @@ -1,5 +1,6 @@ using Gee; using Gtk; +using Gdk; using Pango; using Dino.Entities; @@ -13,8 +14,11 @@ public class ConversationView : Box, Plugins.ConversationItemCollection, Plugins [GtkChild] public ScrolledWindow scrolled; [GtkChild] private Revealer notification_revealer; + [GtkChild] private Box message_menu_box; [GtkChild] private Box notifications; [GtkChild] private Box main; + [GtkChild] private EventBox main_event_box; + [GtkChild] private EventBox main_wrap_event_box; [GtkChild] private Stack stack; private StreamInteractor stream_interactor; @@ -25,6 +29,7 @@ public class ConversationView : Box, Plugins.ConversationItemCollection, Plugins private Gee.List<ConversationItemSkeleton> item_skeletons = new Gee.ArrayList<ConversationItemSkeleton>(); private ContentProvider content_populator; private SubscriptionNotitication subscription_notification; + private bool enable_menu_box = false; private double? was_value; private double? was_upper; @@ -35,6 +40,10 @@ public class ConversationView : Box, Plugins.ConversationItemCollection, Plugins private bool firstLoad = true; private bool at_current_content = true; private bool reload_messages = true; + Widget currently_highlighted = null; + ContentItem current_highlighted_item = null; + bool mouse_inside = false; + int last_y_root = -1; public ConversationView init(StreamInteractor stream_interactor) { this.stream_interactor = stream_interactor; @@ -57,9 +66,89 @@ public class ConversationView : Box, Plugins.ConversationItemCollection, Plugins } return true; }); + + main_wrap_event_box.events = EventMask.ENTER_NOTIFY_MASK; + main_wrap_event_box.events = EventMask.LEAVE_NOTIFY_MASK; + main_wrap_event_box.leave_notify_event.connect(on_leave_notify_event); + main_wrap_event_box.enter_notify_event.connect(on_enter_notify_event); + main_event_box.events = EventMask.POINTER_MOTION_MASK; + main_event_box.motion_notify_event.connect(on_motion_notify_event); + return this; } + private bool on_enter_notify_event(Gdk.EventCrossing event) { + mouse_inside = true; + update_highlight((int)event.x_root, (int)event.y_root); + return false; + } + + private bool on_leave_notify_event(Gdk.EventCrossing event) { + mouse_inside = false; + if (currently_highlighted != null) currently_highlighted.unset_state_flags(StateFlags.PRELIGHT); + message_menu_box.visible = false; + return false; + } + + private bool on_motion_notify_event(Gdk.EventMotion event) { + mouse_inside = true; + update_highlight((int)event.x_root, (int)event.y_root); + return false; + } + + private void update_highlight(int x_root, int y_root) { + if ((last_y_root - y_root).abs() <= 2) { + return; + } + + last_y_root = y_root; + message_menu_box.visible = enable_menu_box; + + // Get pointer location in main + int geometry_x, geometry_y, geometry_width, geometry_height, dest_x, dest_y; + Widget toplevel_widget = this.get_toplevel(); + toplevel_widget.get_window().get_geometry(out geometry_x, out geometry_y, out geometry_width, out geometry_height); + toplevel_widget.translate_coordinates(main, x_root - geometry_x, y_root - geometry_y, out dest_x, out dest_y); + + // Get widget under pointer + int h = 0; + bool @break = false; + Widget w = null; + main.@foreach((widget) => { + if (break) return; + + h += widget.get_allocated_height(); + w = widget; + if (h >= dest_y) { + @break = true; + return; + } + }); + + // Get widget coordinates in main + int widget_x, widget_y; + w.translate_coordinates(main, 0, 0, out widget_x, out widget_y); + + // Get MessageItem + var iter = widgets.map_iterator(); + while (iter.next()) { + if (iter.get_value() == w) { + Plugins.MetaConversationItem meta_item = iter.get_key(); + var meta_content_item = meta_item as ContentMetaItem; + if (meta_content_item == null) return; + current_highlighted_item = meta_content_item.content_item; + } + } + + // Highlight widget + if (currently_highlighted != null) currently_highlighted.unset_state_flags(StateFlags.PRELIGHT); + w.set_state_flags(StateFlags.PRELIGHT, true); + currently_highlighted = w; + + // Move message menu + message_menu_box.margin_top = widget_y - 10; + } + public void initialize_for_conversation(Conversation? conversation) { // Workaround for rendering issues if (firstLoad) { @@ -75,6 +164,8 @@ public class ConversationView : Box, Plugins.ConversationItemCollection, Plugins initialize_for_conversation_(conversation); display_latest(); stack.set_visible_child_name("main"); + + enable_menu_box = false; } public void initialize_around_message(Conversation conversation, ContentItem content_item) { @@ -231,24 +322,15 @@ public class ConversationView : Box, Plugins.ConversationItemCollection, Plugins Plugins.MetaConversationItem? lower_item = meta_items.lower(item); // Fill datastructure - ConversationItemSkeleton item_skeleton = new ConversationItemSkeleton(stream_interactor, conversation, item) { visible=true }; + ConversationItemSkeleton item_skeleton = new ConversationItemSkeleton(stream_interactor, conversation, item, !animate) { visible=true }; item_item_skeletons[item] = item_skeleton; int index = lower_item != null ? item_skeletons.index_of(item_item_skeletons[lower_item]) + 1 : 0; item_skeletons.insert(index, item_skeleton); // Insert widget - Widget insert = item_skeleton; - if (animate) { - Revealer revealer = new Revealer() {transition_duration = 200, transition_type = RevealerTransitionType.SLIDE_UP, visible = true}; - revealer.add(item_skeleton); - insert = revealer; - main.add(insert); - revealer.reveal_child = true; - } else { - main.add(insert); - } - widgets[item] = insert; - main.reorder_child(insert, index); + widgets[item] = item_skeleton; + main.add(item_skeleton); + main.reorder_child(item_skeleton, index); if (lower_item != null) { if (can_merge(item, lower_item)) { @@ -279,7 +361,7 @@ public class ConversationView : Box, Plugins.ConversationItemCollection, Plugins } } } - return insert; + return item_skeleton; } private bool can_merge(Plugins.MetaConversationItem upper_item /*more recent, displayed below*/, Plugins.MetaConversationItem lower_item /*less recent, displayed above*/) { |