added support for min/max contrast to eeprom interface and use it (#5473)
[opentx.git] / companion / src / modelprinter.cpp
blobdca0221c762234ed3bbdaecb5a8b8d7db782fc5c
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "helpers.h"
22 #include "modelprinter.h"
23 #include "multiprotocols.h"
25 #include <QApplication>
26 #include <QPainter>
27 #include <QFile>
28 #include <QUrl>
29 #include "multiprotocols.h"
31 QString changeColor(const QString & input, const QString & to, const QString & from)
33 QString result = input;
34 return result.replace("color="+from, "color="+to);
37 ModelPrinter::ModelPrinter(Firmware * firmware, const GeneralSettings & generalSettings, const ModelData & model):
38 firmware(firmware),
39 generalSettings(generalSettings),
40 model(model)
44 ModelPrinter::~ModelPrinter()
48 void debugHtml(const QString & html)
50 QFile file("foo.html");
51 file.open(QIODevice::Truncate | QIODevice::WriteOnly);
52 file.write(html.toUtf8());
53 file.close();
56 QString addFont(const QString & input, const QString & color, const QString & size, const QString & face)
58 QString colorStr;
59 if (!color.isEmpty()) {
60 colorStr = "color=" + color;
62 QString sizeStr;
63 if (!size.isEmpty()) {
64 sizeStr = "size=" + size;
66 QString faceStr;
67 if (!face.isEmpty()) {
68 faceStr = "face='" + face + "'";
70 return "<font " + sizeStr + " " + faceStr + " " + colorStr + ">" + input + "</font>";
73 QString ModelPrinter::printEEpromSize()
75 return tr("%1 bytes").arg(getCurrentEEpromInterface()->getSize(model));
78 QString ModelPrinter::printChannelName(int idx)
80 QString str = RawSource(SOURCE_TYPE_CH, idx).toString(&model, &generalSettings);
81 if (firmware->getCapability(ChannelsName)) {
82 str = str.leftJustified(firmware->getCapability(ChannelsName) + 5, ' ', false);
84 str.append(' ');
85 return str.toHtmlEscaped();
88 QString ModelPrinter::printTrimIncrementMode()
90 switch (model.trimInc) {
91 case -2:
92 return tr("Exponential");
93 case -1:
94 return tr("Extra Fine");
95 case 0:
96 return tr("Fine");
97 case 1:
98 return tr("Medium");
99 case 2:
100 return tr("Coarse");
101 default:
102 return tr("Unknown");
106 QString ModelPrinter::printThrottleTrimMode()
108 return model.thrTrim ? tr("Enabled") : tr("Disabled");
111 QString ModelPrinter::printModuleProtocol(unsigned int protocol)
113 static const char * strings[] = {
114 "OFF",
115 "PPM",
116 "Silverlit A", "Silverlit B", "Silverlit C",
117 "CTP1009",
118 "LP45", "DSM2", "DSMX",
119 "PPM16", "PPMsim",
120 "FrSky XJT (D16)", "FrSky XJT (D8)", "FrSky XJT (LR12)", "FrSky DJT",
121 "Crossfire",
122 "DIY Multiprotocol Module",
123 "FrSky R9M Module",
124 "SBUS output at VBat"
127 return CHECK_IN_ARRAY(strings, protocol);
130 QString ModelPrinter::printMultiRfProtocol(int rfProtocol, bool custom)
132 static const char *strings[] = {
133 "FlySky", "Hubsan", "FrSky", "Hisky", "V2x2", "DSM", "Devo", "YD717", "KN", "SymaX", "SLT", "CX10", "CG023",
134 "Bayang", "ESky", "MT99XX", "MJXQ", "Shenqi", "FY326", "SFHSS", "J6 PRO","FQ777","Assan","Hontai","OLRS",
135 "FlySky AFHDS2A", "Q2x2", "Walkera", "Q303", "GW008", "DM002", "CABELL", "Esky 150", "H8 3D"
137 if (custom)
138 return "Custom - proto " + QString::number(rfProtocol);
139 else
140 return CHECK_IN_ARRAY(strings, rfProtocol);
143 QString ModelPrinter::printMultiSubType(int rfProtocol, bool custom, unsigned int subType) {
144 /* custom protocols */
146 if (custom)
147 rfProtocol = MM_RF_CUSTOM_SELECTED;
149 Multiprotocols::MultiProtocolDefinition pdef = multiProtocols.getProtocol(rfProtocol);
151 if (subType < (unsigned int) pdef.subTypeStrings.size())
152 return qApp->translate("Multiprotocols", qPrintable(pdef.subTypeStrings[subType]));
153 else
154 return "???";
157 QString ModelPrinter::printModule(int idx) {
158 const ModuleData &module = model.moduleData[idx];
159 if (module.protocol == PULSES_OFF)
160 return printModuleProtocol(module.protocol);
161 else if (module.protocol == PULSES_PPM)
162 return tr("%1, Channels(%2-%3), PPM delay(%4usec), Pulse polarity(%5)").arg(printModuleProtocol(module.protocol)).arg(module.channelsStart + 1).arg(module.channelsStart + module.channelsCount).arg(module.ppm.delay).arg(module.polarityToString());
163 else {
164 QString result = tr("%1, Channels(%2-%3)").arg(printModuleProtocol(module.protocol)).arg(module.channelsStart+1).arg(module.channelsStart+module.channelsCount);
165 if (module.protocol != PULSES_PXX_XJT_D8) {
166 result += " " + tr("Receiver number(%1)").arg(module.modelId);
168 if (module.protocol == PULSES_MULTIMODULE)
169 result += " " + tr("radio Protocol %1, subType %2, option value %3").arg(printMultiRfProtocol(module.multi.rfProtocol, module.multi.customProto)).arg(printMultiSubType(module.multi.rfProtocol, module.multi.customProto, module.subType)).arg(module.multi.optionValue);
170 return result;
174 QString ModelPrinter::printTrainerMode()
176 QString result;
177 switch (model.trainerMode) {
178 case 1:
179 result = tr("Slave/Jack"); // TODO + tr(": Channel start: %1, %2 Channels, %3usec Delay, Pulse polarity %4").arg(module.channelsStart+1).arg(module.channelsCount).arg(module.ppm.delay).arg(module.polarityToString());
180 break;
181 case 2:
182 result = tr("Master/SBUS Module");
183 break;
184 case 3:
185 result = tr("Master/CPPM Module");
186 break;
187 case 4:
188 result = tr("Master/SBUS in battery compartment");
189 break;
190 default:
191 result = tr("Master/Jack");
193 return result;
196 QString ModelPrinter::printHeliSwashType ()
198 switch (model.swashRingData.type) {
199 case HELI_SWASH_TYPE_90:
200 return tr("90");
201 case HELI_SWASH_TYPE_120:
202 return tr("120");
203 case HELI_SWASH_TYPE_120X:
204 return tr("120X");
205 case HELI_SWASH_TYPE_140:
206 return tr("140");
207 case HELI_SWASH_TYPE_NONE:
208 return tr("Off");
209 default:
210 return "???";
215 QString ModelPrinter::printCenterBeep()
217 QStringList strl;
218 if (model.beepANACenter & 0x01)
219 strl << tr("Rudder");
220 if (model.beepANACenter & 0x02)
221 strl << tr("Elevator");
222 if (model.beepANACenter & 0x04)
223 strl << tr("Throttle");
224 if (model.beepANACenter & 0x08)
225 strl << tr("Aileron");
226 if (IS_HORUS(firmware->getBoard())) {
227 // TODO
228 qDebug() << "ModelPrinter::printCenterBeep() TODO";
230 else if (IS_TARANIS(firmware->getBoard())) {
231 if (model.beepANACenter & 0x10)
232 strl << "S1";
233 if (model.beepANACenter & 0x20)
234 strl << "S2";
235 if (model.beepANACenter & 0x40)
236 strl << "S3";
237 if (model.beepANACenter & 0x80)
238 strl << "LS";
239 if (model.beepANACenter & 0x100)
240 strl << "RS";
242 else {
243 if (model.beepANACenter & 0x10)
244 strl << "P1";
245 if (model.beepANACenter & 0x20)
246 strl << "P2";
247 if (model.beepANACenter & 0x40)
248 strl << "P3";
250 return strl.join(", ");
253 QString ModelPrinter::printTimer(int idx)
255 return printTimer(model.timers[idx]);
258 QString ModelPrinter::printTimer(const TimerData & timer)
260 QStringList result;
261 if (firmware->getCapability(TimersName) && timer.name[0])
262 result += tr("Name(%1)").arg(timer.name);
263 result += QString("%1:%2").arg(timer.val/60, 2, 10, QChar('0')).arg(timer.val%60, 2, 10, QChar('0'));
264 result += timer.mode.toString();
265 if (timer.persistent)
266 result += tr("Persistent");
267 if (timer.minuteBeep)
268 result += tr("MinuteBeep");
269 if (timer.countdownBeep == TimerData::COUNTDOWN_BEEPS)
270 result += tr("CountDown(Beeps)");
271 else if (timer.countdownBeep == TimerData::COUNTDOWN_VOICE)
272 result += tr("CountDown(Voice)");
273 else if (timer.countdownBeep == TimerData::COUNTDOWN_HAPTIC)
274 result += tr("CountDown(Haptic)");
275 return result.join(", ");
278 QString ModelPrinter::printTrim(int flightModeIndex, int stickIndex)
280 const FlightModeData & fm = model.flightModeData[flightModeIndex];
282 if (fm.trimMode[stickIndex] == -1) {
283 return tr("Off");
285 else {
286 if (fm.trimRef[stickIndex] == flightModeIndex) {
287 return QString("%1").arg(fm.trim[stickIndex]);
289 else {
290 if (fm.trimMode[stickIndex] == 0) {
291 return tr("FM%1").arg(fm.trimRef[stickIndex]);
293 else {
294 if (fm.trim[stickIndex] < 0)
295 return tr("FM%1%2").arg(fm.trimRef[stickIndex]).arg(fm.trim[stickIndex]);
296 else
297 return tr("FM%1+%2").arg(fm.trimRef[stickIndex]).arg(fm.trim[stickIndex]);
303 QString ModelPrinter::printGlobalVar(int flightModeIndex, int gvarIndex)
305 const FlightModeData & fm = model.flightModeData[flightModeIndex];
307 if (fm.gvars[gvarIndex] <= 1024) {
308 //double val = fm.gvars[gvarIndex] * model.gvarData[gvarIndex].multiplierGet();
309 return QString("%1").arg(fm.gvars[gvarIndex] * model.gvarData[gvarIndex].multiplierGet());
311 else {
312 int num = fm.gvars[gvarIndex] - 1025;
313 if (num >= flightModeIndex) num++;
314 return tr("FM%1").arg(num);
318 QString ModelPrinter::printRotaryEncoder(int flightModeIndex, int reIndex)
320 const FlightModeData & fm = model.flightModeData[flightModeIndex];
322 if (fm.rotaryEncoders[reIndex] <= 1024) {
323 return QString("%1").arg(fm.rotaryEncoders[reIndex]);
325 else {
326 int num = fm.rotaryEncoders[reIndex] - 1025;
327 if (num >= flightModeIndex) num++;
328 return tr("FM%1").arg(num);
332 QString ModelPrinter::printInputName(int idx)
334 RawSourceType srcType = (firmware->getCapability(VirtualInputs) ? SOURCE_TYPE_VIRTUAL_INPUT : SOURCE_TYPE_STICK);
335 return RawSource(srcType, idx).toString(&model, &generalSettings).toHtmlEscaped();
338 QString ModelPrinter::printInputLine(int idx)
340 return printInputLine(model.expoData[idx]);
343 QString ModelPrinter::printInputLine(const ExpoData & input)
345 QString str = "&nbsp;";
347 switch (input.mode) {
348 case (1): str += "&lt;-&nbsp;"; break;
349 case (2): str += "-&gt;&nbsp;"; break;
350 default: str += "&nbsp;&nbsp;&nbsp;"; break;
353 if (firmware->getCapability(VirtualInputs)) {
354 str += input.srcRaw.toString(&model, &generalSettings).toHtmlEscaped();
357 str += " " + tr("Weight").toHtmlEscaped() + QString("(%1)").arg(Helpers::getAdjustmentString(input.weight, &model, true).toHtmlEscaped());
358 if (input.curve.value)
359 str += " " + input.curve.toString(&model).toHtmlEscaped();
361 QString flightModesStr = printFlightModes(input.flightModes);
362 if (!flightModesStr.isEmpty())
363 str += " " + flightModesStr.toHtmlEscaped();
365 if (input.swtch.type != SWITCH_TYPE_NONE)
366 str += " " + tr("Switch").toHtmlEscaped() + QString("(%1)").arg(input.swtch.toString(getCurrentBoard(), &generalSettings)).toHtmlEscaped();
369 if (firmware->getCapability(VirtualInputs)) {
370 if (input.carryTrim>0)
371 str += " " + tr("NoTrim").toHtmlEscaped();
372 else if (input.carryTrim<0)
373 str += " " + RawSource(SOURCE_TYPE_TRIM, (-(input.carryTrim)-1)).toString(&model, &generalSettings).toHtmlEscaped();
376 if (input.offset)
377 str += " " + tr("Offset(%1)").arg(Helpers::getAdjustmentString(input.offset, &model)).toHtmlEscaped();
379 if (firmware->getCapability(HasExpoNames) && input.name[0])
380 str += QString(" [%1]").arg(input.name).toHtmlEscaped();
382 return str;
385 QString ModelPrinter::printMixerLine(const MixData & mix, bool showMultiplex, int highlightedSource)
387 QString str = "&nbsp;";
389 if (showMultiplex) {
390 switch(mix.mltpx) {
391 case (1): str += "*="; break;
392 case (2): str += ":="; break;
393 default: str += "+="; break;
396 else {
397 str += "&nbsp;&nbsp;";
399 // highlight source if needed
400 QString source = mix.srcRaw.toString(&model, &generalSettings).toHtmlEscaped();
401 if ( (mix.srcRaw.type == SOURCE_TYPE_CH) && (mix.srcRaw.index+1 == (int)highlightedSource) ) {
402 source = "<b>" + source + "</b>";
404 str += "&nbsp;" + source;
406 if (mix.mltpx == MLTPX_MUL && !showMultiplex)
407 str += " " + QString("MULT!").toHtmlEscaped();
408 else
409 str += " " + tr("Weight(%1)").arg(Helpers::getAdjustmentString(mix.weight, &model, true)).toHtmlEscaped();
411 QString flightModesStr = printFlightModes(mix.flightModes);
412 if (!flightModesStr.isEmpty())
413 str += " " + flightModesStr.toHtmlEscaped();
415 if (mix.swtch.type != SWITCH_TYPE_NONE)
416 str += " " + tr("Switch(%1)").arg(mix.swtch.toString(getCurrentBoard(), &generalSettings)).toHtmlEscaped();
418 if (mix.carryTrim > 0)
419 str += " " + tr("NoTrim").toHtmlEscaped();
420 else if (mix.carryTrim < 0)
421 str += " " + RawSource(SOURCE_TYPE_TRIM, (-(mix.carryTrim)-1)).toString(&model, &generalSettings);
423 if (firmware->getCapability(HasNoExpo) && mix.noExpo)
424 str += " " + tr("No DR/Expo").toHtmlEscaped();
425 if (mix.sOffset)
426 str += " " + tr("Offset(%1)").arg(Helpers::getAdjustmentString(mix.sOffset, &model)).toHtmlEscaped();
427 if (mix.curve.value)
428 str += " " + mix.curve.toString(&model).toHtmlEscaped();
429 int scale = firmware->getCapability(SlowScale);
430 if (scale == 0)
431 scale = 1;
432 if (mix.delayDown || mix.delayUp)
433 str += " " + tr("Delay(u%1:d%2)").arg((double)mix.delayUp/scale).arg((double)mix.delayDown/scale).toHtmlEscaped();
434 if (mix.speedDown || mix.speedUp)
435 str += " " + tr("Slow(u%1:d%2)").arg((double)mix.speedUp/scale).arg((double)mix.speedDown/scale).toHtmlEscaped();
436 if (mix.mixWarn)
437 str += " " + tr("Warn(%1)").arg(mix.mixWarn).toHtmlEscaped();
438 if (firmware->getCapability(HasMixerNames) && mix.name[0])
439 str += QString(" [%1]").arg(mix.name).toHtmlEscaped();
440 return str;
443 QString ModelPrinter::printFlightModeSwitch(const RawSwitch & swtch)
445 return swtch.toString(getCurrentBoard(), &generalSettings);
448 QString ModelPrinter::printFlightModeName(int index)
450 const FlightModeData & fm = model.flightModeData[index];
451 if (strlen(fm.name) > 0) {
452 return QString("%1").arg(fm.name);
454 else {
455 return tr("FM%1").arg(index);
459 QString ModelPrinter::printFlightModes(unsigned int flightModes)
461 int numFlightModes = firmware->getCapability(FlightModes);
462 if (numFlightModes && flightModes) {
463 if (flightModes == (unsigned int)(1<<numFlightModes) - 1) {
464 return tr("Disabled in all flight modes");
466 else {
467 QStringList list;
468 for (int i=0; i<numFlightModes; i++) {
469 if (!(flightModes & (1<<i))) {
470 list << printFlightModeName(i);
473 if (list.size() > 1)
474 return tr("Flight modes(%1)").arg(list.join(", "));
475 else
476 return tr("Flight mode(%1)").arg(list.join(", "));
479 else return "";
482 QString ModelPrinter::printLogicalSwitchLine(int idx)
484 QString result = "";
485 const LogicalSwitchData & ls = model.logicalSw[idx];
486 const QString sw1Name = RawSwitch(ls.val1).toString(getCurrentBoard(), &generalSettings);
487 const QString sw2Name = RawSwitch(ls.val2).toString(getCurrentBoard(), &generalSettings);
489 if (ls.isEmpty())
490 return result;
492 if (ls.andsw!=0) {
493 result +="( ";
495 switch (ls.getFunctionFamily()) {
496 case LS_FAMILY_EDGE:
497 result += tr("Edge(%1, [%2:%3])").arg(sw1Name).arg(ValToTim(ls.val2)).arg(ls.val3<0 ? tr("instant") : QString("%1").arg(ValToTim(ls.val2+ls.val3)));
498 break;
499 case LS_FAMILY_STICKY:
500 result += tr("Sticky(%1, %2)").arg(sw1Name).arg(sw2Name);
501 break;
502 case LS_FAMILY_TIMER:
503 result += tr("Timer(%1, %2)").arg(ValToTim(ls.val1)).arg(ValToTim(ls.val2));
504 break;
505 case LS_FAMILY_VOFS: {
506 RawSource source = RawSource(ls.val1);
507 RawSourceRange range = source.getRange(&model, generalSettings);
508 QString res;
509 if (ls.val1)
510 res += source.toString(&model, &generalSettings);
511 else
512 res += "0";
513 res.remove(" ");
514 if (ls.func == LS_FN_APOS || ls.func == LS_FN_ANEG)
515 res = "|" + res + "|";
516 else if (ls.func == LS_FN_DAPOS)
517 res = "|d(" + res + ")|";
518 else if (ls.func == LS_FN_DPOS)
519 result = "d(" + res + ")";
520 result += res;
521 if (ls.func == LS_FN_VEQUAL)
522 result += " = ";
523 else if (ls.func == LS_FN_APOS || ls.func == LS_FN_VPOS || ls.func == LS_FN_DPOS || ls.func == LS_FN_DAPOS)
524 result += " &gt; ";
525 else if (ls.func == LS_FN_ANEG || ls.func == LS_FN_VNEG)
526 result += " &lt; ";
527 else if (ls.func == LS_FN_VALMOSTEQUAL)
528 result += " ~ ";
529 else
530 result += " missing";
531 result += QString::number(range.step * (ls.val2 /*TODO+ source.getRawOffset(model)*/) + range.offset);
532 break;
534 case LS_FAMILY_VBOOL:
535 result += sw1Name;
536 switch (ls.func) {
537 case LS_FN_AND:
538 result += " AND ";
539 break;
540 case LS_FN_OR:
541 result += " OR ";
542 break;
543 case LS_FN_XOR:
544 result += " XOR ";
545 break;
546 default:
547 result += " bar ";
548 break;
550 result += sw2Name;
551 break;
553 case LS_FAMILY_VCOMP:
554 if (ls.val1)
555 result += RawSource(ls.val1).toString(&model, &generalSettings);
556 else
557 result += "0";
558 switch (ls.func) {
559 case LS_FN_EQUAL:
560 case LS_FN_VEQUAL:
561 result += " = ";
562 break;
563 case LS_FN_NEQUAL:
564 result += " != ";
565 break;
566 case LS_FN_GREATER:
567 result += " &gt; ";
568 break;
569 case LS_FN_LESS:
570 result += " &lt; ";
571 break;
572 case LS_FN_EGREATER:
573 result += " &gt;= ";
574 break;
575 case LS_FN_ELESS:
576 result += " &lt;= ";
577 break;
578 default:
579 result += " foo ";
580 break;
582 if (ls.val2)
583 result += RawSource(ls.val2).toString(&model, &generalSettings);
584 else
585 result += "0";
586 break;
589 if (ls.andsw != 0) {
590 result +=" ) AND ";
591 result += RawSwitch(ls.andsw).toString(getCurrentBoard(), &generalSettings);
594 if (firmware->getCapability(LogicalSwitchesExt)) {
595 if (ls.duration)
596 result += " " + tr("Duration(%1s)").arg(ls.duration/10.0);
597 if (ls.delay)
598 result += " " + tr("Delay(%1s)").arg(ls.delay/10.0);
601 return result;
604 QString ModelPrinter::printCustomFunctionLine(int idx)
606 QString result;
607 const CustomFunctionData & cf = model.customFn[idx];
608 if (cf.swtch.type == SWITCH_TYPE_NONE)
609 return result;
611 result += cf.swtch.toString(getCurrentBoard(), &generalSettings) + " - ";
612 result += cf.funcToString(&model) + " (";
613 result += cf.paramToString(&model) + ")";
614 if (!cf.repeatToString().isEmpty())
615 result += " " + cf.repeatToString();
616 if (!cf.enabledToString().isEmpty())
617 result += " " + cf.enabledToString();
618 return result;
621 QString ModelPrinter::printCurveName(int idx)
623 return model.curves[idx].nameToString(idx).toHtmlEscaped();
626 QString ModelPrinter::printCurve(int idx)
628 QString result;
629 const CurveData & curve = model.curves[idx];
630 result += (curve.type == CurveData::CURVE_TYPE_CUSTOM) ? tr("Custom") : tr("Standard");
631 result += ", [";
632 if (curve.type == CurveData::CURVE_TYPE_CUSTOM) {
633 for (int j=0; j<curve.count; j++) {
634 if (j != 0)
635 result += ", ";
636 result += QString("(%1, %2)").arg(curve.points[j].x).arg(curve.points[j].y);
639 else {
640 for (int j=0; j<curve.count; j++) {
641 if (j != 0)
642 result += ", ";
643 result += QString("%1").arg(curve.points[j].y);
646 result += "]";
647 return result;
650 CurveImage::CurveImage():
651 size(200),
652 image(size+1, size+1, QImage::Format_RGB32),
653 painter(&image)
655 painter.setBrush(QBrush("#FFFFFF"));
656 painter.setPen(QColor(0, 0, 0));
657 painter.drawRect(0, 0, size, size);
659 painter.setPen(QColor(0, 0, 0));
660 painter.drawLine(0, size/2, size, size/2);
661 painter.drawLine(size/2, 0, size/2, size);
662 for (int i=0; i<21; i++) {
663 painter.drawLine(size/2-5, (size*i)/(20), size/2+5, (size*i)/(20));
664 painter.drawLine((size*i)/(20), size/2-5, (size*i)/(20), size/2+5);
668 void CurveImage::drawCurve(const CurveData & curve, QColor color)
670 painter.setPen(QPen(color, 2, Qt::SolidLine));
671 for (int j=1; j<curve.count; j++) {
672 if (curve.type == CurveData::CURVE_TYPE_CUSTOM)
673 painter.drawLine(size/2+(size*curve.points[j-1].x)/200, size/2-(size*curve.points[j-1].y)/200, size/2+(size*curve.points[j].x)/200, size/2-(size*curve.points[j].y)/200);
674 else
675 painter.drawLine(size*(j-1)/(curve.count-1), size/2-(size*curve.points[j-1].y)/200, size*(j)/(curve.count-1), size/2-(size*curve.points[j].y)/200);
679 QString ModelPrinter::createCurveImage(int idx, QTextDocument * document)
681 CurveImage image;
682 image.drawCurve(model.curves[idx], colors[idx]);
683 QString filename = QString("mydata://curve-%1-%2.png").arg((uint64_t)this).arg(idx);
684 if (document)
685 document->addResource(QTextDocument::ImageResource, QUrl(filename), image.get());
686 // qDebug() << "ModelPrinter::createCurveImage()" << idx << filename;
687 return filename;
690 QString ModelPrinter::printGlobalVarUnit(int idx)
692 return model.gvarData[idx].unitToString().toHtmlEscaped();
695 QString ModelPrinter::printGlobalVarPrec(int idx)
697 return model.gvarData[idx].precToString().toHtmlEscaped();
700 QString ModelPrinter::printGlobalVarMin(int idx)
702 return QString::number(model.gvarData[idx].getMinPrec());
705 QString ModelPrinter::printGlobalVarMax(int idx)
707 return QString::number(model.gvarData[idx].getMaxPrec());
710 QString ModelPrinter::printGlobalVarPopup(int idx)
712 return (model.gvarData[idx].popup ? "Y" : "N" );
715 QString ModelPrinter::printOutputValueGVar(int val)
717 QString result = "";
718 if (abs(val) > 10000) {
719 if (val < 0)
720 result = "-";
721 result.append(RawSource(SOURCE_TYPE_GVAR, abs(val)-10001).toString(&model));
723 else {
724 if (val >= 0)
725 result = "+";
726 result.append(QString::number((qreal)val/10, 'f', 1) + "%");
728 return result;
731 QString ModelPrinter::printOutputOffset(int idx)
733 return printOutputValueGVar(model.limitData[idx].offset);
736 QString ModelPrinter::printOutputMin(int idx)
738 return printOutputValueGVar(model.limitData[idx].min);
741 QString ModelPrinter::printOutputMax(int idx)
743 return printOutputValueGVar(model.limitData[idx].max);
746 QString ModelPrinter::printOutputRevert(int idx)
748 return model.limitData[idx].revertToString();
751 QString ModelPrinter::printOutputPpmCenter(int idx)
753 return QString::number(model.limitData[idx].ppmCenter + 1500);
756 QString ModelPrinter::printOutputCurve(int idx)
758 return CurveReference(CurveReference::CURVE_REF_CUSTOM, model.limitData[idx].curve.value).toString(&model, false);
761 QString ModelPrinter::printOutputSymetrical(int idx)
763 return (model.limitData[idx].symetrical ? "Y": "N");