Daniel Brötzmann pushed to branch mainwindow at gajim / gajim

Commits:

4 changed files:

Changes:

  • gajim/data/gui/main.ui
    ... ... @@ -175,28 +175,25 @@
    175 175
                               </packing>
    
    176 176
                             </child>
    
    177 177
                             <child>
    
    178
    -                          <object class="GtkButton" id="edit_workspace_button">
    
    178
    +                          <object class="GtkMenuButton" id="workspace_menu_button">
    
    179 179
                                 <property name="visible">True</property>
    
    180 180
                                 <property name="can-focus">True</property>
    
    181
    +                            <property name="focus-on-click">False</property>
    
    181 182
                                 <property name="receives-default">True</property>
    
    182
    -                            <property name="tooltip-text" translatable="yes">Edit Workspace</property>
    
    183
    -                            <property name="relief">none</property>
    
    183
    +                            <property name="use-popover">False</property>
    
    184 184
                                 <child>
    
    185 185
                                   <object class="GtkImage">
    
    186 186
                                     <property name="visible">True</property>
    
    187 187
                                     <property name="can-focus">False</property>
    
    188
    -                                <property name="icon-name">document-edit-symbolic</property>
    
    188
    +                                <property name="icon-name">open-menu-symbolic</property>
    
    189 189
                                   </object>
    
    190 190
                                 </child>
    
    191
    -                            <style>
    
    192
    -                              <class name="flat"/>
    
    193
    -                            </style>
    
    194 191
                               </object>
    
    195 192
                               <packing>
    
    196 193
                                 <property name="expand">False</property>
    
    197 194
                                 <property name="fill">True</property>
    
    198 195
                                 <property name="pack-type">end</property>
    
    199
    -                            <property name="position">1</property>
    
    196
    +                            <property name="position">2</property>
    
    200 197
                               </packing>
    
    201 198
                             </child>
    
    202 199
                           </object>
    

  • gajim/data/style/gajim.css
    ... ... @@ -61,12 +61,12 @@
    61 61
     /* Workspace sidebar */
    
    62 62
     .workspace-sidebar {
    
    63 63
     	background: transparent;
    
    64
    -	margin-left: 12px;
    
    64
    +	margin-left: 6px;
    
    65 65
     	margin-right: 6px;
    
    66 66
     }
    
    67 67
     .workspace-sidebar-item {
    
    68 68
     	padding-top: 0px;
    
    69
    -	padding-bottom: 6px;
    
    69
    +	padding-bottom: 0px;
    
    70 70
     }
    
    71 71
     .workspace-sidebar-item:selected,
    
    72 72
     .workspace-sidebar-item:hover {
    
    ... ... @@ -80,8 +80,13 @@
    80 80
     }
    
    81 81
     .workspace-sidebar-item image {
    
    82 82
     	border-radius: 9px;
    
    83
    -	margin-top: 6px;
    
    84
    -	margin-right: 6px;
    
    83
    +	margin: 6px;
    
    84
    +}
    
    85
    +.workspace-sidebar-item.drag-hover-top {
    
    86
    +    border-top: 1px solid #4e9a06;
    
    87
    +}
    
    88
    +.workspace-sidebar-item.drag-hover-bottom {
    
    89
    +    border-bottom: 1px solid #4e9a06;
    
    85 90
     }
    
    86 91
     
    
    87 92
     /* Account sidebar */
    

  • gajim/gtk/main.py
    ... ... @@ -27,6 +27,11 @@
    27 27
     
    
    28 28
     log = logging.getLogger('gajim.gui.main')
    
    29 29
     
    
    30
    +WORKSPACE_MENU_DICT = {
    
    31
    +    'edit': _('Edit…'),
    
    32
    +    'remove': _('Remove'),
    
    33
    +}
    
    34
    +
    
    30 35
     
    
    31 36
     class MainWindow(Gtk.ApplicationWindow, EventHelper):
    
    32 37
         def __init__(self):
    
    ... ... @@ -64,8 +69,12 @@ def __init__(self):
    64 69
     
    
    65 70
             self._ui.right_grid.add(self._chat_stack)
    
    66 71
     
    
    67
    -        self._ui.edit_workspace_button.connect(
    
    68
    -            'clicked', self._on_edit_workspace_clicked)
    
    72
    +        workspace_menu = Gio.Menu()
    
    73
    +        for action, label in WORKSPACE_MENU_DICT.items():
    
    74
    +            workspace_menu.append(label, f'win.{action.lower()}-workspace')
    
    75
    +
    
    76
    +        self._ui.workspace_menu_button.set_menu_model(workspace_menu)
    
    77
    +
    
    69 78
             self._ui.start_chat_button.connect(
    
    70 79
                 'clicked', self._on_start_chat_clicked)
    
    71 80
             self._ui.connect_signals(self)
    
    ... ... @@ -146,7 +155,8 @@ def _on_button_release(paned, event):
    146 155
         def _add_actions(self):
    
    147 156
             actions = [
    
    148 157
                 ('add-workspace', 's', self._add_workspace),
    
    149
    -            ('remove-workspace', 's', self._remove_workspace),
    
    158
    +            ('edit-workspace', None, self._edit_workspace),
    
    159
    +            ('remove-workspace', None, self._remove_workspace),
    
    150 160
                 ('activate-workspace', 's', self._activate_workspace),
    
    151 161
                 ('add-chat', 'as', self._add_chat),
    
    152 162
                 ('add-group-chat', 'as', self._add_group_chat),
    
    ... ... @@ -155,7 +165,8 @@ def _add_actions(self):
    155 165
     
    
    156 166
             for action in actions:
    
    157 167
                 action_name, variant, func = action
    
    158
    -            variant = GLib.VariantType.new(variant)
    
    168
    +            if variant is not None:
    
    169
    +                variant = GLib.VariantType.new(variant)
    
    159 170
                 act = Gio.SimpleAction.new(action_name, variant)
    
    160 171
                 act.connect('activate', func)
    
    161 172
                 self.add_action(act)
    
    ... ... @@ -311,9 +322,19 @@ def add_workspace(self, workspace_id):
    311 322
             self._workspace_side_bar.activate_workspace(workspace_id)
    
    312 323
             self._chat_list_stack.show_chat_list(workspace_id)
    
    313 324
     
    
    314
    -    def _remove_workspace(self, _action, param):
    
    315
    -        workspace_id = param.get_string()
    
    316
    -        self.remove_workspace(workspace_id)
    
    325
    +    def _edit_workspace(self, _action, _param):
    
    326
    +        workspace_id = self.get_active_workspace()
    
    327
    +        if workspace_id is not None:
    
    328
    +            self.edit_workspace(workspace_id)
    
    329
    +
    
    330
    +    @staticmethod
    
    331
    +    def edit_workspace(workspace_id):
    
    332
    +        open_window('WorkspaceDialog', workspace_id=workspace_id)
    
    333
    +
    
    334
    +    def _remove_workspace(self, _action, _param):
    
    335
    +        workspace_id = self.get_active_workspace()
    
    336
    +        if workspace_id is not None:
    
    337
    +            self.remove_workspace(workspace_id)
    
    317 338
     
    
    318 339
         def remove_workspace(self, workspace_id):
    
    319 340
             was_active = self.get_active_workspace() == workspace_id
    
    ... ... @@ -452,10 +473,6 @@ def _load_chats(self):
    452 473
         def _on_start_chat_clicked(self, _button):
    
    453 474
             app.app.activate_action('start-chat', GLib.Variant('s', ''))
    
    454 475
     
    
    455
    -    def _on_edit_workspace_clicked(self, _button):
    
    456
    -        open_window('WorkspaceDialog',
    
    457
    -                    workspace_id=self.get_active_workspace())
    
    458
    -
    
    459 476
         def _on_event(self, event):
    
    460 477
             if event.name == 'caps-update':
    
    461 478
                 #TODO
    

  • gajim/gtk/workspace_side_bar.py
    1 1
     
    
    2
    +from gi.repository import Gdk
    
    2 3
     from gi.repository import Gtk
    
    3 4
     from gi.repository import GLib
    
    4
    -from gajim.common.const import AvatarSize
    
    5
    -from gajim.common import app
    
    6 5
     
    
    6
    +from gajim.common import app
    
    7
    +from gajim.common.const import AvatarSize
    
    7 8
     from gajim.common.i18n import _
    
    8 9
     
    
    9 10
     from .util import open_window
    
    ... ... @@ -14,18 +15,119 @@ def __init__(self, chat_list_stack):
    14 15
             Gtk.ListBox.__init__(self)
    
    15 16
             self.set_vexpand(True)
    
    16 17
             self.set_valign(Gtk.Align.START)
    
    17
    -        self.set_sort_func(self._sort_func)
    
    18 18
             self.get_style_context().add_class('workspace-sidebar')
    
    19
    -        self.add(AddWorkspace('add'))
    
    20
    -        self.connect('button-press-event', self._on_button_press)
    
    19
    +
    
    20
    +        # Drag and Drop
    
    21
    +        entries = [Gtk.TargetEntry.new(
    
    22
    +            'WORKSPACE_SIDEBAR_ITEM',
    
    23
    +            Gtk.TargetFlags.SAME_APP,
    
    24
    +            0)]
    
    25
    +        self.drag_dest_set(
    
    26
    +            Gtk.DestDefaults.MOTION | Gtk.DestDefaults.DROP,
    
    27
    +            entries,
    
    28
    +            Gdk.DragAction.MOVE)
    
    29
    +
    
    30
    +        self.drag_row = None
    
    31
    +        self.row_before = None
    
    32
    +        self.row_after = None
    
    33
    +
    
    34
    +        self.connect('drag-motion', self._on_drag_motion)
    
    35
    +        self.connect('drag-data-received', self._on_drag_data_received)
    
    36
    +        self.connect('drag-leave', self._on_drag_leave)
    
    37
    +
    
    21 38
             self.connect('row-activated', self._on_row_activated)
    
    22 39
     
    
    40
    +        self.add(AddWorkspace('add'))
    
    41
    +
    
    23 42
             chat_list_stack.connect('unread-count-changed',
    
    24 43
                                     self._on_unread_count_changed)
    
    25 44
             chat_list_stack.connect('chat-selected',
    
    26 45
                                     self._on_chat_selected)
    
    27 46
             self._workspaces = {}
    
    28 47
     
    
    48
    +    def _on_drag_motion(self, _widget, _drag_context, _x_coord, y_coord,
    
    49
    +                        _time):
    
    50
    +        row = self.get_row_at_y(y_coord)
    
    51
    +
    
    52
    +        if self.row_before:
    
    53
    +            self.row_before.get_style_context().remove_class(
    
    54
    +                'drag-hover-bottom')
    
    55
    +        if self.row_after:
    
    56
    +            self.row_after.get_style_context().remove_class(
    
    57
    +                'drag-hover-top')
    
    58
    +
    
    59
    +        if row:
    
    60
    +            alloc = row.get_allocation()
    
    61
    +            hover_row_y = alloc.y
    
    62
    +            hover_row_height = alloc.height
    
    63
    +            if y_coord < hover_row_y + hover_row_height / 2:
    
    64
    +                self.row_after = row
    
    65
    +                self.row_before = self._get_row_before(row)
    
    66
    +            else:
    
    67
    +                self.row_before = row
    
    68
    +                self.row_after = self._get_row_after(row)
    
    69
    +        else:
    
    70
    +            self.row_before = self._get_last_workspace_row()
    
    71
    +            self.row_after = None
    
    72
    +
    
    73
    +        if self.drag_row in (self.row_before, self.row_after):
    
    74
    +            return False
    
    75
    +
    
    76
    +        if self.row_before and self.row_before.workspace_id != 'add':
    
    77
    +            self.row_before.get_style_context().add_class('drag-hover-bottom')
    
    78
    +        if self.row_after:
    
    79
    +            self.row_after.get_style_context().add_class('drag-hover-top')
    
    80
    +        return True
    
    81
    +
    
    82
    +    def _on_drag_data_received(self, _widget, _drag_context, _x_coord,
    
    83
    +                               _y_coord, selection_data, _info, _time):
    
    84
    +        if self.row_before:
    
    85
    +            self.row_before.get_style_context().remove_class(
    
    86
    +                'drag-hover-bottom')
    
    87
    +        if self.row_after:
    
    88
    +            self.row_after.get_style_context().remove_class(
    
    89
    +                'drag-hover-top')
    
    90
    +
    
    91
    +        data = selection_data.get_data()
    
    92
    +        workspace_id = data.decode('utf-8')
    
    93
    +        row = self.get_workspace_by_id(workspace_id)
    
    94
    +
    
    95
    +        if row in (self.row_after, None):
    
    96
    +            return
    
    97
    +
    
    98
    +        self.remove(row)
    
    99
    +
    
    100
    +        if self.row_after:
    
    101
    +            pos = self.row_after.get_index()
    
    102
    +        elif self.row_before and self.row_before.workspace_id != 'add':
    
    103
    +            pos = self.row_before.get_index() + 1
    
    104
    +        else:
    
    105
    +            pos = len(self.get_children()) - 1
    
    106
    +
    
    107
    +        self.insert(row, pos)
    
    108
    +        app.window.activate_workspace(workspace_id)
    
    109
    +
    
    110
    +    def _on_drag_leave(self, _widget, _drag_context, _time):
    
    111
    +        if self.row_before:
    
    112
    +            self.row_before.get_style_context().remove_class(
    
    113
    +                'drag-hover-bottom')
    
    114
    +        if self.row_after:
    
    115
    +            self.row_after.get_style_context().remove_class(
    
    116
    +                'drag-hover-top')
    
    117
    +
    
    118
    +    def _get_row_before(self, row):
    
    119
    +        return self.get_row_at_index(row.get_index() - 1)
    
    120
    +
    
    121
    +    def _get_row_after(self, row):
    
    122
    +        return self.get_row_at_index(row.get_index() + 1)
    
    123
    +
    
    124
    +    def _get_last_workspace_row(self):
    
    125
    +        # len(children) would include AddWorkspace
    
    126
    +        return self.get_row_at_index(len(self.get_children()) - 1)
    
    127
    +
    
    128
    +    def set_drag_row(self, row):
    
    129
    +        self.drag_row = row
    
    130
    +
    
    29 131
         def _on_unread_count_changed(self, _chat_list_stack, workspace_id, count):
    
    30 132
             workspace = self._workspaces[workspace_id]
    
    31 133
             workspace.set_unread_count(count)
    
    ... ... @@ -33,21 +135,6 @@ def _on_unread_count_changed(self, _chat_list_stack, workspace_id, count):
    33 135
         def _on_chat_selected(self, _chat_list_stack, workspace_id, *args):
    
    34 136
             self.activate_workspace(workspace_id)
    
    35 137
     
    
    36
    -    @staticmethod
    
    37
    -    def _sort_func(child1, child2):
    
    38
    -        if child1.sort_index < child2.sort_index:
    
    39
    -            return -1
    
    40
    -
    
    41
    -        if child1.sort_index == child2.sort_index:
    
    42
    -            return 0
    
    43
    -        return 1
    
    44
    -
    
    45
    -    def _on_button_press(self, _listbox, button_event):
    
    46
    -        if button_event.button != 3:
    
    47
    -            return
    
    48
    -        row = self.get_row_at_y(button_event.y)
    
    49
    -        WorspaceMenu(row)
    
    50
    -
    
    51 138
         @staticmethod
    
    52 139
         def _on_row_activated(_listbox, row):
    
    53 140
             if row.workspace_id == 'add':
    
    ... ... @@ -58,7 +145,8 @@ def _on_row_activated(_listbox, row):
    58 145
         def add_workspace(self, workspace_id):
    
    59 146
             row = Workspace(workspace_id)
    
    60 147
             self._workspaces[workspace_id] = row
    
    61
    -        self.add(row)
    
    148
    +        # Insert row before AddWorkspace row
    
    149
    +        self.insert(row, len(self.get_children()) - 1)
    
    62 150
     
    
    63 151
         def remove_workspace(self, workspace_id):
    
    64 152
             if len(self._workspaces) == 1:
    
    ... ... @@ -85,6 +173,12 @@ def get_first_workspace(self):
    85 173
             for row in self.get_children():
    
    86 174
                 return row.workspace_id
    
    87 175
     
    
    176
    +    def get_workspace_by_id(self, workspace_id):
    
    177
    +        for row in self.get_children():
    
    178
    +            if row.workspace_id == workspace_id:
    
    179
    +                return row
    
    180
    +        return None
    
    181
    +
    
    88 182
         def update_avatar(self, workspace_id):
    
    89 183
             row = self._workspaces[workspace_id]
    
    90 184
             row.update_avatar()
    
    ... ... @@ -102,8 +196,6 @@ class Workspace(CommonWorkspace):
    102 196
         def __init__(self, workspace_id):
    
    103 197
             CommonWorkspace.__init__(self, workspace_id)
    
    104 198
     
    
    105
    -        self.sort_index = 0
    
    106
    -
    
    107 199
             self._unread_label = Gtk.Label()
    
    108 200
             self._unread_label.get_style_context().add_class(
    
    109 201
                 'unread-counter')
    
    ... ... @@ -118,7 +210,21 @@ def __init__(self, workspace_id):
    118 210
             overlay.add(self._image)
    
    119 211
             overlay.add_overlay(self._unread_label)
    
    120 212
     
    
    121
    -        self.add(overlay)
    
    213
    +        # Drag and Drop
    
    214
    +        entries = [Gtk.TargetEntry.new(
    
    215
    +            'WORKSPACE_SIDEBAR_ITEM',
    
    216
    +            Gtk.TargetFlags.SAME_APP,
    
    217
    +            0)]
    
    218
    +        eventbox = Gtk.EventBox()
    
    219
    +        eventbox.drag_source_set(
    
    220
    +            Gdk.ModifierType.BUTTON1_MASK,
    
    221
    +            entries,
    
    222
    +            Gdk.DragAction.MOVE)
    
    223
    +        eventbox.connect('drag-begin', self._on_drag_begin)
    
    224
    +        eventbox.connect('drag-data-get', self._on_drag_data_get)
    
    225
    +        eventbox.add(overlay)
    
    226
    +
    
    227
    +        self.add(eventbox)
    
    122 228
             self.show_all()
    
    123 229
     
    
    124 230
         def update_avatar(self):
    
    ... ... @@ -131,15 +237,27 @@ def set_unread_count(self, count):
    131 237
                 self._unread_label.set_text('999+')
    
    132 238
             self._unread_label.set_visible(bool(count))
    
    133 239
     
    
    240
    +    def _on_drag_begin(self, _widget, drag_context):
    
    241
    +        scale = self.get_scale_factor()
    
    242
    +        surface = app.interface.avatar_storage.get_workspace_surface(
    
    243
    +            self.workspace_id, AvatarSize.WORKSPACE, scale)
    
    244
    +        Gtk.drag_set_icon_surface(drag_context, surface)
    
    245
    +
    
    246
    +        listbox = self.get_parent()
    
    247
    +        listbox.set_drag_row(self)
    
    248
    +
    
    249
    +    def _on_drag_data_get(self, _widget, _drag_context, selection_data,
    
    250
    +                          _info, _time):
    
    251
    +        drop_type = Gdk.Atom.intern_static_string('WORKSPACE_SIDEBAR_ITEM')
    
    252
    +        data = self.workspace_id.encode('utf-8')
    
    253
    +        selection_data.set(drop_type, 32, data)
    
    254
    +
    
    134 255
     
    
    135 256
     class AddWorkspace(CommonWorkspace):
    
    136 257
         def __init__(self, workspace_id):
    
    137 258
             CommonWorkspace.__init__(self, workspace_id)
    
    138
    -
    
    139 259
             self.set_selectable(False)
    
    140 260
     
    
    141
    -        self.sort_index = 10000
    
    142
    -
    
    143 261
             image = Gtk.Image.new_from_icon_name('list-add-symbolic',
    
    144 262
                                                  Gtk.IconSize.DND)
    
    145 263
             image.set_halign(Gtk.Align.CENTER)
    
    ... ... @@ -148,33 +266,6 @@ def __init__(self, workspace_id):
    148 266
             self.show_all()
    
    149 267
     
    
    150 268
     
    
    151
    -class WorspaceMenu(Gtk.Popover):
    
    152
    -    def __init__(self, row):
    
    153
    -        Gtk.Popover.__init__(self)
    
    154
    -        entries = [
    
    155
    -            (_('Remove'), 'remove-workspace'),
    
    156
    -        ]
    
    157
    -
    
    158
    -        self._workspace_id = row.workspace_id
    
    159
    -
    
    160
    -        box = Gtk.Box()
    
    161
    -        for label, action in entries:
    
    162
    -            button = Gtk.Button(label=label)
    
    163
    -            button.connect('clicked', self._on_click, action)
    
    164
    -            box.add(button)
    
    165
    -        box.show_all()
    
    166
    -
    
    167
    -        self.add(box)
    
    168
    -        self.set_relative_to(row)
    
    169
    -        self.popup()
    
    170
    -
    
    171
    -    def _on_click(self, _button, action):
    
    172
    -        self.popdown()
    
    173
    -        self.set_relative_to(None)
    
    174
    -        app.window.activate_action(action,
    
    175
    -                                   GLib.Variant('s', self._workspace_id))
    
    176
    -
    
    177
    -
    
    178 269
     class WorkspaceAvatar(Gtk.Image):
    
    179 270
         def __init__(self, workspace_id):
    
    180 271
             Gtk.Image.__init__(self)