1 /*******************************************************************
2
3 Part of the Fritzing project - http://fritzing.org
4 Copyright (c) 2007-2014 Fachhochschule Potsdam - http://fh-potsdam.de
5
6 Fritzing 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 3 of the License, or
9 (at your option) any later version.
10
11 Fritzing 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 Fritzing. If not, see <http://www.gnu.org/licenses/>.
18
19 ********************************************************************
20
21 $Revision: 6984 $:
22 $Author: irascibl@gmail.com $:
23 $Date: 2013-04-22 23:44:56 +0200 (Mo, 22. Apr 2013) $
24
25 ********************************************************************/
26
27 #include "ruler.h"
28 #include "../utils/graphicsutils.h"
29 #include "../fsvgrenderer.h"
30 #include "../sketch/infographicsview.h"
31 #include "../svg/svgfilesplitter.h"
32 #include "moduleidnames.h"
33 #include "../utils/textutils.h"
34 #include "../utils/boundedregexpvalidator.h"
35
36 #include <QHBoxLayout>
37 #include <QVBoxLayout>
38 #include <QFrame>
39 #include <QLabel>
40 #include <QLineEdit>
41 #include <QRegExp>
42 #include <qmath.h>
43
44 static const int IndexCm = 0;
45 static const int IndexIn = 1;
46
47 static QString DefaultWidth = "";
48
Ruler(ModelPart * modelPart,ViewLayer::ViewID viewID,const ViewGeometry & viewGeometry,long id,QMenu * itemMenu,bool doLabel)49 Ruler::Ruler( ModelPart * modelPart, ViewLayer::ViewID viewID, const ViewGeometry & viewGeometry, long id, QMenu * itemMenu, bool doLabel)
50 : PaletteItem(modelPart, viewID, viewGeometry, id, itemMenu, doLabel)
51 {
52 m_widthEditor = NULL;
53 m_unitsEditor = NULL;
54 m_widthValidator = NULL;
55 QString w = modelPart->localProp("width").toString();
56 if (w.isEmpty()) {
57 if (DefaultWidth.isEmpty()) {
58 DefaultWidth = modelPart->properties().value("width", "10cm");
59 }
60 m_modelPart->setLocalProp("width", DefaultWidth);
61 }
62 }
63
~Ruler()64 Ruler::~Ruler() {
65 }
66
resizeMM(double magnitude,double unitsFlag,const LayerHash & viewLayers)67 void Ruler::resizeMM(double magnitude, double unitsFlag, const LayerHash & viewLayers) {
68
69 // note this really isn't resizeMM but resizeUnits
70
71 Q_UNUSED(viewLayers);
72
73 double w = TextUtils::convertToInches(prop("width"));
74 QString units((unitsFlag == IndexCm) ? "cm" : "in");
75 double newW = TextUtils::convertToInches(QString::number(magnitude) + units);
76 if (w == newW) return;
77
78 QString s = makeSvg(newW);
79
80 bool result = resetRenderer(s);
81 if (result) {
82 modelPart()->setLocalProp("width", QVariant(QString::number(magnitude) + units));
83 }
84 // DebugDialog::debug(QString("fast load result %1 %2").arg(result).arg(s));
85
86 }
87
retrieveSvg(ViewLayer::ViewLayerID viewLayerID,QHash<QString,QString> & svgHash,bool blackOnly,double dpi,double & factor)88 QString Ruler::retrieveSvg(ViewLayer::ViewLayerID viewLayerID, QHash<QString, QString> & svgHash, bool blackOnly, double dpi, double & factor)
89 {
90 double w = TextUtils::convertToInches(m_modelPart->localProp("width").toString());
91 if (w != 0) {
92 QString xml;
93 switch (viewLayerID) {
94 case ViewLayer::BreadboardRuler:
95 case ViewLayer::SchematicRuler:
96 case ViewLayer::PcbRuler:
97 xml = makeSvg(w);
98 break;
99 default:
100 break;
101 }
102
103 if (!xml.isEmpty()) {
104 return PaletteItemBase::normalizeSvg(xml, viewLayerID, blackOnly, dpi, factor);
105 }
106 }
107
108 return PaletteItemBase::retrieveSvg(viewLayerID, svgHash, blackOnly, dpi, factor);
109 }
110
makeSvg(double inches)111 QString Ruler::makeSvg(double inches) {
112 double cm = 1 / 2.54;
113 double offset = 0.125;
114 double mmW = inches * 25.4;
115 QString svg = TextUtils::makeSVGHeader(GraphicsUtils::SVGDPI, GraphicsUtils::StandardFritzingDPI, (inches + offset + offset) * GraphicsUtils::SVGDPI, GraphicsUtils::SVGDPI);
116 svg += "<g font-family='Droid Sans' text-anchor='middle' font-size='100' stroke-width='1' stroke='black'>";
117 int counter = 0;
118 for (int i = 0; i <= qCeil(mmW); i++) {
119 double h = cm / 4;
120 double x = (offset + (i / 25.4)) * GraphicsUtils::StandardFritzingDPI;
121 if (i % 10 == 0) {
122 h = cm / 2;
123 double y = (h + .1) * GraphicsUtils::StandardFritzingDPI;
124 svg += QString("<text x='%1' y='%2'>%3</text>")
125 .arg(x)
126 .arg(y)
127 .arg(QString::number(counter++));
128 if (counter == 1) {
129 svg += QString("<text x='%1' y='%2'>cm</text>").arg(x + 103).arg(y);
130 }
131 }
132 else if (i % 5 == 0) {
133 h = 3 * cm / 8;
134 }
135 svg += QString("<line x1='%1' y1='0' x2='%1' y2='%2' />\n")
136 .arg(x)
137 .arg(h * GraphicsUtils::StandardFritzingDPI);
138 }
139 counter = 0;
140 for (int i = 0; i <= inches * 16; i++) {
141 double h = 0.125;
142 double x = (offset + (i / 16.0)) * GraphicsUtils::StandardFritzingDPI;
143 if (i % 16 == 0) {
144 h = .125 + (3.0 / 16);
145 double y = 1000 - ((h + .015) * GraphicsUtils::StandardFritzingDPI);
146 svg += QString("<text x='%1' y='%2'>%3</text>")
147 .arg(x)
148 .arg(y)
149 .arg(QString::number(counter++));
150 if (counter == 1) {
151 svg += QString("<text x='%1' y='%2'>in</text>").arg(x + 81).arg(y);
152 }
153 }
154 else if (i % 8 == 0) {
155 h = .125 + (2.0 / 16);
156 }
157 else if (i % 4 == 0) {
158 h = .125 + (1.0 / 16);
159 }
160 svg += QString("<line x1='%1' y1='%2' x2='%1' y2='1000' />\n")
161 .arg(x)
162 .arg(1000 - (h * GraphicsUtils::StandardFritzingDPI));
163 }
164
165 for (int i = 0; i <= inches * 10; i++) {
166 double x = (offset + (i / 10.0)) * GraphicsUtils::StandardFritzingDPI;
167 double h = .125 + (3.0 / 16);
168 double h2 = h - (cm / 4);
169 if (i % 10 != 0) {
170 if (i % 5 == 0) {
171 h2 = .125 + (2.0 / 16);
172 }
173 svg += QString("<line x1='%1' y1='%2' x2='%1' y2='%3' />\n")
174 .arg(x)
175 .arg(1000 - (h * GraphicsUtils::StandardFritzingDPI))
176 .arg(1000 - (h2 * GraphicsUtils::StandardFritzingDPI));
177 }
178 }
179
180 svg += QString("<line x1='%1' y1='%2' x2='%3' y2='%2' stroke-width='1' stroke='black' />\n")
181 .arg(offset * GraphicsUtils::StandardFritzingDPI)
182 .arg((GraphicsUtils::StandardFritzingDPI / 2) - 40)
183 .arg((inches + offset) * GraphicsUtils::StandardFritzingDPI);
184 svg += "<g font-size='40'>\n";
185 svg += QString("<text x='%1' y='%2'>1/10</text>").arg((GraphicsUtils::StandardFritzingDPI * offset / 2.0) + 7).arg(780);
186 svg += QString("<text x='%1' y='%2'>1/16</text>").arg((GraphicsUtils::StandardFritzingDPI * offset / 2.0) + 7).arg(990);
187 svg += "</g>";
188
189
190 svg += "</g></svg>";
191 return svg;
192 }
193
hasCustomSVG()194 bool Ruler::hasCustomSVG() {
195 switch (m_viewID) {
196 case ViewLayer::PCBView:
197 case ViewLayer::SchematicView:
198 case ViewLayer::BreadboardView:
199 return true;
200 default:
201 return ItemBase::hasCustomSVG();
202 }
203 }
204
collectExtraInfo(QWidget * parent,const QString & family,const QString & prop,const QString & value,bool swappingEnabled,QString & returnProp,QString & returnValue,QWidget * & returnWidget,bool & hide)205 bool Ruler::collectExtraInfo(QWidget * parent, const QString & family, const QString & prop, const QString & value, bool swappingEnabled, QString & returnProp, QString & returnValue, QWidget * & returnWidget, bool & hide)
206 {
207 bool result = PaletteItem::collectExtraInfo(parent, family, prop, value, swappingEnabled, returnProp, returnValue, returnWidget, hide);
208
209 if (prop.compare("width", Qt::CaseInsensitive) == 0) {
210 returnProp = tr("width");
211
212 int units = m_modelPart->localProp("width").toString().contains("cm") ? IndexCm : IndexIn;
213 QLineEdit * e1 = new QLineEdit();
214 QDoubleValidator * validator = new QDoubleValidator(e1);
215 validator->setRange(1.0, 20 * ((units == IndexCm) ? 2.54 : 1), 2);
216 validator->setNotation(QDoubleValidator::StandardNotation);
217 validator->setLocale(QLocale::C);
218 e1->setValidator(validator);
219 e1->setEnabled(swappingEnabled);
220 QString temp = m_modelPart->localProp("width").toString();
221 temp.chop(2);
222 e1->setText(temp);
223 e1->setObjectName("infoViewLineEdit");
224 e1->setMaximumWidth(80);
225
226 m_widthEditor = e1;
227 m_widthValidator = validator;
228
229 QComboBox * comboBox = new QComboBox(parent);
230 comboBox->setEditable(false);
231 comboBox->setEnabled(swappingEnabled);
232 comboBox->addItem("cm");
233 comboBox->addItem("in");
234 comboBox->setCurrentIndex(units);
235 m_unitsEditor = comboBox;
236 comboBox->setObjectName("infoViewComboBox");
237 comboBox->setMinimumWidth(60);
238
239
240 QHBoxLayout * hboxLayout = new QHBoxLayout();
241 hboxLayout->setAlignment(Qt::AlignLeft);
242 hboxLayout->setContentsMargins(0, 0, 0, 0);
243 hboxLayout->setSpacing(0);
244 hboxLayout->setMargin(0);
245
246
247 hboxLayout->addWidget(e1);
248 hboxLayout->addWidget(comboBox);
249
250 QFrame * frame = new QFrame();
251 frame->setLayout(hboxLayout);
252 frame->setObjectName("infoViewPartFrame");
253
254 connect(e1, SIGNAL(editingFinished()), this, SLOT(widthEntry()));
255 connect(comboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(unitsEntry(const QString &)));
256
257 returnValue = temp + QString::number(units);
258 returnWidget = frame;
259
260 return true;
261 }
262
263 return result;
264 }
265
widthEntry()266 void Ruler::widthEntry() {
267 QLineEdit * edit = qobject_cast<QLineEdit *>(sender());
268 if (edit == NULL) return;
269
270 QString t = edit->text();
271 QString w = prop("width");
272 w.chop(2);
273 if (t.compare(w) == 0) {
274 return;
275 }
276
277 InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
278 if (infoGraphicsView != NULL) {
279 int units = (m_unitsEditor->currentText() == "cm") ? IndexCm : IndexIn;
280 DefaultWidth = edit->text() + m_unitsEditor->currentText();
281 infoGraphicsView->resizeBoard(edit->text().toDouble(), units, false);
282 }
283 }
284
unitsEntry(const QString & units)285 void Ruler::unitsEntry(const QString & units) {
286 double inches = TextUtils::convertToInches(prop("width"));
287 if (units == "in") {
288 modelPart()->setLocalProp("width", QVariant(QString::number(inches) + "in"));
289 m_widthEditor->setText(QString::number(inches));
290 m_widthValidator->setTop(20);
291 }
292 else {
293 modelPart()->setLocalProp("width", QVariant(QString::number(inches * 2.54) + "cm"));
294 m_widthEditor->setText(QString::number(inches * 2.54));
295 m_widthValidator->setTop(20 * 2.54);
296 }
297 DefaultWidth = prop("width");
298 }
299
stickyEnabled()300 bool Ruler::stickyEnabled() {
301 return false;
302 }
303
hasPartLabel()304 bool Ruler::hasPartLabel() {
305 return false;
306 }
307
isPlural()308 ItemBase::PluralType Ruler::isPlural() {
309 return Singular;
310 }
311
312
addedToScene(bool temporary)313 void Ruler::addedToScene(bool temporary)
314 {
315 if (this->scene()) {
316 LayerHash viewLayers;
317 QString w = prop("width");
318 modelPart()->setLocalProp("width", ""); // makes sure resizeMM will do the work
319 double inches = TextUtils::convertToInches(w);
320 if (w.endsWith("cm")) {
321 resizeMM(inches * 2.54, IndexCm, viewLayers);
322 }
323 else {
324 resizeMM(inches, IndexIn, viewLayers);
325 }
326 }
327
328 return PaletteItem::addedToScene(temporary);
329 }
330
hasPartNumberProperty()331 bool Ruler::hasPartNumberProperty()
332 {
333 return false;
334 }
335
canFindConnectorsUnder()336 bool Ruler::canFindConnectorsUnder() {
337 return false;
338 }
339
useViewIDForPixmap(ViewLayer::ViewID,bool)340 ViewLayer::ViewID Ruler::useViewIDForPixmap(ViewLayer::ViewID, bool)
341 {
342 return ViewLayer::IconView;
343 }
344