summaryrefslogtreecommitdiffstats
path: root/mbbsd/visio.c
blob: 789b6e60d695233663127c0658f3016a15a878a2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/* $Id$ */
#include "bbs.h"

/*
 * visio.c
 * High-level virtual screen input output control
 *
 * This is not the original visio.c from maple3.
 * m3 visio = (ptt) visio+screen.
 * This visio contains only high level UI element/widgets.
 * In fact the only APIs from m3 are vmsg/vget...
 *
 * To add API here, please...
 * (1) name the API in prefix of 'v'.
 * (2) use only screen.c APIs.
 * (3) take care of wide screen.
 * (4) utilize the colos in visio.h, and name asa VCLR_* (visio color)
 */

// ---- DEFINITION ---------------------------------------------------
#define MAX_COL     (t_columns-1)
#define SAFE_MAX_COL    (MAX_COL-1)

// ---- UTILITIES ----------------------------------------------------
inline void
outnc(int n, unsigned char c)
{
    while (n-- > 0)
    outc(c);
}

inline void
nblank(int n)
{
    outnc(n, ' ');
}

// ---- HIGH LEVEL API -----------------------------------------------

/**
 * vbarf(s, ...): 格式化輸出左右對齊的字串 (MAX_COL)
 *
 * s 裡 \t 後的內容會對齊右端。
 */
void
vbarf(const char *s, ...)
{
    char msg[512], *s2;
    va_list ap;
    va_start(ap, s);
    vsnprintf(msg, sizeof(msg), s, ap);
    va_end(ap);

    s2 = strchr(msg, '\t');
    if (s2) *s2++ = 0;
    else s2 = "";

    return vbar(msg, s2);
}

/**
 * vbar(l, r): 左右對齊畫滿螢幕 (MAX_COL)
 *
 * 注意 r 的後面不會補空白。
 * l r 都可以含 ANSI 控制碼。 
 * 注意: 目前的實作自動認定游標已在行開頭。
 */
void
vbar(const char *l, const char *r)
{
    // TODO strlen_noansi 跑兩次... 其實 l 可以邊 output 邊算。
    int szl = strlen_noansi(l),
    szr = strlen_noansi(r);
    // assume we are already in (y, 0)
    clrtoeol();
    outs(l);
    szl = MAX_COL - szl;
    if (szl > szr)
    {
    nblank(szl - szr);
    szl = szr;
    }
    if (szl == szr)
    outs(r);
    else if (szl > 0)
    nblank(szl);
    outs(ANSI_RESET);
}

/**
 * vfooter(caption, msg): 在螢幕底部印出格式化的 caption msg 
 *
 * msg 中若有 () 則會變色, \t 後的文字會靠右。
 * 最後面會自動留一個空白 (以避免自動偵測中文字的問題)。
 */
void 
vfooter(const char *caption, const char *msg)
{
    int i = 0;
    move(b_lines, 0); clrtoeol();

    if (caption)
    {
    outs(VCLR_FOOTER_CAPTION);
    outs(caption); i+= strlen(caption);
    }

    if (!msg) msg = "";
    outs(VCLR_FOOTER);

    while (*msg && i < SAFE_MAX_COL)
    {
    if (*msg == '(')
        outs(VCLR_FOOTER_QUOTE);
    else if (*msg == '\t')
    {
        // if we don't have enough space, ignore whole.
        int l = strlen(++msg);
        if (i + l > SAFE_MAX_COL) break;
        l = SAFE_MAX_COL - l - i;
        nblank(l); 
        i += l;
        continue;
    }
    outc(*msg); i++;
    if (*msg == ')')
        outs(VCLR_FOOTER);
    msg ++;
    }
    nblank(SAFE_MAX_COL-i);
    outc(' ');
    outs(ANSI_RESET);
}