info_bar.py 5.73 KB
Newer Older
1 2 3 4 5 6 7 8
"""
Module defining the global info bar

This window is the one listing the current opened tabs in poezio.
The GlobalInfoBar can be either horizontal or vertical
(VerticalGlobalInfoBar).
"""
import logging
9
import itertools
10 11 12 13
log = logging.getLogger(__name__)

import curses

14
from poezio.config import config
Link Mauve's avatar
Link Mauve committed
15
from poezio.windows.base_wins import Win
16
from poezio.theming import get_theme, to_curses_attr
17
from poezio.common import unique_prefix_of
18

mathieui's avatar
mathieui committed
19

20
class GlobalInfoBar(Win):
21 22
    __slots__ = ('core')

23
    def __init__(self, core) -> None:
24
        Win.__init__(self)
25
        self.core = core
26

27
    def refresh(self) -> None:
28
        log.debug('Refresh: %s', self.__class__.__name__)
29
        self._win.erase()
30
        theme = get_theme()
mathieui's avatar
mathieui committed
31
        self.addstr(0, 0, "[",
32
                    to_curses_attr(theme.COLOR_INFORMATION_BAR))
33

34 35 36
        show_names = config.get('show_tab_names')
        show_nums = config.get('show_tab_numbers')
        use_nicks = config.get('use_tab_nicks')
mathieui's avatar
mathieui committed
37
        show_inactive = config.get('show_inactive_tabs')
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
        unique_prefix_tab_names = config.get('unique_prefix_tab_names')

        if unique_prefix_tab_names:
            unique_prefixes = [None] * len(self.core.tabs)
            sorted_tab_indices = sorted(
                (str(tab.name), i)
                for i, tab in enumerate(self.core.tabs)
            )
            prev_name = ""
            for (name, i), next_item in itertools.zip_longest(
                    sorted_tab_indices, sorted_tab_indices[1:]):
                # TODO: should this maybe use something smarter than .lower()?
                # something something stringprep?
                name = name.lower()
                prefix_prev = unique_prefix_of(name, prev_name)
                if next_item is not None:
                    prefix_next = unique_prefix_of(name, next_item[0].lower())
                else:
                    prefix_next = name[0]

                # to be unique, we have to use the longest prefix
                if len(prefix_next) > len(prefix_prev):
                    prefix = prefix_next
                else:
                    prefix = prefix_prev

                unique_prefixes[i] = prefix
                prev_name = name
66

67
        for nb, tab in enumerate(self.core.tabs):
68 69
            if not tab:
                continue
70
            color = tab.color
71
            if not show_inactive and color is theme.COLOR_TAB_NORMAL:
72 73 74 75
                continue
            try:
                if show_nums or not show_names:
                    self.addstr("%s" % str(nb), to_curses_attr(color))
76
                    if show_names:
77 78
                        self.addstr(' ', to_curses_attr(color))
                if show_names:
79 80 81
                    if unique_prefix_tab_names:
                        self.addstr(unique_prefixes[nb], to_curses_attr(color))
                    elif use_nicks:
mathieui's avatar
mathieui committed
82 83
                        self.addstr("%s" % str(tab.get_nick()),
                                    to_curses_attr(color))
84 85
                    else:
                        self.addstr("%s" % tab.name, to_curses_attr(color))
mathieui's avatar
mathieui committed
86
                self.addstr("|",
87
                            to_curses_attr(theme.COLOR_INFORMATION_BAR))
mathieui's avatar
mathieui committed
88
            except:  # end of line
89
                break
90
        (y, x) = self._win.getyx()
mathieui's avatar
mathieui committed
91
        self.addstr(y, x - 1, '] ',
92
                    to_curses_attr(theme.COLOR_INFORMATION_BAR))
93 94
        (y, x) = self._win.getyx()
        remaining_size = self.width - x
mathieui's avatar
mathieui committed
95
        self.addnstr(' ' * remaining_size, remaining_size,
96
                     to_curses_attr(theme.COLOR_INFORMATION_BAR))
97
        self._refresh()
98

mathieui's avatar
mathieui committed
99

100
class VerticalGlobalInfoBar(Win):
101 102
    __slots__ = ('core')

103
    def __init__(self, core, scr) -> None:
104
        Win.__init__(self)
105
        self.core = core
106 107
        self._win = scr

108
    def refresh(self) -> None:
109 110 111
        height, width = self._win.getmaxyx()
        self._win.erase()
        sorted_tabs = [tab for tab in self.core.tabs if tab]
112
        theme = get_theme()
113
        if not config.get('show_inactive_tabs'):
114 115
            sorted_tabs = [
                tab for tab in sorted_tabs
116
                if tab.vertical_color != theme.COLOR_VERTICAL_TAB_NORMAL
117
            ]
118
        nb_tabs = len(sorted_tabs)
119
        use_nicks = config.get('use_tab_nicks')
120
        if nb_tabs >= height:
121 122 123 124
            # TODO: As sorted_tabs filters out gap tabs this ensures pos is
            # always set, preventing UnboundLocalError. Now is this how this
            # should be fixed.
            pos = 0
125
            for y, tab in enumerate(sorted_tabs):
126
                if tab.vertical_color == theme.COLOR_VERTICAL_TAB_CURRENT:
127 128 129
                    pos = y
                    break
            # center the current tab as much as possible
mathieui's avatar
mathieui committed
130
            if pos < height // 2:
131
                sorted_tabs = sorted_tabs[:height]
mathieui's avatar
mathieui committed
132
            elif nb_tabs - pos <= height // 2:
133 134
                sorted_tabs = sorted_tabs[-height:]
            else:
mathieui's avatar
mathieui committed
135
                sorted_tabs = sorted_tabs[pos - height // 2:pos + height // 2]
mathieui's avatar
mathieui committed
136
        asc_sort = (config.get('vertical_tab_list_sort') == 'asc')
137 138
        for y, tab in enumerate(sorted_tabs):
            color = tab.vertical_color
mathieui's avatar
mathieui committed
139
            if asc_sort:
140 141
                y = height - y - 1
            self.addstr(y, 0, "%2d" % tab.nb,
142
                        to_curses_attr(theme.COLOR_VERTICAL_TAB_NUMBER))
143 144
            self.addstr('.')
            if use_nicks:
mathieui's avatar
mathieui committed
145 146
                self.addnstr("%s" % tab.get_nick(), width - 4,
                             to_curses_attr(color))
147 148
            else:
                self.addnstr("%s" % tab.name, width - 4, to_curses_attr(color))
149
        separator = to_curses_attr(theme.COLOR_VERTICAL_SEPARATOR)
150
        self._win.attron(separator)
mathieui's avatar
mathieui committed
151
        self._win.vline(0, width - 1, curses.ACS_VLINE, height)
152 153
        self._win.attroff(separator)
        self._refresh()