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