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