Daniel Brötzmann pushed to branch master at gajim / gajim
Commits:
-
d7732dfa
by Daniel Brötzmann at 2021-03-25T21:09:05+01:00
-
fadc7596
by Daniel Brötzmann at 2021-03-25T21:09:09+01:00
7 changed files:
- gajim/chat_control_base.py
- gajim/common/modules/chatstates.py
- gajim/data/style/default-dark.css
- gajim/data/style/default.css
- gajim/data/style/gajim.css
- gajim/groupchat_control.py
- gajim/gtk/message_input.py
Changes:
| ... | ... | @@ -203,8 +203,8 @@ def __init__(self, parent_win, widget_name, contact, acct, |
| 203 | 203 |
self._on_message_textview_key_press_event)
|
| 204 | 204 |
self.msg_textview.connect('populate-popup',
|
| 205 | 205 |
self.on_msg_textview_populate_popup)
|
| 206 |
- self.msg_textview.connect('text-changed',
|
|
| 207 |
- self._on_message_tv_buffer_changed)
|
|
| 206 |
+ self.msg_textview.get_buffer().connect(
|
|
| 207 |
+ 'changed', self._on_message_tv_buffer_changed)
|
|
| 208 | 208 |
|
| 209 | 209 |
# Send message button
|
| 210 | 210 |
self.xml.send_message_button.set_action_name(
|
| ... | ... | @@ -217,6 +217,8 @@ def __init__(self, parent_win, widget_name, contact, acct, |
| 217 | 217 |
'set_visible')
|
| 218 | 218 |
|
| 219 | 219 |
self.msg_scrolledwindow = ScrolledWindow()
|
| 220 |
+ self.msg_scrolledwindow.get_style_context().add_class(
|
|
| 221 |
+ 'message-input-border')
|
|
| 220 | 222 |
self.msg_scrolledwindow.add(self.msg_textview)
|
| 221 | 223 |
|
| 222 | 224 |
self.xml.hbox.pack_start(self.msg_scrolledwindow, True, True, 0)
|
| ... | ... | @@ -742,7 +744,6 @@ def on_msg_textview_populate_popup(self, _textview, menu): |
| 742 | 744 |
menu.show_all()
|
| 743 | 745 |
|
| 744 | 746 |
def insert_as_quote(self, text: str) -> None:
|
| 745 |
- self.msg_textview.remove_placeholder()
|
|
| 746 | 747 |
text = '> ' + text.replace('\n', '\n> ') + '\n'
|
| 747 | 748 |
message_buffer = self.msg_textview.get_buffer()
|
| 748 | 749 |
message_buffer.insert_at_cursor(text)
|
| ... | ... | @@ -1060,7 +1061,7 @@ def _on_window_motion_notify(self, *args): |
| 1060 | 1061 |
con.get_module('Chatstate').set_mouse_activity(
|
| 1061 | 1062 |
self.contact, self.msg_textview.has_text())
|
| 1062 | 1063 |
|
| 1063 |
- def _on_message_tv_buffer_changed(self, textview, textbuffer):
|
|
| 1064 |
+ def _on_message_tv_buffer_changed(self, textbuffer):
|
|
| 1064 | 1065 |
has_text = self.msg_textview.has_text()
|
| 1065 | 1066 |
if self.parent_win is not None:
|
| 1066 | 1067 |
self.parent_win.window.lookup_action(
|
| ... | ... | @@ -1072,7 +1073,7 @@ def _on_message_tv_buffer_changed(self, textview, textbuffer): |
| 1072 | 1073 |
|
| 1073 | 1074 |
con = app.connections[self.account]
|
| 1074 | 1075 |
con.get_module('Chatstate').set_keyboard_activity(self.contact)
|
| 1075 |
- if not textview.has_text():
|
|
| 1076 |
+ if not has_text:
|
|
| 1076 | 1077 |
con.get_module('Chatstate').set_chatstate_delayed(self.contact,
|
| 1077 | 1078 |
Chatstate.ACTIVE)
|
| 1078 | 1079 |
return
|
| ... | ... | @@ -1285,7 +1286,6 @@ def set_emoticon_popover(self): |
| 1285 | 1286 |
self._on_emoticon_button_clicked)
|
| 1286 | 1287 |
|
| 1287 | 1288 |
def _on_emoticon_button_clicked(self, _widget):
|
| 1288 |
- self.msg_textview.remove_placeholder()
|
|
| 1289 | 1289 |
# Present GTK emoji chooser (not cross platform compatible)
|
| 1290 | 1290 |
self.msg_textview.emit('insert-emoji')
|
| 1291 | 1291 |
self.xml.emoticons_button.set_property('active', False)
|
| ... | ... | @@ -237,8 +237,8 @@ def get_active_chatstate(self, contact: ContactT) -> Optional[str]: |
| 237 | 237 |
def block_chatstates(self, contact: ContactT, block: bool) -> None:
|
| 238 | 238 |
# Block sending chatstates to a contact
|
| 239 | 239 |
# Used for example if we cycle through the MUC nick list, which
|
| 240 |
- # produces a lot of text-changed signals from the textview. This
|
|
| 241 |
- # Would lead to sending ACTIVE -> COMPOSING -> ACTIVE ...
|
|
| 240 |
+ # produces a lot of buffer 'changed' signals from the input textview.
|
|
| 241 |
+ # This would lead to sending ACTIVE -> COMPOSING -> ACTIVE ...
|
|
| 242 | 242 |
if block:
|
| 243 | 243 |
self._blocked.append(contact.jid)
|
| 244 | 244 |
else:
|
| ... | ... | @@ -41,9 +41,6 @@ |
| 41 | 41 |
.gajim-state-paused {
|
| 42 | 42 |
color: rgb(20, 210, 160);
|
| 43 | 43 |
}
|
| 44 |
-.gajim-message-placeholder {
|
|
| 45 |
- color: rgb(195, 195, 195);
|
|
| 46 |
-}
|
|
| 47 | 44 |
.gajim-msg-correcting text {
|
| 48 | 45 |
background: rgb(100, 100, 50);
|
| 49 | 46 |
}
|
| ... | ... | @@ -41,9 +41,6 @@ |
| 41 | 41 |
.gajim-state-paused {
|
| 42 | 42 |
color: rgb(20, 160, 120);
|
| 43 | 43 |
}
|
| 44 |
-.gajim-message-placeholder {
|
|
| 45 |
- color: rgb(170, 170, 170);
|
|
| 46 |
-}
|
|
| 47 | 44 |
.gajim-msg-correcting text {
|
| 48 | 45 |
background: rgb(240, 230, 170);
|
| 49 | 46 |
}
|
| ... | ... | @@ -30,6 +30,14 @@ |
| 30 | 30 |
|
| 31 | 31 |
.chatcontrol-separator {margin-bottom: 5px;}
|
| 32 | 32 |
|
| 33 |
+.message-input-border {
|
|
| 34 |
+ border: 2px solid transparent;
|
|
| 35 |
+}
|
|
| 36 |
+.message-input-focus {
|
|
| 37 |
+ border: 2px solid @theme_selected_bg_color;
|
|
| 38 |
+ border-radius: 4px;
|
|
| 39 |
+}
|
|
| 40 |
+ |
|
| 33 | 41 |
.link-button { min-height: 0px; }
|
| 34 | 42 |
|
| 35 | 43 |
/* VCardWindow */
|
| ... | ... | @@ -1915,7 +1915,6 @@ def _start_private_message(self, nick): |
| 1915 | 1915 |
return ctrl
|
| 1916 | 1916 |
|
| 1917 | 1917 |
def append_nick_in_msg_textview(self, _widget, nick):
|
| 1918 |
- self.msg_textview.remove_placeholder()
|
|
| 1919 | 1918 |
message_buffer = self.msg_textview.get_buffer()
|
| 1920 | 1919 |
start_iter, end_iter = message_buffer.get_bounds()
|
| 1921 | 1920 |
cursor_position = message_buffer.get_insert()
|
| ... | ... | @@ -20,14 +20,11 @@ |
| 20 | 20 |
from gi.repository import Gtk
|
| 21 | 21 |
from gi.repository import Gdk
|
| 22 | 22 |
from gi.repository import GLib
|
| 23 |
-from gi.repository import GObject
|
|
| 24 | 23 |
from gi.repository import Pango
|
| 25 | 24 |
|
| 26 | 25 |
from nbxmpp.modules.misc import build_xhtml_body
|
| 27 | 26 |
|
| 28 | 27 |
from gajim.common import app
|
| 29 |
-from gajim.common.i18n import _
|
|
| 30 |
-from gajim.common.const import StyleAttr
|
|
| 31 | 28 |
from gajim.common.regex import LINK_REGEX
|
| 32 | 29 |
|
| 33 | 30 |
from .util import scroll_to_end
|
| ... | ... | @@ -41,12 +38,7 @@ class MessageInputTextView(Gtk.TextView): |
| 41 | 38 |
Class for the message textview (where user writes new messages) for
|
| 42 | 39 |
chat/groupchat windows
|
| 43 | 40 |
"""
|
| 44 |
- __gsignals__ = {
|
|
| 45 |
- 'text-changed': (GObject.SignalFlags.RUN_LAST, None, (Gtk.TextBuffer,))
|
|
| 46 |
- }
|
|
| 47 |
- |
|
| 48 | 41 |
UNDO_LIMIT = 20
|
| 49 |
- PLACEHOLDER = _('Write a message…')
|
|
| 50 | 42 |
|
| 51 | 43 |
def __init__(self):
|
| 52 | 44 |
Gtk.TextView.__init__(self)
|
| ... | ... | @@ -70,8 +62,6 @@ def __init__(self): |
| 70 | 62 |
# needed to know if we undid something
|
| 71 | 63 |
self.undo_pressed = False
|
| 72 | 64 |
|
| 73 |
- buffer_ = self.get_buffer()
|
|
| 74 |
- buffer_.connect('changed', self._on_buffer_changed)
|
|
| 75 | 65 |
self._last_text = ''
|
| 76 | 66 |
|
| 77 | 67 |
self.begin_tags = {}
|
| ... | ... | @@ -80,11 +70,7 @@ def __init__(self): |
| 80 | 70 |
self.fonts_tags = []
|
| 81 | 71 |
self.other_tags = {}
|
| 82 | 72 |
|
| 83 |
- color = app.css_config.get_value(
|
|
| 84 |
- '.gajim-message-placeholder', StyleAttr.COLOR)
|
|
| 85 |
- self.placeholder_tag = buffer_.create_tag('placeholder')
|
|
| 86 |
- self.placeholder_tag.set_property('foreground', color)
|
|
| 87 |
- |
|
| 73 |
+ buffer_ = self.get_buffer()
|
|
| 88 | 74 |
self.other_tags['bold'] = buffer_.create_tag('bold')
|
| 89 | 75 |
self.other_tags['bold'].set_property('weight', Pango.Weight.BOLD)
|
| 90 | 76 |
self.begin_tags['bold'] = '<strong>'
|
| ... | ... | @@ -105,10 +91,8 @@ def __init__(self): |
| 105 | 91 |
self.begin_tags['strike'] = strike
|
| 106 | 92 |
self.end_tags['strike'] = '</span>'
|
| 107 | 93 |
|
| 108 |
- self.connect('paste-clipboard', self._paste_clipboard)
|
|
| 109 | 94 |
self.connect_after('paste-clipboard', self._after_paste_clipboard)
|
| 110 |
- self.connect('focus-in-event', self._on_grab_focus)
|
|
| 111 |
- self.connect('grab-focus', self._on_grab_focus)
|
|
| 95 |
+ self.connect('focus-in-event', self._on_focus_in)
|
|
| 112 | 96 |
self.connect('focus-out-event', self._on_focus_out)
|
| 113 | 97 |
self.connect('destroy', self._on_destroy)
|
| 114 | 98 |
|
| ... | ... | @@ -123,15 +107,15 @@ def _on_destroy(self, *args): |
| 123 | 107 |
None,
|
| 124 | 108 |
Gdk.DragAction.DEFAULT)
|
| 125 | 109 |
|
| 126 |
- def _on_buffer_changed(self, *args):
|
|
| 127 |
- text = self.get_text()
|
|
| 128 |
- # Because of inserting and removing PLACEHOLDER text
|
|
| 129 |
- # the signal becomes unreliable when determining if the user
|
|
| 130 |
- # typed in new text. So we send our own signal depending on if
|
|
| 131 |
- # there is real new text that is not the PLACEHOLDER
|
|
| 132 |
- if text != self._last_text:
|
|
| 133 |
- self.emit('text-changed', self.get_buffer())
|
|
| 134 |
- self._last_text = text
|
|
| 110 |
+ def _on_focus_in(self, _widget, _event):
|
|
| 111 |
+ scrolled = self.get_parent()
|
|
| 112 |
+ scrolled.get_style_context().add_class('message-input-focus')
|
|
| 113 |
+ return False
|
|
| 114 |
+ |
|
| 115 |
+ def _on_focus_out(self, _widget, _event):
|
|
| 116 |
+ scrolled = self.get_parent()
|
|
| 117 |
+ scrolled.get_style_context().remove_class('message-input-focus')
|
|
| 118 |
+ return False
|
|
| 135 | 119 |
|
| 136 | 120 |
def insert_text(self, text):
|
| 137 | 121 |
self.get_buffer().insert_at_cursor(text)
|
| ... | ... | @@ -148,50 +132,19 @@ def has_text(self): |
| 148 | 132 |
buf = self.get_buffer()
|
| 149 | 133 |
start, end = buf.get_bounds()
|
| 150 | 134 |
text = buf.get_text(start, end, True)
|
| 151 |
- return text not in (self.PLACEHOLDER, '')
|
|
| 135 |
+ return text != ''
|
|
| 152 | 136 |
|
| 153 | 137 |
def get_text(self):
|
| 154 |
- # gets the text if its not PLACEHOLDER
|
|
| 155 | 138 |
buf = self.get_buffer()
|
| 156 | 139 |
start, end = buf.get_bounds()
|
| 157 | 140 |
text = self.get_buffer().get_text(start, end, True)
|
| 158 |
- if text == self.PLACEHOLDER:
|
|
| 159 |
- return ''
|
|
| 160 | 141 |
return text
|
| 161 | 142 |
|
| 162 |
- def is_placeholder(self):
|
|
| 163 |
- buf = self.get_buffer()
|
|
| 164 |
- start, end = buf.get_bounds()
|
|
| 165 |
- text = buf.get_text(start, end, True)
|
|
| 166 |
- return text == self.PLACEHOLDER
|
|
| 167 |
- |
|
| 168 |
- def remove_placeholder(self):
|
|
| 169 |
- if self.is_placeholder():
|
|
| 170 |
- self.get_buffer().set_text('')
|
|
| 171 |
- self.toggle_speller(True)
|
|
| 172 |
- |
|
| 173 |
- def _on_grab_focus(self, *args):
|
|
| 174 |
- self.remove_placeholder()
|
|
| 175 |
- |
|
| 176 |
- def _on_focus_out(self, *args):
|
|
| 177 |
- buf = self.get_buffer()
|
|
| 178 |
- start, end = buf.get_bounds()
|
|
| 179 |
- text = buf.get_text(start, end, True)
|
|
| 180 |
- if text == '':
|
|
| 181 |
- buf.insert_with_tags(
|
|
| 182 |
- start, self.PLACEHOLDER, self.placeholder_tag)
|
|
| 183 |
- self.toggle_speller(False)
|
|
| 184 |
- |
|
| 185 | 143 |
def toggle_speller(self, activate):
|
| 186 | 144 |
if app.is_installed('GSPELL') and app.settings.get('use_speller'):
|
| 187 | 145 |
spell_view = Gspell.TextView.get_from_gtk_text_view(self)
|
| 188 | 146 |
spell_view.set_inline_spell_checking(activate)
|
| 189 | 147 |
|
| 190 |
- @staticmethod
|
|
| 191 |
- def _paste_clipboard(textview):
|
|
| 192 |
- if textview.is_placeholder():
|
|
| 193 |
- textview.get_buffer().set_text('')
|
|
| 194 |
- |
|
| 195 | 148 |
@staticmethod
|
| 196 | 149 |
def _after_paste_clipboard(textview):
|
| 197 | 150 |
buffer_ = textview.get_buffer()
|
| ... | ... | @@ -429,7 +382,6 @@ def replace_char_at_iter(self, iter_, new_char): |
| 429 | 382 |
buffer_.insert(iter_, new_char)
|
| 430 | 383 |
|
| 431 | 384 |
def insert_emoji(self, codepoint, pixbuf):
|
| 432 |
- self.remove_placeholder()
|
|
| 433 | 385 |
buffer_ = self.get_buffer()
|
| 434 | 386 |
if buffer_.get_char_count():
|
| 435 | 387 |
# buffer contains text
|