1 /************************************************************************
2 ************************************************************************
3 FAUST compiler
4 Copyright (C) 2003-2018 GRAME, Centre National de Creation Musicale
5 ---------------------------------------------------------------------
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 ************************************************************************
20 ************************************************************************/
21
22 #include <algorithm>
23
24 #include "blockSchema.h"
25 #include "exception.hh"
26
27 using namespace std;
28
quantize(int n)29 static double quantize(int n)
30 {
31 int q = 3;
32 return dLetter * (q * ((n + q - 1) / q));
33 }
34
35 /**
36 * Build a simple colored blockSchema with a certain number of
37 * inputs and outputs, a text to be displayed, and an optional link.
38 * Computes the size of the box according to the length of the text
39 * and the maximum number of ports.
40 */
makeBlockSchema(unsigned int inputs,unsigned int outputs,const string & text,const string & color,const string & link)41 schema* makeBlockSchema(unsigned int inputs, unsigned int outputs, const string& text, const string& color,
42 const string& link)
43 {
44 // determine the optimal size of the box
45 double minimal = 3 * dWire;
46 double w = 2 * dHorz + max(minimal, quantize((int)text.size()));
47 double h = 2 * dVert + max(minimal, max(inputs, outputs) * dWire);
48
49 return new blockSchema(inputs, outputs, w, h, text, color, link);
50 }
51
52 /**
53 * Build a simple colored blockSchema with a certain number of
54 * inputs and outputs, a text to be displayed, and an optional link.
55 * The length of the text as well as th number of inputs and outputs
56 * are used to compute the size of the blockSchema
57 */
blockSchema(unsigned int inputs,unsigned int outputs,double width,double height,const string & text,const string & color,const string & link)58 blockSchema::blockSchema(unsigned int inputs, unsigned int outputs, double width, double height, const string& text,
59 const string& color, const string& link)
60
61 : schema(inputs, outputs, width, height), fText(text), fColor(color), fLink(link)
62 {
63 for (unsigned int i = 0; i < inputs; i++) fInputPoint.push_back(point(0, 0));
64 for (unsigned int i = 0; i < outputs; i++) fOutputPoint.push_back(point(0, 0));
65 }
66
67 /**
68 * Define the graphic position of the blockSchema. Computes the graphic
69 * position of all the elements, in particular the inputs and outputs.
70 * This method must be called before draw(), otherwise draw is not allowed
71 */
place(double x,double y,int orientation)72 void blockSchema::place(double x, double y, int orientation)
73 {
74 beginPlace(x, y, orientation);
75
76 placeInputPoints();
77 placeOutputPoints();
78
79 endPlace();
80 }
81
82 /**
83 * Returns an input point
84 */
inputPoint(unsigned int i) const85 point blockSchema::inputPoint(unsigned int i) const
86 {
87 faustassert(placed());
88 faustassert(i < inputs());
89 return fInputPoint[i];
90 }
91
92 /**
93 * Returns an output point
94 */
outputPoint(unsigned int i) const95 point blockSchema::outputPoint(unsigned int i) const
96 {
97 faustassert(placed());
98 faustassert(i < outputs());
99 return fOutputPoint[i];
100 }
101
102 /**
103 * Computes the input points according to the position and the
104 * orientation of the blockSchema
105 */
placeInputPoints()106 void blockSchema::placeInputPoints()
107 {
108 int N = inputs();
109
110 if (orientation() == kLeftRight) {
111 double px = x();
112 double py = y() + (height() - dWire * (N - 1)) / 2;
113
114 for (int i = 0; i < N; i++) {
115 fInputPoint[i] = point(px, py + i * dWire);
116 }
117
118 } else {
119 double px = x() + width();
120 double py = y() + height() - (height() - dWire * (N - 1)) / 2;
121
122 for (int i = 0; i < N; i++) {
123 fInputPoint[i] = point(px, py - i * dWire);
124 }
125 }
126 }
127
128 /**
129 * Computes the output points according to the position and the
130 * orientation of the blockSchema
131 */
placeOutputPoints()132 void blockSchema::placeOutputPoints()
133 {
134 int N = outputs();
135
136 if (orientation() == kLeftRight) {
137 double px = x() + width();
138 double py = y() + (height() - dWire * (N - 1)) / 2;
139
140 for (int i = 0; i < N; i++) {
141 fOutputPoint[i] = point(px, py + i * dWire);
142 }
143
144 } else {
145 double px = x();
146 double py = y() + height() - (height() - dWire * (N - 1)) / 2;
147
148 for (int i = 0; i < N; i++) {
149 fOutputPoint[i] = point(px, py - i * dWire);
150 }
151 }
152 }
153
154 /**
155 * Draw the blockSchema on the device. This methos can only
156 * be called after the blockSchema have been placed
157 */
draw(device & dev)158 void blockSchema::draw(device& dev)
159 {
160 faustassert(placed());
161
162 drawRectangle(dev);
163 drawText(dev);
164 drawOrientationMark(dev);
165 drawInputArrows(dev);
166 }
167
168 /**
169 * Draw the colored rectangle with the optional link
170 */
drawRectangle(device & dev)171 void blockSchema::drawRectangle(device& dev)
172 {
173 dev.rect(x() + dHorz, y() + dVert, width() - 2 * dHorz, height() - 2 * dVert, fColor.c_str(), fLink.c_str());
174 }
175
176 /**
177 * Draw the text centered on the box
178 */
drawText(device & dev)179 void blockSchema::drawText(device& dev)
180 {
181 dev.text(x() + width() / 2, y() + height() / 2, fText.c_str(), fLink.c_str());
182 }
183
184 /**
185 * Draw the orientation mark, a small point that indicates
186 * the first input (like integrated circuits)
187 */
drawOrientationMark(device & dev)188 void blockSchema::drawOrientationMark(device& dev)
189 {
190 double px, py;
191
192 if (orientation() == kLeftRight) {
193 px = x() + dHorz;
194 py = y() + dVert;
195 } else {
196 px = x() + width() - dHorz;
197 py = y() + height() - dVert;
198 }
199
200 dev.markSens(px, py, orientation());
201 }
202
203 /**
204 * Draw horizontal arrows from the input points to the
205 * blockSchema rectangle
206 */
drawInputArrows(device & dev)207 void blockSchema::drawInputArrows(device& dev)
208 {
209 double dx = (orientation() == kLeftRight) ? dHorz : -dHorz;
210
211 for (unsigned int i = 0; i < inputs(); i++) {
212 point p = fInputPoint[i];
213 dev.fleche(p.x + dx, p.y, 0, orientation());
214 }
215 }
216
217 /**
218 * Draw horizontal arrows from the input points to the
219 * blockSchema rectangle
220 */
collectTraits(collector & c)221 void blockSchema::collectTraits(collector& c)
222 {
223 collectInputWires(c);
224 collectOutputWires(c);
225 }
226
227 /**
228 * Draw horizontal arrows from the input points to the
229 * blockSchema rectangle
230 */
collectInputWires(collector & c)231 void blockSchema::collectInputWires(collector& c)
232 {
233 double dx = (orientation() == kLeftRight) ? dHorz : -dHorz;
234
235 for (unsigned int i = 0; i < inputs(); i++) {
236 point p = fInputPoint[i];
237 c.addTrait(trait(point(p.x, p.y), point(p.x + dx, p.y))); // in->out direction
238 c.addInput(point(p.x + dx, p.y));
239 }
240 }
241
242 /**
243 * Draw horizontal line from the blockSchema rectangle to the
244 * output points
245 */
collectOutputWires(collector & c)246 void blockSchema::collectOutputWires(collector& c)
247 {
248 double dx = (orientation() == kLeftRight) ? dHorz : -dHorz;
249
250 for (unsigned int i = 0; i < outputs(); i++) {
251 point p = fOutputPoint[i];
252 c.addTrait(trait(point(p.x - dx, p.y), point(p.x, p.y))); // in->out direction
253 c.addOutput(point(p.x - dx, p.y));
254 }
255 }
256