1# Copyright (c) 2009, Tomohiro Kusumi
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are met:
6#
7# 1. Redistributions of source code must retain the above copyright notice, this
8#    list of conditions and the following disclaimer.
9# 2. Redistributions in binary form must reproduce the above copyright notice,
10#    this list of conditions and the following disclaimer in the documentation
11#    and/or other materials provided with the distribution.
12#
13# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
24import os
25import sys
26
27from . import log
28from . import setting
29from . import terminal
30from . import util
31
32if not setting.use_stdout:
33    from . import ncurses as _screen
34else:
35    from . import stdout as _screen
36
37Error = _screen.Error
38
39_std = None
40_size = util.Pair()
41_signaled = False
42_soft_resize = False
43
44# no .get() wrapper, out of range input is error
45chr_repr = {}
46buf_attr = {}
47
48A_NONE          = _screen.A_NONE
49A_BOLD          = _screen.A_BOLD
50A_REVERSE       = _screen.A_REVERSE # unused
51A_STANDOUT      = _screen.A_STANDOUT
52A_UNDERLINE     = _screen.A_UNDERLINE
53A_COLOR_FB      = _screen.A_NONE
54A_COLOR_CURRENT = _screen.A_NONE
55A_COLOR_ZERO    = _screen.A_NONE
56A_COLOR_FF      = _screen.A_NONE
57A_COLOR_PRINT   = _screen.A_NONE
58A_COLOR_DEFAULT = _screen.A_NONE
59A_COLOR_VISUAL  = _screen.A_NONE
60
61BUTTON1_CLICKED        = _screen.BUTTON1_CLICKED
62BUTTON1_PRESSED        = _screen.BUTTON1_PRESSED
63BUTTON1_RELEASED       = _screen.BUTTON1_RELEASED
64BUTTON1_DOUBLE_CLICKED = _screen.BUTTON1_DOUBLE_CLICKED
65BUTTON1_TRIPLE_CLICKED = _screen.BUTTON1_TRIPLE_CLICKED
66REPORT_MOUSE_POSITION  = _screen.REPORT_MOUSE_POSITION
67
68def init():
69    global _std, A_COLOR_FB, A_COLOR_CURRENT, A_COLOR_ZERO, A_COLOR_FF, \
70        A_COLOR_PRINT, A_COLOR_DEFAULT, A_COLOR_VISUAL
71    if update_size() == -1:
72        return -1
73    if _std:
74        return -1
75    _std, A_COLOR_FB, A_COLOR_CURRENT, A_COLOR_ZERO, A_COLOR_FF, \
76        A_COLOR_PRINT, A_COLOR_DEFAULT, A_COLOR_VISUAL = _screen.init()
77    _std.keypad(1)
78    _std.bkgd(' ', A_COLOR_FB)
79    _std.refresh()
80
81    this = sys.modules[__name__]
82    l = []
83    for x in ("NONE", "BOLD", "REVERSE", "STANDOUT", "UNDERLINE", "COLOR_FB",
84        "COLOR_CURRENT", "COLOR_ZERO", "COLOR_FF", "COLOR_PRINT",
85        "COLOR_DEFAULT", "COLOR_VISUAL"):
86        l.append("A_{0}=0x{1:X}".format(x, getattr(this, "A_" + x)))
87    log.debug("screen: {0}".format(l))
88
89    chr_repr.clear()
90    for x in util.get_xrange(0, 256):
91        chr_repr[x] = chr(x) if util.isprint(x) else '.'
92
93    buf_attr.clear()
94    for x in util.get_xrange(0, 256):
95        if setting.has_buffer_attr():
96            if x == 0:
97                _ = A_COLOR_ZERO
98            elif x == 0xff:
99                _ = A_COLOR_FF
100            elif util.isprint(x):
101                _ = A_COLOR_PRINT
102            else:
103                _ = A_COLOR_DEFAULT
104        else:
105            _ = A_NONE
106        buf_attr[x] = _
107    log.debug("buf_attr: {0}".format(set(sorted(buf_attr.values()))))
108
109def cleanup():
110    global _std
111    clear_size()
112    if _std:
113        _std.keypad(0)
114        _std = None
115    _screen.cleanup() # must always cleanup regardless of _std
116
117def clear_refresh():
118    _std.clear() # erase contents
119    _std.refresh() # refresh screen
120
121# XXX adhoc way to find if in stream
122def __test_stream():
123    return os.path.isfile(setting.get_stream_path())
124
125def doupdate():
126    _screen.doupdate()
127
128def flash():
129    # ignore flash if in stream (too slow depending on stream size)
130    if not __test_stream():
131        _screen.flash()
132
133def get_size_y():
134    return _size.y
135
136def get_size_x():
137    return _size.x
138
139def update_size():
140    y, x = terminal.get_size()
141    y = __override_size(y, setting.terminal_height)
142    x = __override_size(x, setting.terminal_width)
143    if y > 0 and x > 0:
144        _size.set(y, x)
145    else:
146        clear_size()
147        return -1
148
149def __override_size(term_size, cfg_size):
150    if cfg_size <= 0:
151        return term_size
152    if term_size == -1:
153        return cfg_size
154    assert term_size > 0, term_size
155    assert cfg_size > 0, cfg_size
156    if cfg_size > term_size:
157        return term_size
158    else:
159        return cfg_size
160
161def clear_size():
162    _size.set(0, 0)
163
164def sti():
165    global _signaled
166    _signaled = True
167
168def cli():
169    global _signaled
170    _signaled = False
171
172def test_signal():
173    ret = _signaled
174    if ret:
175        cli()
176    return ret
177
178def set_soft_resize():
179    global _soft_resize
180    _soft_resize = True
181
182def clear_soft_resize():
183    global _soft_resize
184    _soft_resize = False
185
186def test_soft_resize():
187    return _soft_resize
188
189def has_chgat():
190    return _screen.has_chgat()
191
192def use_alt_chgat():
193    return setting.use_alt_chgat or not has_chgat()
194
195def has_color():
196    return _screen.has_color()
197
198def use_color():
199    return _screen.use_color()
200
201def iter_color_name():
202    for s in _screen.iter_color_name():
203        yield s
204
205def getmouse():
206    return _screen.getmouse()
207
208def get_mouse_event_name(bstate):
209    return _screen.get_mouse_event_name(bstate)
210
211def alloc_all(ref=None):
212    return alloc(get_size_y(), get_size_x(), 0, 0, ref)
213
214def alloc(leny, lenx, begy, begx, ref=None):
215    scr = _screen.newwin(leny, lenx, begy, begx, ref)
216    scr.scrollok(0)
217    scr.idlok(0)
218    scr.keypad(1)
219    scr.bkgd(' ', A_COLOR_FB)
220    return scr
221