1 // $Id: TTYGraph.cc 5748 2014-10-11 19:38:53Z flaterco $
2
3 /* TTYGraph Graph implemented on dumb terminal
4
5 Copyright (C) 1998 David Flater.
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "libxtide.hh"
22 #include "Graph.hh"
23 #include "PixelatedGraph.hh"
24 #include "TTYGraph.hh"
25
26 namespace libxtide {
27
28
29 // Fudge factor to correct aspect ratio on TTY
30 // Correct 80x24 of VT100 to match 4/3 aspect
31 static const double TTYaspectfudge = 2.5;
32
33
TTYGraph(unsigned xSize,unsigned ySize,GraphStyle style)34 TTYGraph::TTYGraph (unsigned xSize, unsigned ySize, GraphStyle style):
35 PixelatedGraph (xSize, ySize, style),
36 VT100_mode (Global::codeset == "VT100") {
37 assert (xSize >= Global::minTTYwidth && ySize >= Global::minTTYheight);
38 tty.resize (xSize * ySize);
39 }
40
41
stringWidth(const Dstr & s) const42 const unsigned TTYGraph::stringWidth (const Dstr &s) const {
43 return s.length();
44 }
45
46
fontHeight() const47 const unsigned TTYGraph::fontHeight() const {
48 return 1;
49 }
50
51
oughtHeight() const52 const unsigned TTYGraph::oughtHeight() const {
53 return 1;
54 }
55
56
oughtVerticalMargin() const57 const unsigned TTYGraph::oughtVerticalMargin() const {
58 return 0;
59 }
60
61
hourTickLen() const62 const unsigned TTYGraph::hourTickLen() const {
63 return 1;
64 }
65
66
hourTickVerticalMargin() const67 const unsigned TTYGraph::hourTickVerticalMargin() const {
68 return 0;
69 }
70
71
depthLabelLeftMargin() const72 const unsigned TTYGraph::depthLabelLeftMargin() const {
73 return 0;
74 }
75
76
depthLabelRightMargin() const77 const unsigned TTYGraph::depthLabelRightMargin() const {
78 return 1;
79 }
80
81
depthLineVerticalMargin() const82 const unsigned TTYGraph::depthLineVerticalMargin() const {
83 return 0;
84 }
85
86
aspectFudgeFactor() const87 const double TTYGraph::aspectFudgeFactor() const {
88 return TTYaspectfudge;
89 }
90
91
startPosition(unsigned labelWidth) const92 const unsigned TTYGraph::startPosition (unsigned labelWidth) const {
93 return labelWidth;
94 }
95
96
blurbMargin() const97 const int TTYGraph::blurbMargin() const {
98 return 0;
99 }
100
101
setPixel(int x,int y,Colors::Colorchoice c)102 void TTYGraph::setPixel (int x, int y, Colors::Colorchoice c) {
103 assert (c < (int)Colors::numColors);
104 char color_analog;
105 switch (c) {
106 case Colors::daytime:
107 color_analog = ' ';
108 break;
109 case Colors::nighttime:
110 color_analog = (VT100_mode ? '�' : '�');
111 break;
112 default:
113 color_analog = '*';
114 }
115 setPixel (x, y, color_analog);
116 }
117
118
setPixel(int x,int y,char c)119 void TTYGraph::setPixel (int x, int y, char c) {
120 if (x < 0 || x >= (int)_xSize || y < 0 || y >= (int)_ySize)
121 return;
122 tty[y * _xSize + x] = c;
123 }
124
125
drawHorizontalLineP(int xlo,int xhi,int y,Colors::Colorchoice c unusedParameter)126 void TTYGraph::drawHorizontalLineP (int xlo, int xhi, int y,
127 Colors::Colorchoice c unusedParameter) {
128 for (int i=xlo; i<=xhi; ++i)
129 setPixel (i, y, '-');
130 }
131
132
drawHorizontalLinePxSy(int xlo,int xhi,double y,Colors::Colorchoice c)133 void TTYGraph::drawHorizontalLinePxSy (int xlo, int xhi, double y,
134 Colors::Colorchoice c) {
135 if (!VT100_mode || isBanner())
136 PixelatedGraph::drawHorizontalLinePxSy (xlo, xhi, y, c);
137 else {
138 // VT100 glyphs are 10 pixels high. Special Graphics characters o-s are
139 // horizontal lines at scan lines 0,2,4,6,8, so the y ranges that they
140 // cover are 0.05, 0.25, 0.45, 0.65, 0.85 � 0.1. That means that the
141 // upper 5% wants to go on the next line of text, which could mess things
142 // up. The following is just wrong 5% of the time.
143 const int yi (Global::ifloor (y));
144 const char lineChar (0x80 | ('o' + std::min (4U,
145 (unsigned)Global::iround((y-floor(y)-0.05)*5))));
146 for (int i=xlo; i<=xhi; ++i)
147 setPixel (i, yi, lineChar);
148 }
149 }
150
151
drawHourTick(double x,Colors::Colorchoice c unusedParameter,bool thick)152 void TTYGraph::drawHourTick (double x, Colors::Colorchoice c unusedParameter,
153 bool thick) {
154 int ix = Global::ifloor(x);
155 setPixel (ix, _ySize-1, '|');
156 if (thick) {
157 setPixel (ix-1, _ySize-1, '|');
158 setPixel (ix+1, _ySize-1, '|');
159 }
160 }
161
162
drawStringP(int x,int y,const Dstr & s)163 void TTYGraph::drawStringP (int x, int y, const Dstr &s) {
164 for (unsigned a=0; a<s.length(); ++a)
165 setPixel (x+a, y, s[a]);
166 }
167
168
169 // "In" is US-ASCII (G0). "Out" is Special Graphics (G1). The high bit is
170 // used to indicate characters from the Special Graphics set. Special
171 // Graphics and US-ASCII differ only in the range 95-127, so it is not
172 // necessary to shift all of the time. (N.B., xterm draws Special Graphics
173 // character 95 as underscore, same as US-ASCII, but it's supposed to be a
174 // blank.)
VT100_postproc(Dstr & text)175 void TTYGraph::VT100_postproc (Dstr &text) {
176 Dstr text_out;
177 // Banners get the SCS in the text_boilerplate; graphs don't.
178 if (!isBanner())
179 text_out = Global::VT100_init;
180 const char SI ('\017'), SO ('\016');
181 bool shifted (false);
182 const unsigned l (text.length());
183 for (unsigned i=0; i<l; ++i) {
184 const char c8 (text[i]);
185 const bool hibit (c8 & 0x80);
186 const char c7 (c8 & 0x7F);
187 if (c7 >= '_') {
188 if (hibit && !shifted) {
189 text_out += SO;
190 shifted = true;
191 } else if (!hibit && shifted) {
192 text_out += SI;
193 shifted = false;
194 }
195 }
196 text_out += c7;
197 }
198 if (shifted)
199 text_out += SI; // Be kind, rewind.
200 text = text_out;
201 }
202
203
print(Dstr & text_out)204 void TTYGraph::print (Dstr &text_out) {
205 text_out = (char *)NULL;
206 SafeVector<char> lineBuf (_xSize+2);
207 lineBuf[_xSize] = '\n';
208 lineBuf[_xSize+1] = '\0';
209 for (SafeVector<char>::const_iterator it (tty.begin());
210 it != tty.end();
211 it += _xSize) {
212 std::copy (it, it+_xSize, lineBuf.begin());
213 text_out += &(lineBuf[0]);
214 }
215 if (VT100_mode)
216 VT100_postproc (text_out);
217 else
218 Global::finalizeCodeset (text_out, Global::codeset, Format::text);
219 }
220
221
drawX(double x,double y)222 void TTYGraph::drawX (double x, double y) {
223 setPixel (Global::ifloor(x), Global::ifloor(y), '+');
224 }
225
226 }
227